aboutsummaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
Diffstat (limited to 'sources')
-rw-r--r--sources/CHANGES.md1219
-rw-r--r--sources/LICENSE.md1641
-rw-r--r--sources/README.md39
-rw-r--r--sources/adapters/jquery.js379
-rw-r--r--sources/ckeditor.js48
-rw-r--r--sources/config.js17
-rw-r--r--sources/contents.css208
-rw-r--r--sources/core/_bootstrap.js74
-rw-r--r--sources/core/ckeditor.js204
-rw-r--r--sources/core/ckeditor_base.js318
-rw-r--r--sources/core/ckeditor_basic.js94
-rw-r--r--sources/core/command.js275
-rw-r--r--sources/core/commanddefinition.js162
-rw-r--r--sources/core/config.js451
-rw-r--r--sources/core/creators/inline.js157
-rw-r--r--sources/core/creators/themedui.js541
-rw-r--r--sources/core/dataprocessor.js70
-rw-r--r--sources/core/dom.js13
-rw-r--r--sources/core/dom/comment.js53
-rw-r--r--sources/core/dom/document.js326
-rw-r--r--sources/core/dom/documentfragment.js62
-rw-r--r--sources/core/dom/domobject.js266
-rw-r--r--sources/core/dom/element.js2183
-rw-r--r--sources/core/dom/elementpath.js251
-rw-r--r--sources/core/dom/event.js208
-rw-r--r--sources/core/dom/iterator.js565
-rw-r--r--sources/core/dom/node.js902
-rw-r--r--sources/core/dom/nodelist.js43
-rw-r--r--sources/core/dom/range.js2978
-rw-r--r--sources/core/dom/rangelist.js199
-rw-r--r--sources/core/dom/text.js135
-rw-r--r--sources/core/dom/walker.js652
-rw-r--r--sources/core/dom/window.js95
-rw-r--r--sources/core/dtd.js349
-rw-r--r--sources/core/editable.js3266
-rw-r--r--sources/core/editor.js2039
-rw-r--r--sources/core/editor_basic.js36
-rw-r--r--sources/core/env.js361
-rw-r--r--sources/core/event.js389
-rw-r--r--sources/core/eventInfo.js115
-rw-r--r--sources/core/filter.js2540
-rw-r--r--sources/core/focusmanager.js281
-rw-r--r--sources/core/htmldataprocessor.js1036
-rw-r--r--sources/core/htmlparser.js205
-rw-r--r--sources/core/htmlparser/basicwriter.js152
-rw-r--r--sources/core/htmlparser/cdata.js48
-rw-r--r--sources/core/htmlparser/comment.js80
-rw-r--r--sources/core/htmlparser/element.js568
-rw-r--r--sources/core/htmlparser/filter.js407
-rw-r--r--sources/core/htmlparser/fragment.js646
-rw-r--r--sources/core/htmlparser/node.js156
-rw-r--r--sources/core/htmlparser/text.js70
-rw-r--r--sources/core/keystrokehandler.js169
-rw-r--r--sources/core/lang.js103
-rw-r--r--sources/core/loader.js225
-rw-r--r--sources/core/log.js127
-rw-r--r--sources/core/plugindefinition.js177
-rw-r--r--sources/core/plugins.js119
-rw-r--r--sources/core/resourcemanager.js228
-rw-r--r--sources/core/scriptloader.js202
-rw-r--r--sources/core/selection.js2204
-rw-r--r--sources/core/skin.js350
-rw-r--r--sources/core/style.js2102
-rw-r--r--sources/core/template.js68
-rw-r--r--sources/core/tools.js1916
-rw-r--r--sources/core/ui.js185
-rw-r--r--sources/lang/_translationstatus.txt63
-rw-r--r--sources/lang/af.js117
-rw-r--r--sources/lang/ar.js117
-rw-r--r--sources/lang/az.js117
-rw-r--r--sources/lang/bg.js117
-rw-r--r--sources/lang/bn.js117
-rw-r--r--sources/lang/bs.js117
-rw-r--r--sources/lang/ca.js117
-rw-r--r--sources/lang/cs.js117
-rw-r--r--sources/lang/cy.js117
-rw-r--r--sources/lang/da.js117
-rw-r--r--sources/lang/de-ch.js116
-rw-r--r--sources/lang/de.js117
-rw-r--r--sources/lang/el.js117
-rw-r--r--sources/lang/en-au.js117
-rw-r--r--sources/lang/en-ca.js117
-rw-r--r--sources/lang/en-gb.js117
-rw-r--r--sources/lang/en.js117
-rw-r--r--sources/lang/eo.js117
-rw-r--r--sources/lang/es.js117
-rw-r--r--sources/lang/et.js117
-rw-r--r--sources/lang/eu.js117
-rw-r--r--sources/lang/fa.js117
-rw-r--r--sources/lang/fi.js117
-rw-r--r--sources/lang/fo.js117
-rw-r--r--sources/lang/fr-ca.js117
-rw-r--r--sources/lang/fr.js117
-rw-r--r--sources/lang/gl.js117
-rw-r--r--sources/lang/gu.js117
-rw-r--r--sources/lang/he.js117
-rw-r--r--sources/lang/hi.js117
-rw-r--r--sources/lang/hr.js117
-rw-r--r--sources/lang/hu.js117
-rw-r--r--sources/lang/id.js116
-rw-r--r--sources/lang/is.js117
-rw-r--r--sources/lang/it.js117
-rw-r--r--sources/lang/ja.js117
-rw-r--r--sources/lang/ka.js117
-rw-r--r--sources/lang/km.js117
-rw-r--r--sources/lang/ko.js117
-rw-r--r--sources/lang/ku.js116
-rw-r--r--sources/lang/lt.js117
-rw-r--r--sources/lang/lv.js117
-rw-r--r--sources/lang/mk.js116
-rw-r--r--sources/lang/mn.js117
-rw-r--r--sources/lang/ms.js117
-rw-r--r--sources/lang/nb.js117
-rw-r--r--sources/lang/nl.js117
-rw-r--r--sources/lang/no.js117
-rw-r--r--sources/lang/oc.js117
-rw-r--r--sources/lang/pl.js117
-rw-r--r--sources/lang/pt-br.js116
-rw-r--r--sources/lang/pt.js117
-rw-r--r--sources/lang/ro.js117
-rw-r--r--sources/lang/ru.js117
-rw-r--r--sources/lang/si.js116
-rw-r--r--sources/lang/sk.js117
-rw-r--r--sources/lang/sl.js117
-rw-r--r--sources/lang/sq.js116
-rw-r--r--sources/lang/sr-latn.js117
-rw-r--r--sources/lang/sr.js117
-rw-r--r--sources/lang/sv.js116
-rw-r--r--sources/lang/th.js117
-rw-r--r--sources/lang/tr.js116
-rw-r--r--sources/lang/tt.js117
-rw-r--r--sources/lang/ug.js116
-rw-r--r--sources/lang/uk.js117
-rw-r--r--sources/lang/vi.js117
-rw-r--r--sources/lang/zh-cn.js117
-rw-r--r--sources/lang/zh.js117
-rw-r--r--sources/plugins/a11yhelp/dialogs/a11yhelp.js217
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/_translationstatus.txt25
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/af.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ar.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/az.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/bg.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ca.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/cs.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/cy.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/da.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/de-ch.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/de.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/el.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/en-gb.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/en.js159
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/eo.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/es.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/et.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/eu.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/fa.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/fi.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/fo.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/fr-ca.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/fr.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/gl.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/gu.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/he.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/hi.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/hr.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/hu.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/id.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/it.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ja.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/km.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ko.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ku.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/lt.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/lv.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/mk.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/mn.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/nb.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/nl.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/no.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/oc.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/pl.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/pt-br.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/pt.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ro.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ru.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/si.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sk.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sl.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sq.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sr-latn.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sr.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/sv.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/th.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/tr.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/tt.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/ug.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/uk.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/vi.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/zh-cn.js140
-rw-r--r--sources/plugins/a11yhelp/dialogs/lang/zh.js140
-rw-r--r--sources/plugins/a11yhelp/plugin.js51
-rw-r--r--sources/plugins/basicstyles/icons/bold.pngbin0 -> 580 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/bold.pngbin0 -> 1207 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/italic.pngbin0 -> 854 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/strike.pngbin0 -> 1357 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/subscript.pngbin0 -> 1189 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/superscript.pngbin0 -> 1156 bytes
-rw-r--r--sources/plugins/basicstyles/icons/hidpi/underline.pngbin0 -> 1084 bytes
-rw-r--r--sources/plugins/basicstyles/icons/italic.pngbin0 -> 611 bytes
-rw-r--r--sources/plugins/basicstyles/icons/strike.pngbin0 -> 627 bytes
-rw-r--r--sources/plugins/basicstyles/icons/subscript.pngbin0 -> 584 bytes
-rw-r--r--sources/plugins/basicstyles/icons/superscript.pngbin0 -> 594 bytes
-rw-r--r--sources/plugins/basicstyles/icons/underline.pngbin0 -> 541 bytes
-rw-r--r--sources/plugins/basicstyles/lang/af.js12
-rw-r--r--sources/plugins/basicstyles/lang/ar.js12
-rw-r--r--sources/plugins/basicstyles/lang/az.js12
-rw-r--r--sources/plugins/basicstyles/lang/bg.js12
-rw-r--r--sources/plugins/basicstyles/lang/bn.js12
-rw-r--r--sources/plugins/basicstyles/lang/bs.js12
-rw-r--r--sources/plugins/basicstyles/lang/ca.js12
-rw-r--r--sources/plugins/basicstyles/lang/cs.js12
-rw-r--r--sources/plugins/basicstyles/lang/cy.js12
-rw-r--r--sources/plugins/basicstyles/lang/da.js12
-rw-r--r--sources/plugins/basicstyles/lang/de-ch.js12
-rw-r--r--sources/plugins/basicstyles/lang/de.js12
-rw-r--r--sources/plugins/basicstyles/lang/el.js12
-rw-r--r--sources/plugins/basicstyles/lang/en-au.js12
-rw-r--r--sources/plugins/basicstyles/lang/en-ca.js12
-rw-r--r--sources/plugins/basicstyles/lang/en-gb.js12
-rw-r--r--sources/plugins/basicstyles/lang/en.js12
-rw-r--r--sources/plugins/basicstyles/lang/eo.js12
-rw-r--r--sources/plugins/basicstyles/lang/es.js12
-rw-r--r--sources/plugins/basicstyles/lang/et.js12
-rw-r--r--sources/plugins/basicstyles/lang/eu.js12
-rw-r--r--sources/plugins/basicstyles/lang/fa.js12
-rw-r--r--sources/plugins/basicstyles/lang/fi.js12
-rw-r--r--sources/plugins/basicstyles/lang/fo.js12
-rw-r--r--sources/plugins/basicstyles/lang/fr-ca.js12
-rw-r--r--sources/plugins/basicstyles/lang/fr.js12
-rw-r--r--sources/plugins/basicstyles/lang/gl.js12
-rw-r--r--sources/plugins/basicstyles/lang/gu.js12
-rw-r--r--sources/plugins/basicstyles/lang/he.js12
-rw-r--r--sources/plugins/basicstyles/lang/hi.js12
-rw-r--r--sources/plugins/basicstyles/lang/hr.js12
-rw-r--r--sources/plugins/basicstyles/lang/hu.js12
-rw-r--r--sources/plugins/basicstyles/lang/id.js12
-rw-r--r--sources/plugins/basicstyles/lang/is.js12
-rw-r--r--sources/plugins/basicstyles/lang/it.js12
-rw-r--r--sources/plugins/basicstyles/lang/ja.js12
-rw-r--r--sources/plugins/basicstyles/lang/ka.js12
-rw-r--r--sources/plugins/basicstyles/lang/km.js12
-rw-r--r--sources/plugins/basicstyles/lang/ko.js12
-rw-r--r--sources/plugins/basicstyles/lang/ku.js12
-rw-r--r--sources/plugins/basicstyles/lang/lt.js12
-rw-r--r--sources/plugins/basicstyles/lang/lv.js12
-rw-r--r--sources/plugins/basicstyles/lang/mk.js12
-rw-r--r--sources/plugins/basicstyles/lang/mn.js12
-rw-r--r--sources/plugins/basicstyles/lang/ms.js12
-rw-r--r--sources/plugins/basicstyles/lang/nb.js12
-rw-r--r--sources/plugins/basicstyles/lang/nl.js12
-rw-r--r--sources/plugins/basicstyles/lang/no.js12
-rw-r--r--sources/plugins/basicstyles/lang/oc.js12
-rw-r--r--sources/plugins/basicstyles/lang/pl.js12
-rw-r--r--sources/plugins/basicstyles/lang/pt-br.js12
-rw-r--r--sources/plugins/basicstyles/lang/pt.js12
-rw-r--r--sources/plugins/basicstyles/lang/ro.js12
-rw-r--r--sources/plugins/basicstyles/lang/ru.js12
-rw-r--r--sources/plugins/basicstyles/lang/si.js12
-rw-r--r--sources/plugins/basicstyles/lang/sk.js12
-rw-r--r--sources/plugins/basicstyles/lang/sl.js12
-rw-r--r--sources/plugins/basicstyles/lang/sq.js12
-rw-r--r--sources/plugins/basicstyles/lang/sr-latn.js12
-rw-r--r--sources/plugins/basicstyles/lang/sr.js12
-rw-r--r--sources/plugins/basicstyles/lang/sv.js12
-rw-r--r--sources/plugins/basicstyles/lang/th.js12
-rw-r--r--sources/plugins/basicstyles/lang/tr.js12
-rw-r--r--sources/plugins/basicstyles/lang/tt.js12
-rw-r--r--sources/plugins/basicstyles/lang/ug.js12
-rw-r--r--sources/plugins/basicstyles/lang/uk.js12
-rw-r--r--sources/plugins/basicstyles/lang/vi.js12
-rw-r--r--sources/plugins/basicstyles/lang/zh-cn.js12
-rw-r--r--sources/plugins/basicstyles/lang/zh.js12
-rw-r--r--sources/plugins/basicstyles/plugin.js209
-rw-r--r--sources/plugins/button/lang/af.js8
-rw-r--r--sources/plugins/button/lang/ar.js8
-rw-r--r--sources/plugins/button/lang/az.js8
-rw-r--r--sources/plugins/button/lang/bg.js8
-rw-r--r--sources/plugins/button/lang/ca.js8
-rw-r--r--sources/plugins/button/lang/cs.js8
-rw-r--r--sources/plugins/button/lang/da.js8
-rw-r--r--sources/plugins/button/lang/de-ch.js8
-rw-r--r--sources/plugins/button/lang/de.js8
-rw-r--r--sources/plugins/button/lang/el.js8
-rw-r--r--sources/plugins/button/lang/en-gb.js8
-rw-r--r--sources/plugins/button/lang/en.js8
-rw-r--r--sources/plugins/button/lang/eo.js8
-rw-r--r--sources/plugins/button/lang/es.js8
-rw-r--r--sources/plugins/button/lang/eu.js8
-rw-r--r--sources/plugins/button/lang/fa.js8
-rw-r--r--sources/plugins/button/lang/fi.js8
-rw-r--r--sources/plugins/button/lang/fr.js8
-rw-r--r--sources/plugins/button/lang/gl.js8
-rw-r--r--sources/plugins/button/lang/he.js8
-rw-r--r--sources/plugins/button/lang/hu.js8
-rw-r--r--sources/plugins/button/lang/id.js8
-rw-r--r--sources/plugins/button/lang/it.js8
-rw-r--r--sources/plugins/button/lang/ja.js8
-rw-r--r--sources/plugins/button/lang/km.js8
-rw-r--r--sources/plugins/button/lang/ko.js8
-rw-r--r--sources/plugins/button/lang/ku.js8
-rw-r--r--sources/plugins/button/lang/lt.js8
-rw-r--r--sources/plugins/button/lang/nb.js8
-rw-r--r--sources/plugins/button/lang/nl.js8
-rw-r--r--sources/plugins/button/lang/no.js8
-rw-r--r--sources/plugins/button/lang/oc.js8
-rw-r--r--sources/plugins/button/lang/pl.js8
-rw-r--r--sources/plugins/button/lang/pt-br.js8
-rw-r--r--sources/plugins/button/lang/pt.js8
-rw-r--r--sources/plugins/button/lang/ro.js8
-rw-r--r--sources/plugins/button/lang/ru.js8
-rw-r--r--sources/plugins/button/lang/sk.js8
-rw-r--r--sources/plugins/button/lang/sl.js8
-rw-r--r--sources/plugins/button/lang/sq.js8
-rw-r--r--sources/plugins/button/lang/sv.js8
-rw-r--r--sources/plugins/button/lang/tr.js8
-rw-r--r--sources/plugins/button/lang/tt.js8
-rw-r--r--sources/plugins/button/lang/ug.js8
-rw-r--r--sources/plugins/button/lang/uk.js8
-rw-r--r--sources/plugins/button/lang/vi.js8
-rw-r--r--sources/plugins/button/lang/zh-cn.js8
-rw-r--r--sources/plugins/button/lang/zh.js8
-rw-r--r--sources/plugins/button/plugin.js389
-rw-r--r--sources/plugins/clipboard/dev/clipboard.html190
-rw-r--r--sources/plugins/clipboard/dev/console.js49
-rw-r--r--sources/plugins/clipboard/dev/dnd.html185
-rw-r--r--sources/plugins/clipboard/dialogs/paste.js254
-rw-r--r--sources/plugins/clipboard/icons/copy-rtl.pngbin0 -> 506 bytes
-rw-r--r--sources/plugins/clipboard/icons/copy.pngbin0 -> 506 bytes
-rw-r--r--sources/plugins/clipboard/icons/cut-rtl.pngbin0 -> 776 bytes
-rw-r--r--sources/plugins/clipboard/icons/cut.pngbin0 -> 776 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/copy-rtl.pngbin0 -> 759 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/copy.pngbin0 -> 759 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/cut-rtl.pngbin0 -> 1576 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/cut.pngbin0 -> 1576 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/paste-rtl.pngbin0 -> 854 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/paste.pngbin0 -> 854 bytes
-rw-r--r--sources/plugins/clipboard/icons/paste-rtl.pngbin0 -> 464 bytes
-rw-r--r--sources/plugins/clipboard/icons/paste.pngbin0 -> 464 bytes
-rw-r--r--sources/plugins/clipboard/lang/af.js15
-rw-r--r--sources/plugins/clipboard/lang/ar.js15
-rw-r--r--sources/plugins/clipboard/lang/az.js15
-rw-r--r--sources/plugins/clipboard/lang/bg.js15
-rw-r--r--sources/plugins/clipboard/lang/bn.js15
-rw-r--r--sources/plugins/clipboard/lang/bs.js15
-rw-r--r--sources/plugins/clipboard/lang/ca.js15
-rw-r--r--sources/plugins/clipboard/lang/cs.js15
-rw-r--r--sources/plugins/clipboard/lang/cy.js15
-rw-r--r--sources/plugins/clipboard/lang/da.js15
-rw-r--r--sources/plugins/clipboard/lang/de-ch.js15
-rw-r--r--sources/plugins/clipboard/lang/de.js15
-rw-r--r--sources/plugins/clipboard/lang/el.js15
-rw-r--r--sources/plugins/clipboard/lang/en-au.js15
-rw-r--r--sources/plugins/clipboard/lang/en-ca.js15
-rw-r--r--sources/plugins/clipboard/lang/en-gb.js15
-rw-r--r--sources/plugins/clipboard/lang/en.js15
-rw-r--r--sources/plugins/clipboard/lang/eo.js15
-rw-r--r--sources/plugins/clipboard/lang/es.js15
-rw-r--r--sources/plugins/clipboard/lang/et.js15
-rw-r--r--sources/plugins/clipboard/lang/eu.js15
-rw-r--r--sources/plugins/clipboard/lang/fa.js15
-rw-r--r--sources/plugins/clipboard/lang/fi.js15
-rw-r--r--sources/plugins/clipboard/lang/fo.js15
-rw-r--r--sources/plugins/clipboard/lang/fr-ca.js15
-rw-r--r--sources/plugins/clipboard/lang/fr.js15
-rw-r--r--sources/plugins/clipboard/lang/gl.js15
-rw-r--r--sources/plugins/clipboard/lang/gu.js15
-rw-r--r--sources/plugins/clipboard/lang/he.js15
-rw-r--r--sources/plugins/clipboard/lang/hi.js15
-rw-r--r--sources/plugins/clipboard/lang/hr.js15
-rw-r--r--sources/plugins/clipboard/lang/hu.js15
-rw-r--r--sources/plugins/clipboard/lang/id.js15
-rw-r--r--sources/plugins/clipboard/lang/is.js15
-rw-r--r--sources/plugins/clipboard/lang/it.js15
-rw-r--r--sources/plugins/clipboard/lang/ja.js15
-rw-r--r--sources/plugins/clipboard/lang/ka.js15
-rw-r--r--sources/plugins/clipboard/lang/km.js15
-rw-r--r--sources/plugins/clipboard/lang/ko.js15
-rw-r--r--sources/plugins/clipboard/lang/ku.js15
-rw-r--r--sources/plugins/clipboard/lang/lt.js15
-rw-r--r--sources/plugins/clipboard/lang/lv.js15
-rw-r--r--sources/plugins/clipboard/lang/mk.js15
-rw-r--r--sources/plugins/clipboard/lang/mn.js15
-rw-r--r--sources/plugins/clipboard/lang/ms.js15
-rw-r--r--sources/plugins/clipboard/lang/nb.js15
-rw-r--r--sources/plugins/clipboard/lang/nl.js15
-rw-r--r--sources/plugins/clipboard/lang/no.js15
-rw-r--r--sources/plugins/clipboard/lang/oc.js15
-rw-r--r--sources/plugins/clipboard/lang/pl.js15
-rw-r--r--sources/plugins/clipboard/lang/pt-br.js15
-rw-r--r--sources/plugins/clipboard/lang/pt.js15
-rw-r--r--sources/plugins/clipboard/lang/ro.js15
-rw-r--r--sources/plugins/clipboard/lang/ru.js15
-rw-r--r--sources/plugins/clipboard/lang/si.js15
-rw-r--r--sources/plugins/clipboard/lang/sk.js15
-rw-r--r--sources/plugins/clipboard/lang/sl.js15
-rw-r--r--sources/plugins/clipboard/lang/sq.js15
-rw-r--r--sources/plugins/clipboard/lang/sr-latn.js15
-rw-r--r--sources/plugins/clipboard/lang/sr.js15
-rw-r--r--sources/plugins/clipboard/lang/sv.js15
-rw-r--r--sources/plugins/clipboard/lang/th.js15
-rw-r--r--sources/plugins/clipboard/lang/tr.js15
-rw-r--r--sources/plugins/clipboard/lang/tt.js15
-rw-r--r--sources/plugins/clipboard/lang/ug.js15
-rw-r--r--sources/plugins/clipboard/lang/uk.js15
-rw-r--r--sources/plugins/clipboard/lang/vi.js15
-rw-r--r--sources/plugins/clipboard/lang/zh-cn.js15
-rw-r--r--sources/plugins/clipboard/lang/zh.js15
-rw-r--r--sources/plugins/clipboard/plugin.js2772
-rw-r--r--sources/plugins/contextmenu/lang/af.js7
-rw-r--r--sources/plugins/contextmenu/lang/ar.js7
-rw-r--r--sources/plugins/contextmenu/lang/az.js7
-rw-r--r--sources/plugins/contextmenu/lang/bg.js7
-rw-r--r--sources/plugins/contextmenu/lang/bn.js7
-rw-r--r--sources/plugins/contextmenu/lang/bs.js7
-rw-r--r--sources/plugins/contextmenu/lang/ca.js7
-rw-r--r--sources/plugins/contextmenu/lang/cs.js7
-rw-r--r--sources/plugins/contextmenu/lang/cy.js7
-rw-r--r--sources/plugins/contextmenu/lang/da.js7
-rw-r--r--sources/plugins/contextmenu/lang/de-ch.js7
-rw-r--r--sources/plugins/contextmenu/lang/de.js7
-rw-r--r--sources/plugins/contextmenu/lang/el.js7
-rw-r--r--sources/plugins/contextmenu/lang/en-au.js7
-rw-r--r--sources/plugins/contextmenu/lang/en-ca.js7
-rw-r--r--sources/plugins/contextmenu/lang/en-gb.js7
-rw-r--r--sources/plugins/contextmenu/lang/en.js7
-rw-r--r--sources/plugins/contextmenu/lang/eo.js7
-rw-r--r--sources/plugins/contextmenu/lang/es.js7
-rw-r--r--sources/plugins/contextmenu/lang/et.js7
-rw-r--r--sources/plugins/contextmenu/lang/eu.js7
-rw-r--r--sources/plugins/contextmenu/lang/fa.js7
-rw-r--r--sources/plugins/contextmenu/lang/fi.js7
-rw-r--r--sources/plugins/contextmenu/lang/fo.js7
-rw-r--r--sources/plugins/contextmenu/lang/fr-ca.js7
-rw-r--r--sources/plugins/contextmenu/lang/fr.js7
-rw-r--r--sources/plugins/contextmenu/lang/gl.js7
-rw-r--r--sources/plugins/contextmenu/lang/gu.js7
-rw-r--r--sources/plugins/contextmenu/lang/he.js7
-rw-r--r--sources/plugins/contextmenu/lang/hi.js7
-rw-r--r--sources/plugins/contextmenu/lang/hr.js7
-rw-r--r--sources/plugins/contextmenu/lang/hu.js7
-rw-r--r--sources/plugins/contextmenu/lang/id.js7
-rw-r--r--sources/plugins/contextmenu/lang/is.js7
-rw-r--r--sources/plugins/contextmenu/lang/it.js7
-rw-r--r--sources/plugins/contextmenu/lang/ja.js7
-rw-r--r--sources/plugins/contextmenu/lang/ka.js7
-rw-r--r--sources/plugins/contextmenu/lang/km.js7
-rw-r--r--sources/plugins/contextmenu/lang/ko.js7
-rw-r--r--sources/plugins/contextmenu/lang/ku.js7
-rw-r--r--sources/plugins/contextmenu/lang/lt.js7
-rw-r--r--sources/plugins/contextmenu/lang/lv.js7
-rw-r--r--sources/plugins/contextmenu/lang/mk.js7
-rw-r--r--sources/plugins/contextmenu/lang/mn.js7
-rw-r--r--sources/plugins/contextmenu/lang/ms.js7
-rw-r--r--sources/plugins/contextmenu/lang/nb.js7
-rw-r--r--sources/plugins/contextmenu/lang/nl.js7
-rw-r--r--sources/plugins/contextmenu/lang/no.js7
-rw-r--r--sources/plugins/contextmenu/lang/oc.js7
-rw-r--r--sources/plugins/contextmenu/lang/pl.js7
-rw-r--r--sources/plugins/contextmenu/lang/pt-br.js7
-rw-r--r--sources/plugins/contextmenu/lang/pt.js7
-rw-r--r--sources/plugins/contextmenu/lang/ro.js7
-rw-r--r--sources/plugins/contextmenu/lang/ru.js7
-rw-r--r--sources/plugins/contextmenu/lang/si.js7
-rw-r--r--sources/plugins/contextmenu/lang/sk.js7
-rw-r--r--sources/plugins/contextmenu/lang/sl.js7
-rw-r--r--sources/plugins/contextmenu/lang/sq.js7
-rw-r--r--sources/plugins/contextmenu/lang/sr-latn.js7
-rw-r--r--sources/plugins/contextmenu/lang/sr.js7
-rw-r--r--sources/plugins/contextmenu/lang/sv.js7
-rw-r--r--sources/plugins/contextmenu/lang/th.js7
-rw-r--r--sources/plugins/contextmenu/lang/tr.js7
-rw-r--r--sources/plugins/contextmenu/lang/tt.js7
-rw-r--r--sources/plugins/contextmenu/lang/ug.js7
-rw-r--r--sources/plugins/contextmenu/lang/uk.js7
-rw-r--r--sources/plugins/contextmenu/lang/vi.js7
-rw-r--r--sources/plugins/contextmenu/lang/zh-cn.js7
-rw-r--r--sources/plugins/contextmenu/lang/zh.js7
-rw-r--r--sources/plugins/contextmenu/plugin.js159
-rw-r--r--sources/plugins/dialog/dialogDefinition.js1032
-rw-r--r--sources/plugins/dialog/plugin.js3399
-rw-r--r--sources/plugins/dialog/samples/assets/my_dialog.js49
-rw-r--r--sources/plugins/dialog/samples/dialog.html190
-rw-r--r--sources/plugins/dialogadvtab/plugin.js196
-rw-r--r--sources/plugins/dialogui/plugin.js1530
-rw-r--r--sources/plugins/elementspath/lang/af.js8
-rw-r--r--sources/plugins/elementspath/lang/ar.js8
-rw-r--r--sources/plugins/elementspath/lang/az.js8
-rw-r--r--sources/plugins/elementspath/lang/bg.js8
-rw-r--r--sources/plugins/elementspath/lang/bn.js8
-rw-r--r--sources/plugins/elementspath/lang/bs.js8
-rw-r--r--sources/plugins/elementspath/lang/ca.js8
-rw-r--r--sources/plugins/elementspath/lang/cs.js8
-rw-r--r--sources/plugins/elementspath/lang/cy.js8
-rw-r--r--sources/plugins/elementspath/lang/da.js8
-rw-r--r--sources/plugins/elementspath/lang/de-ch.js8
-rw-r--r--sources/plugins/elementspath/lang/de.js8
-rw-r--r--sources/plugins/elementspath/lang/el.js8
-rw-r--r--sources/plugins/elementspath/lang/en-au.js8
-rw-r--r--sources/plugins/elementspath/lang/en-ca.js8
-rw-r--r--sources/plugins/elementspath/lang/en-gb.js8
-rw-r--r--sources/plugins/elementspath/lang/en.js8
-rw-r--r--sources/plugins/elementspath/lang/eo.js8
-rw-r--r--sources/plugins/elementspath/lang/es.js8
-rw-r--r--sources/plugins/elementspath/lang/et.js8
-rw-r--r--sources/plugins/elementspath/lang/eu.js8
-rw-r--r--sources/plugins/elementspath/lang/fa.js8
-rw-r--r--sources/plugins/elementspath/lang/fi.js8
-rw-r--r--sources/plugins/elementspath/lang/fo.js8
-rw-r--r--sources/plugins/elementspath/lang/fr-ca.js8
-rw-r--r--sources/plugins/elementspath/lang/fr.js8
-rw-r--r--sources/plugins/elementspath/lang/gl.js8
-rw-r--r--sources/plugins/elementspath/lang/gu.js8
-rw-r--r--sources/plugins/elementspath/lang/he.js8
-rw-r--r--sources/plugins/elementspath/lang/hi.js8
-rw-r--r--sources/plugins/elementspath/lang/hr.js8
-rw-r--r--sources/plugins/elementspath/lang/hu.js8
-rw-r--r--sources/plugins/elementspath/lang/is.js8
-rw-r--r--sources/plugins/elementspath/lang/it.js8
-rw-r--r--sources/plugins/elementspath/lang/ja.js8
-rw-r--r--sources/plugins/elementspath/lang/ka.js8
-rw-r--r--sources/plugins/elementspath/lang/km.js8
-rw-r--r--sources/plugins/elementspath/lang/ko.js8
-rw-r--r--sources/plugins/elementspath/lang/ku.js8
-rw-r--r--sources/plugins/elementspath/lang/lt.js8
-rw-r--r--sources/plugins/elementspath/lang/lv.js8
-rw-r--r--sources/plugins/elementspath/lang/mk.js8
-rw-r--r--sources/plugins/elementspath/lang/mn.js8
-rw-r--r--sources/plugins/elementspath/lang/ms.js8
-rw-r--r--sources/plugins/elementspath/lang/nb.js8
-rw-r--r--sources/plugins/elementspath/lang/nl.js8
-rw-r--r--sources/plugins/elementspath/lang/no.js8
-rw-r--r--sources/plugins/elementspath/lang/oc.js8
-rw-r--r--sources/plugins/elementspath/lang/pl.js8
-rw-r--r--sources/plugins/elementspath/lang/pt-br.js8
-rw-r--r--sources/plugins/elementspath/lang/pt.js8
-rw-r--r--sources/plugins/elementspath/lang/ro.js8
-rw-r--r--sources/plugins/elementspath/lang/ru.js8
-rw-r--r--sources/plugins/elementspath/lang/si.js8
-rw-r--r--sources/plugins/elementspath/lang/sk.js8
-rw-r--r--sources/plugins/elementspath/lang/sl.js8
-rw-r--r--sources/plugins/elementspath/lang/sq.js8
-rw-r--r--sources/plugins/elementspath/lang/sr-latn.js8
-rw-r--r--sources/plugins/elementspath/lang/sr.js8
-rw-r--r--sources/plugins/elementspath/lang/sv.js8
-rw-r--r--sources/plugins/elementspath/lang/th.js8
-rw-r--r--sources/plugins/elementspath/lang/tr.js8
-rw-r--r--sources/plugins/elementspath/lang/tt.js8
-rw-r--r--sources/plugins/elementspath/lang/ug.js8
-rw-r--r--sources/plugins/elementspath/lang/uk.js8
-rw-r--r--sources/plugins/elementspath/lang/vi.js8
-rw-r--r--sources/plugins/elementspath/lang/zh-cn.js8
-rw-r--r--sources/plugins/elementspath/lang/zh.js8
-rw-r--r--sources/plugins/elementspath/plugin.js244
-rw-r--r--sources/plugins/enterkey/plugin.js566
-rw-r--r--sources/plugins/enterkey/samples/enterkey.html106
-rw-r--r--sources/plugins/entities/plugin.js239
-rw-r--r--sources/plugins/fakeobjects/lang/af.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ar.js11
-rw-r--r--sources/plugins/fakeobjects/lang/az.js11
-rw-r--r--sources/plugins/fakeobjects/lang/bg.js11
-rw-r--r--sources/plugins/fakeobjects/lang/bn.js11
-rw-r--r--sources/plugins/fakeobjects/lang/bs.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ca.js11
-rw-r--r--sources/plugins/fakeobjects/lang/cs.js11
-rw-r--r--sources/plugins/fakeobjects/lang/cy.js11
-rw-r--r--sources/plugins/fakeobjects/lang/da.js11
-rw-r--r--sources/plugins/fakeobjects/lang/de-ch.js11
-rw-r--r--sources/plugins/fakeobjects/lang/de.js11
-rw-r--r--sources/plugins/fakeobjects/lang/el.js11
-rw-r--r--sources/plugins/fakeobjects/lang/en-au.js11
-rw-r--r--sources/plugins/fakeobjects/lang/en-ca.js11
-rw-r--r--sources/plugins/fakeobjects/lang/en-gb.js11
-rw-r--r--sources/plugins/fakeobjects/lang/en.js11
-rw-r--r--sources/plugins/fakeobjects/lang/eo.js11
-rw-r--r--sources/plugins/fakeobjects/lang/es.js11
-rw-r--r--sources/plugins/fakeobjects/lang/et.js11
-rw-r--r--sources/plugins/fakeobjects/lang/eu.js11
-rw-r--r--sources/plugins/fakeobjects/lang/fa.js11
-rw-r--r--sources/plugins/fakeobjects/lang/fi.js11
-rw-r--r--sources/plugins/fakeobjects/lang/fo.js11
-rw-r--r--sources/plugins/fakeobjects/lang/fr-ca.js11
-rw-r--r--sources/plugins/fakeobjects/lang/fr.js11
-rw-r--r--sources/plugins/fakeobjects/lang/gl.js11
-rw-r--r--sources/plugins/fakeobjects/lang/gu.js11
-rw-r--r--sources/plugins/fakeobjects/lang/he.js11
-rw-r--r--sources/plugins/fakeobjects/lang/hi.js11
-rw-r--r--sources/plugins/fakeobjects/lang/hr.js11
-rw-r--r--sources/plugins/fakeobjects/lang/hu.js11
-rw-r--r--sources/plugins/fakeobjects/lang/id.js11
-rw-r--r--sources/plugins/fakeobjects/lang/is.js11
-rw-r--r--sources/plugins/fakeobjects/lang/it.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ja.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ka.js11
-rw-r--r--sources/plugins/fakeobjects/lang/km.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ko.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ku.js11
-rw-r--r--sources/plugins/fakeobjects/lang/lt.js11
-rw-r--r--sources/plugins/fakeobjects/lang/lv.js11
-rw-r--r--sources/plugins/fakeobjects/lang/mk.js11
-rw-r--r--sources/plugins/fakeobjects/lang/mn.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ms.js11
-rw-r--r--sources/plugins/fakeobjects/lang/nb.js11
-rw-r--r--sources/plugins/fakeobjects/lang/nl.js11
-rw-r--r--sources/plugins/fakeobjects/lang/no.js11
-rw-r--r--sources/plugins/fakeobjects/lang/oc.js11
-rw-r--r--sources/plugins/fakeobjects/lang/pl.js11
-rw-r--r--sources/plugins/fakeobjects/lang/pt-br.js11
-rw-r--r--sources/plugins/fakeobjects/lang/pt.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ro.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ru.js11
-rw-r--r--sources/plugins/fakeobjects/lang/si.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sk.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sl.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sq.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sr-latn.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sr.js11
-rw-r--r--sources/plugins/fakeobjects/lang/sv.js11
-rw-r--r--sources/plugins/fakeobjects/lang/th.js11
-rw-r--r--sources/plugins/fakeobjects/lang/tr.js11
-rw-r--r--sources/plugins/fakeobjects/lang/tt.js11
-rw-r--r--sources/plugins/fakeobjects/lang/ug.js11
-rw-r--r--sources/plugins/fakeobjects/lang/uk.js11
-rw-r--r--sources/plugins/fakeobjects/lang/vi.js11
-rw-r--r--sources/plugins/fakeobjects/lang/zh-cn.js11
-rw-r--r--sources/plugins/fakeobjects/lang/zh.js11
-rw-r--r--sources/plugins/fakeobjects/plugin.js183
-rw-r--r--sources/plugins/filebrowser/plugin.js573
-rw-r--r--sources/plugins/floatingspace/plugin.js406
-rw-r--r--sources/plugins/floatpanel/plugin.js598
-rw-r--r--sources/plugins/format/lang/af.js18
-rw-r--r--sources/plugins/format/lang/ar.js18
-rw-r--r--sources/plugins/format/lang/az.js18
-rw-r--r--sources/plugins/format/lang/bg.js18
-rw-r--r--sources/plugins/format/lang/bn.js18
-rw-r--r--sources/plugins/format/lang/bs.js18
-rw-r--r--sources/plugins/format/lang/ca.js18
-rw-r--r--sources/plugins/format/lang/cs.js18
-rw-r--r--sources/plugins/format/lang/cy.js18
-rw-r--r--sources/plugins/format/lang/da.js18
-rw-r--r--sources/plugins/format/lang/de-ch.js18
-rw-r--r--sources/plugins/format/lang/de.js18
-rw-r--r--sources/plugins/format/lang/el.js18
-rw-r--r--sources/plugins/format/lang/en-au.js18
-rw-r--r--sources/plugins/format/lang/en-ca.js18
-rw-r--r--sources/plugins/format/lang/en-gb.js18
-rw-r--r--sources/plugins/format/lang/en.js18
-rw-r--r--sources/plugins/format/lang/eo.js18
-rw-r--r--sources/plugins/format/lang/es.js18
-rw-r--r--sources/plugins/format/lang/et.js18
-rw-r--r--sources/plugins/format/lang/eu.js18
-rw-r--r--sources/plugins/format/lang/fa.js18
-rw-r--r--sources/plugins/format/lang/fi.js18
-rw-r--r--sources/plugins/format/lang/fo.js18
-rw-r--r--sources/plugins/format/lang/fr-ca.js18
-rw-r--r--sources/plugins/format/lang/fr.js18
-rw-r--r--sources/plugins/format/lang/gl.js18
-rw-r--r--sources/plugins/format/lang/gu.js18
-rw-r--r--sources/plugins/format/lang/he.js18
-rw-r--r--sources/plugins/format/lang/hi.js18
-rw-r--r--sources/plugins/format/lang/hr.js18
-rw-r--r--sources/plugins/format/lang/hu.js18
-rw-r--r--sources/plugins/format/lang/id.js18
-rw-r--r--sources/plugins/format/lang/is.js18
-rw-r--r--sources/plugins/format/lang/it.js18
-rw-r--r--sources/plugins/format/lang/ja.js18
-rw-r--r--sources/plugins/format/lang/ka.js18
-rw-r--r--sources/plugins/format/lang/km.js18
-rw-r--r--sources/plugins/format/lang/ko.js18
-rw-r--r--sources/plugins/format/lang/ku.js18
-rw-r--r--sources/plugins/format/lang/lt.js18
-rw-r--r--sources/plugins/format/lang/lv.js18
-rw-r--r--sources/plugins/format/lang/mk.js18
-rw-r--r--sources/plugins/format/lang/mn.js18
-rw-r--r--sources/plugins/format/lang/ms.js18
-rw-r--r--sources/plugins/format/lang/nb.js18
-rw-r--r--sources/plugins/format/lang/nl.js18
-rw-r--r--sources/plugins/format/lang/no.js18
-rw-r--r--sources/plugins/format/lang/oc.js18
-rw-r--r--sources/plugins/format/lang/pl.js18
-rw-r--r--sources/plugins/format/lang/pt-br.js18
-rw-r--r--sources/plugins/format/lang/pt.js18
-rw-r--r--sources/plugins/format/lang/ro.js18
-rw-r--r--sources/plugins/format/lang/ru.js18
-rw-r--r--sources/plugins/format/lang/si.js18
-rw-r--r--sources/plugins/format/lang/sk.js18
-rw-r--r--sources/plugins/format/lang/sl.js18
-rw-r--r--sources/plugins/format/lang/sq.js18
-rw-r--r--sources/plugins/format/lang/sr-latn.js18
-rw-r--r--sources/plugins/format/lang/sr.js18
-rw-r--r--sources/plugins/format/lang/sv.js18
-rw-r--r--sources/plugins/format/lang/th.js18
-rw-r--r--sources/plugins/format/lang/tr.js18
-rw-r--r--sources/plugins/format/lang/tt.js18
-rw-r--r--sources/plugins/format/lang/ug.js18
-rw-r--r--sources/plugins/format/lang/uk.js18
-rw-r--r--sources/plugins/format/lang/vi.js18
-rw-r--r--sources/plugins/format/lang/zh-cn.js18
-rw-r--r--sources/plugins/format/lang/zh.js18
-rw-r--r--sources/plugins/format/plugin.js279
-rw-r--r--sources/plugins/horizontalrule/icons/hidpi/horizontalrule.pngbin0 -> 530 bytes
-rw-r--r--sources/plugins/horizontalrule/icons/horizontalrule.pngbin0 -> 432 bytes
-rw-r--r--sources/plugins/horizontalrule/lang/af.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ar.js7
-rw-r--r--sources/plugins/horizontalrule/lang/az.js7
-rw-r--r--sources/plugins/horizontalrule/lang/bg.js7
-rw-r--r--sources/plugins/horizontalrule/lang/bn.js7
-rw-r--r--sources/plugins/horizontalrule/lang/bs.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ca.js7
-rw-r--r--sources/plugins/horizontalrule/lang/cs.js7
-rw-r--r--sources/plugins/horizontalrule/lang/cy.js7
-rw-r--r--sources/plugins/horizontalrule/lang/da.js7
-rw-r--r--sources/plugins/horizontalrule/lang/de-ch.js7
-rw-r--r--sources/plugins/horizontalrule/lang/de.js7
-rw-r--r--sources/plugins/horizontalrule/lang/el.js7
-rw-r--r--sources/plugins/horizontalrule/lang/en-au.js7
-rw-r--r--sources/plugins/horizontalrule/lang/en-ca.js7
-rw-r--r--sources/plugins/horizontalrule/lang/en-gb.js7
-rw-r--r--sources/plugins/horizontalrule/lang/en.js7
-rw-r--r--sources/plugins/horizontalrule/lang/eo.js7
-rw-r--r--sources/plugins/horizontalrule/lang/es.js7
-rw-r--r--sources/plugins/horizontalrule/lang/et.js7
-rw-r--r--sources/plugins/horizontalrule/lang/eu.js7
-rw-r--r--sources/plugins/horizontalrule/lang/fa.js7
-rw-r--r--sources/plugins/horizontalrule/lang/fi.js7
-rw-r--r--sources/plugins/horizontalrule/lang/fo.js7
-rw-r--r--sources/plugins/horizontalrule/lang/fr-ca.js7
-rw-r--r--sources/plugins/horizontalrule/lang/fr.js7
-rw-r--r--sources/plugins/horizontalrule/lang/gl.js7
-rw-r--r--sources/plugins/horizontalrule/lang/gu.js7
-rw-r--r--sources/plugins/horizontalrule/lang/he.js7
-rw-r--r--sources/plugins/horizontalrule/lang/hi.js7
-rw-r--r--sources/plugins/horizontalrule/lang/hr.js7
-rw-r--r--sources/plugins/horizontalrule/lang/hu.js7
-rw-r--r--sources/plugins/horizontalrule/lang/id.js7
-rw-r--r--sources/plugins/horizontalrule/lang/is.js7
-rw-r--r--sources/plugins/horizontalrule/lang/it.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ja.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ka.js7
-rw-r--r--sources/plugins/horizontalrule/lang/km.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ko.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ku.js7
-rw-r--r--sources/plugins/horizontalrule/lang/lt.js7
-rw-r--r--sources/plugins/horizontalrule/lang/lv.js7
-rw-r--r--sources/plugins/horizontalrule/lang/mk.js7
-rw-r--r--sources/plugins/horizontalrule/lang/mn.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ms.js7
-rw-r--r--sources/plugins/horizontalrule/lang/nb.js7
-rw-r--r--sources/plugins/horizontalrule/lang/nl.js7
-rw-r--r--sources/plugins/horizontalrule/lang/no.js7
-rw-r--r--sources/plugins/horizontalrule/lang/oc.js7
-rw-r--r--sources/plugins/horizontalrule/lang/pl.js7
-rw-r--r--sources/plugins/horizontalrule/lang/pt-br.js7
-rw-r--r--sources/plugins/horizontalrule/lang/pt.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ro.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ru.js7
-rw-r--r--sources/plugins/horizontalrule/lang/si.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sk.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sl.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sq.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sr-latn.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sr.js7
-rw-r--r--sources/plugins/horizontalrule/lang/sv.js7
-rw-r--r--sources/plugins/horizontalrule/lang/th.js7
-rw-r--r--sources/plugins/horizontalrule/lang/tr.js7
-rw-r--r--sources/plugins/horizontalrule/lang/tt.js7
-rw-r--r--sources/plugins/horizontalrule/lang/ug.js7
-rw-r--r--sources/plugins/horizontalrule/lang/uk.js7
-rw-r--r--sources/plugins/horizontalrule/lang/vi.js7
-rw-r--r--sources/plugins/horizontalrule/lang/zh-cn.js7
-rw-r--r--sources/plugins/horizontalrule/lang/zh.js7
-rw-r--r--sources/plugins/horizontalrule/plugin.js43
-rw-r--r--sources/plugins/htmlwriter/plugin.js360
-rw-r--r--sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.flabin0 -> 85504 bytes
-rw-r--r--sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.swfbin0 -> 15571 bytes
-rw-r--r--sources/plugins/htmlwriter/samples/assets/outputforflash/swfobject.js5
-rw-r--r--sources/plugins/htmlwriter/samples/outputforflash.html283
-rw-r--r--sources/plugins/htmlwriter/samples/outputhtml.html224
-rw-r--r--sources/plugins/iframe/dialogs/iframe.js207
-rw-r--r--sources/plugins/iframe/icons/hidpi/iframe.pngbin0 -> 1837 bytes
-rw-r--r--sources/plugins/iframe/icons/iframe.pngbin0 -> 816 bytes
-rw-r--r--sources/plugins/iframe/images/placeholder.pngbin0 -> 265 bytes
-rw-r--r--sources/plugins/iframe/lang/af.js11
-rw-r--r--sources/plugins/iframe/lang/ar.js11
-rw-r--r--sources/plugins/iframe/lang/az.js11
-rw-r--r--sources/plugins/iframe/lang/bg.js11
-rw-r--r--sources/plugins/iframe/lang/bn.js11
-rw-r--r--sources/plugins/iframe/lang/bs.js11
-rw-r--r--sources/plugins/iframe/lang/ca.js11
-rw-r--r--sources/plugins/iframe/lang/cs.js11
-rw-r--r--sources/plugins/iframe/lang/cy.js11
-rw-r--r--sources/plugins/iframe/lang/da.js11
-rw-r--r--sources/plugins/iframe/lang/de-ch.js11
-rw-r--r--sources/plugins/iframe/lang/de.js11
-rw-r--r--sources/plugins/iframe/lang/el.js11
-rw-r--r--sources/plugins/iframe/lang/en-au.js11
-rw-r--r--sources/plugins/iframe/lang/en-ca.js11
-rw-r--r--sources/plugins/iframe/lang/en-gb.js11
-rw-r--r--sources/plugins/iframe/lang/en.js11
-rw-r--r--sources/plugins/iframe/lang/eo.js11
-rw-r--r--sources/plugins/iframe/lang/es.js11
-rw-r--r--sources/plugins/iframe/lang/et.js11
-rw-r--r--sources/plugins/iframe/lang/eu.js11
-rw-r--r--sources/plugins/iframe/lang/fa.js11
-rw-r--r--sources/plugins/iframe/lang/fi.js11
-rw-r--r--sources/plugins/iframe/lang/fo.js11
-rw-r--r--sources/plugins/iframe/lang/fr-ca.js11
-rw-r--r--sources/plugins/iframe/lang/fr.js11
-rw-r--r--sources/plugins/iframe/lang/gl.js11
-rw-r--r--sources/plugins/iframe/lang/gu.js11
-rw-r--r--sources/plugins/iframe/lang/he.js11
-rw-r--r--sources/plugins/iframe/lang/hi.js11
-rw-r--r--sources/plugins/iframe/lang/hr.js11
-rw-r--r--sources/plugins/iframe/lang/hu.js11
-rw-r--r--sources/plugins/iframe/lang/id.js11
-rw-r--r--sources/plugins/iframe/lang/is.js11
-rw-r--r--sources/plugins/iframe/lang/it.js11
-rw-r--r--sources/plugins/iframe/lang/ja.js11
-rw-r--r--sources/plugins/iframe/lang/ka.js11
-rw-r--r--sources/plugins/iframe/lang/km.js11
-rw-r--r--sources/plugins/iframe/lang/ko.js11
-rw-r--r--sources/plugins/iframe/lang/ku.js11
-rw-r--r--sources/plugins/iframe/lang/lt.js11
-rw-r--r--sources/plugins/iframe/lang/lv.js11
-rw-r--r--sources/plugins/iframe/lang/mk.js11
-rw-r--r--sources/plugins/iframe/lang/mn.js11
-rw-r--r--sources/plugins/iframe/lang/ms.js11
-rw-r--r--sources/plugins/iframe/lang/nb.js11
-rw-r--r--sources/plugins/iframe/lang/nl.js11
-rw-r--r--sources/plugins/iframe/lang/no.js11
-rw-r--r--sources/plugins/iframe/lang/oc.js11
-rw-r--r--sources/plugins/iframe/lang/pl.js11
-rw-r--r--sources/plugins/iframe/lang/pt-br.js11
-rw-r--r--sources/plugins/iframe/lang/pt.js11
-rw-r--r--sources/plugins/iframe/lang/ro.js11
-rw-r--r--sources/plugins/iframe/lang/ru.js11
-rw-r--r--sources/plugins/iframe/lang/si.js11
-rw-r--r--sources/plugins/iframe/lang/sk.js11
-rw-r--r--sources/plugins/iframe/lang/sl.js11
-rw-r--r--sources/plugins/iframe/lang/sq.js11
-rw-r--r--sources/plugins/iframe/lang/sr-latn.js11
-rw-r--r--sources/plugins/iframe/lang/sr.js11
-rw-r--r--sources/plugins/iframe/lang/sv.js11
-rw-r--r--sources/plugins/iframe/lang/th.js11
-rw-r--r--sources/plugins/iframe/lang/tr.js11
-rw-r--r--sources/plugins/iframe/lang/tt.js11
-rw-r--r--sources/plugins/iframe/lang/ug.js11
-rw-r--r--sources/plugins/iframe/lang/uk.js11
-rw-r--r--sources/plugins/iframe/lang/vi.js11
-rw-r--r--sources/plugins/iframe/lang/zh-cn.js11
-rw-r--r--sources/plugins/iframe/lang/zh.js11
-rw-r--r--sources/plugins/iframe/plugin.js85
-rw-r--r--sources/plugins/image/dialogs/image.js1254
-rw-r--r--sources/plugins/image/icons/hidpi/image.pngbin0 -> 905 bytes
-rw-r--r--sources/plugins/image/icons/image.pngbin0 -> 498 bytes
-rw-r--r--sources/plugins/image/images/noimage.pngbin0 -> 1610 bytes
-rw-r--r--sources/plugins/image/lang/af.js25
-rw-r--r--sources/plugins/image/lang/ar.js25
-rw-r--r--sources/plugins/image/lang/az.js25
-rw-r--r--sources/plugins/image/lang/bg.js25
-rw-r--r--sources/plugins/image/lang/bn.js25
-rw-r--r--sources/plugins/image/lang/bs.js25
-rw-r--r--sources/plugins/image/lang/ca.js25
-rw-r--r--sources/plugins/image/lang/cs.js25
-rw-r--r--sources/plugins/image/lang/cy.js25
-rw-r--r--sources/plugins/image/lang/da.js25
-rw-r--r--sources/plugins/image/lang/de-ch.js25
-rw-r--r--sources/plugins/image/lang/de.js25
-rw-r--r--sources/plugins/image/lang/el.js25
-rw-r--r--sources/plugins/image/lang/en-au.js25
-rw-r--r--sources/plugins/image/lang/en-ca.js25
-rw-r--r--sources/plugins/image/lang/en-gb.js25
-rw-r--r--sources/plugins/image/lang/en.js25
-rw-r--r--sources/plugins/image/lang/eo.js25
-rw-r--r--sources/plugins/image/lang/es.js25
-rw-r--r--sources/plugins/image/lang/et.js25
-rw-r--r--sources/plugins/image/lang/eu.js25
-rw-r--r--sources/plugins/image/lang/fa.js25
-rw-r--r--sources/plugins/image/lang/fi.js25
-rw-r--r--sources/plugins/image/lang/fo.js25
-rw-r--r--sources/plugins/image/lang/fr-ca.js25
-rw-r--r--sources/plugins/image/lang/fr.js25
-rw-r--r--sources/plugins/image/lang/gl.js25
-rw-r--r--sources/plugins/image/lang/gu.js25
-rw-r--r--sources/plugins/image/lang/he.js25
-rw-r--r--sources/plugins/image/lang/hi.js25
-rw-r--r--sources/plugins/image/lang/hr.js25
-rw-r--r--sources/plugins/image/lang/hu.js25
-rw-r--r--sources/plugins/image/lang/id.js25
-rw-r--r--sources/plugins/image/lang/is.js25
-rw-r--r--sources/plugins/image/lang/it.js25
-rw-r--r--sources/plugins/image/lang/ja.js25
-rw-r--r--sources/plugins/image/lang/ka.js25
-rw-r--r--sources/plugins/image/lang/km.js25
-rw-r--r--sources/plugins/image/lang/ko.js25
-rw-r--r--sources/plugins/image/lang/ku.js25
-rw-r--r--sources/plugins/image/lang/lt.js25
-rw-r--r--sources/plugins/image/lang/lv.js25
-rw-r--r--sources/plugins/image/lang/mk.js25
-rw-r--r--sources/plugins/image/lang/mn.js25
-rw-r--r--sources/plugins/image/lang/ms.js25
-rw-r--r--sources/plugins/image/lang/nb.js25
-rw-r--r--sources/plugins/image/lang/nl.js25
-rw-r--r--sources/plugins/image/lang/no.js25
-rw-r--r--sources/plugins/image/lang/oc.js25
-rw-r--r--sources/plugins/image/lang/pl.js25
-rw-r--r--sources/plugins/image/lang/pt-br.js25
-rw-r--r--sources/plugins/image/lang/pt.js25
-rw-r--r--sources/plugins/image/lang/ro.js25
-rw-r--r--sources/plugins/image/lang/ru.js25
-rw-r--r--sources/plugins/image/lang/si.js25
-rw-r--r--sources/plugins/image/lang/sk.js25
-rw-r--r--sources/plugins/image/lang/sl.js25
-rw-r--r--sources/plugins/image/lang/sq.js25
-rw-r--r--sources/plugins/image/lang/sr-latn.js25
-rw-r--r--sources/plugins/image/lang/sr.js25
-rw-r--r--sources/plugins/image/lang/sv.js25
-rw-r--r--sources/plugins/image/lang/th.js25
-rw-r--r--sources/plugins/image/lang/tr.js25
-rw-r--r--sources/plugins/image/lang/tt.js25
-rw-r--r--sources/plugins/image/lang/ug.js25
-rw-r--r--sources/plugins/image/lang/uk.js25
-rw-r--r--sources/plugins/image/lang/vi.js25
-rw-r--r--sources/plugins/image/lang/zh-cn.js25
-rw-r--r--sources/plugins/image/lang/zh.js25
-rw-r--r--sources/plugins/image/plugin.js183
-rw-r--r--sources/plugins/indent/dev/indent.html284
-rw-r--r--sources/plugins/indent/icons/hidpi/indent-rtl.pngbin0 -> 757 bytes
-rw-r--r--sources/plugins/indent/icons/hidpi/indent.pngbin0 -> 1001 bytes
-rw-r--r--sources/plugins/indent/icons/hidpi/outdent-rtl.pngbin0 -> 738 bytes
-rw-r--r--sources/plugins/indent/icons/hidpi/outdent.pngbin0 -> 754 bytes
-rw-r--r--sources/plugins/indent/icons/indent-rtl.pngbin0 -> 438 bytes
-rw-r--r--sources/plugins/indent/icons/indent.pngbin0 -> 489 bytes
-rw-r--r--sources/plugins/indent/icons/outdent-rtl.pngbin0 -> 450 bytes
-rw-r--r--sources/plugins/indent/icons/outdent.pngbin0 -> 413 bytes
-rw-r--r--sources/plugins/indent/lang/af.js8
-rw-r--r--sources/plugins/indent/lang/ar.js8
-rw-r--r--sources/plugins/indent/lang/az.js8
-rw-r--r--sources/plugins/indent/lang/bg.js8
-rw-r--r--sources/plugins/indent/lang/bn.js8
-rw-r--r--sources/plugins/indent/lang/bs.js8
-rw-r--r--sources/plugins/indent/lang/ca.js8
-rw-r--r--sources/plugins/indent/lang/cs.js8
-rw-r--r--sources/plugins/indent/lang/cy.js8
-rw-r--r--sources/plugins/indent/lang/da.js8
-rw-r--r--sources/plugins/indent/lang/de-ch.js8
-rw-r--r--sources/plugins/indent/lang/de.js8
-rw-r--r--sources/plugins/indent/lang/el.js8
-rw-r--r--sources/plugins/indent/lang/en-au.js8
-rw-r--r--sources/plugins/indent/lang/en-ca.js8
-rw-r--r--sources/plugins/indent/lang/en-gb.js8
-rw-r--r--sources/plugins/indent/lang/en.js8
-rw-r--r--sources/plugins/indent/lang/eo.js8
-rw-r--r--sources/plugins/indent/lang/es.js8
-rw-r--r--sources/plugins/indent/lang/et.js8
-rw-r--r--sources/plugins/indent/lang/eu.js8
-rw-r--r--sources/plugins/indent/lang/fa.js8
-rw-r--r--sources/plugins/indent/lang/fi.js8
-rw-r--r--sources/plugins/indent/lang/fo.js8
-rw-r--r--sources/plugins/indent/lang/fr-ca.js8
-rw-r--r--sources/plugins/indent/lang/fr.js8
-rw-r--r--sources/plugins/indent/lang/gl.js8
-rw-r--r--sources/plugins/indent/lang/gu.js8
-rw-r--r--sources/plugins/indent/lang/he.js8
-rw-r--r--sources/plugins/indent/lang/hi.js8
-rw-r--r--sources/plugins/indent/lang/hr.js8
-rw-r--r--sources/plugins/indent/lang/hu.js8
-rw-r--r--sources/plugins/indent/lang/id.js8
-rw-r--r--sources/plugins/indent/lang/is.js8
-rw-r--r--sources/plugins/indent/lang/it.js8
-rw-r--r--sources/plugins/indent/lang/ja.js8
-rw-r--r--sources/plugins/indent/lang/ka.js8
-rw-r--r--sources/plugins/indent/lang/km.js8
-rw-r--r--sources/plugins/indent/lang/ko.js8
-rw-r--r--sources/plugins/indent/lang/ku.js8
-rw-r--r--sources/plugins/indent/lang/lt.js8
-rw-r--r--sources/plugins/indent/lang/lv.js8
-rw-r--r--sources/plugins/indent/lang/mk.js8
-rw-r--r--sources/plugins/indent/lang/mn.js8
-rw-r--r--sources/plugins/indent/lang/ms.js8
-rw-r--r--sources/plugins/indent/lang/nb.js8
-rw-r--r--sources/plugins/indent/lang/nl.js8
-rw-r--r--sources/plugins/indent/lang/no.js8
-rw-r--r--sources/plugins/indent/lang/oc.js8
-rw-r--r--sources/plugins/indent/lang/pl.js8
-rw-r--r--sources/plugins/indent/lang/pt-br.js8
-rw-r--r--sources/plugins/indent/lang/pt.js8
-rw-r--r--sources/plugins/indent/lang/ro.js8
-rw-r--r--sources/plugins/indent/lang/ru.js8
-rw-r--r--sources/plugins/indent/lang/si.js8
-rw-r--r--sources/plugins/indent/lang/sk.js8
-rw-r--r--sources/plugins/indent/lang/sl.js8
-rw-r--r--sources/plugins/indent/lang/sq.js8
-rw-r--r--sources/plugins/indent/lang/sr-latn.js8
-rw-r--r--sources/plugins/indent/lang/sr.js8
-rw-r--r--sources/plugins/indent/lang/sv.js8
-rw-r--r--sources/plugins/indent/lang/th.js8
-rw-r--r--sources/plugins/indent/lang/tr.js8
-rw-r--r--sources/plugins/indent/lang/tt.js8
-rw-r--r--sources/plugins/indent/lang/ug.js8
-rw-r--r--sources/plugins/indent/lang/uk.js8
-rw-r--r--sources/plugins/indent/lang/vi.js8
-rw-r--r--sources/plugins/indent/lang/zh-cn.js8
-rw-r--r--sources/plugins/indent/lang/zh.js8
-rw-r--r--sources/plugins/indent/plugin.js461
-rw-r--r--sources/plugins/indentblock/plugin.js312
-rw-r--r--sources/plugins/indentlist/plugin.js318
-rw-r--r--sources/plugins/justify/icons/hidpi/justifyblock.pngbin0 -> 533 bytes
-rw-r--r--sources/plugins/justify/icons/hidpi/justifycenter.pngbin0 -> 576 bytes
-rw-r--r--sources/plugins/justify/icons/hidpi/justifyleft.pngbin0 -> 569 bytes
-rw-r--r--sources/plugins/justify/icons/hidpi/justifyright.pngbin0 -> 549 bytes
-rw-r--r--sources/plugins/justify/icons/justifyblock.pngbin0 -> 315 bytes
-rw-r--r--sources/plugins/justify/icons/justifycenter.pngbin0 -> 564 bytes
-rw-r--r--sources/plugins/justify/icons/justifyleft.pngbin0 -> 342 bytes
-rw-r--r--sources/plugins/justify/icons/justifyright.pngbin0 -> 348 bytes
-rw-r--r--sources/plugins/justify/lang/af.js10
-rw-r--r--sources/plugins/justify/lang/ar.js10
-rw-r--r--sources/plugins/justify/lang/az.js10
-rw-r--r--sources/plugins/justify/lang/bg.js10
-rw-r--r--sources/plugins/justify/lang/bn.js10
-rw-r--r--sources/plugins/justify/lang/bs.js10
-rw-r--r--sources/plugins/justify/lang/ca.js10
-rw-r--r--sources/plugins/justify/lang/cs.js10
-rw-r--r--sources/plugins/justify/lang/cy.js10
-rw-r--r--sources/plugins/justify/lang/da.js10
-rw-r--r--sources/plugins/justify/lang/de-ch.js10
-rw-r--r--sources/plugins/justify/lang/de.js10
-rw-r--r--sources/plugins/justify/lang/el.js10
-rw-r--r--sources/plugins/justify/lang/en-au.js10
-rw-r--r--sources/plugins/justify/lang/en-ca.js10
-rw-r--r--sources/plugins/justify/lang/en-gb.js10
-rw-r--r--sources/plugins/justify/lang/en.js10
-rw-r--r--sources/plugins/justify/lang/eo.js10
-rw-r--r--sources/plugins/justify/lang/es.js10
-rw-r--r--sources/plugins/justify/lang/et.js10
-rw-r--r--sources/plugins/justify/lang/eu.js10
-rw-r--r--sources/plugins/justify/lang/fa.js10
-rw-r--r--sources/plugins/justify/lang/fi.js10
-rw-r--r--sources/plugins/justify/lang/fo.js10
-rw-r--r--sources/plugins/justify/lang/fr-ca.js10
-rw-r--r--sources/plugins/justify/lang/fr.js10
-rw-r--r--sources/plugins/justify/lang/gl.js10
-rw-r--r--sources/plugins/justify/lang/gu.js10
-rw-r--r--sources/plugins/justify/lang/he.js10
-rw-r--r--sources/plugins/justify/lang/hi.js10
-rw-r--r--sources/plugins/justify/lang/hr.js10
-rw-r--r--sources/plugins/justify/lang/hu.js10
-rw-r--r--sources/plugins/justify/lang/id.js10
-rw-r--r--sources/plugins/justify/lang/is.js10
-rw-r--r--sources/plugins/justify/lang/it.js10
-rw-r--r--sources/plugins/justify/lang/ja.js10
-rw-r--r--sources/plugins/justify/lang/ka.js10
-rw-r--r--sources/plugins/justify/lang/km.js10
-rw-r--r--sources/plugins/justify/lang/ko.js10
-rw-r--r--sources/plugins/justify/lang/ku.js10
-rw-r--r--sources/plugins/justify/lang/lt.js10
-rw-r--r--sources/plugins/justify/lang/lv.js10
-rw-r--r--sources/plugins/justify/lang/mk.js10
-rw-r--r--sources/plugins/justify/lang/mn.js10
-rw-r--r--sources/plugins/justify/lang/ms.js10
-rw-r--r--sources/plugins/justify/lang/nb.js10
-rw-r--r--sources/plugins/justify/lang/nl.js10
-rw-r--r--sources/plugins/justify/lang/no.js10
-rw-r--r--sources/plugins/justify/lang/oc.js10
-rw-r--r--sources/plugins/justify/lang/pl.js10
-rw-r--r--sources/plugins/justify/lang/pt-br.js10
-rw-r--r--sources/plugins/justify/lang/pt.js10
-rw-r--r--sources/plugins/justify/lang/ro.js10
-rw-r--r--sources/plugins/justify/lang/ru.js10
-rw-r--r--sources/plugins/justify/lang/si.js10
-rw-r--r--sources/plugins/justify/lang/sk.js10
-rw-r--r--sources/plugins/justify/lang/sl.js10
-rw-r--r--sources/plugins/justify/lang/sq.js10
-rw-r--r--sources/plugins/justify/lang/sr-latn.js10
-rw-r--r--sources/plugins/justify/lang/sr.js10
-rw-r--r--sources/plugins/justify/lang/sv.js10
-rw-r--r--sources/plugins/justify/lang/th.js10
-rw-r--r--sources/plugins/justify/lang/tr.js10
-rw-r--r--sources/plugins/justify/lang/tt.js10
-rw-r--r--sources/plugins/justify/lang/ug.js10
-rw-r--r--sources/plugins/justify/lang/uk.js10
-rw-r--r--sources/plugins/justify/lang/vi.js10
-rw-r--r--sources/plugins/justify/lang/zh-cn.js10
-rw-r--r--sources/plugins/justify/lang/zh.js10
-rw-r--r--sources/plugins/justify/plugin.js245
-rw-r--r--sources/plugins/lineutils/dev/dnd.html172
-rw-r--r--sources/plugins/lineutils/dev/magicfinger.html285
-rw-r--r--sources/plugins/lineutils/plugin.js1018
-rw-r--r--sources/plugins/link/dialogs/anchor.js105
-rw-r--r--sources/plugins/link/dialogs/link.js979
-rw-r--r--sources/plugins/link/icons/anchor-rtl.pngbin0 -> 523 bytes
-rw-r--r--sources/plugins/link/icons/anchor.pngbin0 -> 517 bytes
-rw-r--r--sources/plugins/link/icons/hidpi/anchor-rtl.pngbin0 -> 957 bytes
-rw-r--r--sources/plugins/link/icons/hidpi/anchor.pngbin0 -> 917 bytes
-rw-r--r--sources/plugins/link/icons/hidpi/link.pngbin0 -> 935 bytes
-rw-r--r--sources/plugins/link/icons/hidpi/unlink.pngbin0 -> 1317 bytes
-rw-r--r--sources/plugins/link/icons/link.pngbin0 -> 533 bytes
-rw-r--r--sources/plugins/link/icons/unlink.pngbin0 -> 692 bytes
-rw-r--r--sources/plugins/link/images/anchor.pngbin0 -> 752 bytes
-rw-r--r--sources/plugins/link/images/hidpi/anchor.pngbin0 -> 1109 bytes
-rw-r--r--sources/plugins/link/lang/af.js67
-rw-r--r--sources/plugins/link/lang/ar.js67
-rw-r--r--sources/plugins/link/lang/az.js67
-rw-r--r--sources/plugins/link/lang/bg.js67
-rw-r--r--sources/plugins/link/lang/bn.js67
-rw-r--r--sources/plugins/link/lang/bs.js67
-rw-r--r--sources/plugins/link/lang/ca.js67
-rw-r--r--sources/plugins/link/lang/cs.js67
-rw-r--r--sources/plugins/link/lang/cy.js67
-rw-r--r--sources/plugins/link/lang/da.js67
-rw-r--r--sources/plugins/link/lang/de-ch.js67
-rw-r--r--sources/plugins/link/lang/de.js67
-rw-r--r--sources/plugins/link/lang/el.js67
-rw-r--r--sources/plugins/link/lang/en-au.js67
-rw-r--r--sources/plugins/link/lang/en-ca.js67
-rw-r--r--sources/plugins/link/lang/en-gb.js67
-rw-r--r--sources/plugins/link/lang/en.js67
-rw-r--r--sources/plugins/link/lang/eo.js67
-rw-r--r--sources/plugins/link/lang/es.js67
-rw-r--r--sources/plugins/link/lang/et.js67
-rw-r--r--sources/plugins/link/lang/eu.js67
-rw-r--r--sources/plugins/link/lang/fa.js67
-rw-r--r--sources/plugins/link/lang/fi.js67
-rw-r--r--sources/plugins/link/lang/fo.js67
-rw-r--r--sources/plugins/link/lang/fr-ca.js67
-rw-r--r--sources/plugins/link/lang/fr.js67
-rw-r--r--sources/plugins/link/lang/gl.js67
-rw-r--r--sources/plugins/link/lang/gu.js67
-rw-r--r--sources/plugins/link/lang/he.js67
-rw-r--r--sources/plugins/link/lang/hi.js67
-rw-r--r--sources/plugins/link/lang/hr.js67
-rw-r--r--sources/plugins/link/lang/hu.js67
-rw-r--r--sources/plugins/link/lang/id.js67
-rw-r--r--sources/plugins/link/lang/is.js67
-rw-r--r--sources/plugins/link/lang/it.js67
-rw-r--r--sources/plugins/link/lang/ja.js67
-rw-r--r--sources/plugins/link/lang/ka.js67
-rw-r--r--sources/plugins/link/lang/km.js67
-rw-r--r--sources/plugins/link/lang/ko.js67
-rw-r--r--sources/plugins/link/lang/ku.js67
-rw-r--r--sources/plugins/link/lang/lt.js67
-rw-r--r--sources/plugins/link/lang/lv.js67
-rw-r--r--sources/plugins/link/lang/mk.js67
-rw-r--r--sources/plugins/link/lang/mn.js67
-rw-r--r--sources/plugins/link/lang/ms.js67
-rw-r--r--sources/plugins/link/lang/nb.js67
-rw-r--r--sources/plugins/link/lang/nl.js67
-rw-r--r--sources/plugins/link/lang/no.js67
-rw-r--r--sources/plugins/link/lang/oc.js67
-rw-r--r--sources/plugins/link/lang/pl.js67
-rw-r--r--sources/plugins/link/lang/pt-br.js67
-rw-r--r--sources/plugins/link/lang/pt.js67
-rw-r--r--sources/plugins/link/lang/ro.js67
-rw-r--r--sources/plugins/link/lang/ru.js67
-rw-r--r--sources/plugins/link/lang/si.js67
-rw-r--r--sources/plugins/link/lang/sk.js67
-rw-r--r--sources/plugins/link/lang/sl.js67
-rw-r--r--sources/plugins/link/lang/sq.js67
-rw-r--r--sources/plugins/link/lang/sr-latn.js67
-rw-r--r--sources/plugins/link/lang/sr.js67
-rw-r--r--sources/plugins/link/lang/sv.js67
-rw-r--r--sources/plugins/link/lang/th.js67
-rw-r--r--sources/plugins/link/lang/tr.js67
-rw-r--r--sources/plugins/link/lang/tt.js67
-rw-r--r--sources/plugins/link/lang/ug.js67
-rw-r--r--sources/plugins/link/lang/uk.js67
-rw-r--r--sources/plugins/link/lang/vi.js67
-rw-r--r--sources/plugins/link/lang/zh-cn.js67
-rw-r--r--sources/plugins/link/lang/zh.js67
-rw-r--r--sources/plugins/link/plugin.js828
-rw-r--r--sources/plugins/list/icons/bulletedlist-rtl.pngbin0 -> 367 bytes
-rw-r--r--sources/plugins/list/icons/bulletedlist.pngbin0 -> 370 bytes
-rw-r--r--sources/plugins/list/icons/hidpi/bulletedlist-rtl.pngbin0 -> 820 bytes
-rw-r--r--sources/plugins/list/icons/hidpi/bulletedlist.pngbin0 -> 828 bytes
-rw-r--r--sources/plugins/list/icons/hidpi/numberedlist-rtl.pngbin0 -> 628 bytes
-rw-r--r--sources/plugins/list/icons/hidpi/numberedlist.pngbin0 -> 655 bytes
-rw-r--r--sources/plugins/list/icons/numberedlist-rtl.pngbin0 -> 390 bytes
-rw-r--r--sources/plugins/list/icons/numberedlist.pngbin0 -> 390 bytes
-rw-r--r--sources/plugins/list/lang/af.js8
-rw-r--r--sources/plugins/list/lang/ar.js8
-rw-r--r--sources/plugins/list/lang/az.js8
-rw-r--r--sources/plugins/list/lang/bg.js8
-rw-r--r--sources/plugins/list/lang/bn.js8
-rw-r--r--sources/plugins/list/lang/bs.js8
-rw-r--r--sources/plugins/list/lang/ca.js8
-rw-r--r--sources/plugins/list/lang/cs.js8
-rw-r--r--sources/plugins/list/lang/cy.js8
-rw-r--r--sources/plugins/list/lang/da.js8
-rw-r--r--sources/plugins/list/lang/de-ch.js8
-rw-r--r--sources/plugins/list/lang/de.js8
-rw-r--r--sources/plugins/list/lang/el.js8
-rw-r--r--sources/plugins/list/lang/en-au.js8
-rw-r--r--sources/plugins/list/lang/en-ca.js8
-rw-r--r--sources/plugins/list/lang/en-gb.js8
-rw-r--r--sources/plugins/list/lang/en.js8
-rw-r--r--sources/plugins/list/lang/eo.js8
-rw-r--r--sources/plugins/list/lang/es.js8
-rw-r--r--sources/plugins/list/lang/et.js8
-rw-r--r--sources/plugins/list/lang/eu.js8
-rw-r--r--sources/plugins/list/lang/fa.js8
-rw-r--r--sources/plugins/list/lang/fi.js8
-rw-r--r--sources/plugins/list/lang/fo.js8
-rw-r--r--sources/plugins/list/lang/fr-ca.js8
-rw-r--r--sources/plugins/list/lang/fr.js8
-rw-r--r--sources/plugins/list/lang/gl.js8
-rw-r--r--sources/plugins/list/lang/gu.js8
-rw-r--r--sources/plugins/list/lang/he.js8
-rw-r--r--sources/plugins/list/lang/hi.js8
-rw-r--r--sources/plugins/list/lang/hr.js8
-rw-r--r--sources/plugins/list/lang/hu.js8
-rw-r--r--sources/plugins/list/lang/id.js8
-rw-r--r--sources/plugins/list/lang/is.js8
-rw-r--r--sources/plugins/list/lang/it.js8
-rw-r--r--sources/plugins/list/lang/ja.js8
-rw-r--r--sources/plugins/list/lang/ka.js8
-rw-r--r--sources/plugins/list/lang/km.js8
-rw-r--r--sources/plugins/list/lang/ko.js8
-rw-r--r--sources/plugins/list/lang/ku.js8
-rw-r--r--sources/plugins/list/lang/lt.js8
-rw-r--r--sources/plugins/list/lang/lv.js8
-rw-r--r--sources/plugins/list/lang/mk.js8
-rw-r--r--sources/plugins/list/lang/mn.js8
-rw-r--r--sources/plugins/list/lang/ms.js8
-rw-r--r--sources/plugins/list/lang/nb.js8
-rw-r--r--sources/plugins/list/lang/nl.js8
-rw-r--r--sources/plugins/list/lang/no.js8
-rw-r--r--sources/plugins/list/lang/oc.js8
-rw-r--r--sources/plugins/list/lang/pl.js8
-rw-r--r--sources/plugins/list/lang/pt-br.js8
-rw-r--r--sources/plugins/list/lang/pt.js8
-rw-r--r--sources/plugins/list/lang/ro.js8
-rw-r--r--sources/plugins/list/lang/ru.js8
-rw-r--r--sources/plugins/list/lang/si.js8
-rw-r--r--sources/plugins/list/lang/sk.js8
-rw-r--r--sources/plugins/list/lang/sl.js8
-rw-r--r--sources/plugins/list/lang/sq.js8
-rw-r--r--sources/plugins/list/lang/sr-latn.js8
-rw-r--r--sources/plugins/list/lang/sr.js8
-rw-r--r--sources/plugins/list/lang/sv.js8
-rw-r--r--sources/plugins/list/lang/th.js8
-rw-r--r--sources/plugins/list/lang/tr.js8
-rw-r--r--sources/plugins/list/lang/tt.js8
-rw-r--r--sources/plugins/list/lang/ug.js8
-rw-r--r--sources/plugins/list/lang/uk.js8
-rw-r--r--sources/plugins/list/lang/vi.js8
-rw-r--r--sources/plugins/list/lang/zh-cn.js8
-rw-r--r--sources/plugins/list/lang/zh.js8
-rw-r--r--sources/plugins/list/plugin.js1111
-rw-r--r--sources/plugins/listblock/plugin.js241
-rw-r--r--sources/plugins/liststyle/dialogs/liststyle.js189
-rw-r--r--sources/plugins/liststyle/lang/af.js25
-rw-r--r--sources/plugins/liststyle/lang/ar.js25
-rw-r--r--sources/plugins/liststyle/lang/az.js25
-rw-r--r--sources/plugins/liststyle/lang/bg.js25
-rw-r--r--sources/plugins/liststyle/lang/bn.js25
-rw-r--r--sources/plugins/liststyle/lang/bs.js25
-rw-r--r--sources/plugins/liststyle/lang/ca.js25
-rw-r--r--sources/plugins/liststyle/lang/cs.js25
-rw-r--r--sources/plugins/liststyle/lang/cy.js25
-rw-r--r--sources/plugins/liststyle/lang/da.js25
-rw-r--r--sources/plugins/liststyle/lang/de-ch.js25
-rw-r--r--sources/plugins/liststyle/lang/de.js25
-rw-r--r--sources/plugins/liststyle/lang/el.js25
-rw-r--r--sources/plugins/liststyle/lang/en-au.js25
-rw-r--r--sources/plugins/liststyle/lang/en-ca.js25
-rw-r--r--sources/plugins/liststyle/lang/en-gb.js25
-rw-r--r--sources/plugins/liststyle/lang/en.js25
-rw-r--r--sources/plugins/liststyle/lang/eo.js25
-rw-r--r--sources/plugins/liststyle/lang/es.js25
-rw-r--r--sources/plugins/liststyle/lang/et.js25
-rw-r--r--sources/plugins/liststyle/lang/eu.js25
-rw-r--r--sources/plugins/liststyle/lang/fa.js25
-rw-r--r--sources/plugins/liststyle/lang/fi.js25
-rw-r--r--sources/plugins/liststyle/lang/fo.js25
-rw-r--r--sources/plugins/liststyle/lang/fr-ca.js25
-rw-r--r--sources/plugins/liststyle/lang/fr.js25
-rw-r--r--sources/plugins/liststyle/lang/gl.js25
-rw-r--r--sources/plugins/liststyle/lang/gu.js25
-rw-r--r--sources/plugins/liststyle/lang/he.js25
-rw-r--r--sources/plugins/liststyle/lang/hi.js25
-rw-r--r--sources/plugins/liststyle/lang/hr.js25
-rw-r--r--sources/plugins/liststyle/lang/hu.js25
-rw-r--r--sources/plugins/liststyle/lang/id.js25
-rw-r--r--sources/plugins/liststyle/lang/is.js25
-rw-r--r--sources/plugins/liststyle/lang/it.js25
-rw-r--r--sources/plugins/liststyle/lang/ja.js25
-rw-r--r--sources/plugins/liststyle/lang/ka.js25
-rw-r--r--sources/plugins/liststyle/lang/km.js25
-rw-r--r--sources/plugins/liststyle/lang/ko.js25
-rw-r--r--sources/plugins/liststyle/lang/ku.js25
-rw-r--r--sources/plugins/liststyle/lang/lt.js25
-rw-r--r--sources/plugins/liststyle/lang/lv.js25
-rw-r--r--sources/plugins/liststyle/lang/mk.js25
-rw-r--r--sources/plugins/liststyle/lang/mn.js25
-rw-r--r--sources/plugins/liststyle/lang/ms.js25
-rw-r--r--sources/plugins/liststyle/lang/nb.js25
-rw-r--r--sources/plugins/liststyle/lang/nl.js25
-rw-r--r--sources/plugins/liststyle/lang/no.js25
-rw-r--r--sources/plugins/liststyle/lang/oc.js25
-rw-r--r--sources/plugins/liststyle/lang/pl.js25
-rw-r--r--sources/plugins/liststyle/lang/pt-br.js25
-rw-r--r--sources/plugins/liststyle/lang/pt.js25
-rw-r--r--sources/plugins/liststyle/lang/ro.js25
-rw-r--r--sources/plugins/liststyle/lang/ru.js25
-rw-r--r--sources/plugins/liststyle/lang/si.js25
-rw-r--r--sources/plugins/liststyle/lang/sk.js25
-rw-r--r--sources/plugins/liststyle/lang/sl.js25
-rw-r--r--sources/plugins/liststyle/lang/sq.js25
-rw-r--r--sources/plugins/liststyle/lang/sr-latn.js25
-rw-r--r--sources/plugins/liststyle/lang/sr.js25
-rw-r--r--sources/plugins/liststyle/lang/sv.js25
-rw-r--r--sources/plugins/liststyle/lang/th.js25
-rw-r--r--sources/plugins/liststyle/lang/tr.js25
-rw-r--r--sources/plugins/liststyle/lang/tt.js25
-rw-r--r--sources/plugins/liststyle/lang/ug.js25
-rw-r--r--sources/plugins/liststyle/lang/uk.js25
-rw-r--r--sources/plugins/liststyle/lang/vi.js25
-rw-r--r--sources/plugins/liststyle/lang/zh-cn.js25
-rw-r--r--sources/plugins/liststyle/lang/zh.js25
-rw-r--r--sources/plugins/liststyle/plugin.js75
-rw-r--r--sources/plugins/magicline/dev/magicline.html594
-rw-r--r--sources/plugins/magicline/images/hidpi/icon-rtl.pngbin0 -> 176 bytes
-rw-r--r--sources/plugins/magicline/images/hidpi/icon.pngbin0 -> 199 bytes
-rw-r--r--sources/plugins/magicline/images/icon-rtl.pngbin0 -> 138 bytes
-rw-r--r--sources/plugins/magicline/images/icon.pngbin0 -> 133 bytes
-rw-r--r--sources/plugins/magicline/lang/af.js8
-rw-r--r--sources/plugins/magicline/lang/ar.js8
-rw-r--r--sources/plugins/magicline/lang/az.js8
-rw-r--r--sources/plugins/magicline/lang/bg.js8
-rw-r--r--sources/plugins/magicline/lang/ca.js8
-rw-r--r--sources/plugins/magicline/lang/cs.js8
-rw-r--r--sources/plugins/magicline/lang/cy.js8
-rw-r--r--sources/plugins/magicline/lang/da.js8
-rw-r--r--sources/plugins/magicline/lang/de-ch.js8
-rw-r--r--sources/plugins/magicline/lang/de.js8
-rw-r--r--sources/plugins/magicline/lang/el.js8
-rw-r--r--sources/plugins/magicline/lang/en-gb.js8
-rw-r--r--sources/plugins/magicline/lang/en.js8
-rw-r--r--sources/plugins/magicline/lang/eo.js8
-rw-r--r--sources/plugins/magicline/lang/es.js8
-rw-r--r--sources/plugins/magicline/lang/et.js8
-rw-r--r--sources/plugins/magicline/lang/eu.js8
-rw-r--r--sources/plugins/magicline/lang/fa.js8
-rw-r--r--sources/plugins/magicline/lang/fi.js8
-rw-r--r--sources/plugins/magicline/lang/fr-ca.js8
-rw-r--r--sources/plugins/magicline/lang/fr.js8
-rw-r--r--sources/plugins/magicline/lang/gl.js8
-rw-r--r--sources/plugins/magicline/lang/he.js8
-rw-r--r--sources/plugins/magicline/lang/hr.js8
-rw-r--r--sources/plugins/magicline/lang/hu.js8
-rw-r--r--sources/plugins/magicline/lang/id.js8
-rw-r--r--sources/plugins/magicline/lang/it.js8
-rw-r--r--sources/plugins/magicline/lang/ja.js8
-rw-r--r--sources/plugins/magicline/lang/km.js8
-rw-r--r--sources/plugins/magicline/lang/ko.js8
-rw-r--r--sources/plugins/magicline/lang/ku.js8
-rw-r--r--sources/plugins/magicline/lang/lv.js8
-rw-r--r--sources/plugins/magicline/lang/nb.js8
-rw-r--r--sources/plugins/magicline/lang/nl.js8
-rw-r--r--sources/plugins/magicline/lang/no.js8
-rw-r--r--sources/plugins/magicline/lang/oc.js8
-rw-r--r--sources/plugins/magicline/lang/pl.js8
-rw-r--r--sources/plugins/magicline/lang/pt-br.js8
-rw-r--r--sources/plugins/magicline/lang/pt.js8
-rw-r--r--sources/plugins/magicline/lang/ru.js8
-rw-r--r--sources/plugins/magicline/lang/si.js8
-rw-r--r--sources/plugins/magicline/lang/sk.js8
-rw-r--r--sources/plugins/magicline/lang/sl.js8
-rw-r--r--sources/plugins/magicline/lang/sq.js8
-rw-r--r--sources/plugins/magicline/lang/sv.js8
-rw-r--r--sources/plugins/magicline/lang/tr.js8
-rw-r--r--sources/plugins/magicline/lang/tt.js8
-rw-r--r--sources/plugins/magicline/lang/ug.js8
-rw-r--r--sources/plugins/magicline/lang/uk.js8
-rw-r--r--sources/plugins/magicline/lang/vi.js8
-rw-r--r--sources/plugins/magicline/lang/zh-cn.js8
-rw-r--r--sources/plugins/magicline/lang/zh.js8
-rw-r--r--sources/plugins/magicline/plugin.js1874
-rw-r--r--sources/plugins/magicline/samples/magicline.html209
-rw-r--r--sources/plugins/maximize/icons/hidpi/maximize.pngbin0 -> 1112 bytes
-rw-r--r--sources/plugins/maximize/icons/maximize.pngbin0 -> 461 bytes
-rw-r--r--sources/plugins/maximize/lang/af.js8
-rw-r--r--sources/plugins/maximize/lang/ar.js8
-rw-r--r--sources/plugins/maximize/lang/az.js8
-rw-r--r--sources/plugins/maximize/lang/bg.js8
-rw-r--r--sources/plugins/maximize/lang/bn.js8
-rw-r--r--sources/plugins/maximize/lang/bs.js8
-rw-r--r--sources/plugins/maximize/lang/ca.js8
-rw-r--r--sources/plugins/maximize/lang/cs.js8
-rw-r--r--sources/plugins/maximize/lang/cy.js8
-rw-r--r--sources/plugins/maximize/lang/da.js8
-rw-r--r--sources/plugins/maximize/lang/de-ch.js8
-rw-r--r--sources/plugins/maximize/lang/de.js8
-rw-r--r--sources/plugins/maximize/lang/el.js8
-rw-r--r--sources/plugins/maximize/lang/en-au.js8
-rw-r--r--sources/plugins/maximize/lang/en-ca.js8
-rw-r--r--sources/plugins/maximize/lang/en-gb.js8
-rw-r--r--sources/plugins/maximize/lang/en.js8
-rw-r--r--sources/plugins/maximize/lang/eo.js8
-rw-r--r--sources/plugins/maximize/lang/es.js8
-rw-r--r--sources/plugins/maximize/lang/et.js8
-rw-r--r--sources/plugins/maximize/lang/eu.js8
-rw-r--r--sources/plugins/maximize/lang/fa.js8
-rw-r--r--sources/plugins/maximize/lang/fi.js8
-rw-r--r--sources/plugins/maximize/lang/fo.js8
-rw-r--r--sources/plugins/maximize/lang/fr-ca.js8
-rw-r--r--sources/plugins/maximize/lang/fr.js8
-rw-r--r--sources/plugins/maximize/lang/gl.js8
-rw-r--r--sources/plugins/maximize/lang/gu.js8
-rw-r--r--sources/plugins/maximize/lang/he.js8
-rw-r--r--sources/plugins/maximize/lang/hi.js8
-rw-r--r--sources/plugins/maximize/lang/hr.js8
-rw-r--r--sources/plugins/maximize/lang/hu.js8
-rw-r--r--sources/plugins/maximize/lang/id.js8
-rw-r--r--sources/plugins/maximize/lang/is.js8
-rw-r--r--sources/plugins/maximize/lang/it.js8
-rw-r--r--sources/plugins/maximize/lang/ja.js8
-rw-r--r--sources/plugins/maximize/lang/ka.js8
-rw-r--r--sources/plugins/maximize/lang/km.js8
-rw-r--r--sources/plugins/maximize/lang/ko.js8
-rw-r--r--sources/plugins/maximize/lang/ku.js8
-rw-r--r--sources/plugins/maximize/lang/lt.js8
-rw-r--r--sources/plugins/maximize/lang/lv.js8
-rw-r--r--sources/plugins/maximize/lang/mk.js8
-rw-r--r--sources/plugins/maximize/lang/mn.js8
-rw-r--r--sources/plugins/maximize/lang/ms.js8
-rw-r--r--sources/plugins/maximize/lang/nb.js8
-rw-r--r--sources/plugins/maximize/lang/nl.js8
-rw-r--r--sources/plugins/maximize/lang/no.js8
-rw-r--r--sources/plugins/maximize/lang/oc.js8
-rw-r--r--sources/plugins/maximize/lang/pl.js8
-rw-r--r--sources/plugins/maximize/lang/pt-br.js8
-rw-r--r--sources/plugins/maximize/lang/pt.js8
-rw-r--r--sources/plugins/maximize/lang/ro.js8
-rw-r--r--sources/plugins/maximize/lang/ru.js8
-rw-r--r--sources/plugins/maximize/lang/si.js8
-rw-r--r--sources/plugins/maximize/lang/sk.js8
-rw-r--r--sources/plugins/maximize/lang/sl.js8
-rw-r--r--sources/plugins/maximize/lang/sq.js8
-rw-r--r--sources/plugins/maximize/lang/sr-latn.js8
-rw-r--r--sources/plugins/maximize/lang/sr.js8
-rw-r--r--sources/plugins/maximize/lang/sv.js8
-rw-r--r--sources/plugins/maximize/lang/th.js8
-rw-r--r--sources/plugins/maximize/lang/tr.js8
-rw-r--r--sources/plugins/maximize/lang/tt.js8
-rw-r--r--sources/plugins/maximize/lang/ug.js8
-rw-r--r--sources/plugins/maximize/lang/uk.js8
-rw-r--r--sources/plugins/maximize/lang/vi.js8
-rw-r--r--sources/plugins/maximize/lang/zh-cn.js8
-rw-r--r--sources/plugins/maximize/lang/zh.js8
-rw-r--r--sources/plugins/maximize/plugin.js314
-rw-r--r--sources/plugins/menu/plugin.js572
-rw-r--r--sources/plugins/oembed/LICENSE.md21
-rw-r--r--sources/plugins/oembed/README.md201
-rw-r--r--sources/plugins/oembed/icons/hidpi/oembed.pngbin0 -> 1849 bytes
-rw-r--r--sources/plugins/oembed/icons/oembed.pngbin0 -> 3143 bytes
-rw-r--r--sources/plugins/oembed/lang/de.js23
-rw-r--r--sources/plugins/oembed/lang/en.js23
-rw-r--r--sources/plugins/oembed/lang/fr.js25
-rw-r--r--sources/plugins/oembed/lang/nl.js23
-rw-r--r--sources/plugins/oembed/lang/pl.js23
-rw-r--r--sources/plugins/oembed/lang/pt-br.js23
-rw-r--r--sources/plugins/oembed/lang/ru.js23
-rw-r--r--sources/plugins/oembed/lang/tr.js23
-rw-r--r--sources/plugins/oembed/libs/jquery.oembed.min.js1
-rw-r--r--sources/plugins/oembed/plugin.js446
-rw-r--r--sources/plugins/panel/plugin.js403
-rw-r--r--sources/plugins/popup/plugin.js65
-rw-r--r--sources/plugins/removeformat/icons/hidpi/removeformat.pngbin0 -> 1219 bytes
-rw-r--r--sources/plugins/removeformat/icons/removeformat.pngbin0 -> 637 bytes
-rw-r--r--sources/plugins/removeformat/lang/af.js7
-rw-r--r--sources/plugins/removeformat/lang/ar.js7
-rw-r--r--sources/plugins/removeformat/lang/az.js7
-rw-r--r--sources/plugins/removeformat/lang/bg.js7
-rw-r--r--sources/plugins/removeformat/lang/bn.js7
-rw-r--r--sources/plugins/removeformat/lang/bs.js7
-rw-r--r--sources/plugins/removeformat/lang/ca.js7
-rw-r--r--sources/plugins/removeformat/lang/cs.js7
-rw-r--r--sources/plugins/removeformat/lang/cy.js7
-rw-r--r--sources/plugins/removeformat/lang/da.js7
-rw-r--r--sources/plugins/removeformat/lang/de-ch.js7
-rw-r--r--sources/plugins/removeformat/lang/de.js7
-rw-r--r--sources/plugins/removeformat/lang/el.js7
-rw-r--r--sources/plugins/removeformat/lang/en-au.js7
-rw-r--r--sources/plugins/removeformat/lang/en-ca.js7
-rw-r--r--sources/plugins/removeformat/lang/en-gb.js7
-rw-r--r--sources/plugins/removeformat/lang/en.js7
-rw-r--r--sources/plugins/removeformat/lang/eo.js7
-rw-r--r--sources/plugins/removeformat/lang/es.js7
-rw-r--r--sources/plugins/removeformat/lang/et.js7
-rw-r--r--sources/plugins/removeformat/lang/eu.js7
-rw-r--r--sources/plugins/removeformat/lang/fa.js7
-rw-r--r--sources/plugins/removeformat/lang/fi.js7
-rw-r--r--sources/plugins/removeformat/lang/fo.js7
-rw-r--r--sources/plugins/removeformat/lang/fr-ca.js7
-rw-r--r--sources/plugins/removeformat/lang/fr.js7
-rw-r--r--sources/plugins/removeformat/lang/gl.js7
-rw-r--r--sources/plugins/removeformat/lang/gu.js7
-rw-r--r--sources/plugins/removeformat/lang/he.js7
-rw-r--r--sources/plugins/removeformat/lang/hi.js7
-rw-r--r--sources/plugins/removeformat/lang/hr.js7
-rw-r--r--sources/plugins/removeformat/lang/hu.js7
-rw-r--r--sources/plugins/removeformat/lang/id.js7
-rw-r--r--sources/plugins/removeformat/lang/is.js7
-rw-r--r--sources/plugins/removeformat/lang/it.js7
-rw-r--r--sources/plugins/removeformat/lang/ja.js7
-rw-r--r--sources/plugins/removeformat/lang/ka.js7
-rw-r--r--sources/plugins/removeformat/lang/km.js7
-rw-r--r--sources/plugins/removeformat/lang/ko.js7
-rw-r--r--sources/plugins/removeformat/lang/ku.js7
-rw-r--r--sources/plugins/removeformat/lang/lt.js7
-rw-r--r--sources/plugins/removeformat/lang/lv.js7
-rw-r--r--sources/plugins/removeformat/lang/mk.js7
-rw-r--r--sources/plugins/removeformat/lang/mn.js7
-rw-r--r--sources/plugins/removeformat/lang/ms.js7
-rw-r--r--sources/plugins/removeformat/lang/nb.js7
-rw-r--r--sources/plugins/removeformat/lang/nl.js7
-rw-r--r--sources/plugins/removeformat/lang/no.js7
-rw-r--r--sources/plugins/removeformat/lang/oc.js7
-rw-r--r--sources/plugins/removeformat/lang/pl.js7
-rw-r--r--sources/plugins/removeformat/lang/pt-br.js7
-rw-r--r--sources/plugins/removeformat/lang/pt.js7
-rw-r--r--sources/plugins/removeformat/lang/ro.js7
-rw-r--r--sources/plugins/removeformat/lang/ru.js7
-rw-r--r--sources/plugins/removeformat/lang/si.js7
-rw-r--r--sources/plugins/removeformat/lang/sk.js7
-rw-r--r--sources/plugins/removeformat/lang/sl.js7
-rw-r--r--sources/plugins/removeformat/lang/sq.js7
-rw-r--r--sources/plugins/removeformat/lang/sr-latn.js7
-rw-r--r--sources/plugins/removeformat/lang/sr.js7
-rw-r--r--sources/plugins/removeformat/lang/sv.js7
-rw-r--r--sources/plugins/removeformat/lang/th.js7
-rw-r--r--sources/plugins/removeformat/lang/tr.js7
-rw-r--r--sources/plugins/removeformat/lang/tt.js7
-rw-r--r--sources/plugins/removeformat/lang/ug.js7
-rw-r--r--sources/plugins/removeformat/lang/uk.js7
-rw-r--r--sources/plugins/removeformat/lang/vi.js7
-rw-r--r--sources/plugins/removeformat/lang/zh-cn.js7
-rw-r--r--sources/plugins/removeformat/lang/zh.js7
-rw-r--r--sources/plugins/removeformat/plugin.js193
-rw-r--r--sources/plugins/resize/plugin.js187
-rw-r--r--sources/plugins/richcombo/plugin.js434
-rw-r--r--sources/plugins/showborders/plugin.js174
-rw-r--r--sources/plugins/sourcearea/icons/hidpi/source-rtl.pngbin0 -> 1018 bytes
-rw-r--r--sources/plugins/sourcearea/icons/hidpi/source.pngbin0 -> 1041 bytes
-rw-r--r--sources/plugins/sourcearea/icons/source-rtl.pngbin0 -> 565 bytes
-rw-r--r--sources/plugins/sourcearea/icons/source.pngbin0 -> 571 bytes
-rw-r--r--sources/plugins/sourcearea/lang/af.js7
-rw-r--r--sources/plugins/sourcearea/lang/ar.js7
-rw-r--r--sources/plugins/sourcearea/lang/az.js7
-rw-r--r--sources/plugins/sourcearea/lang/bg.js7
-rw-r--r--sources/plugins/sourcearea/lang/bn.js7
-rw-r--r--sources/plugins/sourcearea/lang/bs.js7
-rw-r--r--sources/plugins/sourcearea/lang/ca.js7
-rw-r--r--sources/plugins/sourcearea/lang/cs.js7
-rw-r--r--sources/plugins/sourcearea/lang/cy.js7
-rw-r--r--sources/plugins/sourcearea/lang/da.js7
-rw-r--r--sources/plugins/sourcearea/lang/de-ch.js7
-rw-r--r--sources/plugins/sourcearea/lang/de.js7
-rw-r--r--sources/plugins/sourcearea/lang/el.js7
-rw-r--r--sources/plugins/sourcearea/lang/en-au.js7
-rw-r--r--sources/plugins/sourcearea/lang/en-ca.js7
-rw-r--r--sources/plugins/sourcearea/lang/en-gb.js7
-rw-r--r--sources/plugins/sourcearea/lang/en.js7
-rw-r--r--sources/plugins/sourcearea/lang/eo.js7
-rw-r--r--sources/plugins/sourcearea/lang/es.js7
-rw-r--r--sources/plugins/sourcearea/lang/et.js7
-rw-r--r--sources/plugins/sourcearea/lang/eu.js7
-rw-r--r--sources/plugins/sourcearea/lang/fa.js7
-rw-r--r--sources/plugins/sourcearea/lang/fi.js7
-rw-r--r--sources/plugins/sourcearea/lang/fo.js7
-rw-r--r--sources/plugins/sourcearea/lang/fr-ca.js7
-rw-r--r--sources/plugins/sourcearea/lang/fr.js7
-rw-r--r--sources/plugins/sourcearea/lang/gl.js7
-rw-r--r--sources/plugins/sourcearea/lang/gu.js7
-rw-r--r--sources/plugins/sourcearea/lang/he.js7
-rw-r--r--sources/plugins/sourcearea/lang/hi.js7
-rw-r--r--sources/plugins/sourcearea/lang/hr.js7
-rw-r--r--sources/plugins/sourcearea/lang/hu.js7
-rw-r--r--sources/plugins/sourcearea/lang/id.js7
-rw-r--r--sources/plugins/sourcearea/lang/is.js7
-rw-r--r--sources/plugins/sourcearea/lang/it.js7
-rw-r--r--sources/plugins/sourcearea/lang/ja.js7
-rw-r--r--sources/plugins/sourcearea/lang/ka.js7
-rw-r--r--sources/plugins/sourcearea/lang/km.js7
-rw-r--r--sources/plugins/sourcearea/lang/ko.js7
-rw-r--r--sources/plugins/sourcearea/lang/ku.js7
-rw-r--r--sources/plugins/sourcearea/lang/lt.js7
-rw-r--r--sources/plugins/sourcearea/lang/lv.js7
-rw-r--r--sources/plugins/sourcearea/lang/mk.js7
-rw-r--r--sources/plugins/sourcearea/lang/mn.js7
-rw-r--r--sources/plugins/sourcearea/lang/ms.js7
-rw-r--r--sources/plugins/sourcearea/lang/nb.js7
-rw-r--r--sources/plugins/sourcearea/lang/nl.js7
-rw-r--r--sources/plugins/sourcearea/lang/no.js7
-rw-r--r--sources/plugins/sourcearea/lang/oc.js7
-rw-r--r--sources/plugins/sourcearea/lang/pl.js7
-rw-r--r--sources/plugins/sourcearea/lang/pt-br.js7
-rw-r--r--sources/plugins/sourcearea/lang/pt.js7
-rw-r--r--sources/plugins/sourcearea/lang/ro.js7
-rw-r--r--sources/plugins/sourcearea/lang/ru.js7
-rw-r--r--sources/plugins/sourcearea/lang/si.js7
-rw-r--r--sources/plugins/sourcearea/lang/sk.js7
-rw-r--r--sources/plugins/sourcearea/lang/sl.js7
-rw-r--r--sources/plugins/sourcearea/lang/sq.js7
-rw-r--r--sources/plugins/sourcearea/lang/sr-latn.js7
-rw-r--r--sources/plugins/sourcearea/lang/sr.js7
-rw-r--r--sources/plugins/sourcearea/lang/sv.js7
-rw-r--r--sources/plugins/sourcearea/lang/th.js7
-rw-r--r--sources/plugins/sourcearea/lang/tr.js7
-rw-r--r--sources/plugins/sourcearea/lang/tt.js7
-rw-r--r--sources/plugins/sourcearea/lang/ug.js7
-rw-r--r--sources/plugins/sourcearea/lang/uk.js7
-rw-r--r--sources/plugins/sourcearea/lang/vi.js7
-rw-r--r--sources/plugins/sourcearea/lang/zh-cn.js7
-rw-r--r--sources/plugins/sourcearea/lang/zh.js7
-rw-r--r--sources/plugins/sourcearea/plugin.js168
-rw-r--r--sources/plugins/tab/plugin.js302
-rw-r--r--sources/plugins/toolbar/lang/af.js22
-rw-r--r--sources/plugins/toolbar/lang/ar.js22
-rw-r--r--sources/plugins/toolbar/lang/az.js22
-rw-r--r--sources/plugins/toolbar/lang/bg.js22
-rw-r--r--sources/plugins/toolbar/lang/bn.js22
-rw-r--r--sources/plugins/toolbar/lang/bs.js22
-rw-r--r--sources/plugins/toolbar/lang/ca.js22
-rw-r--r--sources/plugins/toolbar/lang/cs.js22
-rw-r--r--sources/plugins/toolbar/lang/cy.js22
-rw-r--r--sources/plugins/toolbar/lang/da.js22
-rw-r--r--sources/plugins/toolbar/lang/de-ch.js22
-rw-r--r--sources/plugins/toolbar/lang/de.js22
-rw-r--r--sources/plugins/toolbar/lang/el.js22
-rw-r--r--sources/plugins/toolbar/lang/en-au.js22
-rw-r--r--sources/plugins/toolbar/lang/en-ca.js22
-rw-r--r--sources/plugins/toolbar/lang/en-gb.js22
-rw-r--r--sources/plugins/toolbar/lang/en.js22
-rw-r--r--sources/plugins/toolbar/lang/eo.js22
-rw-r--r--sources/plugins/toolbar/lang/es.js22
-rw-r--r--sources/plugins/toolbar/lang/et.js22
-rw-r--r--sources/plugins/toolbar/lang/eu.js22
-rw-r--r--sources/plugins/toolbar/lang/fa.js22
-rw-r--r--sources/plugins/toolbar/lang/fi.js22
-rw-r--r--sources/plugins/toolbar/lang/fo.js22
-rw-r--r--sources/plugins/toolbar/lang/fr-ca.js22
-rw-r--r--sources/plugins/toolbar/lang/fr.js22
-rw-r--r--sources/plugins/toolbar/lang/gl.js22
-rw-r--r--sources/plugins/toolbar/lang/gu.js22
-rw-r--r--sources/plugins/toolbar/lang/he.js22
-rw-r--r--sources/plugins/toolbar/lang/hi.js22
-rw-r--r--sources/plugins/toolbar/lang/hr.js22
-rw-r--r--sources/plugins/toolbar/lang/hu.js22
-rw-r--r--sources/plugins/toolbar/lang/id.js22
-rw-r--r--sources/plugins/toolbar/lang/is.js22
-rw-r--r--sources/plugins/toolbar/lang/it.js22
-rw-r--r--sources/plugins/toolbar/lang/ja.js22
-rw-r--r--sources/plugins/toolbar/lang/ka.js22
-rw-r--r--sources/plugins/toolbar/lang/km.js22
-rw-r--r--sources/plugins/toolbar/lang/ko.js22
-rw-r--r--sources/plugins/toolbar/lang/ku.js22
-rw-r--r--sources/plugins/toolbar/lang/lt.js22
-rw-r--r--sources/plugins/toolbar/lang/lv.js22
-rw-r--r--sources/plugins/toolbar/lang/mk.js22
-rw-r--r--sources/plugins/toolbar/lang/mn.js22
-rw-r--r--sources/plugins/toolbar/lang/ms.js22
-rw-r--r--sources/plugins/toolbar/lang/nb.js22
-rw-r--r--sources/plugins/toolbar/lang/nl.js22
-rw-r--r--sources/plugins/toolbar/lang/no.js22
-rw-r--r--sources/plugins/toolbar/lang/oc.js22
-rw-r--r--sources/plugins/toolbar/lang/pl.js22
-rw-r--r--sources/plugins/toolbar/lang/pt-br.js22
-rw-r--r--sources/plugins/toolbar/lang/pt.js22
-rw-r--r--sources/plugins/toolbar/lang/ro.js22
-rw-r--r--sources/plugins/toolbar/lang/ru.js22
-rw-r--r--sources/plugins/toolbar/lang/si.js22
-rw-r--r--sources/plugins/toolbar/lang/sk.js22
-rw-r--r--sources/plugins/toolbar/lang/sl.js22
-rw-r--r--sources/plugins/toolbar/lang/sq.js22
-rw-r--r--sources/plugins/toolbar/lang/sr-latn.js22
-rw-r--r--sources/plugins/toolbar/lang/sr.js22
-rw-r--r--sources/plugins/toolbar/lang/sv.js22
-rw-r--r--sources/plugins/toolbar/lang/th.js22
-rw-r--r--sources/plugins/toolbar/lang/tr.js22
-rw-r--r--sources/plugins/toolbar/lang/tt.js22
-rw-r--r--sources/plugins/toolbar/lang/ug.js22
-rw-r--r--sources/plugins/toolbar/lang/uk.js22
-rw-r--r--sources/plugins/toolbar/lang/vi.js22
-rw-r--r--sources/plugins/toolbar/lang/zh-cn.js22
-rw-r--r--sources/plugins/toolbar/lang/zh.js22
-rw-r--r--sources/plugins/toolbar/plugin.js806
-rw-r--r--sources/plugins/toolbar/samples/toolbar.html235
-rw-r--r--sources/plugins/widget/dev/assets/contents.css23
-rw-r--r--sources/plugins/widget/dev/assets/sample.jpgbin0 -> 17932 bytes
-rw-r--r--sources/plugins/widget/dev/assets/simplebox/contents.css36
-rw-r--r--sources/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js51
-rw-r--r--sources/plugins/widget/dev/assets/simplebox/icons/simplebox.pngbin0 -> 286 bytes
-rw-r--r--sources/plugins/widget/dev/assets/simplebox/plugin.js114
-rw-r--r--sources/plugins/widget/dev/console.js131
-rw-r--r--sources/plugins/widget/dev/nestedwidgets.html134
-rw-r--r--sources/plugins/widget/dev/widgetstyles.html144
-rw-r--r--sources/plugins/widget/images/handle.pngbin0 -> 220 bytes
-rw-r--r--sources/plugins/widget/lang/af.js8
-rw-r--r--sources/plugins/widget/lang/ar.js8
-rw-r--r--sources/plugins/widget/lang/az.js8
-rw-r--r--sources/plugins/widget/lang/bg.js8
-rw-r--r--sources/plugins/widget/lang/ca.js8
-rw-r--r--sources/plugins/widget/lang/cs.js8
-rw-r--r--sources/plugins/widget/lang/cy.js8
-rw-r--r--sources/plugins/widget/lang/da.js8
-rw-r--r--sources/plugins/widget/lang/de-ch.js8
-rw-r--r--sources/plugins/widget/lang/de.js8
-rw-r--r--sources/plugins/widget/lang/el.js8
-rw-r--r--sources/plugins/widget/lang/en-gb.js8
-rw-r--r--sources/plugins/widget/lang/en.js8
-rw-r--r--sources/plugins/widget/lang/eo.js8
-rw-r--r--sources/plugins/widget/lang/es.js8
-rw-r--r--sources/plugins/widget/lang/eu.js8
-rw-r--r--sources/plugins/widget/lang/fa.js8
-rw-r--r--sources/plugins/widget/lang/fi.js8
-rw-r--r--sources/plugins/widget/lang/fr.js8
-rw-r--r--sources/plugins/widget/lang/gl.js8
-rw-r--r--sources/plugins/widget/lang/he.js8
-rw-r--r--sources/plugins/widget/lang/hr.js8
-rw-r--r--sources/plugins/widget/lang/hu.js8
-rw-r--r--sources/plugins/widget/lang/id.js8
-rw-r--r--sources/plugins/widget/lang/it.js8
-rw-r--r--sources/plugins/widget/lang/ja.js8
-rw-r--r--sources/plugins/widget/lang/km.js8
-rw-r--r--sources/plugins/widget/lang/ko.js8
-rw-r--r--sources/plugins/widget/lang/ku.js8
-rw-r--r--sources/plugins/widget/lang/lv.js8
-rw-r--r--sources/plugins/widget/lang/nb.js8
-rw-r--r--sources/plugins/widget/lang/nl.js8
-rw-r--r--sources/plugins/widget/lang/no.js8
-rw-r--r--sources/plugins/widget/lang/oc.js8
-rw-r--r--sources/plugins/widget/lang/pl.js8
-rw-r--r--sources/plugins/widget/lang/pt-br.js8
-rw-r--r--sources/plugins/widget/lang/pt.js8
-rw-r--r--sources/plugins/widget/lang/ru.js8
-rw-r--r--sources/plugins/widget/lang/sk.js8
-rw-r--r--sources/plugins/widget/lang/sl.js8
-rw-r--r--sources/plugins/widget/lang/sq.js8
-rw-r--r--sources/plugins/widget/lang/sv.js8
-rw-r--r--sources/plugins/widget/lang/tr.js8
-rw-r--r--sources/plugins/widget/lang/tt.js8
-rw-r--r--sources/plugins/widget/lang/ug.js8
-rw-r--r--sources/plugins/widget/lang/uk.js8
-rw-r--r--sources/plugins/widget/lang/vi.js8
-rw-r--r--sources/plugins/widget/lang/zh-cn.js8
-rw-r--r--sources/plugins/widget/lang/zh.js8
-rw-r--r--sources/plugins/widget/plugin.js4126
-rw-r--r--sources/plugins/widgetselection/plugin.js366
-rw-r--r--sources/plugins/wysiwygarea/plugin.js713
-rw-r--r--sources/plugins/wysiwygarea/samples/fullpage.html80
-rw-r--r--sources/samples/css/samples.css1632
-rw-r--r--sources/samples/img/github-top.pngbin0 -> 383 bytes
-rw-r--r--sources/samples/img/header-bg.pngbin0 -> 13086 bytes
-rw-r--r--sources/samples/img/header-separator.pngbin0 -> 123 bytes
-rw-r--r--sources/samples/img/logo.pngbin0 -> 5891 bytes
-rw-r--r--sources/samples/img/navigation-tip.pngbin0 -> 12029 bytes
-rw-r--r--sources/samples/index.html128
-rw-r--r--sources/samples/js/sample.js54
-rw-r--r--sources/samples/js/sf.js673
-rw-r--r--sources/samples/old/ajax.html85
-rw-r--r--sources/samples/old/api.html210
-rw-r--r--sources/samples/old/appendto.html59
-rw-r--r--sources/samples/old/assets/inlineall/logo.pngbin0 -> 4283 bytes
-rw-r--r--sources/samples/old/assets/outputxhtml/outputxhtml.css204
-rw-r--r--sources/samples/old/assets/posteddata.php59
-rw-r--r--sources/samples/old/assets/sample.jpgbin0 -> 14449 bytes
-rw-r--r--sources/samples/old/assets/uilanguages/languages.js92
-rw-r--r--sources/samples/old/datafiltering.html508
-rw-r--r--sources/samples/old/divreplace.html144
-rw-r--r--sources/samples/old/index.html111
-rw-r--r--sources/samples/old/inlineall.html314
-rw-r--r--sources/samples/old/inlinebycode.html124
-rw-r--r--sources/samples/old/inlinetextarea.html113
-rw-r--r--sources/samples/old/jquery.html103
-rw-r--r--sources/samples/old/readonly.html76
-rw-r--r--sources/samples/old/replacebyclass.html60
-rw-r--r--sources/samples/old/replacebycode.html59
-rw-r--r--sources/samples/old/sample.css357
-rw-r--r--sources/samples/old/sample.js51
-rw-r--r--sources/samples/old/sample_posteddata.php16
-rw-r--r--sources/samples/old/tabindex.html78
-rw-r--r--sources/samples/old/uicolor.html72
-rw-r--r--sources/samples/old/uilanguages.html122
-rw-r--r--sources/samples/old/xhtmlstyle.html234
-rw-r--r--sources/samples/toolbarconfigurator/bender.js52
-rw-r--r--sources/samples/toolbarconfigurator/css/fontello.css55
-rw-r--r--sources/samples/toolbarconfigurator/font/LICENSE.txt12
-rw-r--r--sources/samples/toolbarconfigurator/font/config.json28
-rw-r--r--sources/samples/toolbarconfigurator/font/fontello.eotbin0 -> 4988 bytes
-rw-r--r--sources/samples/toolbarconfigurator/font/fontello.svg14
-rw-r--r--sources/samples/toolbarconfigurator/font/fontello.ttfbin0 -> 4820 bytes
-rw-r--r--sources/samples/toolbarconfigurator/font/fontello.woffbin0 -> 2904 bytes
-rw-r--r--sources/samples/toolbarconfigurator/index.html446
-rw-r--r--sources/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js566
-rw-r--r--sources/samples/toolbarconfigurator/js/fulltoolbareditor.js365
-rw-r--r--sources/samples/toolbarconfigurator/js/toolbarmodifier.js1366
-rw-r--r--sources/samples/toolbarconfigurator/js/toolbartextmodifier.js623
-rw-r--r--sources/samples/toolbarconfigurator/less/base.less38
-rw-r--r--sources/samples/toolbarconfigurator/less/toolbarmodifier.less508
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/LICENSE19
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/README.md12
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/codemirror.css325
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/codemirror.js8738
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/javascript.js701
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/neo.css36
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/show-hint.css38
-rw-r--r--sources/samples/toolbarconfigurator/lib/codemirror/show-hint.js392
-rw-r--r--sources/samples/toolbarconfigurator/package.json12
-rw-r--r--sources/samples/toolbarconfigurator/tests/one.js9
-rw-r--r--sources/skins/moono/colorpanel.css127
-rw-r--r--sources/skins/moono/dev/icons16.pngbin0 -> 29947 bytes
-rw-r--r--sources/skins/moono/dev/icons16.svg2374
-rw-r--r--sources/skins/moono/dev/icons32.pngbin0 -> 75488 bytes
-rw-r--r--sources/skins/moono/dev/icons32.svg2722
-rw-r--r--sources/skins/moono/dev/locations.json145
-rw-r--r--sources/skins/moono/dialog.css1060
-rw-r--r--sources/skins/moono/dialog_ie.css62
-rw-r--r--sources/skins/moono/dialog_ie7.css68
-rw-r--r--sources/skins/moono/dialog_ie8.css24
-rw-r--r--sources/skins/moono/dialog_iequirks.css21
-rw-r--r--sources/skins/moono/editor.css69
-rw-r--r--sources/skins/moono/editor_gecko.css25
-rw-r--r--sources/skins/moono/editor_ie.css71
-rw-r--r--sources/skins/moono/editor_ie7.css213
-rw-r--r--sources/skins/moono/editor_ie8.css27
-rw-r--r--sources/skins/moono/editor_iequirks.css79
-rw-r--r--sources/skins/moono/elementspath.css76
-rw-r--r--sources/skins/moono/icons/about.pngbin0 -> 1101 bytes
-rw-r--r--sources/skins/moono/icons/anchor-rtl.pngbin0 -> 893 bytes
-rw-r--r--sources/skins/moono/icons/anchor.pngbin0 -> 913 bytes
-rw-r--r--sources/skins/moono/icons/bgcolor.pngbin0 -> 1005 bytes
-rw-r--r--sources/skins/moono/icons/bidiltr.pngbin0 -> 954 bytes
-rw-r--r--sources/skins/moono/icons/bidirtl.pngbin0 -> 986 bytes
-rw-r--r--sources/skins/moono/icons/blockquote.pngbin0 -> 1126 bytes
-rw-r--r--sources/skins/moono/icons/bold.pngbin0 -> 985 bytes
-rw-r--r--sources/skins/moono/icons/bulletedlist-rtl.pngbin0 -> 814 bytes
-rw-r--r--sources/skins/moono/icons/bulletedlist.pngbin0 -> 811 bytes
-rw-r--r--sources/skins/moono/icons/button.pngbin0 -> 637 bytes
-rw-r--r--sources/skins/moono/icons/checkbox.pngbin0 -> 1005 bytes
-rw-r--r--sources/skins/moono/icons/codesnippet.pngbin0 -> 827 bytes
-rw-r--r--sources/skins/moono/icons/copy-rtl.pngbin0 -> 1011 bytes
-rw-r--r--sources/skins/moono/icons/copy.pngbin0 -> 1011 bytes
-rw-r--r--sources/skins/moono/icons/copyformatting.pngbin0 -> 1293 bytes
-rw-r--r--sources/skins/moono/icons/creatediv.pngbin0 -> 1128 bytes
-rw-r--r--sources/skins/moono/icons/cut-rtl.pngbin0 -> 1177 bytes
-rw-r--r--sources/skins/moono/icons/cut.pngbin0 -> 1177 bytes
-rw-r--r--sources/skins/moono/icons/docprops-rtl.pngbin0 -> 1093 bytes
-rw-r--r--sources/skins/moono/icons/docprops.pngbin0 -> 1078 bytes
-rw-r--r--sources/skins/moono/icons/find-rtl.pngbin0 -> 1132 bytes
-rw-r--r--sources/skins/moono/icons/find.pngbin0 -> 1132 bytes
-rw-r--r--sources/skins/moono/icons/flash.pngbin0 -> 1162 bytes
-rw-r--r--sources/skins/moono/icons/form.pngbin0 -> 819 bytes
-rw-r--r--sources/skins/moono/icons/hiddenfield.pngbin0 -> 1092 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/.DS_Storebin0 -> 12292 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/about.pngbin0 -> 2197 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/anchor-rtl.pngbin0 -> 1474 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/anchor.pngbin0 -> 1527 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bgcolor.pngbin0 -> 2169 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bidiltr.pngbin0 -> 1672 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bidirtl.pngbin0 -> 1702 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/blockquote.pngbin0 -> 2421 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bold.pngbin0 -> 1987 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bulletedlist-rtl.pngbin0 -> 1659 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/bulletedlist.pngbin0 -> 1639 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/button.pngbin0 -> 988 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/checkbox.pngbin0 -> 1905 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/codesnippet.pngbin0 -> 1893 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/copy-rtl.pngbin0 -> 1905 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/copy.pngbin0 -> 1905 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/copyformatting.pngbin0 -> 1642 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/creatediv.pngbin0 -> 3049 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/cut-rtl.pngbin0 -> 2855 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/cut.pngbin0 -> 2855 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/docprops-rtl.pngbin0 -> 2179 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/docprops.pngbin0 -> 2228 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/find-rtl.pngbin0 -> 2407 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/find.pngbin0 -> 2407 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/flash.pngbin0 -> 2614 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/form.pngbin0 -> 1187 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/hiddenfield.pngbin0 -> 2346 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/horizontalrule.pngbin0 -> 894 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/iframe.pngbin0 -> 3099 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/image.pngbin0 -> 1782 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/imagebutton.pngbin0 -> 1462 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/indent-rtl.pngbin0 -> 1988 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/indent.pngbin0 -> 2024 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/italic.pngbin0 -> 1687 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/justifyblock.pngbin0 -> 830 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/justifycenter.pngbin0 -> 1372 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/justifyleft.pngbin0 -> 1092 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/justifyright.pngbin0 -> 1094 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/language.pngbin0 -> 1874 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/link.pngbin0 -> 1627 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/maximize.pngbin0 -> 2395 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/newpage-rtl.pngbin0 -> 1197 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/newpage.pngbin0 -> 1285 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/numberedlist-rtl.pngbin0 -> 1471 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/numberedlist.pngbin0 -> 1523 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/outdent-rtl.pngbin0 -> 1976 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/outdent.pngbin0 -> 1928 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pagebreak-rtl.pngbin0 -> 1379 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pagebreak.pngbin0 -> 1351 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/paste-rtl.pngbin0 -> 1956 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/paste.pngbin0 -> 1956 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pastefromword-rtl.pngbin0 -> 2071 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pastefromword.pngbin0 -> 2115 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pastetext-rtl.pngbin0 -> 1964 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/pastetext.pngbin0 -> 1963 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/placeholder.pngbin0 -> 1812 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/preview-rtl.pngbin0 -> 2336 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/preview.pngbin0 -> 2409 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/print.pngbin0 -> 1758 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/radio.pngbin0 -> 2676 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/redo-rtl.pngbin0 -> 1868 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/redo.pngbin0 -> 1885 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/removeformat.pngbin0 -> 2358 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/replace.pngbin0 -> 2822 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/save.pngbin0 -> 1678 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/scayt.pngbin0 -> 2854 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/select-rtl.pngbin0 -> 1601 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/select.pngbin0 -> 1608 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/selectall.pngbin0 -> 1149 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/showblocks-rtl.pngbin0 -> 2084 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/showblocks.pngbin0 -> 2030 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/smiley.pngbin0 -> 3096 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/source-rtl.pngbin0 -> 1955 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/source.pngbin0 -> 2035 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/sourcedialog-rtl.pngbin0 -> 1955 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/sourcedialog.pngbin0 -> 2035 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/specialchar.pngbin0 -> 2707 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/spellchecker.pngbin0 -> 2854 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/strike.pngbin0 -> 2256 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/subscript.pngbin0 -> 2025 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/superscript.pngbin0 -> 2029 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/table.pngbin0 -> 1201 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/templates-rtl.pngbin0 -> 1515 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/templates.pngbin0 -> 1515 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/textarea-rtl.pngbin0 -> 1988 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/textarea.pngbin0 -> 1857 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/textcolor.pngbin0 -> 1961 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/textfield-rtl.pngbin0 -> 1501 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/textfield.pngbin0 -> 1501 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/uicolor.pngbin0 -> 2234 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/underline.pngbin0 -> 1739 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/undo-rtl.pngbin0 -> 1885 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/undo.pngbin0 -> 1868 bytes
-rw-r--r--sources/skins/moono/icons/hidpi/unlink.pngbin0 -> 2293 bytes
-rw-r--r--sources/skins/moono/icons/horizontalrule.pngbin0 -> 560 bytes
-rw-r--r--sources/skins/moono/icons/iframe.pngbin0 -> 1227 bytes
-rw-r--r--sources/skins/moono/icons/image.pngbin0 -> 973 bytes
-rw-r--r--sources/skins/moono/icons/imagebutton.pngbin0 -> 813 bytes
-rw-r--r--sources/skins/moono/icons/indent-rtl.pngbin0 -> 959 bytes
-rw-r--r--sources/skins/moono/icons/indent.pngbin0 -> 967 bytes
-rw-r--r--sources/skins/moono/icons/italic.pngbin0 -> 932 bytes
-rw-r--r--sources/skins/moono/icons/justifyblock.pngbin0 -> 610 bytes
-rw-r--r--sources/skins/moono/icons/justifycenter.pngbin0 -> 830 bytes
-rw-r--r--sources/skins/moono/icons/justifyleft.pngbin0 -> 715 bytes
-rw-r--r--sources/skins/moono/icons/justifyright.pngbin0 -> 751 bytes
-rw-r--r--sources/skins/moono/icons/language.pngbin0 -> 885 bytes
-rw-r--r--sources/skins/moono/icons/link.pngbin0 -> 811 bytes
-rw-r--r--sources/skins/moono/icons/maximize.pngbin0 -> 1085 bytes
-rw-r--r--sources/skins/moono/icons/newpage-rtl.pngbin0 -> 858 bytes
-rw-r--r--sources/skins/moono/icons/newpage.pngbin0 -> 873 bytes
-rw-r--r--sources/skins/moono/icons/numberedlist-rtl.pngbin0 -> 821 bytes
-rw-r--r--sources/skins/moono/icons/numberedlist.pngbin0 -> 849 bytes
-rw-r--r--sources/skins/moono/icons/outdent-rtl.pngbin0 -> 959 bytes
-rw-r--r--sources/skins/moono/icons/outdent.pngbin0 -> 924 bytes
-rw-r--r--sources/skins/moono/icons/pagebreak-rtl.pngbin0 -> 804 bytes
-rw-r--r--sources/skins/moono/icons/pagebreak.pngbin0 -> 783 bytes
-rw-r--r--sources/skins/moono/icons/paste-rtl.pngbin0 -> 969 bytes
-rw-r--r--sources/skins/moono/icons/paste.pngbin0 -> 969 bytes
-rw-r--r--sources/skins/moono/icons/pastefromword-rtl.pngbin0 -> 967 bytes
-rw-r--r--sources/skins/moono/icons/pastefromword.pngbin0 -> 991 bytes
-rw-r--r--sources/skins/moono/icons/pastetext-rtl.pngbin0 -> 969 bytes
-rw-r--r--sources/skins/moono/icons/pastetext.pngbin0 -> 989 bytes
-rw-r--r--sources/skins/moono/icons/placeholder.pngbin0 -> 865 bytes
-rw-r--r--sources/skins/moono/icons/preview-rtl.pngbin0 -> 1077 bytes
-rw-r--r--sources/skins/moono/icons/preview.pngbin0 -> 1077 bytes
-rw-r--r--sources/skins/moono/icons/print.pngbin0 -> 920 bytes
-rw-r--r--sources/skins/moono/icons/radio.pngbin0 -> 1092 bytes
-rw-r--r--sources/skins/moono/icons/redo-rtl.pngbin0 -> 1012 bytes
-rw-r--r--sources/skins/moono/icons/redo.pngbin0 -> 1000 bytes
-rw-r--r--sources/skins/moono/icons/removeformat.pngbin0 -> 1079 bytes
-rw-r--r--sources/skins/moono/icons/replace.pngbin0 -> 1143 bytes
-rw-r--r--sources/skins/moono/icons/save.pngbin0 -> 896 bytes
-rw-r--r--sources/skins/moono/icons/scayt.pngbin0 -> 1094 bytes
-rw-r--r--sources/skins/moono/icons/select-rtl.pngbin0 -> 889 bytes
-rw-r--r--sources/skins/moono/icons/select.pngbin0 -> 882 bytes
-rw-r--r--sources/skins/moono/icons/selectall.pngbin0 -> 813 bytes
-rw-r--r--sources/skins/moono/icons/showblocks-rtl.pngbin0 -> 1000 bytes
-rw-r--r--sources/skins/moono/icons/showblocks.pngbin0 -> 1004 bytes
-rw-r--r--sources/skins/moono/icons/smiley.pngbin0 -> 1130 bytes
-rw-r--r--sources/skins/moono/icons/source-rtl.pngbin0 -> 1002 bytes
-rw-r--r--sources/skins/moono/icons/source.pngbin0 -> 988 bytes
-rw-r--r--sources/skins/moono/icons/sourcedialog-rtl.pngbin0 -> 1002 bytes
-rw-r--r--sources/skins/moono/icons/sourcedialog.pngbin0 -> 988 bytes
-rw-r--r--sources/skins/moono/icons/specialchar.pngbin0 -> 1156 bytes
-rw-r--r--sources/skins/moono/icons/spellchecker.pngbin0 -> 1094 bytes
-rw-r--r--sources/skins/moono/icons/strike.pngbin0 -> 1016 bytes
-rw-r--r--sources/skins/moono/icons/subscript.pngbin0 -> 978 bytes
-rw-r--r--sources/skins/moono/icons/superscript.pngbin0 -> 1015 bytes
-rw-r--r--sources/skins/moono/icons/table.pngbin0 -> 664 bytes
-rw-r--r--sources/skins/moono/icons/templates-rtl.pngbin0 -> 857 bytes
-rw-r--r--sources/skins/moono/icons/templates.pngbin0 -> 857 bytes
-rw-r--r--sources/skins/moono/icons/textarea-rtl.pngbin0 -> 986 bytes
-rw-r--r--sources/skins/moono/icons/textarea.pngbin0 -> 982 bytes
-rw-r--r--sources/skins/moono/icons/textcolor.pngbin0 -> 944 bytes
-rw-r--r--sources/skins/moono/icons/textfield-rtl.pngbin0 -> 859 bytes
-rw-r--r--sources/skins/moono/icons/textfield.pngbin0 -> 859 bytes
-rw-r--r--sources/skins/moono/icons/uicolor.pngbin0 -> 1090 bytes
-rw-r--r--sources/skins/moono/icons/underline.pngbin0 -> 895 bytes
-rw-r--r--sources/skins/moono/icons/undo-rtl.pngbin0 -> 1000 bytes
-rw-r--r--sources/skins/moono/icons/undo.pngbin0 -> 1011 bytes
-rw-r--r--sources/skins/moono/icons/unlink.pngbin0 -> 996 bytes
-rw-r--r--sources/skins/moono/images/anchor.pngbin0 -> 929 bytes
-rw-r--r--sources/skins/moono/images/arrow.pngbin0 -> 191 bytes
-rw-r--r--sources/skins/moono/images/close.pngbin0 -> 869 bytes
-rw-r--r--sources/skins/moono/images/hidpi/anchor.pngbin0 -> 1510 bytes
-rw-r--r--sources/skins/moono/images/hidpi/close.pngbin0 -> 1732 bytes
-rw-r--r--sources/skins/moono/images/hidpi/lock-open.pngbin0 -> 1582 bytes
-rw-r--r--sources/skins/moono/images/hidpi/lock.pngbin0 -> 1644 bytes
-rw-r--r--sources/skins/moono/images/hidpi/refresh.pngbin0 -> 2311 bytes
-rw-r--r--sources/skins/moono/images/lock-open.pngbin0 -> 801 bytes
-rw-r--r--sources/skins/moono/images/lock.pngbin0 -> 849 bytes
-rw-r--r--sources/skins/moono/images/refresh.pngbin0 -> 1050 bytes
-rw-r--r--sources/skins/moono/images/spinner.gifbin0 -> 2984 bytes
-rw-r--r--sources/skins/moono/mainui.css214
-rw-r--r--sources/skins/moono/menu.css207
-rw-r--r--sources/skins/moono/notification.css168
-rw-r--r--sources/skins/moono/panel.css237
-rw-r--r--sources/skins/moono/presets.css41
-rw-r--r--sources/skins/moono/readme.md49
-rw-r--r--sources/skins/moono/reset.css115
-rw-r--r--sources/skins/moono/richcombo.css210
-rw-r--r--sources/skins/moono/skin.js316
-rw-r--r--sources/skins/moono/toolbar.css387
-rw-r--r--sources/styles.js138
2048 files changed, 138798 insertions, 0 deletions
diff --git a/sources/CHANGES.md b/sources/CHANGES.md
new file mode 100644
index 0000000..1419e55
--- /dev/null
+++ b/sources/CHANGES.md
@@ -0,0 +1,1219 @@
1CKEditor 4 Changelog
2====================
3
4## CKEditor 4.6.2
5
6New Features:
7
8* [#16733](http://dev.ckeditor.com/ticket/16733): Added a new pastel color palette for the [Color Button](http://ckeditor.com/addon/colorbutton) plugin and a new [`config.colorButton_colorsPerRow`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-colorButton_colorsPerRow) configuration option for setting the number of rows in the color selector.
9* [#16752](http://dev.ckeditor.com/ticket/16752): Added a new Azerbaijani localization. Thanks to the [Azerbaijani language team](https://www.transifex.com/ckeditor/teams/11143/az/)!
10* [#13818](http://dev.ckeditor.com/ticket/13818): It is now possible to group [Widget](http://ckeditor.com/addon/widget) [style definitions](http://docs.ckeditor.com/#!/guide/dev_styles-section-widget-styles), so applying one style disables the other.
11
12Fixed Issues:
13
14* [#13446](http://dev.ckeditor.com/ticket/13446): [Chrome] Fixed: It is possible to type in an unfocused inline editor.
15* [#14856](http://dev.ckeditor.com/ticket/14856): Fixed: [Font size and font family](http://ckeditor.com/addon/font) reset each other when modified at certain positions.
16* [#16745](http://dev.ckeditor.com/ticket/16745): [Edge] Fixed: List items are lost when [pasted from Word](http://ckeditor.com/addon/pastefromword).
17* [#16682](http://dev.ckeditor.com/ticket/16682): [Edge] Fixed: A list gets [pasted from Word](http://ckeditor.com/addon/pastefromword) as a set of paragraphs. Added the [`config.pasteFromWord_heuristicsEdgeList`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWord_heuristicsEdgeList) configuration option.
18* [#10373](http://dev.ckeditor.com/ticket/10373): Fixed: Context menu items can be dragged into the editor.
19* [#16728](http://dev.ckeditor.com/ticket/16728): [IE] Fixed: [Copy Formatting](http://ckeditor.com/addon/copyformatting) breaks the editor in Quirks Mode.
20* [#16795](http://dev.ckeditor.com/ticket/16795): [IE] Fixed: [Copy Formatting](http://ckeditor.com/addon/copyformatting) breaks the editor in Compatibility Mode.
21* [#16675](http://dev.ckeditor.com/ticket/16675): Fixed: Styles applied with [Copy Formatting](http://ckeditor.com/addon/copyformatting) to a single table cell are applied to the whole table.
22* [#16753](http://dev.ckeditor.com/ticket/16753): Fixed: [`element.setSize`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-setSize) sets incorrect editor dimensions if the border width is represented as a fraction of pixels.
23* [#16705](http://dev.ckeditor.com/ticket/16705): [Firefox] Fixed: Unable to paste images as Base64 strings when using [Clipboard](http://ckeditor.com/addon/clipboard).
24* [#14869](http://dev.ckeditor.com/ticket/14869): Fixed: JavaScript error is thrown when trying to use [Find](http://ckeditor.com/addon/find) in a [`<div>`-based editor](http://ckeditor.com/addon/divarea).
25
26## CKEditor 4.6.1
27
28New Features:
29
30* [#16639](http://dev.ckeditor.com/ticket/16639): The `callback` parameter in the [CKEDITOR.ajax.post](http://docs.ckeditor.com/#!/api/CKEDITOR.ajax-method-post) method became optional.
31
32Fixed Issues:
33
34* [#11064](http://dev.ckeditor.com/ticket/11064): [Blink, WebKit] Fixed: Cannot select all editor content when a widget or a non-editable element is the first or last element of the content. Also fixes this issue in the [Select All](http://ckeditor.com/addon/selectall) plugin.
35* [#14755](http://dev.ckeditor.com/ticket/14755): [Blink, WebKit, IE8] Fixed: Browser hangs when a table is inserted in the place of a selected list with an empty last item.
36* [#16624](http://dev.ckeditor.com/ticket/16624): Fixed: Improved the [Color Button](http://ckeditor.com/addon/colorbutton) plugin which will now normalize the CSS `background` property if it only contains a color value. This fixes missing background colors when using [Paste from Word](http://ckeditor.com/addon/pastefromword).
37* [#16600](http://dev.ckeditor.com/ticket/16600): [Blink, WebKit] Fixed: Error thrown occasionally by an uninitialized editable for multiple CKEditor instances on the same page.
38
39## CKEditor 4.6
40
41New Features:
42
43* [#14569](http://dev.ckeditor.com/ticket/14569): Added a new, flat, default CKEditor skin called [Moono-Lisa](http://ckeditor.com/addon/moono-lisa). Refreshed default colors available in the [Color Button](http://ckeditor.com/addon/colorbutton) plugin ([Text Color and Background Color](http://docs.ckeditor.com/#!/guide/dev_colorbutton) feature).
44* [#14707](http://dev.ckeditor.com/ticket/14707): Added a new [Copy Formatting](http://ckeditor.com/addon/copyformatting) feature to enable easy copying of styles between your document parts.
45* Introduced the completely rewritten [Paste from Word](http://ckeditor.com/addon/pastefromword) plugin:
46 * Backward incompatibility: The [`config.pasteFromWordRemoveFontStyles`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWordRemoveFontStyles) option now defaults to `false`. This option will be deprecated in the future. Use [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_acf) to replicate the effect of setting it to `true`.
47 * Backward incompatibility: The [`config.pasteFromWordNumberedHeadingToList`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWordNumberedHeadingToList) and [`config.pasteFromWordRemoveStyles`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWordRemoveStyles) options were dropped and no longer have any effect on pasted content.
48 * Major improvements in preservation of list numbering, styling and indentation (nested lists with multiple levels).
49 * Major improvements in document structure parsing that fix plenty of issues with distorted or missing content after paste.
50* Added new translation: Occitan. Thanks to [Cédric Valmary](https://totenoc.eu/)!
51* [#10015](http://dev.ckeditor.com/ticket/10015): Keyboard shortcuts (relevant to the operating system in use) will now be displayed in tooltips and context menus.
52* [#13794](http://dev.ckeditor.com/ticket/13794): The [Upload Image](http://ckeditor.com/addon/uploadimage) feature now uses `uploaded.width/height` if set.
53* [#12541](http://dev.ckeditor.com/ticket/12541): Added the [Upload File](http://ckeditor.com/addon/uploadfile) plugin that lets you upload a file by drag&amp;dropping it into the editor content.
54* [#14449](http://dev.ckeditor.com/ticket/14449): Introduced the [Balloon Panel](http://ckeditor.com/addon/balloonpanel) plugin that lets you create stylish floating UI elements for the editor.
55* [#12077](https://dev.ckeditor.com/ticket/12077): Added support for the HTML5 `download` attribute in link (`<a>`) elements. Selecting the "Force Download" checkbox in the [Link](http://ckeditor.com/addon/link) dialog will cause the linked file to be downloaded automatically. Thanks to [sbusse](https://github.com/sbusse)!
56* [#13518](http://dev.ckeditor.com/ticket/13518): Introduced the [`additionalRequestParameters`](http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools.uploadWidgetDefinition-property-additionalRequestParameters) property for file uploads to make it possible to send additional information about the uploaded file to the server.
57* [#14889](http://dev.ckeditor.com/ticket/14889): Added the [`config.image2_altRequired`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image2_altRequired) option for the [Enhanced Image](http://ckeditor.com/addon/image2) plugin to allow making alternative text a mandatory field. Thanks to [Andrey Fedoseev](https://github.com/andreyfedoseev)!
58
59Fixed Issues:
60
61* [#9991](http://dev.ckeditor.com/ticket/9991): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) should only normalize input data.
62* [#7209](http://dev.ckeditor.com/ticket/7209): Fixed: Lists with 3 levels not [pasted from Word](http://ckeditor.com/addon/pastefromword) correctly.
63* [#14335](http://dev.ckeditor.com/ticket/14335): Fixed: Pasting a numbered list starting with a value different from "1" from Microsoft Word does not work correctly.
64* [#14542](http://dev.ckeditor.com/ticket/14542): Fixed: Copying a numbered list from Microsoft Word does not preserve list formatting.
65* [#14544](http://dev.ckeditor.com/ticket/14544): Fixed: Copying a nested list from Microsoft Word results in an empty list.
66* [#14660](http://dev.ckeditor.com/ticket/14660): Fixed: [Pasting text from Word](http://ckeditor.com/addon/pastefromword) breaks the styling in some cases.
67* [#14867](http://dev.ckeditor.com/ticket/14867): [Firefox] Fixed: Text gets stripped when [pasting content from Word](http://ckeditor.com/addon/pastefromword).
68* [#2507](http://dev.ckeditor.com/ticket/2507): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) does not detect pasting a part of a paragraph.
69* [#3336](http://dev.ckeditor.com/ticket/3336): Fixed: Extra blank row added on top of the content [pasted from Word](http://ckeditor.com/addon/pastefromword).
70* [#6115](http://dev.ckeditor.com/ticket/6115): Fixed: When Right-to-Left text direction is applied to a table [pasted from Word](http://ckeditor.com/addon/pastefromword), borders are missing on one side.
71* [#6342](http://dev.ckeditor.com/ticket/6342): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) filters out a basic text style when it is [configured to use attributes](http://docs.ckeditor.com/#!/guide/dev_basicstyles-section-custom-basic-text-style-definition).
72* [#6457](http://dev.ckeditor.com/ticket/6457): [IE] Fixed: [Pasting from Word](http://ckeditor.com/addon/pastefromword) is extremely slow.
73* [#6789](http://dev.ckeditor.com/ticket/6789): Fixed: The `mso-list: ignore` style is not handled properly when [pasting from Word](http://ckeditor.com/addon/pastefromword).
74* [#7262](http://dev.ckeditor.com/ticket/7262): Fixed: Lists in preformatted body disappear when [pasting from Word](http://ckeditor.com/addon/pastefromword).
75* [#7662](http://dev.ckeditor.com/ticket/7662): [Opera] Fixed: Extra empty number/bullet shown in the editor body when editing a multi-level list [pasted from Word](http://ckeditor.com/addon/pastefromword).
76* [#7807](http://dev.ckeditor.com/ticket/7807): Fixed: Last item in a list not converted to a `<li>` element after [pasting from Word](http://ckeditor.com/addon/pastefromword).
77* [#7950](http://dev.ckeditor.com/ticket/7950): [IE] Fixed: Content [from Word pasted](http://ckeditor.com/addon/pastefromword) differently than in other browsers.
78* [#7982](http://dev.ckeditor.com/ticket/7982): Fixed: Multi-level lists get split into smaller ones when [pasting from Word](http://ckeditor.com/addon/pastefromword).
79* [#8231](http://dev.ckeditor.com/ticket/8231): [WebKit, Opera] Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) inserts empty paragraphs.
80* [#8266](http://dev.ckeditor.com/ticket/8266): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) inserts a blank line at the top.
81* [#8341](http://dev.ckeditor.com/ticket/8341), [#7646](http://dev.ckeditor.com/ticket/7646): Fixed: Faulty removal of empty `<span>` elements in [Paste from Word](http://ckeditor.com/addon/pastefromword) content cleanup breaking content formatting.
82* [#8754](http://dev.ckeditor.com/ticket/8754): [Firefox] Fixed: Incorrect pasting of multiple nested lists in [Paste from Word](http://ckeditor.com/addon/pastefromword).
83* [#8983](http://dev.ckeditor.com/ticket/8983): Fixed: Alignment lost when [pasting from Word](http://ckeditor.com/addon/pastefromword) with [`config.enterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode) set to [`CKEDITOR.ENTER_BR`](http://docs.ckeditor.com/#!/api/CKEDITOR-property-ENTER_BR).
84* [#9331](http://dev.ckeditor.com/ticket/9331): [IE] Fixed: [Pasting text from Word](http://ckeditor.com/addon/pastefromword) creates a simple Caesar cipher.
85* [#9422](http://dev.ckeditor.com/ticket/9422): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) leaves an unwanted `color:windowtext` style.
86* [#10011](http://dev.ckeditor.com/ticket/10011): [IE9-10] Fixed: [`config.pasteFromWordRemoveFontStyles`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWordRemoveFontStyles) is ignored under certain conditions.
87* [#10643](http://dev.ckeditor.com/ticket/10643): Fixed: Differences between using <kbd>Ctrl+V</kbd> and pasting from the [Paste from Word](http://ckeditor.com/addon/pastefromword) dialog.
88* [#10784](http://dev.ckeditor.com/ticket/10784): Fixed: Lines missing when [pasting from Word](http://ckeditor.com/addon/pastefromword).
89* [#11294](http://dev.ckeditor.com/ticket/11294): [IE10] Fixed: Font size is not preserved when [pasting from Word](http://ckeditor.com/addon/pastefromword).
90* [#11627](http://dev.ckeditor.com/ticket/11627): Fixed: Missing words when [pasting from Word](http://ckeditor.com/addon/pastefromword).
91* [#12784](http://dev.ckeditor.com/ticket/12784): Fixed: Bulleted list with custom bullets gets changed to a numbered list when [pasting from Word](http://ckeditor.com/addon/pastefromword).
92* [#13174](http://dev.ckeditor.com/ticket/13174): Fixed: Data loss after [pasting from Word](http://ckeditor.com/addon/pastefromword).
93* [#13828](http://dev.ckeditor.com/ticket/13828): Fixed: Widget classes should be added to the wrapper rather than the widget element.
94* [#13829](http://dev.ckeditor.com/ticket/13829): Fixed: No class in [Widget](http://ckeditor.com/addon/widget) wrapper to identify the widget type.
95* [#13519](http://dev.ckeditor.com/ticket/13519): Server response received when uploading files should be more flexible.
96
97Other Changes:
98
99* Updated [SCAYT](http://ckeditor.com/addon/scayt) (Spell Check As You Type) and [WebSpellChecker](http://ckeditor.com/addon/wsc) plugins:
100 * Support for the new default Moono-Lisa skin.
101 * [#121](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/121): Fixed: [Basic Styles](http://ckeditor.com/addon/basicstyles) do not work when SCAYT is enabled.
102 * [#125](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/125): Fixed: Inline styles are not continued when writing multiple lines of styled text with SCAYT enabled.
103 * [#127](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/127): Fixed: Uncaught TypeError after enabling SCAYT in the CKEditor `<div>` element.
104 * [#128](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/128): Fixed: Error thrown after enabling SCAYT caused by conflicts with RequireJS.
105
106## CKEditor 4.5.11
107
108**Security Updates:**
109
110* [Severity: minor] Fixed the `target="_blank"` vulnerability reported by James Gaskell.
111
112 Issue summary: If a victim had access to a spoofed version of ckeditor.com via HTTP (e.g. due to DNS spoofing, using a hacked public network or mailicious hotspot), then when using a link to the ckeditor.com website it was possible for the attacker to change the current URL of the opening page, even if the opening page was protected with SSL.
113
114 An upgrade is recommended.
115
116New Features:
117
118* [#14747](http://dev.ckeditor.com/ticket/14747): The [Enhanced Image](http://ckeditor.com/addon/image2) caption now supports the link `target` attribute.
119* [#7154](http://dev.ckeditor.com/ticket/7154): Added support for the "Display Text" field to the [Link](http://ckeditor.com/addon/link) dialog. Thanks to [Ryan Guill](https://github.com/ryanguill)!
120
121Fixed Issues:
122
123* [#13362](http://dev.ckeditor.com/ticket/13362): [Blink, WebKit] Fixed: Active widget element is not cached when it is losing focus and it is inside an editable element.
124* [#13755](http://dev.ckeditor.com/ticket/13755): [Edge] Fixed: Pasting images does not work.
125* [#13548](http://dev.ckeditor.com/ticket/13548): [IE] Fixed: Clicking the [elements path](http://ckeditor.com/addon/elementspath) disables Cut and Copy icons.
126* [#13812](http://dev.ckeditor.com/ticket/13812): Fixed: When aborting file upload the placeholder for image is left.
127* [#14659](http://dev.ckeditor.com/ticket/14659): [Blink] Fixed: Content scrolled to the top after closing the dialog in a [`<div>`-based editor](http://ckeditor.com/addon/divarea).
128* [#14825](http://dev.ckeditor.com/ticket/14825): [Edge] Fixed: Focusing the editor causes unwanted scrolling due to dropped support for the `setActive` method.
129
130## CKEditor 4.5.10
131
132Fixed Issues:
133
134* [#10750](http://dev.ckeditor.com/ticket/10750): Fixed: The editor does not escape the `font-style` family property correctly, removing quotes and whitespace from font names.
135* [#14413](http://dev.ckeditor.com/ticket/14413): Fixed: The [Auto Grow](http://ckeditor.com/addon/autogrow) plugin with the [`config.autoGrow_onStartup`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-autoGrow_onStartup) option set to `true` does not work properly for an editor that is not visible.
136* [#14451](http://dev.ckeditor.com/ticket/14451): Fixed: Numeric element ID not escaped properly. Thanks to [Jakub Chalupa](https://github.com/chaluja7)!
137* [#14590](http://dev.ckeditor.com/ticket/14590): Fixed: Additional line break appearing after inline elements when switching modes. Thanks to [dpidcock](https://github.com/dpidcock)!
138* [#14539](https://dev.ckeditor.com/ticket/14539): Fixed: JAWS reads "selected Blank" instead of "selected <widget name>" when selecting a widget.
139* [#14701](http://dev.ckeditor.com/ticket/14701): Fixed: More precise labels for [Enhanced Image](http://ckeditor.com/addon/image2) and [Placeholder](http://ckeditor.com/addon/placeholder) widgets.
140* [#14667](http://dev.ckeditor.com/ticket/14667): [IE] Fixed: Removing background color from selected text removes background color from the whole paragraph.
141* [#14252](http://dev.ckeditor.com/ticket/14252): [IE] Fixed: Styles drop-down list does not always reflect the current style of the text line.
142* [#14275](http://dev.ckeditor.com/ticket/14275): [IE9+] Fixed: `onerror` and `onload` events are not used in browsers it could have been used when loading scripts dynamically.
143
144## CKEditor 4.5.9
145
146Fixed Issues:
147
148* [#10685](http://dev.ckeditor.com/ticket/10685): Fixed: Unreadable toolbar icons after updating to the new editor version. Fixed with [6876179](https://github.com/ckeditor/ckeditor-dev/commit/6876179db4ee97e786b07b8fd72e6b4120732185) in [ckeditor-dev](https://github.com/ckeditor/ckeditor-dev) and [6c9189f4](https://github.com/ckeditor/ckeditor-presets/commit/6c9189f46392d2c126854fe8889b820b8c76d291) in [ckeditor-presets](https://github.com/ckeditor/ckeditor-presets).
149* [#14573](https://dev.ckeditor.com/ticket/14573): Fixed: Missing [Widget](http://ckeditor.com/addon/widget) drag handler CSS when there are multiple editor instances.
150* [#14620](https://dev.ckeditor.com/ticket/14620): Fixed: Setting both the `min-height` style for the `<body>` element and the `height` style for the `<html>` element breaks the [Auto Grow](http://ckeditor.com/addon/autogrow) plugin.
151* [#14538](http://dev.ckeditor.com/ticket/14538): Fixed: Keyboard focus goes into an embedded `<iframe>` element.
152* [#14602](http://dev.ckeditor.com/ticket/14602): Fixed: The [`dom.element.removeAttribute()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-removeAttribute) method does not remove all attributes if no parameter is given.
153* [#8679](http://dev.ckeditor.com/ticket/8679): Fixed: Better focus indication and ability to style the selected color in the [color picker dialog](http://ckeditor.com/addon/colordialog).
154* [#11697](http://dev.ckeditor.com/ticket/11697): Fixed: Content is replaced ignoring the letter case setting in the [Find and Replace](http://ckeditor.com/addon/find) dialog window.
155* [#13886](http://dev.ckeditor.com/ticket/13886): Fixed: Invalid handling of the [`CKEDITOR.style`](http://docs.ckeditor.com/#!/api/CKEDITOR.style) instance with the `styles` property by [`CKEDITOR.filter`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter).
156* [#14535](http://dev.ckeditor.com/ticket/14535): Fixed: CSS syntax corrections. Thanks to [mdjdenormandie](https://github.com/mdjdenormandie)!
157
158## CKEditor 4.5.8
159
160New Features:
161
162* [#12440](http://dev.ckeditor.com/ticket/12440): Added the [`config.colorButton_enableAutomatic`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-colorButton_enableAutomatic) option to allow hiding the "Automatic" option in the [color picker](http://ckeditor.com/addon/colorbutton).
163
164Fixed Issues:
165
166* [#10448](http://dev.ckeditor.com/ticket/10448): Fixed: Lack of scrollbar in the [right-to-left text direction](http://ckeditor.com/addon/bidi).
167* [#12707](http://dev.ckeditor.com/ticket/12707): Fixed: The order of table elements does not comply with the HTML specification.
168* [#13756](http://dev.ckeditor.com/ticket/13756): [Edge] Fixed: Context menus are cut-off.
169
170## CKEditor 4.5.7
171
172New Features:
173
174* [#14327](http://dev.ckeditor.com/ticket/14327): Added Swiss German localization. Thanks to [Miro Grenda](https://twitter.com/mirogrenda)!
175
176Fixed Issues:
177
178* [#13816](http://dev.ckeditor.com/ticket/13816): Introduced a new strategy for Filling Character handling to avoid changes in DOM. This fixes the following issues:
179 * [#12727](http://dev.ckeditor.com/ticket/12727): [Blink] `IndexSizeError` when using the [Div Editing Area](http://ckeditor.com/addon/divarea) and [Content Templates](http://ckeditor.com/addon/templates) plugins.
180 * [#13377](http://dev.ckeditor.com/ticket/13377): [Widget](http://ckeditor.com/addon/widget) plugin issue when typing in Korean.
181 * [#13389](http://dev.ckeditor.com/ticket/13389): [Blink] [`editor.getData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData) fails when the cursor is next to an `<hr>` tag.
182 * [#13513](http://dev.ckeditor.com/ticket/13513): [Blink, WebKit] [Div Editing Area](http://ckeditor.com/addon/divarea) and [`editor.getData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData) throw an error when an image is the only data in the editor.
183* [#13884](http://dev.ckeditor.com/ticket/13884): [Firefox] Fixed: Copying and pasting a table results in just the first cell being pasted.
184* [#14234](http://dev.ckeditor.com/ticket/14234): Fixed: URL input field is not marked as required in the [Media Embed](http://ckeditor.com/addon/embed) dialog.
185
186## CKEditor 4.5.6
187
188New Features:
189
190* Introduced the [`CKEDITOR.tools.getCookie()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-getCookie) and [`CKEDITOR.tools.setCookie()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-setCookie) methods for accessing cookies.
191* Introduced the [`CKEDITOR.tools.getCsrfToken()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-getCsrfToken) method. The CSRF token is now automatically sent by the [File Browser](http://ckeditor.com/addon/filebrowser) and [File Tools](http://ckeditor.com/addon/filetools) plugins during file uploads. The server-side upload handlers may check it and use it to additionally secure the communication.
192
193Other Changes:
194
195* Updated [SCAYT](http://ckeditor.com/addon/scayt) (Spell Check As You Type):
196 - New features:
197 - CKEditor [Language](http://ckeditor.com/addon/language) plugin support.
198 - CKEditor [Placeholder](http://ckeditor.com/addon/placeholder) plugin support.
199 - [Drag&Drop](http://sdk.ckeditor.com/samples/fileupload.html) support.
200 - **Experimental** [GRAYT](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-grayt_autoStartup) (Grammar As You Type) functionality.
201 - Fixed issues:
202 * [#98](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/98): SCAYT affects dialog double-click. Fixed in SCAYT core.
203 * [#102](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/102): SCAYT core performance enhancements.
204 * [#104](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/104): SCAYT's spans leak into the clipboard and after pasting.
205 * [#105](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/105): A JavaScript error fired in case of multiple instances of CKEditor on one page.
206 * [#107](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/107): SCAYT should not check non-editable parts of content.
207 * [#108](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/108): Latest SCAYT copies the ID of the editor element to the iframe.
208 * SCAYT stops working when CKEditor [Undo plugin](http://ckeditor.com/addon/undo) not enabled.
209 * Issue with pasting SCAYT markup in CKEditor.
210 * SCAYT stops working after pressing the *Cancel* button in the WSC dialog.
211
212## CKEditor 4.5.5
213
214Fixed Issues:
215
216* [#13887](https://dev.ckeditor.com/ticket/13887): Fixed: [Link](http://ckeditor.com/addon/link) plugin alters the `target` attribute value. Thanks to [SamZiemer](https://github.com/SamZiemer)!
217* [#12189](http://dev.ckeditor.com/ticket/12189): Fixed: The [Link](http://ckeditor.com/addon/link) plugin dialog does not display the subject of email links if the subject parameter is not lowercase.
218* [#9192](http://dev.ckeditor.com/ticket/9192): Fixed: An `undefined` string is appended to an email address added with the [Link](http://ckeditor.com/addon/link) plugin if subject and email body are empty and [`config.emailProtection`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-emailProtection) is set to `encode`.
219* [#13790](https://dev.ckeditor.com/ticket/13790): Fixed: It is not possible to destroy the editor `<iframe>` after the editor was detached from DOM. Thanks to [Stefan Rijnhart](https://github.com/StefanRijnhart)!
220* [#13803](https://dev.ckeditor.com/ticket/13803): Fixed: The editor cannot be destroyed before being fully initialized. Thanks to [Cyril Fluck](https://github.com/cyril-sf)!
221* [#13867](http://dev.ckeditor.com/ticket/13867): Fixed: CKEditor does not work when the `classList` polyfill is used.
222* [#13885](http://dev.ckeditor.com/ticket/13885): Fixed: [Enhanced Image](http://ckeditor.com/addon/image2) requires the [Link](http://ckeditor.com/addon/link) plugin to link an image.
223* [#13883](http://dev.ckeditor.com/ticket/13883): Fixed: Copying a table using the context menu strips off styles.
224* [#13872](http://dev.ckeditor.com/ticket/13872): Fixed: Cutting is possible in the [read-only](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-readOnly) mode.
225* [#12848](http://dev.ckeditor.com/ticket/12848): [Blink] Fixed: Opening the [Find and Replace](http://ckeditor.com/addon/find) dialog window in the [read-only](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-readOnly) mode throws an exception.
226* [#13879](http://dev.ckeditor.com/ticket/13879): Fixed: It is not possible to prevent the [`editor.drop`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-drop) event.
227* [#13361](http://dev.ckeditor.com/ticket/13361): Fixed: Skin images fail when the site path includes parentheses because the `background-image` path needs single quotes around the URL value.
228* [#13771](http://dev.ckeditor.com/ticket/13771): Fixed: The `contents.css` style is not used if the [IFrame Editing Area](http://ckeditor.com/addon/wysiwygarea) plugin is missing.
229* [#13782](http://dev.ckeditor.com/ticket/13782): Fixed: Unclear log messages.
230* [#13919](http://dev.ckeditor.com/ticket/13919): [Edge] Fixed: Browser window crashes when accessing the `isContentEditable` property of an `<input>` DOM element.
231
232Other Changes:
233
234* [#13859](http://dev.ckeditor.com/ticket/13859): Test cases created with `bender.tools.createTestsForEditors` will also receive editor bot as a second parameter.
235
236## CKEditor 4.5.4
237
238New Features:
239
240* [#13632](http://dev.ckeditor.com/ticket/13632): Introduce error logging mechanism.
241* [#13730](http://dev.ckeditor.com/ticket/13730): Switch to the new error logging mechanism.
242
243Fixed Issues:
244
245* [#9856](http://dev.ckeditor.com/ticket/9856): Fixed: Cannot use the native context menu together with the [Div Editing Area](http://ckeditor.com/addon/divarea) plugin. Thanks to [Mark Wade](https://github.com/mark-wade)!
246* [#12733](http://dev.ckeditor.com/ticket/12733): [IE9+] Fixed: Radio button `onChange` does not work. Thanks to [Iliya Kostadinov](https://github.com/iliyakostadinov)!
247* [#13142](http://dev.ckeditor.com/ticket/13142): [Edge] Fixed: *Ctrl+A* and then *Backspace* result in an empty `<div>` element.
248* [#13599](http://dev.ckeditor.com/ticket/13599): Fixed: Cross-editor drag and drop of an inline widget results in error/artifacts.
249* [#13640](http://dev.ckeditor.com/ticket/13640): [IE] Fixed: Dropping a widget outside the `<body>` element is not handled correctly.
250* [#13533](http://dev.ckeditor.com/ticket/13533): Fixed: No progress during upload.
251* [#13680](http://dev.ckeditor.com/ticket/13680): Fixed: The parser should allow the `<h1-6>` element to be a child of the `<summary>` element.
252* [#11724](http://dev.ckeditor.com/ticket/11724): [Touch devices] Fixed: Drop-downs often hide right after opening them.
253* [#13690](http://dev.ckeditor.com/ticket/13690): Fixed: Copying content from IE to Chrome adds an extra paragraph.
254* [#13284](http://dev.ckeditor.com/ticket/13284): Fixed: Cannot drag and drop a widget if the text caret is placed just after the widget instance.
255* [#13516](http://dev.ckeditor.com/ticket/13516): Fixed: CKEditor removes empty HTML5 anchors without the `name` attribute.
256* [#13765](http://dev.ckeditor.com/ticket/13765): [Safari 9] Fixed: Problems with rendering samples.
257
258Other Changes:
259
260* [#11725](http://dev.ckeditor.com/ticket/11725): Marked [`CKEDITOR.env.mobile`](http://docs.ckeditor.com/#!/api/CKEDITOR.env-property-mobile) as deprecated. The reason is that it is no longer clear what "mobile" means.
261* [#13737](http://dev.ckeditor.com/ticket/13737): Upgraded [Bender.js](https://github.com/benderjs/benderjs) to 0.4.1.
262
263## CKEditor 4.5.3
264
265New Features:
266
267* [#13501](http://dev.ckeditor.com/ticket/13501): Added the [`config.fileTools_defaultFileName`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fileTools_defaultFileName) option to allow setting a default file name for paste uploads.
268* [#13603](http://dev.ckeditor.com/ticket/13603): Added support for uploading dropped BMP images.
269
270Fixed Issues:
271
272* [#13590](http://dev.ckeditor.com/ticket/13590): Fixed: Various issues related to the [Paste from Word](http://ckeditor.com/addon/pastefromword) feature. Fixes also:
273 * [#11215](http://dev.ckeditor.com/ticket/11215),
274 * [#8780](http://dev.ckeditor.com/ticket/8780),
275 * [#12762](http://dev.ckeditor.com/ticket/12762).
276* [#13386](http://dev.ckeditor.com/ticket/13386): [Edge] Fixed: Issues with selecting and editing images.
277* [#13568](http://dev.ckeditor.com/ticket/13568): Fixed: The [`editor.getSelectedHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml) method returns invalid results for entire content selection.
278* [#13453](http://dev.ckeditor.com/ticket/13453): Fixed: Drag&drop of entire editor content throws an error.
279* [#13465](http://dev.ckeditor.com/ticket/13465): Fixed: Error is thrown and the widget is lost on drag&drop if it is the only content of the editor.
280* [#13414](http://dev.ckeditor.com/ticket/13414): Fixed: Content auto paragraphing in a nested editable despite editor configuration.
281* [#13429](http://dev.ckeditor.com/ticket/13429): Fixed: Incorrect selection after content insertion by the [Auto Embed](http://ckeditor.com/addon/autoembed) plugin.
282* [#13388](http://dev.ckeditor.com/ticket/13388): Fixed: [Table Resize](http://ckeditor.com/addon/tableresize) integration with [Undo](http://ckeditor.com/addon/undo) is broken.
283
284Other Changes:
285
286* [#13637](https://dev.ckeditor.com/ticket/13637): Several icons were refactored.
287* Updated [Bender.js](https://github.com/benderjs/benderjs) to 0.3.0 and introduced the ability to run tests via HTTPs ([#13265](https://dev.ckeditor.com/ticket/13265)).
288
289## CKEditor 4.5.2
290
291Fixed Issues:
292
293* [#13609](http://dev.ckeditor.com/ticket/13609): [Edge] Fixed: The browser crashes when switching to the source mode. Thanks to [Andrew Williams and Mark Smeed](http://webxsolution.com/)!
294* [PR#201](https://github.com/ckeditor/ckeditor-dev/pull/201): Fixed: Buttons in the toolbar configurator cause form submission. Thanks to [colemanw](https://github.com/colemanw)!
295* [#13422](http://dev.ckeditor.com/ticket/13422): Fixed: A monospaced font should be used in the `<textarea>` element storing editor configuration in the toolbar configurator.
296* [#13494](http://dev.ckeditor.com/ticket/13494): Fixed: Error thrown in the toolbar configurator if plugin requirements are not met.
297* [#13409](http://dev.ckeditor.com/ticket/13409): Fixed: List elements incorrectly merged when pressing *Backspace* or *Delete*.
298* [#13434](http://dev.ckeditor.com/ticket/13434): Fixed: Dialog state indicator broken in Right–To–Left environments.
299* [#13460](http://dev.ckeditor.com/ticket/13460): [IE8] Fixed: Copying inline widgets is broken when [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_acf) is disabled.
300* [#13495](http://dev.ckeditor.com/ticket/13495): [Firefox, IE] Fixed: Text is not word-wrapped in the Paste dialog window.
301* [#13528](http://dev.ckeditor.com/ticket/13528): [Firefox@Windows] Fixed: Content copied from Microsoft Word and other external applications is pasted as a plain text. Removed the `CKEDITOR.plugins.clipboard.isHtmlInExternalDataTransfer` property as the check must be dynamic.
302* [#13583](http://dev.ckeditor.com/ticket/13583): Fixed: [`DataTransfer.getData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.clipboard.dataTransfer-method-getData) should work consistently in all browsers and should not strip valuable content. Fixed pasting tables from Microsoft Excel on Chrome.
303* [#13468](http://dev.ckeditor.com/ticket/13468): [IE] Fixed: Binding drag&drop `dataTransfer` does not work if `text` data was set in the meantime.
304* [#13451](http://dev.ckeditor.com/ticket/13451): [IE8-9] Fixed: One drag&drop operation may affect following ones.
305* [#13184](http://dev.ckeditor.com/ticket/13184): Fixed: Web page reloaded after a drop on editor UI.
306* [#13129](http://dev.ckeditor.com/ticket/13129) Fixed: Block widget blurred after a drop followed by an undo.
307* [#13397](http://dev.ckeditor.com/ticket/13397): Fixed: Drag&drop of a widget inside its nested widget crashes the editor.
308* [#13385](http://dev.ckeditor.com/ticket/13385): Fixed: [`editor.getSnapshot()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSnapshot) may return a non-string value.
309* [#13419](http://dev.ckeditor.com/ticket/13419): Fixed: The [Auto Link](http://ckeditor.com/addon/autolink) plugin does not encode double quotes in URLs.
310* [#13420](http://dev.ckeditor.com/ticket/13420): Fixed: The [Auto Embed](http://ckeditor.com/addon/autoembed) plugin ignores encoded characters in URL parameters.
311* [#13410](http://dev.ckeditor.com/ticket/13410): Fixed: Error thrown in the [Auto Embed](http://ckeditor.com/addon/autoembed) plugin when undoing right after pasting a link.
312* [#13566](http://dev.ckeditor.com/ticket/13566): Fixed: Suppressed notifications in the [Media Embed Base](http://ckeditor.com/addon/embedbase) plugin.
313* [#11616](http://dev.ckeditor.com/ticket/11616): [Chrome] Fixed: Resizing the editor while it is not displayed breaks the editable. Fixes also [#9160](http://dev.ckeditor.com/ticket/9160) and [#9715](http://dev.ckeditor.com/ticket/9715).
314* [#11376](http://dev.ckeditor.com/ticket/11376): [IE11] Fixed: Loss of text when pasting bulleted lists from Microsoft Word.
315* [#13143](http://dev.ckeditor.com/ticket/13143): [Edge] Fixed: Focus lost when opening the panel.
316* [#13387](http://dev.ckeditor.com/ticket/13387): [Edge] Fixed: "Permission denied" error thrown when loading the editor with developer tools open.
317* [#13574](http://dev.ckeditor.com/ticket/13574): [Edge] Fixed: "Permission denied" error thrown when opening editor dialog windows.
318* [#13441](http://dev.ckeditor.com/ticket/13441): [Edge] Fixed: The [Clipboard](http://ckeditor.com/addon/clipboard) plugin breaks the state of [Undo](http://ckeditor.com/addon/undo) commands after a paste.
319* [#13554](http://dev.ckeditor.com/ticket/13554): [Edge] Fixed: Paste dialog's iframe does not receive focus on show.
320* [#13440](http://dev.ckeditor.com/ticket/13440): [Edge] Fixed: Unable to paste a widget.
321
322Other Changes:
323
324* [#13421](http://dev.ckeditor.com/ticket/13421): UX improvements to notifications in the [Auto Embed](http://ckeditor.com/addon/autoembed) plugin.
325
326## CKEditor 4.5.1
327
328Fixed Issues:
329
330* [#13486](http://dev.ckeditor.com/ticket/13486): Fixed: The [Upload Image](http://ckeditor.com/addon/uploadimage) plugin should log an error, not throw an error when upload URL is not set.
331
332## CKEditor 4.5
333
334New Features:
335
336* [#13304](http://dev.ckeditor.com/ticket/13304): Added support for passing DOM elements to [`config.sharedSpaces`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-sharedSpaces). Thanks to [Undergrounder](https://github.com/Undergrounder)!
337* [#13215](http://dev.ckeditor.com/ticket/13215): Added ability to cancel fetching a resource by the Embed plugins.
338* [#13213](http://dev.ckeditor.com/ticket/13213): Added the [`dialog#setState()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dialog-method-setState) method and used it in the [Embed](http://ckeditor.com/addon/embed) dialog to indicate that a resource is being loaded.
339* [#13337](http://dev.ckeditor.com/ticket/13337): Added the [`repository.onWidget()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-onWidget) method &mdash; a convenient way to listen to [widget](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget) events through the [repository](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository).
340* [#13214](http://dev.ckeditor.com/ticket/13214): Added support for pasting links that convert into embeddable resources on the fly.
341
342Fixed Issues:
343
344* [#13334](http://dev.ckeditor.com/ticket/13334): Fixed: Error after nesting widgets and playing with undo/redo.
345* [#13118](http://dev.ckeditor.com/ticket/13118): Fixed: The [`editor.getSelectedHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml) method throws an error when called in the source mode.
346* [#13158](http://dev.ckeditor.com/ticket/13158): Fixed: Error after canceling a dialog when creating a widget.
347* [#13197](http://dev.ckeditor.com/ticket/13197): Fixed: Linked inline [Enhanced Image](http://ckeditor.com/addon/image2) alignment class is not transferred to the widget wrapper.
348* [#13199](http://dev.ckeditor.com/ticket/13199): Fixed: [Semantic Embed](http://ckeditor.com/addon/embedsemantic) does not support widget classes.
349* [#13003](http://dev.ckeditor.com/ticket/13003): Fixed: Anchors are uploaded when moving them by drag and drop.
350* [#13032](http://dev.ckeditor.com/ticket/13032): Fixed: When upload is done, notification update should be marked as important.
351* [#13300](http://dev.ckeditor.com/ticket/13300): Fixed: The `internalCommit` argument in the [Image](http://ckeditor.com/addon/image) dialog seems to be never used.
352* [#13036](http://dev.ckeditor.com/ticket/13036): Fixed: Notifications are moved 10px to the right.
353* [#13280](http://dev.ckeditor.com/ticket/13280): [IE8] Fixed: Undo after inline widget drag&drop throws an error.
354* [#13186](http://dev.ckeditor.com/ticket/13186): Fixed: Content dropped into a nested editable is not filtered by [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_acf).
355* [#13140](http://dev.ckeditor.com/ticket/13140): Fixed: Error thrown when dropping a block widget right after itself.
356* [#13176](http://dev.ckeditor.com/ticket/13176): [IE8] Fixed: Errors on drag&drop of embed widgets.
357* [#13015](http://dev.ckeditor.com/ticket/13015): Fixed: Dropping an image file on [Enhanced Image](http://ckeditor.com/addon/image2) causes a page reload.
358* [#13080](http://dev.ckeditor.com/ticket/13080): Fixed: Ugly notification shown when the response contains HTML content.
359* [#13011](http://dev.ckeditor.com/ticket/13011): [IE8] Fixed: Anchors are duplicated on drag&drop in specific locations.
360* [#13105](http://dev.ckeditor.com/ticket/13105): Fixed: Various issues related to [`CKEDITOR.tools.htmlEncode()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-htmlEncode) and [`CKEDITOR.tools.htmlDecode()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-htmlDecode) methods.
361* [#11976](http://dev.ckeditor.com/ticket/11976): [Chrome] Fixed: Copy&paste and drag&drop lists from Microsoft Word.
362* [#13128](http://dev.ckeditor.com/ticket/13128): Fixed: Various issues with cloning element IDs:
363 * Fixed the default behavior of [`range.cloneContents()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-cloneContents) and [`range.extractContents()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-extractContents) methods which now clone IDs similarly to their native counterparts.
364 * Added `cloneId` arguments to the above methods, [`range.splitBlock()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-splitBlock) and [`element.breakParent()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-breakParent). Mind the default values and special behavior in the `extractContents()` method!
365 * Fixed issues where IDs were lost on copy&paste and drag&drop.
366* Toolbar configurators:
367 * [#13185](http://dev.ckeditor.com/ticket/13185): Fixed: Wrong position of the suggestion box if there is not enough space below the caret.
368 * [#13138](http://dev.ckeditor.com/ticket/13138): Fixed: The "Toggle empty elements" button label is unclear.
369 * [#13136](http://dev.ckeditor.com/ticket/13136): Fixed: Autocompleter is far too intrusive.
370 * [#13133](http://dev.ckeditor.com/ticket/13133): Fixed: Tab leaves the editor.
371 * [#13173](http://dev.ckeditor.com/ticket/13173): Fixed: [`config.removeButtons`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-removeButtons) is ignored by the advanced toolbar configurator.
372
373Other Changes:
374
375* [#13119](http://dev.ckeditor.com/ticket/13119): Improved compatibility of editor skins ([Moono](http://ckeditor.com/addon/moono) and [Kama](http://ckeditor.com/addon/kama)) with external web page style sheets.
376* Toolbar configurators:
377 * [#13147](http://dev.ckeditor.com/ticket/13147): Added buttons to the sticky toolbar.
378 * [#13207](http://dev.ckeditor.com/ticket/13207): Used modal window to display toolbar configurator help.
379* [#13316](http://dev.ckeditor.com/ticket/13316): Made [`CKEDITOR.env.isCompatible`](http://docs.ckeditor.com/#!/api/CKEDITOR.env-property-isCompatible) a blacklist rather than a whitelist. More about the change in the [Browser Compatibility](http://docs.ckeditor.com/#!/guide/dev_browsers) guide.
380* [#13398](http://dev.ckeditor.com/ticket/13398): Renamed `CKEDITOR.fileTools.UploadsRepository` to [`CKEDITOR.fileTools.UploadRepository`](http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools.uploadRepository) and changed all related properties.
381* [#13279](http://dev.ckeditor.com/ticket/13279): Reviewed CSS vendor prefixes.
382* [#13454](http://dev.ckeditor.com/ticket/13454): Removed unused `lang.image.alertUrl` token from the [Image](http://ckeditor.com/addon/image) plugin.
383
384## CKEditor 4.5 Beta
385
386New Features:
387
388* Clipboard (copy&paste, drag&drop) and file uploading features and improvements ([#11437](http://dev.ckeditor.com/ticket/11437)).
389
390 * Major features:
391 * Support for dropping and pasting files into the editor was introduced. Through a set of new facades for native APIs it is now possible to easily intercept and process inserted files.
392 * [File upload tools](http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools) were introduced in order to simplify controlling the loading, uploading and handling server response, properly handle [new upload configuration](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-uploadUrl) options, etc.
393 * [Upload Image](http://ckeditor.com/addon/uploadimage) widget was introduced to upload dropped images. A base class for the [upload widget](http://docs.ckeditor.com/#!/api/CKEDITOR.fileTools.uploadWidgetDefinition) was exposed, too, to make it simple to create new types of upload widgets which can handle any type of dropped file, show the upload progress and update the content when the process is done. It also handles editing and undo/redo operations when a file is being uploaded and integrates with the [notification aggregator](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.notificationAggregator) to show progress and success or error.
394 * All drag and drop operations were integrated with the editor. All dropped content is passed through the [`editor#paste`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-paste) event and a set of new editor events was introduced &mdash; [`dragstart`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-dragstart), [`drop`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-drop), [`dragend`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-dragend).
395 * The [Data Transfer](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.clipboard.dataTransfer) facade was introduced to unify access to data in various types and files. [Data Transfer](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.clipboard.dataTransfer) is now always available in the [`editor#paste`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-paste) event.
396 * Switched from the pastebin to using the native clipboard access whenever possible. This solved many issues related to pastebin such as unnecessary scrolling or data loss. Additionally, on copy and cut from the editor the clipboard data is set. Therefore, on paste the editor has access to clean data, undisturbed by the browsers.
397 * Drag and drop of inline and block widgets was integrated with the standard clipboard APIs. By listening to drag events you will thus be notified about widgets, too. This opens a possibility to filter pasted and dropped widgets.
398 * The [`editor#paste`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-paste) event can have the `range` parameter so it is possible to change the paste position in the listener or paste in the not selectable position. Also the [`editor.insertHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertHtml) method now accepts `range` as an additional parameter.
399 * [#11621](http://dev.ckeditor.com/ticket/11621): A configurable [paste filter](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFilter) was introduced. The filter is by default turned to `'semantic-content'` on Webkit and Blink for all pasted content coming from external sources because of the low quality of HTML that these engines put into the clipboard. Internal and cross-editor paste is safe due to the change explained in the previous point.
400
401 * Other changes and related fixes:
402 * [#12095](http://dev.ckeditor.com/ticket/12095): On drag and copy of widgets [the same method](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml) is used to get selected HTML as in the normal case. Thanks to that styles applied to inline widgets are not lost.
403 * [#11219](http://dev.ckeditor.com/ticket/11219): Fixed: Dragging a [captioned image](http://ckeditor.com/addon/image2) does not fire the [`editor#paste`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-paste) event.
404 * [#9554](http://dev.ckeditor.com/ticket/9554): [Webkit Mac] Fixed: Editor scrolls on paste.
405 * [#9898](http://dev.ckeditor.com/ticket/9898): [Webkit&Divarea] Fixed: Pasting causes undesirable scrolling.
406 * [#11993](http://dev.ckeditor.com/ticket/11993): [Chrome] Fixed: Pasting content scrolls the document.
407 * [#12613](http://dev.ckeditor.com/ticket/12613): Show the user that they can not drop on editor UI (toolbar, bottom bar).
408 * [#12851](http://dev.ckeditor.com/ticket/12851): [Blink/Webkit] Fixed: Formatting disappears when pasting content into cells.
409 * [#12914](http://dev.ckeditor.com/ticket/12914): Fixed: Copy/Paste of table broken in `div`-based editor.
410
411 * Browser support.<br>Browser support for related features varies significantly (see http://caniuse.com/clipboard).
412 * File APIs needed to operate and file upload is not supported in Internet Explorer 9 and below.
413 * Only Chrome and Safari on Mac OS support setting custom data items in the clipboard, so currently it is possible to recognize the origin of the copied content in these browsers only. All drag and drop operations can be identified thanks to the new Data Transfer facade.
414 * No Internet Explorer browser supports the standard clipboard API which results in small glitches like where only plain text can be dropped from outside the editor. Thanks to the new Data Transfer facade, internal and cross-editor drag and drop supports the full range of data.
415 * Direct access to clipboard could only be implemented in Chrome, Safari on Mac OS, Opera and Firefox. In other browsers the pastebin must still be used.
416
417* [#12875](http://dev.ckeditor.com/ticket/12875): Samples and toolbar configuration tools.
418 * The old set of samples shipped with every CKEditor package was replaced with a shiny new single-page sample. This change concluded a long term plan which started from introducing the [CKEditor SDK](http://sdk.ckeditor.com/) and [CKEditor Functionality Overview](http://docs.ckeditor.com/#!/guide/dev_features) section in the documentation which essentially redefined the old samples.
419 * Toolbar configurators with live previews were introduced. They will be shipped with every CKEditor package and are meant to help in configuring toolbar layouts.
420
421* [#10925](http://dev.ckeditor.com/ticket/10925): The [Media Embed](http://ckeditor.com/addon/embed) and [Semantic Media Embed](http://ckeditor.com/addon/embedsemantic) plugins were introduced. Read more about the new features in the [Embedding Content](http://docs.ckeditor.com/#!/guide/dev_media_embed) article.
422* [#10931](http://dev.ckeditor.com/ticket/10931): Added support for nesting widgets. It is now possible to insert one widget into another widget's nested editable. Note that unless nested editable's [allowed content](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.nestedEditable.definition-property-allowedContent) is defined precisely, starting from CKEditor 4.5 some widget buttons may become enabled. This feature is not supported in IE8. Included issues:
423 * [#12018](http://dev.ckeditor.com/ticket/12018): Fixed and reviewed: Nested widgets garbage collection.
424 * [#12024](http://dev.ckeditor.com/ticket/12024): [Firefox] Fixed: Outline is extended to the left by unpositioned drag handlers.
425 * [#12006](http://dev.ckeditor.com/ticket/12006): Fixed: Drag and drop of nested block widgets.
426 * [#12008](http://dev.ckeditor.com/ticket/12008): Fixed various cases of inserting a single non-editable element using the [`editor.insertHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertHtml) method. Fixes pasting a widget with a nested editable inside another widget's nested editable.
427
428* Notification system:
429 * [#11580](http://dev.ckeditor.com/ticket/11580): Introduced the [notification system](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.notification).
430 * [#12810](http://dev.ckeditor.com/ticket/12810): Introduced a [notification aggregator](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.notificationAggregator) for the [notification system](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.notification) which simplifies displaying progress of many concurrent tasks.
431* [#11636](http://dev.ckeditor.com/ticket/11636): Introduced new, UX-focused, methods for getting selected HTML and deleting it &mdash; [`editor.getSelectedHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml) and [`editor.deleteSelectedHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml).
432* [#12416](http://dev.ckeditor.com/ticket/12416): Added the [`widget.definition.upcastPriority`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.definition-property-upcastPriority) property which gives more control over widget upcasting order to the widget author.
433* [#12036](http://dev.ckeditor.com/ticket/12036): Initialize the editor in [read-only](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-readOnly) mode when the `<textarea>` element has a `readonly` attribute.
434* [#11905](http://dev.ckeditor.com/ticket/11905): The [`resize` event](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-resize) passes the current dimensions in its data.
435* [#12126](http://dev.ckeditor.com/ticket/12126): Introduced [`config.image_prefillDimensions`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image_prefillDimensions) and [`config.image2_prefillDimensions`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image2_prefillDimensions) to make pre-filling `width` and `height` configurable for the [Enhanced Image](http://ckeditor.com/addon/image2).
436* [#12746](http://dev.ckeditor.com/ticket/12746): Added a new configuration option to hide the [Enhanced Image](http://ckeditor.com/addon/image2) resizer.
437* [#12150](http://dev.ckeditor.com/ticket/12150): Exposed the [`getNestedEditable()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-static-method-getNestedEditable) and `is*` [widget helper](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget) functions (see the static methods).
438* [#12448](http://dev.ckeditor.com/ticket/12448): Introduced the [`editable.insertHtmlIntoRange`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertHtmlIntoRange) method.
439* [#12143](http://dev.ckeditor.com/ticket/12143): Added the [`config.floatSpacePreferRight`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-floatSpacePreferRight) configuration option that switches the alignment of the floating toolbar. Thanks to [InvisibleBacon](http://github.com/InvisibleBacon)!
440* [#10986](http://dev.ckeditor.com/ticket/10986): Added support for changing dialog input and textarea text directions by using the *Shift+Alt+Home/End* keystrokes. The direction is stored in the value of the input by prepending the [`\u202A`](http://unicode.org/cldr/utility/character.jsp?a=202A) or [`\u202B`](http://unicode.org/cldr/utility/character.jsp?a=202B) marker to it. Read more in the [documentation](http://docs.ckeditor.com/#!/api/CKEDITOR.dialog.definition.textInput-property-bidi). Thanks to [edithkk](https://github.com/edithkk)!
441* [#12770](http://dev.ckeditor.com/ticket/12770): Added support for passing [widget](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget)'s startup data as a widget command's argument. Thanks to [Rebrov Boris](https://github.com/zipp3r) and [Tieme van Veen](https://github.com/tiemevanveen)!
442* [#11583](http://dev.ckeditor.com/ticket/11583): Added support for the HTML5 `required` attribute in various form elements. Thanks to [Steven Busse](https://github.com/sbusse)!
443
444Changes:
445
446* [#12858](http://dev.ckeditor.com/ticket/12858): Basic [Spartan](http://blogs.windows.com/bloggingwindows/2015/03/30/introducing-project-spartan-the-new-browser-built-for-windows-10/) browser compatibility. Full compatibility will be introduced later, because at the moment Spartan is still too unstable to be used for tests and we see many changes from version to version.
447* [#12948](http://dev.ckeditor.com/ticket/12948): The [`config.mathJaxLibrary`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-mathJaxLib) option does not default to the MathJax CDN any more. It needs to be configured to enable the [Mathematical Formulas](http://ckeditor.com/addon/mathjax) plugin now.
448* [#13069](http://dev.ckeditor.com/ticket/13069): Fixed inconsistencies between [`editable.insertHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertElement) and [`editable.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertElement) when the `range` parameter is used. Now, the `editor.insertElement()` method works on a higher level, which means that it saves undo snapshots and sets the selection after insertion. Use the [`editable.insertElementIntoRange()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertElementIntoRange) method directly for the pre 4.5 behavior of `editable.insertElement()`.
449* [#12870](http://dev.ckeditor.com/ticket/12870): Use [`editor.showNotification()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-showNotification) instead of `alert()` directly whenever possible. When the [Notification plugin](http://ckeditor.com/addon/notification) is loaded, the notification system is used automatically. Otherwise, the native `alert()` is displayed.
450* [#8024](http://dev.ckeditor.com/ticket/8024): Swapped behavior of the Split Cell Vertically and Horizontally features of the [Table Tools](http://ckeditor.com/addon/tabletools) plugin to be more intuitive. Thanks to [kevinisagit](https://github.com/kevinisagit)!
451* [#10903](http://dev.ckeditor.com/ticket/10903): Performance improvements for the [`dom.element.addClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-addClass), [`dom.element.removeClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-removeClass) and [`dom.element.hasClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-hasClass) methods. Note: The previous implementation allowed passing multiple classes to `addClass()` although it was only a side effect of that implementation. The new implementation does not allow this.
452* [#11856](http://dev.ckeditor.com/ticket/11856): The jQuery adapter throws a meaningful error if CKEditor or jQuery are not loaded.
453
454Fixed issues:
455
456* [#11586](http://dev.ckeditor.com/ticket/11586): Fixed: [`range.cloneContents()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-cloneContents) should not change the DOM in order not to affect selection.
457* [#12148](http://dev.ckeditor.com/ticket/12148): Fixed: [`dom.element.getChild()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-getChild) should not modify a passed array.
458* [#12503](http://dev.ckeditor.com/ticket/12503): [Blink/Webkit] Fixed: Incorrect result of Select All and *Backspace* or *Delete*.
459* [#13001](http://dev.ckeditor.com/ticket/13001): [Firefox] Fixed: The `<br />` filler is placed in the wrong position by the [`range.fixBlock()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-fixBlock) method due to quirky Firefox behavior.
460* [#13101](http://dev.ckeditor.com/ticket/13101): [IE8] Fixed: Colons are prepended to HTML5 element names when cloning them.
461
462## CKEditor 4.4.8
463
464**Security Updates:**
465
466* Fixed XSS vulnerability in the HTML parser reported by [Dheeraj Joshi](https://twitter.com/dheerajhere) and [Prem Kumar](https://twitter.com/iAmPr3m).
467
468 Issue summary: It was possible to execute XSS inside CKEditor after persuading the victim to: (i) switch CKEditor to source mode, then (ii) paste a specially crafted HTML code, prepared by the attacker, into the opened CKEditor source area, and (iii) switch back to WYSIWYG mode.
469
470**An upgrade is highly recommended!**
471
472Fixed Issues:
473
474* [#12899](http://dev.ckeditor.com/ticket/12899): Fixed: Corrected wrong tag ending for horizontal box definition in the [Dialog User Interface](http://ckeditor.com/addon/dialogui) plugin. Thanks to [mizafish](https://github.com/mizafish)!
475* [#13254](http://dev.ckeditor.com/ticket/13254): Fixed: Cannot outdent block after indent when using the [Div Editing Area](http://ckeditor.com/addon/divarea) plugin. Thanks to [Jonathan Cottrill](https://github.com/jcttrll)!
476* [#13268](http://dev.ckeditor.com/ticket/13268): Fixed: Documentation for [`CKEDITOR.dom.text`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.text) is incorrect. Thanks to [Ben Kiefer](https://github.com/benkiefer)!
477* [#12739](http://dev.ckeditor.com/ticket/12739): Fixed: Link loses inline styles when edited without the [Advanced Tab for Dialogs](http://ckeditor.com/addon/dialogadvtab) plugin. Thanks to [Віталій Крутько](https://github.com/asmforce)!
478* [#13292](http://dev.ckeditor.com/ticket/13292): Fixed: Protection pattern does not work in attribute in self-closing elements with no space before `/>`. Thanks to [Віталій Крутько](https://github.com/asmforce)!
479* [PR#192](https://github.com/ckeditor/ckeditor-dev/pull/192): Fixed: Variable name typo in the [Dialog User Interface](http://ckeditor.com/addon/dialogui) plugin which caused [`CKEDITOR.ui.dialog.radio`](http://docs.ckeditor.com/#!/api/CKEDITOR.ui.dialog.radio) validation to not work. Thanks to [Florian Ludwig](https://github.com/FlorianLudwig)!
480* [#13232](http://dev.ckeditor.com/ticket/13232): [Safari] Fixed: The [`element.appendText()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-appendText) method does not work properly for empty elements.
481* [#13233](http://dev.ckeditor.com/ticket/13233): Fixed: [HTMLDataProcessor](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor) can process `foo:href` attributes.
482* [#12796](http://dev.ckeditor.com/ticket/12796): Fixed: The [Indent List](http://ckeditor.com/addon/indentlist) plugin unwraps parent `<li>` elements. Thanks to [Andrew Stucki](https://github.com/andrewstucki)!
483* [#12885](http://dev.ckeditor.com/ticket/12885): Added missing [`editor.getData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData) parameter documentation.
484* [#11982](http://dev.ckeditor.com/ticket/11982): Fixed: Bullet added in a wrong position after the *Enter* key is pressed in a nested list.
485* [#13027](http://dev.ckeditor.com/ticket/13027): Fixed: Keyboard navigation in dialog windows with multiple tabs not following IBM CI 162 instructions or [ARIA Authoring Practices](http://www.w3.org/TR/2013/WD-wai-aria-practices-20130307/#tabpanel).
486* [#12256](http://dev.ckeditor.com/ticket/12256): Fixed: Basic styles classes are lost when pasting from Microsoft Word if [basic styles](http://ckeditor.com/addon/basicstyles) were configured to use classes.
487* [#12729](http://dev.ckeditor.com/ticket/12729): Fixed: Incorrect structure created when merging a block into a list item on *Backspace* and *Delete*.
488* [#13031](http://dev.ckeditor.com/ticket/13031): [Firefox] Fixed: No more line breaks in source view since Firefox 36.
489* [#13131](http://dev.ckeditor.com/ticket/13131): Fixed: The [Code Snippet](http://ckeditor.com/addon/codesnippet) plugin cannot be used without the [IFrame Editing Area](http://ckeditor.com/addon/wysiwygarea) plugin.
490* [#9086](http://dev.ckeditor.com/ticket/9086): Fixed: Invalid ARIA property used on paste area `<iframe>`.
491* [#13164](http://dev.ckeditor.com/ticket/13164): Fixed: Error when inserting a hidden field.
492* [#13155](http://dev.ckeditor.com/ticket/13155): Fixed: Incorrect [Line Utilities](http://ckeditor.com/addon/lineutils) positioning when `<body>` has a margin.
493* [#13351](http://dev.ckeditor.com/ticket/13351): Fixed: Link lost when editing a linked image with the Link tab disabled. This also fixed a bug when inserting an image into a fully selected link would throw an error ([#12847](https://dev.ckeditor.com/ticket/12847)).
494* [#13344](http://dev.ckeditor.com/ticket/13344): [WebKit/Blink] Fixed: It is possible to remove or change editor content in [read-only mode](http://docs.ckeditor.com/#!/guide/dev_readonly).
495
496Other Changes:
497
498* [#12844](http://dev.ckeditor.com/ticket/12844) and [#13103](http://dev.ckeditor.com/ticket/13103): Upgraded the [testing environment](http://docs.ckeditor.com/#!/guide/dev_tests) to [Bender.js](https://github.com/benderjs/benderjs) `0.2.3`.
499* [#12930](http://dev.ckeditor.com/ticket/12930): Because of licensing issues, `truncated-mathjax/` is now removed from the `tests/` directory. Now `bender.config.mathJaxLibPath` must be configured manually in order to run [Mathematical Formulas](http://ckeditor.com/addon/mathjax) plugin tests.
500* [#13266](http://dev.ckeditor.com/ticket/13266): Added more shades of gray in the [Color Dialog](http://ckeditor.com/addon/colordialog) window. Thanks to [mizafish](https://github.com/mizafish)!
501
502
503## CKEditor 4.4.7
504
505Fixed Issues:
506
507* [#12825](http://dev.ckeditor.com/ticket/12825): Fixed: Preventing the [Table Resize](http://ckeditor.com/addon/tableresize) plugin from operating on elements outside the editor. Thanks to [Paul Martin](https://github.com/Paul-Martin)!
508* [#12157](http://dev.ckeditor.com/ticket/12157): Fixed: Lost text formatting on pressing *Tab* when the [`config.tabSpaces`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-tabSpaces) configuration option value was greater than zero.
509* [#12777](http://dev.ckeditor.com/ticket/12777): Fixed: The `table-layout` CSS property should be reset by skins. Thanks to [vita10gy](https://github.com/vita10gy)!
510* [#12812](http://dev.ckeditor.com/ticket/12812): Fixed: An uncaught security exception is thrown when [Line Utilities](http://ckeditor.com/addon/lineutils) are used in an inline editor loaded in a cross-domain `iframe`. Thanks to [Vitaliy Zurian](https://github.com/thecatontheflat)!
511* [#12735](http://dev.ckeditor.com/ticket/12735): Fixed: [`config.fillEmptyBlocks`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fillEmptyBlocks) should only apply when outputting data.
512* [#10032](http://dev.ckeditor.com/ticket/10032): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) filter is executed for every paste after using the button.
513* [#12597](http://dev.ckeditor.com/ticket/12597): [Blink/WebKit] Fixed: Multi-byte Japanese characters entry not working properly after *Shift+Enter*.
514* [#12387](http://dev.ckeditor.com/ticket/12387): Fixed: An error is thrown if a skin does not have the [`chameleon`](http://docs.ckeditor.com/#!/api/CKEDITOR.skin-method-chameleon) property defined and [`config.uiColor`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-uiColor) is defined.
515* [#12747](http://dev.ckeditor.com/ticket/12747): [IE8-10] Fixed: Opening a drop-down for a specific selection when the editor is maximized results in incorrect drop-down panel position.
516* [#12850](http://dev.ckeditor.com/ticket/12850): [IEQM] Fixed: An error is thrown after focusing the editor.
517
518## CKEditor 4.4.6
519
520**Security Updates:**
521
522* Fixed XSS vulnerability in the HTML parser reported by [Maco Cortes](https://www.facebook.com/Maaacoooo).
523
524 Issue summary: It was possible to execute XSS inside CKEditor after persuading the victim to: (i) switch CKEditor to source mode, then (ii) paste a specially crafted HTML code, prepared by the attacker, into the opened CKEditor source area, and (iii) switch back to WYSIWYG mode.
525
526**An upgrade is highly recommended!**
527
528New Features:
529
530* [#12501](http://dev.ckeditor.com/ticket/12501): Allowed dashes in element names in the [string format of allowed content rules](http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules-section-string-format).
531* [#12550](http://dev.ckeditor.com/ticket/12550): Added the `<main>` element to the [`CKEDITOR.dtd`](http://docs.ckeditor.com/#!/api/CKEDITOR.dtd).
532
533Fixed Issues:
534
535* [#12506](http://dev.ckeditor.com/ticket/12506): [Safari] Fixed: Cannot paste into inline editor if the page has `user-select: none` style. Thanks to [shaohua](https://github.com/shaohua)!
536* [#12683](http://dev.ckeditor.com/ticket/12683): Fixed: [Filter](http://docs.ckeditor.com/#!/guide/dev_acf) fails to remove custom tags. Thanks to [timselier](https://github.com/timselier)!
537* [#12489](http://dev.ckeditor.com/ticket/12489) and [#12491](http://dev.ckeditor.com/ticket/12491): Fixed: Various issues related to restoring the selection after performing operations on filler character. See the [fixed cases](http://dev.ckeditor.com/ticket/12491#comment:4).
538* [#12621](http://dev.ckeditor.com/ticket/12621): Fixed: Cannot remove inline styles (bold, italic, etc.) in empty lines.
539* [#12630](http://dev.ckeditor.com/ticket/12630): [Chrome] Fixed: Selection is placed outside the paragraph when the [New Page](http://ckeditor.com/addon/newpage) button is clicked. This patch significantly simplified the way how the initial selection (a selection after the content of the editable is overwritten) is being fixed. That might have fixed many related scenarios in all browsers.
540* [#11647](http://dev.ckeditor.com/ticket/11647): Fixed: The [`editor.blur`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-blur) event is not fired on first blur after initializing the inline editor on an already focused element.
541* [#12601](http://dev.ckeditor.com/ticket/12601): Fixed: [Strikethrough](http://ckeditor.com/addon/basicstyles) button tooltip spelling.
542* [#12546](http://dev.ckeditor.com/ticket/12546): Fixed: The Preview tab in the [Document Properties](http://ckeditor.com/addon/docprops) dialog window is always disabled.
543* [#12300](http://dev.ckeditor.com/ticket/12300): Fixed: The [`editor.change`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-change) event fired on first navigation key press after typing.
544* [#12141](http://dev.ckeditor.com/ticket/12141): Fixed: List items are lost when indenting a list item with content wrapped with a block element.
545* [#12515](http://dev.ckeditor.com/ticket/12515): Fixed: Cursor is in the wrong position when undoing after adding an image and typing some text.
546* [#12484](http://dev.ckeditor.com/ticket/12484): [Blink/WebKit] Fixed: DOM is changed outside the editor area in a certain case.
547* [#12688](http://dev.ckeditor.com/ticket/12688): Improved the tests of the [styles system](http://docs.ckeditor.com/#!/api/CKEDITOR.style) and fixed two minor issues.
548* [#12403](http://dev.ckeditor.com/ticket/12403): Fixed: Changing the [font](http://ckeditor.com/addon/font) style should not lead to nesting it in the previous style element.
549* [#12609](http://dev.ckeditor.com/ticket/12609): Fixed: Incorrect `config.magicline_putEverywhere` name used for a [Magic Line](http://ckeditor.com/addon/magicline) all-encompassing [`config.magicline_everywhere`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-magicline_everywhere) configuration option.
550
551
552## CKEditor 4.4.5
553
554New Features:
555
556* [#12279](http://dev.ckeditor.com/ticket/12279): Added a possibility to pass a custom evaluator to [`node.getAscendant()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.node-method-getAscendant).
557
558Fixed Issues:
559
560* [#12423](http://dev.ckeditor.com/ticket/12423): [Safari7.1+] Fixed: *Enter* key moved cursor to a strange position.
561* [#12381](http://dev.ckeditor.com/ticket/12381): [iOS] Fixed: Selection issue. Thanks to [Remiremi](https://github.com/Remiremi)!
562* [#10804](http://dev.ckeditor.com/ticket/10804): Fixed: `CKEDITOR_GETURL` is not used with some plugins where it should be used. Thanks to [Thomas Andraschko](https://github.com/tandraschko)!
563* [#9137](http://dev.ckeditor.com/ticket/9137): Fixed: The `<base>` tag is not created when `<head>` has an attribute. Thanks to [naoki.fujikawa](https://github.com/naoki-fujikawa)!
564* [#12377](http://dev.ckeditor.com/ticket/12377): Fixed: Errors thrown in the [Image](http://ckeditor.com/addon/image) plugin when removing preview from the dialog window definition. Thanks to [Axinet](https://github.com/Axinet)!
565* [#12162](http://dev.ckeditor.com/ticket/12162): Fixed: Auto paragraphing and *Enter* key in nested editables.
566* [#12315](http://dev.ckeditor.com/ticket/12315): Fixed: Marked [`config.autoParagraph`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-autoParagraph) as deprecated.
567* [#12113](http://dev.ckeditor.com/ticket/12113): Fixed: A [code snippet](http://ckeditor.com/addon/codesnippet) should be presented in the [elements path](http://ckeditor.com/addon/elementspath) as "code snippet" (translatable).
568* [#12311](http://dev.ckeditor.com/ticket/12311): Fixed: [Remove Format](http://ckeditor.com/addon/removeformat) should also remove `<cite>` elements.
569* [#12261](http://dev.ckeditor.com/ticket/12261): Fixed: Filter has to be destroyed and removed from [`CKEDITOR.filter.instances`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter-static-property-instances) on editor destroy.
570* [#12398](http://dev.ckeditor.com/ticket/12398): Fixed: [Maximize](http://ckeditor.com/addon/maximize) does not work on an instance without a [title](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-title).
571* [#12097](http://dev.ckeditor.com/ticket/12097): Fixed: JAWS not reading the number of options correctly in the [Text Color and Background Color](http://ckeditor.com/addon/colorbutton) button menu.
572* [#12411](http://dev.ckeditor.com/ticket/12411): Fixed: [Page Break](http://ckeditor.com/addon/pagebreak) used directly in the editable breaks the editor.
573* [#12354](http://dev.ckeditor.com/ticket/12354): Fixed: Various issues in undo manager when holding keys.
574* [#12324](http://dev.ckeditor.com/ticket/12324): [IE8] Fixed: Undo steps are not recorded when changing the caret position by clicking below the body.
575* [#12332](http://dev.ckeditor.com/ticket/12332): Fixed: Lowered DOM events listeners' priorities in undo manager in order to avoid ambiguity.
576* [#12402](http://dev.ckeditor.com/ticket/12402): [Blink] Fixed: Workaround for Blink bug with `document.title` which breaks updating title in the full HTML mode.
577* [#12338](http://dev.ckeditor.com/ticket/12338): Fixed: The CKEditor package contains unoptimized images.
578
579
580## CKEditor 4.4.4
581
582Fixed Issues:
583
584* [#12268](http://dev.ckeditor.com/ticket/12268): Cleanup of [UI Color](http://ckeditor.com/addon/uicolor) YUI styles. Thanks to [CasherWest](https://github.com/CasherWest)!
585* [#12263](http://dev.ckeditor.com/ticket/12263): Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) filter does not properly normalize semicolons style text. Thanks to [Alin Purcaru](https://github.com/mesmerizero)!
586* [#12243](http://dev.ckeditor.com/ticket/12243): Fixed: Text formatting lost when pasting from Word. Thanks to [Alin Purcaru](https://github.com/mesmerizero)!
587* [#111739](http://dev.ckeditor.com/ticket/11739): Fixed: `keypress` listeners should not be used in the undo manager. A complete rewrite of keyboard handling in the undo manager was made. Numerous smaller issues were fixed, among others:
588 * [#10926](http://dev.ckeditor.com/ticket/10926): [Chrome@Android] Fixed: Typing does not record snapshots and does not fire the [`editor.change`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-change) event.
589 * [#11611](http://dev.ckeditor.com/ticket/11611): [Firefox] Fixed: The [`editor.change`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-change) event is fired when pressing Arrow keys.
590 * [#12219](http://dev.ckeditor.com/ticket/12219): [Safari] Fixed: Some modifications of the [`UndoManager.locked`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.undo.UndoManager-property-locked) property violate strict mode in the [Undo](http://ckeditor.com/addon/undo) plugin.
591* [#10916](http://dev.ckeditor.com/ticket/10916): Fixed: [Magic Line](http://ckeditor.com/addon/magicline) icon in Right-To-Left environments.
592* [#11970](http://dev.ckeditor.com/ticket/11970): [IE] Fixed: CKEditor `paste` event is not fired when pasting with *Shift+Ins*.
593* [#12111](http://dev.ckeditor.com/ticket/12111): Fixed: Linked image attributes are not read when opening the image dialog window by doubleclicking.
594* [#10030](http://dev.ckeditor.com/ticket/10030): [IE] Fixed: Prevented "Unspecified Error" thrown in various cases when IE8-9 does not allow access to `document.activeElement`.
595* [#12273](http://dev.ckeditor.com/ticket/12273): Fixed: Applying block style in a description list breaks it.
596* [#12218](http://dev.ckeditor.com/ticket/12218): Fixed: Minor syntax issue in CSS files.
597* [#12178](http://dev.ckeditor.com/ticket/12178): [Blink/WebKit] Fixed: Iterator does not return the block if the selection is located at the end of it.
598* [#12185](http://dev.ckeditor.com/ticket/12185): [IE9QM] Fixed: Error thrown when moving the mouse over focused editor's scrollbar.
599* [#12215](http://dev.ckeditor.com/ticket/12215): Fixed: Basepath resolution does not recognize semicolon as a query separator.
600* [#12135](http://dev.ckeditor.com/ticket/12135): Fixed: [Remove Format](http://ckeditor.com/addon/removeformat) does not work on widgets.
601* [#12298](http://dev.ckeditor.com/ticket/12298): [IE11] Fixed: Clicking below `<body>` in Compatibility Mode will no longer reset selection to the first line.
602* [#12204](http://dev.ckeditor.com/ticket/12204): Fixed: Editor's voice label is not affected by [`config.title`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-title).
603* [#11915](http://dev.ckeditor.com/ticket/11915): Fixed: With [SCAYT](http://ckeditor.com/addon/scayt) enabled, cursor moves to the beginning of the first highlighted, misspelled word after typing or pasting into the editor.
604* [SCAYT](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/69): Fixed: Error thrown in the console after enabling [SCAYT](http://ckeditor.com/addon/scayt) and trying to add a new image.
605
606
607Other Changes:
608
609* [#12296](http://dev.ckeditor.com/ticket/12296): Merged `benderjs-ckeditor` into the main CKEditor repository.
610
611## CKEditor 4.4.3
612
613**Security Updates:**
614
615* Fixed XSS vulnerability in the Preview plugin reported by Mario Heiderich of [Cure53](https://cure53.de/).
616
617**An upgrade is highly recommended!**
618
619New Features:
620
621* [#12164](http://dev.ckeditor.com/ticket/12164): Added the "Justify" option to the "Horizontal Alignment" drop-down in the Table Cell Properties dialog window.
622
623Fixed Issues:
624
625* [#12110](http://dev.ckeditor.com/ticket/12110): Fixed: Editor crash after deleting a table. Thanks to [Alin Purcaru](https://github.com/mesmerizero)!
626* [#11897](http://dev.ckeditor.com/ticket/11897): Fixed: *Enter* key used in an empty list item creates a new line instead of breaking the list. Thanks to [noam-si](https://github.com/noam-si)!
627* [#12140](http://dev.ckeditor.com/ticket/12140): Fixed: Double-clicking linked widgets opens two dialog windows.
628* [#12132](http://dev.ckeditor.com/ticket/12132): Fixed: Image is inserted with `width` and `height` styles even when they are not allowed.
629* [#9317](http://dev.ckeditor.com/ticket/9317): [IE] Fixed: [`config.disableObjectResizing`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-disableObjectResizing) does not work on IE. **Note**: We were not able to fix this issue on IE11+ because necessary events stopped working. See a [last resort workaround](http://dev.ckeditor.com/ticket/9317#comment:16) and make sure to [support our complaint to Microsoft](https://connect.microsoft.com/IE/feedback/details/742593/please-respect-execcommand-enableobjectresizing-in-contenteditable-elements).
630* [#9638](http://dev.ckeditor.com/ticket/9638): Fixed: There should be no information about accessibility help available under the *Alt+0* keyboard shortcut if the [Accessibility Help](http://ckeditor.com/addon/a11yhelp) plugin is not available.
631* [#8117](http://dev.ckeditor.com/ticket/8117) and [#9186](http://dev.ckeditor.com/ticket/9186): Fixed: In HTML5 `<meta>` tags should be allowed everywhere, including inside the `<body>` element.
632* [#10422](http://dev.ckeditor.com/ticket/10422): Fixed: [`config.fillEmptyBlocks`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fillEmptyBlocks) not working properly if a function is specified.
633
634## CKEditor 4.4.2
635
636Important Notes:
637
638* The CKEditor testing environment is now publicly available. Read more about how to set up the environment and execute tests in the [CKEditor Testing Environment](http://docs.ckeditor.com/#!/guide/dev_tests) guide.
639 Please note that the [`tests/`](https://github.com/ckeditor/ckeditor-dev/tree/master/tests) directory which contains editor tests is not available in release packages. It can only be found in the development version of CKEditor on [GitHub](https://github.com/ckeditor/ckeditor-dev/).
640
641New Features:
642
643* [#11909](http://dev.ckeditor.com/ticket/11909): Introduced a parameter to prevent the [`editor.setData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setData) method from recording undo snapshots.
644
645Fixed Issues:
646
647* [#11757](http://dev.ckeditor.com/ticket/11757): Fixed: Imperfections in the [Moono](http://ckeditor.com/addon/moono) skin. Thanks to [danyaPostfactum](https://github.com/danyaPostfactum)!
648* [#10091](http://dev.ckeditor.com/ticket/10091): Blockquote should be treated like an object by the styles system. Thanks to [dan-james-deeson](https://github.com/dan-james-deeson)!
649* [#11478](http://dev.ckeditor.com/ticket/11478): Fixed: Issue with passing jQuery objects to [adapter](http://docs.ckeditor.com/#!/guide/dev_jquery) configuration.
650* [#10867](http://dev.ckeditor.com/ticket/10867): Fixed: Issue with setting encoded URI as image link.
651* [#11983](http://dev.ckeditor.com/ticket/11983): Fixed: Clicking a nested widget does not focus it. Additionally, performance of the [`widget.repository.getByElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-getByElement) method was improved.
652* [#12000](http://dev.ckeditor.com/ticket/12000): Fixed: Nested widgets should be initialized on [`editor.setData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setData) and [`nestedEditable.setData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.nestedEditable-method-setData).
653* [#12022](http://dev.ckeditor.com/ticket/12022): Fixed: Outer widget's drag handler is not created at all if it has any nested widgets inside.
654* [#11960](http://dev.ckeditor.com/ticket/11960): [Blink/WebKit] Fixed: The caret should be scrolled into view on *Backspace* and *Delete* (covers only the merging blocks case).
655* [#11306](http://dev.ckeditor.com/ticket/11306): [OSX][Blink/WebKit] Fixed: No widget entries in the context menu on widget right-click.
656* [#11957](http://dev.ckeditor.com/ticket/11957): Fixed: Alignment labels in the [Enhanced Image](http://ckeditor.com/addon/image2) dialog window are not translated.
657* [#11980](http://dev.ckeditor.com/ticket/11980): [Blink/WebKit] Fixed: `<span>` elements created when joining adjacent elements (non-collapsed selection).
658* [#12009](http://dev.ckeditor.com/ticket/12009): [Nested widgets] Integration with the [Magic Line](http://ckeditor.com/addon/magicline) plugin.
659* [#11387](http://dev.ckeditor.com/ticket/11387): Fixed: `role="radiogroup"` should be applied only to radio inputs' container.
660* [#7975](http://dev.ckeditor.com/ticket/7975): [IE8] Fixed: Errors when trying to select an empty table cell.
661* [#11947](http://dev.ckeditor.com/ticket/11947): [Firefox+IE11] Fixed: *Shift+Enter* in lists produces two line breaks.
662* [#11972](http://dev.ckeditor.com/ticket/11972): Fixed: Feature detection in the [`element.setText()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-setText) method should not trigger the layout engine.
663* [#7634](http://dev.ckeditor.com/ticket/7634): Fixed: The [Flash Dialog](http://ckeditor.com/addon/flash) plugin omits the `allowFullScreen` parameter in the editor data if set to `true`.
664* [#11910](http://dev.ckeditor.com/ticket/11910): Fixed: [Enhanced Image](http://ckeditor.com/addon/image2) does not take [`config.baseHref`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-baseHref) into account when updating image dimensions.
665* [#11753](http://dev.ckeditor.com/ticket/11753): Fixed: Wrong [`checkDirty()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-checkDirty) method value after focusing or blurring a widget.
666* [#11830](http://dev.ckeditor.com/ticket/11830): Fixed: Impossible to pass some arguments to [CKBuilder](https://github.com/ckeditor/ckbuilder) when using the `/dev/builder/build.sh` script.
667* [#11945](http://dev.ckeditor.com/ticket/11945): Fixed: [Form Elements](http://ckeditor.com/addon/forms) plugin should not change a core method.
668* [#11384](http://dev.ckeditor.com/ticket/11384): [IE9+] Fixed: `IndexSizeError` thrown when pasting into a non-empty selection anchored in one text node.
669
670## CKEditor 4.4.1
671
672New Features:
673
674* [#9661](http://dev.ckeditor.com/ticket/9661): Added the option to [configure](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-linkJavaScriptLinksAllowed) anchor tags with JavaScript code in the `href` attribute.
675
676Fixed Issues:
677
678* [#11861](http://dev.ckeditor.com/ticket/11861): [WebKit/Blink] Fixed: Span elements created while joining adjacent elements. **Note:** This patch only covers cases when *Backspace* or *Delete* is pressed on a collapsed (empty) selection. The remaining case, with a non-empty selection, will be fixed in the next release.
679* [#10714](http://dev.ckeditor.com/ticket/10714): [iOS] Fixed: Selection and drop-downs are broken if a touch event listener is used due to a [WebKit bug](https://bugs.webkit.org/show_bug.cgi?id=128924). Thanks to [Arty Gus](https://github.com/artygus)!
680* [#11911](http://dev.ckeditor.com/ticket/11911): Fixed setting the `dir` attribute for a preloaded language in [CKEDITOR.lang](http://docs.ckeditor.com/#!/api/CKEDITOR.lang). Thanks to [Akash Mohapatra](https://github.com/akashmohapatra)!
681* [#11926](http://dev.ckeditor.com/ticket/11926): Fixed: [Code Snippet](http://ckeditor.com/addon/codesnippet) does not decode HTML entities when loading code from the `<code>` element.
682* [#11223](http://dev.ckeditor.com/ticket/11223): Fixed: Issue when [Protected Source](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-protectedSource) was not working in the `<title>` element.
683* [#11859](http://dev.ckeditor.com/ticket/11859): Fixed: Removed the [Source Dialog](http://ckeditor.com/addon/sourcedialog) plugin dependency from the [Code Snippet](http://ckeditor.com/addon/codesnippet) sample.
684* [#11754](http://dev.ckeditor.com/ticket/11754): [Chrome] Fixed: Infinite loop when content includes not closed attributes.
685* [#11848](http://dev.ckeditor.com/ticket/11848): [IE] Fixed: [`editor.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) throwing an exception when there was no selection in the editor.
686* [#11801](http://dev.ckeditor.com/ticket/11801): Fixed: Editor anchors unavailable when linking the [Enhanced Image](http://ckeditor.com/addon/image2) widget.
687* [#11626](http://dev.ckeditor.com/ticket/11626): Fixed: [Table Resize](http://ckeditor.com/addon/tableresize) sets invalid column width.
688* [#11872](http://dev.ckeditor.com/ticket/11872): Made [`element.addClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-addClass) chainable symmetrically to [`element.removeClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-removeClass).
689* [#11813](http://dev.ckeditor.com/ticket/11813): Fixed: Link lost while pasting a captioned image and restoring an undo snapshot ([Enhanced Image](http://ckeditor.com/addon/image2)).
690* [#11814](http://dev.ckeditor.com/ticket/11814): Fixed: _Link_ and _Unlink_ entries persistently displayed in the [Enhanced Image](http://ckeditor.com/addon/image2) context menu.
691* [#11839](http://dev.ckeditor.com/ticket/11839): [IE9] Fixed: The caret jumps out of the editable area when resizing the editor in the source mode.
692* [#11822](http://dev.ckeditor.com/ticket/11822): [WebKit] Fixed: Editing anchors by double-click is broken in some cases.
693* [#11823](http://dev.ckeditor.com/ticket/11823): [IE8] Fixed: [Table Resize](http://ckeditor.com/addon/tableresize) throws an error over scrollbar.
694* [#11788](http://dev.ckeditor.com/ticket/11788): Fixed: It is not possible to change the language back to _Not set_ in the [Code Snippet](http://ckeditor.com/addon/codesnippet) dialog window.
695* [#11788](http://dev.ckeditor.com/ticket/11788): Fixed: [Filter](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.filter) rules are not applied inside elements with the `contenteditable` attribute set to `true`.
696* [#11798](http://dev.ckeditor.com/ticket/11798): Fixed: Inserting a non-editable element inside a table cell breaks the table.
697* [#11793](http://dev.ckeditor.com/ticket/11793): Fixed: Drop-down is not "on" when clicking it while the editor is blurred.
698* [#11850](http://dev.ckeditor.com/ticket/11850): Fixed: Fake objects with the `contenteditable` attribute set to `false` are not downcasted properly.
699* [#11811](http://dev.ckeditor.com/ticket/11811): Fixed: Widget's data is not encoded correctly when passed to an attribute.
700* [#11777](http://dev.ckeditor.com/ticket/11777): Fixed encoding ampersand in the [Mathematical Formulas](http://ckeditor.com/addon/mathjax) plugin.
701* [#11880](http://dev.ckeditor.com/ticket/11880): [IE8-9] Fixed: Linked image has a default thick border.
702
703Other Changes:
704
705* [#11807](http://dev.ckeditor.com/ticket/11807): Updated jQuery version used in the sample to 1.11.0 and tested CKEditor jQuery Adapter with version 1.11.0 and 2.1.0.
706* [#9504](http://dev.ckeditor.com/ticket/9504): Stopped using deprecated `attribute.specified` in all browsers except Internet Explorer.
707* [#11809](http://dev.ckeditor.com/ticket/11809): Changed tab size in `<pre>` to 4 spaces.
708
709## CKEditor 4.4
710
711**Important Notes:**
712
713* Marked the [`editor.beforePaste`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-beforePaste) event as deprecated.
714* The default class of captioned images has changed to `image` (was: `caption`). Please note that once edited in CKEditor 4.4+, all existing images of the `caption` class (`<figure class="caption">`) will be [filtered out](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) unless the [`config.image2_captionedClass`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image2_captionedClass) option is set to `caption`. For backward compatibility (i.e. when upgrading), it is highly recommended to use this setting, which also helps prevent CSS conflicts, etc. This does not apply to new CKEditor integrations.
715* Widgets without defined buttons are no longer registered automatically to the [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter). Before CKEditor 4.4 widgets were registered to the ACF which was an incorrect behavior ([#11567](http://dev.ckeditor.com/ticket/11567)). This change should not have any impact on standard scenarios, but if your button does not execute the widget command, you need to set [`allowedContent`](http://docs.ckeditor.com/#!/api/CKEDITOR.feature-property-allowedContent) and [`requiredContent`](http://docs.ckeditor.com/#!/api/CKEDITOR.feature-property-requiredContent) properties for it manually, because the editor will not be able to find them.
716* The [Show Borders](http://ckeditor.com/addon/showborders) plugin was added to the Standard installation package in order to ensure that unstyled tables are still visible for the user ([#11665](http://dev.ckeditor.com/ticket/11665)).
717* Since CKEditor 4.4 the editor instance should be passed to [`CKEDITOR.style`](http://docs.ckeditor.com/#!/api/CKEDITOR.style) methods to ensure full compatibility with other features (e.g. applying styles to widgets requires that). We ensured backward compatibility though, so the [`CKEDITOR.style`](http://docs.ckeditor.com/#!/api/CKEDITOR.style) will work even when the editor instance is not provided.
718
719New Features:
720
721* [#11297](http://dev.ckeditor.com/ticket/11297): Styles can now be applied to widgets. The definition of a style which can be applied to a specific widget must contain two additional properties &mdash; `type` and `widget`. Read more in the [Widget Styles](http://docs.ckeditor.com/#!/guide/dev_styles-section-widget-styles) section of the "Syles Drop-down" guide. Note that by default, widgets support only classes and no other attributes or styles. Related changes and features:
722 * Introduced the [`CKEDITOR.style.addCustomHandler()`](http://docs.ckeditor.com/#!/api/CKEDITOR.style-static-method-addCustomHandler) method for registering custom style handlers.
723 * The [`CKEDITOR.style.apply()`](http://docs.ckeditor.com/#!/api/CKEDITOR.style-method-apply) and [`CKEDITOR.style.remove()`](http://docs.ckeditor.com/#!/api/CKEDITOR.style-method-remove) methods are now called with an editor instance instead of the document so they can be reused by the [`CKEDITOR.editor.applyStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-applyStyle) and [`CKEDITOR.editor.removeStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-removeStyle) methods. Backward compatibility was preserved, but from CKEditor 4.4 it is highly recommended to pass an editor instead of a document to these methods.
724 * Many new methods and properties were introduced in the [Widget API](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget) to make the handling of styles by widgets fully customizable. See: [`widget.definition.styleableElements`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.definition-property-styleableElements), [`widget.definition.styleToAllowedContentRule`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.definition-property-styleToAllowedContentRules), [`widget.addClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-addClass), [`widget.removeClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-removeClass), [`widget.getClasses()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-getClasses), [`widget.hasClass()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-hasClass), [`widget.applyStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-applyStyle), [`widget.removeStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-removeStyle), [`widget.checkStyleActive()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-method-checkStyleActive).
725 * Integration with the [Allowed Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) required an introduction of the [`CKEDITOR.style.toAllowedContent()`](http://docs.ckeditor.com/#!/api/CKEDITOR.style-method-toAllowedContentRules) method which can be implemented by the custom style handler and if exists, it is used by the [`CKEDITOR.filter`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter) to translate a style to [allowed content rules](http://docs.ckeditor.com/#!/api/CKEDITOR.filter.allowedContentRules).
726* [#11300](http://dev.ckeditor.com/ticket/11300): Various changes in the [Enhanced Image](http://ckeditor.com/addon/image2) plugin:
727 * Introduced the [`config.image2_captionedClass`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image2_captionedClass) option to configure the class of captioned images.
728 * Introduced the [`config.image2_alignClasses`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-image2_alignClasses) option to configure the way images are aligned with CSS classes.
729 If this setting is defined, the editor produces classes instead of inline styles for aligned images.
730 * Default image caption can be translated (customized) with the `editor.lang.image2.captionPlaceholder` string.
731* [#11341](http://dev.ckeditor.com/ticket/11341): [Enhanced Image](http://ckeditor.com/addon/image2) plugin: It is now possible to add a link to any image type.
732* [#10202](http://dev.ckeditor.com/ticket/10202): Introduced wildcard support in the [Allowed Content Rules](http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules) format.
733* [#10276](http://dev.ckeditor.com/ticket/10276): Introduced blacklisting in the [Allowed Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter).
734* [#10480](http://dev.ckeditor.com/ticket/10480): Introduced code snippets with code highlighting. There are two versions available so far &mdash; the default [Code Snippet](http://ckeditor.com/addon/codesnippet) which uses the [highlight.js](http://highlightjs.org) library and the [Code Snippet GeSHi](http://ckeditor.com/addon/codesnippetgeshi) which uses the [GeSHi](http://qbnz.com/highlighter/) library.
735* [#11737](http://dev.ckeditor.com/ticket/11737): Introduced an option to prevent [filtering](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) of an element that matches custom criteria (see [`filter.addElementCallback()`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter-method-addElementCallback)).
736* [#11532](http://dev.ckeditor.com/ticket/11532): Introduced the [`editor.addContentsCss()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-addContentsCss) method that can be used for [adding custom CSS files](http://docs.ckeditor.com/#!/guide/plugin_sdk_styles).
737* [#11536](http://dev.ckeditor.com/ticket/11536): Added the [`CKEDITOR.tools.htmlDecode()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-htmlDecode) method for decoding HTML entities.
738* [#11225](http://dev.ckeditor.com/ticket/11225): Introduced the [`CKEDITOR.tools.transparentImageData`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-property-transparentImageData) property which contains transparent image data to be used in CSS or as image source.
739
740Other Changes:
741
742* [#11377](http://dev.ckeditor.com/ticket/11377): Unified internal representation of empty anchors using the [fake objects](http://ckeditor.com/addon/fakeobjects).
743* [#11422](http://dev.ckeditor.com/ticket/11422): Removed Firefox 3.x, Internet Explorer 6 and Opera 12.x leftovers in code.
744* [#5217](http://dev.ckeditor.com/ticket/5217): Setting data (including switching between modes) creates a new undo snapshot. Besides that:
745 * Introduced the [`editable.status`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-property-status) property.
746 * Introduced a new `forceUpdate` option for the [`editor.lockSnapshot`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-lockSnapshot) event.
747 * Fixed: Selection not being unlocked in inline editor after setting data ([#11500](http://dev.ckeditor.com/ticket/11500)).
748* The [WebSpellChecker](http://ckeditor.com/addon/wsc) plugin was updated to the latest version.
749
750Fixed Issues:
751
752* [#10190](http://dev.ckeditor.com/ticket/10190): Fixed: Removing block style with [`editor.removeStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-removeStyle) should result in a paragraph and not a div.
753* [#11727](http://dev.ckeditor.com/ticket/11727): Fixed: The editor tries to select a non-editable image which was clicked.
754
755## CKEditor 4.3.5
756
757New Features:
758
759* Added new translation: Tatar.
760
761Fixed Issues:
762
763* [#11677](http://dev.ckeditor.com/ticket/11677): Fixed: Undo/Redo keystrokes are blocked in the source mode.
764* [#11717](http://dev.ckeditor.com/ticket/11717): [Document Properties](http://ckeditor.com/addon/docprops) plugin requires the [Color Dialog](http://ckeditor.com/addon/colordialog) plugin to work.
765
766## CKEditor 4.3.4
767
768Fixed Issues:
769
770* [#11597](http://dev.ckeditor.com/ticket/11597): [IE11] Fixed: Error thrown when trying to open the [preview](http://ckeditor.com/addon/preview) using the keyboard.
771* [#11544](http://dev.ckeditor.com/ticket/11544): [Placeholders](http://ckeditor.com/addon/placeholder) will no longer be upcasted in parents not accepting `<span>` elements.
772* [#8663](http://dev.ckeditor.com/ticket/8663): Fixed [`element.renameNode()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-renameNode) not clearing the [`element.getName()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element-method-getName) cache.
773* [#11574](http://dev.ckeditor.com/ticket/11574): Fixed: *Backspace* destroying the DOM structure if an inline editable is placed in a list item.
774* [#11603](http://dev.ckeditor.com/ticket/11603): Fixed: [Table Resize](http://ckeditor.com/addon/tableresize) attaches to tables outside the editable.
775* [#9205](http://dev.ckeditor.com/ticket/9205), [#7805](http://dev.ckeditor.com/ticket/7805), [#8216](http://dev.ckeditor.com/ticket/8216): Fixed: `{cke_protected_1}` appearing in data in various cases where HTML comments are placed next to `"` or `'`.
776* [#11635](http://dev.ckeditor.com/ticket/11635): Fixed: Some attributes are not protected before the content is passed through the fix bin.
777* [#11660](http://dev.ckeditor.com/ticket/11660): [IE] Fixed: Table content is lost when some extra markup is inside the table.
778* [#11641](http://dev.ckeditor.com/ticket/11641): Fixed: Switching between modes in the classic editor removes content styles for the inline editor.
779* [#11568](http://dev.ckeditor.com/ticket/11568): Fixed: [Styles](http://ckeditor.com/addon/stylescombo) drop-down list is not enabled on selection change.
780
781## CKEditor 4.3.3
782
783Fixed Issues:
784
785* [#11500](http://dev.ckeditor.com/ticket/11500): [WebKit/Blink] Fixed: Selection lost when setting data in another inline editor. Additionally, [`selection.removeAllRanges()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-removeAllRanges) is now scoped to selection's [root](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-property-root).
786* [#11104](http://dev.ckeditor.com/ticket/11104): [IE] Fixed: Various issues with scrolling and selection when focusing widgets.
787* [#11487](http://dev.ckeditor.com/ticket/11487): Moving mouse over the [Enhanced Image](http://ckeditor.com/addon/image2) widget will no longer change the value returned by the [`editor.checkDirty()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-checkDirty) method.
788* [#8673](http://dev.ckeditor.com/ticket/8673): [WebKit] Fixed: Cannot select and remove the [Page Break](http://ckeditor.com/addon/pagebreak).
789* [#11413](http://dev.ckeditor.com/ticket/11413): Fixed: Incorrect [`editor.execCommand()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-execCommand) behavior.
790* [#11438](http://dev.ckeditor.com/ticket/11438): Splitting table cells vertically is no longer changing table structure.
791* [#8899](http://dev.ckeditor.com/ticket/8899): Fixed: Links in the [About CKEditor](http://ckeditor.com/addon/about) dialog window now open in a new browser window or tab.
792* [#11490](http://dev.ckeditor.com/ticket/11490): Fixed: [Menu button](http://ckeditor.com/addon/menubutton) panel not showing in the source mode.
793* [#11417](http://dev.ckeditor.com/ticket/11417): The [`widget.doubleclick`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget-event-doubleclick) event is not canceled anymore after editing was triggered.
794* [#11253](http://dev.ckeditor.com/ticket/11253): [IE] Fixed: Clipped upload button in the [Enhanced Image](http://ckeditor.com/addon/image2) dialog window.
795* [#11359](http://dev.ckeditor.com/ticket/11359): Standardized the way anchors are discovered by the [Link](http://ckeditor.com/addon/link) plugin.
796* [#11058](http://dev.ckeditor.com/ticket/11058): [IE8] Fixed: Error when deleting a table row.
797* [#11508](http://dev.ckeditor.com/ticket/11508): Fixed: [`htmlDataProcessor`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor) discovering protected attributes within other attributes' values.
798* [#11533](http://dev.ckeditor.com/ticket/11533): Widgets: Avoid recurring upcasts if the DOM structure was modified during an upcast.
799* [#11400](http://dev.ckeditor.com/ticket/11400): Fixed: The [`domObject.removeAllListeners()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.domObject-method-removeAllListeners) method does not remove custom listeners completely.
800* [#11493](http://dev.ckeditor.com/ticket/11493): Fixed: The [`selection.getRanges()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-getRanges) method does not override cached ranges when used with the `onlyEditables` argument.
801* [#11390](http://dev.ckeditor.com/ticket/11390): [IE] All [XML](http://ckeditor.com/addon/xml) plugin [methods](http://docs.ckeditor.com/#!/api/CKEDITOR.xml) now work in IE10+.
802* [#11542](http://dev.ckeditor.com/ticket/11542): [IE11] Fixed: Blurry toolbar icons when Right-to-Left UI language is set.
803* [#11504](http://dev.ckeditor.com/ticket/11504): Fixed: When [`config.fullPage`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-fullPage) is set to `true`, entities are not encoded in editor output.
804* [#11004](http://dev.ckeditor.com/ticket/11004): Integrated [Enhanced Image](http://ckeditor.com/addon/image2) dialog window with [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter).
805* [#11439](http://dev.ckeditor.com/ticket/11439): Fixed: Properties get cloned in the Cell Properties dialog window if multiple cells are selected.
806
807## CKEditor 4.3.2
808
809Fixed Issues:
810
811* [#11331](http://dev.ckeditor.com/ticket/11331): A menu button will have a changed label when selected instead of using the `aria-pressed` attribute.
812* [#11177](http://dev.ckeditor.com/ticket/11177): Widget drag handler improvements:
813 * [#11176](http://dev.ckeditor.com/ticket/11176): Fixed: Initial position is not updated when the widget data object is empty.
814 * [#11001](http://dev.ckeditor.com/ticket/11001): Fixed: Multiple synchronous layout recalculations are caused by initial drag handler positioning causing performance issues.
815 * [#11161](http://dev.ckeditor.com/ticket/11161): Fixed: Drag handler is not repositioned in various situations.
816 * [#11281](http://dev.ckeditor.com/ticket/11281): Fixed: Drag handler and mask are duplicated after widget reinitialization.
817* [#11207](http://dev.ckeditor.com/ticket/11207): [Firefox] Fixed: Misplaced [Enhanced Image](http://ckeditor.com/addon/image2) resizer in the inline editor.
818* [#11102](http://dev.ckeditor.com/ticket/11102): `CKEDITOR.template` improvements:
819 * [#11102](http://dev.ckeditor.com/ticket/11102): Added newline character support.
820 * [#11216](http://dev.ckeditor.com/ticket/11216): Added "\\'" substring support.
821* [#11121](http://dev.ckeditor.com/ticket/11121): [Firefox] Fixed: High Contrast mode is enabled when the editor is loaded in a hidden iframe.
822* [#11350](http://dev.ckeditor.com/ticket/11350): The default value of [`config.contentsCss`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-contentsCss) is affected by [`CKEDITOR.getUrl()`](http://docs.ckeditor.com/#!/api/CKEDITOR-method-getUrl).
823* [#11097](http://dev.ckeditor.com/ticket/11097): Improved the [Autogrow](http://ckeditor.com/addon/autogrow) plugin performance when dealing with very big tables.
824* [#11290](http://dev.ckeditor.com/ticket/11290): Removed redundant code in the [Source Dialog](http://ckeditor.com/addon/sourcedialog) plugin.
825* [#11133](http://dev.ckeditor.com/ticket/11133): [Page Break](http://ckeditor.com/addon/pagebreak) becomes editable if pasted.
826* [#11126](http://dev.ckeditor.com/ticket/11126): Fixed: Native Undo executed once the bottom of the snapshot stack is reached.
827* [#11131](http://dev.ckeditor.com/ticket/11131): [Div Editing Area](http://ckeditor.com/addon/divarea): Fixed: Error thrown when switching to source mode if the selection was in widget's nested editable.
828* [#11139](http://dev.ckeditor.com/ticket/11139): [Div Editing Area](http://ckeditor.com/addon/divarea): Fixed: Elements Path is not cleared after switching to source mode.
829* [#10778](http://dev.ckeditor.com/ticket/10778): Fixed a bug with range enlargement. The range no longer expands to visible whitespace.
830* [#11146](http://dev.ckeditor.com/ticket/11146): [IE] Fixed: Preview window switches Internet Explorer to Quirks Mode.
831* [#10762](http://dev.ckeditor.com/ticket/10762): [IE] Fixed: JavaScript code displayed in preview window's URL bar.
832* [#11186](http://dev.ckeditor.com/ticket/11186): Introduced the [`widgets.repository.addUpcastCallback()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-addUpcastCallback) method that allows to block upcasting given element to a widget.
833* [#11307](http://dev.ckeditor.com/ticket/11307): Fixed: Paste as Plain Text conflict with the [MooTools](http://mootools.net) library.
834* [#11140](http://dev.ckeditor.com/ticket/11140): [IE11] Fixed: Anchors are not draggable.
835* [#11379](http://dev.ckeditor.com/ticket/11379): Changed default contents `line-height` to unitless values to avoid huge text overlapping (like in [#9696](http://dev.ckeditor.com/ticket/9696)).
836* [#10787](http://dev.ckeditor.com/ticket/10787): [Firefox] Fixed: Broken replacement of text while pasting into `div`-based editor.
837* [#10884](http://dev.ckeditor.com/ticket/10884): Widgets integration with the [Show Blocks](http://ckeditor.com/addon/showblocks) plugin.
838* [#11021](http://dev.ckeditor.com/ticket/11021): Fixed: An error thrown when selecting entire editable contents while fake selection is on.
839* [#11086](http://dev.ckeditor.com/ticket/11086): [IE8] Re-enable inline widgets drag&drop in Internet Explorer 8.
840* [#11372](http://dev.ckeditor.com/ticket/11372): Widgets: Special characters encoded twice in nested editables.
841* [#10068](http://dev.ckeditor.com/ticket/10068): Fixed: Support for protocol-relative URLs.
842* [#11283](http://dev.ckeditor.com/ticket/11283): [Enhanced Image](http://ckeditor.com/addon/image2): A `<div>` element with `text-align: center` and an image inside is not recognised correctly.
843* [#11196](http://dev.ckeditor.com/ticket/11196): [Accessibility Instructions](http://ckeditor.com/addon/a11yhelp): Allowed additional keyboard button labels to be translated in the dialog window.
844
845## CKEditor 4.3.1
846
847**Important Notes:**
848
849* To match the naming convention, the `language` button is now `Language` ([#11201](http://dev.ckeditor.com/ticket/11201)).
850* [Enhanced Image](http://ckeditor.com/addon/image2) button, context menu, command, and icon names match those of the [Image](http://ckeditor.com/addon/image) plugin ([#11222](http://dev.ckeditor.com/ticket/11222)).
851
852Fixed Issues:
853
854* [#11244](http://dev.ckeditor.com/ticket/11244): Changed: The [`widget.repository.checkWidgets()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-checkWidgets) method now fires the [`widget.repository.checkWidgets`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-event-checkWidgets) event, so from CKEditor 4.3.1 it is preferred to use the method rather than fire the event.
855* [#11171](http://dev.ckeditor.com/ticket/11171): Fixed: [`editor.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) and [`editor.insertText()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertText) methods do not call the [`widget.repository.checkWidgets()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.repository-method-checkWidgets) method.
856* [#11085](http://dev.ckeditor.com/ticket/11085): [IE8] Replaced preview generated by the [Mathematical Formulas](http://ckeditor.com/addon/mathjax) widget with a placeholder.
857* [#11044](http://dev.ckeditor.com/ticket/11044): Enhanced WAI-ARIA support for the [Language](http://ckeditor.com/addon/language) plugin drop-down menu.
858* [#11075](http://dev.ckeditor.com/ticket/11075): With drop-down menu button focused, pressing the *Down Arrow* key will now open the menu and focus its first option.
859* [#11165](http://dev.ckeditor.com/ticket/11165): Fixed: The [File Browser](http://ckeditor.com/addon/filebrowser) plugin cannot be removed from the editor.
860* [#11159](http://dev.ckeditor.com/ticket/11159): [IE9-10] [Enhanced Image](http://ckeditor.com/addon/image2): Fixed buggy discovery of image dimensions.
861* [#11101](http://dev.ckeditor.com/ticket/11101): Drop-down lists no longer break when given double quotes.
862* [#11077](http://dev.ckeditor.com/ticket/11077): [Enhanced Image](http://ckeditor.com/addon/image2): Empty undo step recorded when resizing the image.
863* [#10853](http://dev.ckeditor.com/ticket/10853): [Enhanced Image](http://ckeditor.com/addon/image2): Widget has paragraph wrapper when de-captioning unaligned image.
864* [#11198](http://dev.ckeditor.com/ticket/11198): Widgets: Drag handler is not fully visible when an inline widget is in a heading.
865* [#11132](http://dev.ckeditor.com/ticket/11132): [Firefox] Fixed: Caret is lost after drag and drop of an inline widget.
866* [#11182](http://dev.ckeditor.com/ticket/11182): [IE10-11] Fixed: Editor crashes (IE11) or works with minor issues (IE10) if a page is loaded in Quirks Mode. See [`env.quirks`](http://docs.ckeditor.com/#!/api/CKEDITOR.env-property-quirks) for more details.
867* [#11204](http://dev.ckeditor.com/ticket/11204): Added `figure` and `figcaption` styles to the `contents.css` file so [Enhanced Image](http://ckeditor.com/addon/image2) looks nicer.
868* [#11202](http://dev.ckeditor.com/ticket/11202): Fixed: No newline in [BBCode](http://ckeditor.com/addon/bbcode) mode.
869* [#10890](http://dev.ckeditor.com/ticket/10890): Fixed: Error thrown when pressing the *Delete* key in a list item.
870* [#10055](http://dev.ckeditor.com/ticket/10055): [IE8-10] Fixed: *Delete* pressed on a selected image causes the browser to go back.
871* [#11183](http://dev.ckeditor.com/ticket/11183): Fixed: Inserting a horizontal rule or a table in multiple row selection causes a browser crash. Additionally, the [`editor.insertElement()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) method does not insert the element into every range of a selection any more.
872* [#11042](http://dev.ckeditor.com/ticket/11042): Fixed: Selection made on an element containing a non-editable element was not auto faked.
873* [#11125](http://dev.ckeditor.com/ticket/11125): Fixed: Keyboard navigation through menu and drop-down items will now cycle.
874* [#11011](http://dev.ckeditor.com/ticket/11011): Fixed: The [`editor.applyStyle()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-applyStyle) method removes attributes from nested elements.
875* [#11179](http://dev.ckeditor.com/ticket/11179): Fixed: [`editor.destroy()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-destroy) does not cleanup content generated by the [Table Resize](http://ckeditor.com/addon/tableresize) plugin for inline editors.
876* [#11237](http://dev.ckeditor.com/ticket/11237): Fixed: Table border attribute value is deleted when pasting content from Microsoft Word.
877* [#11250](http://dev.ckeditor.com/ticket/11250): Fixed: HTML entities inside the `<textarea>` element are not encoded.
878* [#11260](http://dev.ckeditor.com/ticket/11260): Fixed: Initially disabled buttons are not read by JAWS as disabled.
879* [#11200](http://dev.ckeditor.com/ticket/11200): Added [Clipboard](http://ckeditor.com/addon/clipboard) plugin as a dependency for [Widget](http://ckeditor.com/addon/widget) to fix drag and drop.
880
881## CKEditor 4.3
882
883New Features:
884
885* [#10612](http://dev.ckeditor.com/ticket/10612): Internet Explorer 11 support.
886* [#10869](http://dev.ckeditor.com/ticket/10869): Widgets: Added better integration with the [Elements Path](http://ckeditor.com/addon/elementspath) plugin.
887* [#10886](http://dev.ckeditor.com/ticket/10886): Widgets: Added tooltip to the drag handle.
888* [#10933](http://dev.ckeditor.com/ticket/10933): Widgets: Introduced drag and drop of block widgets with the [Line Utilities](http://ckeditor.com/addon/lineutils) plugin.
889* [#10936](http://dev.ckeditor.com/ticket/10936): Widget System changes for easier integration with other dialog systems.
890* [#10895](http://dev.ckeditor.com/ticket/10895): [Enhanced Image](http://ckeditor.com/addon/image2): Added file browser integration.
891* [#11002](http://dev.ckeditor.com/ticket/11002): Added the [`draggable`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.definition-property-draggable) option to disable drag and drop support for widgets.
892* [#10937](http://dev.ckeditor.com/ticket/10937): [Mathematical Formulas](http://ckeditor.com/addon/mathjax) widget improvements:
893 * loading indicator ([#10948](http://dev.ckeditor.com/ticket/10948)),
894 * applying paragraph changes (like font color change) to iframe ([#10841](http://dev.ckeditor.com/ticket/10841)),
895 * Firefox and IE9 clipboard fixes ([#10857](http://dev.ckeditor.com/ticket/10857)),
896 * fixing same origin policy issue ([#10840](http://dev.ckeditor.com/ticket/10840)),
897 * fixing undo bugs ([#10842](http://dev.ckeditor.com/ticket/10842), [#10930](http://dev.ckeditor.com/ticket/10930)),
898 * fixing other minor bugs.
899* [#10862](http://dev.ckeditor.com/ticket/10862): [Placeholder](http://ckeditor.com/addon/placeholder) plugin was rewritten as a widget.
900* [#10822](http://dev.ckeditor.com/ticket/10822): Added styles system integration with non-editable elements (for example widgets) and their nested editables. Styles cannot change non-editable content and are applied in nested editable only if allowed by its type and content filter.
901* [#10856](http://dev.ckeditor.com/ticket/10856): Menu buttons will now toggle the visibility of their panels when clicked multiple times. [Language](http://ckeditor.com/addon/language) plugin fixes: Added active language highlighting, added an option to remove the language.
902* [#10028](http://dev.ckeditor.com/ticket/10028): New [`config.dialog_noConfirmCancel`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-dialog_noConfirmCancel) configuration option that eliminates the need to confirm closing of a dialog window when the user changed any of its fields.
903* [#10848](http://dev.ckeditor.com/ticket/10848): Integrate remaining plugins ([Styles](http://ckeditor.com/addon/stylescombo), [Format](http://ckeditor.com/addon/format), [Font](http://ckeditor.com/addon/font), [Color Button](http://ckeditor.com/addon/colorbutton), [Language](http://ckeditor.com/addon/language) and [Indent](http://ckeditor.com/addon/indent)) with [active filter](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-activeFilter).
904* [#10855](http://dev.ckeditor.com/ticket/10855): Change the extension of emoticons in the [BBCode](http://ckeditor.com/addon/bbcode) sample from GIF to PNG.
905
906Fixed Issues:
907
908* [#10831](http://dev.ckeditor.com/ticket/10831): [Enhanced Image](http://ckeditor.com/addon/image2): Merged `image2inline` and `image2block` into one `image2` widget.
909* [#10835](http://dev.ckeditor.com/ticket/10835): [Enhanced Image](http://ckeditor.com/addon/image2): Improved visibility of the resize handle.
910* [#10836](http://dev.ckeditor.com/ticket/10836): [Enhanced Image](http://ckeditor.com/addon/image2): Preserve custom mouse cursor while resizing the image.
911* [#10939](http://dev.ckeditor.com/ticket/10939): [Firefox] [Enhanced Image](http://ckeditor.com/addon/image2): hovering the image causes it to change.
912* [#10866](http://dev.ckeditor.com/ticket/10866): Fixed: Broken *Tab* key navigation in the [Enhanced Image](http://ckeditor.com/addon/image2) dialog window.
913* [#10833](http://dev.ckeditor.com/ticket/10833): Fixed: *Lock ratio* option should be on by default in the [Enhanced Image](http://ckeditor.com/addon/image2) dialog window.
914* [#10881](http://dev.ckeditor.com/ticket/10881): Various improvements to *Enter* key behavior in nested editables.
915* [#10879](http://dev.ckeditor.com/ticket/10879): [Remove Format](http://ckeditor.com/addon/removeformat) should not leak from a nested editable.
916* [#10877](http://dev.ckeditor.com/ticket/10877): Fixed: [WebSpellChecker](http://ckeditor.com/addon/wsc) fails to apply changes if a nested editable was focused.
917* [#10877](http://dev.ckeditor.com/ticket/10877): Fixed: [SCAYT](http://ckeditor.com/addon/wsc) blocks typing in nested editables.
918* [#11079](http://dev.ckeditor.com/ticket/11079): Add button icons to the [Placeholder](http://ckeditor.com/addon/placeholder) sample.
919* [#10870](http://dev.ckeditor.com/ticket/10870): The `paste` command is no longer being disabled when the clipboard is empty.
920* [#10854](http://dev.ckeditor.com/ticket/10854): Fixed: Firefox prepends `<br>` to `<body>`, so it is stripped by the HTML data processor.
921* [#10823](http://dev.ckeditor.com/ticket/10823): Fixed: [Link](http://ckeditor.com/addon/link) plugin does not work with non-editable content.
922* [#10828](http://dev.ckeditor.com/ticket/10828): [Magic Line](http://ckeditor.com/addon/magicline) integration with the Widget System.
923* [#10865](http://dev.ckeditor.com/ticket/10865): Improved hiding copybin, so copying widgets works smoothly.
924* [#11066](http://dev.ckeditor.com/ticket/11066): Widget's private parts use CSS reset.
925* [#11027](http://dev.ckeditor.com/ticket/11027): Fixed: Block commands break on widgets; added the [`contentDomInvalidated`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-contentDomInvalidated) event.
926* [#10430](http://dev.ckeditor.com/ticket/10430): Resolve dependence of the [Image](http://ckeditor.com/addon/image) plugin on the [Form Elements](http://ckeditor.com/addon/forms) plugin.
927* [#10911](http://dev.ckeditor.com/ticket/10911): Fixed: Browser *Alt* hotkeys will no longer be blocked while a widget is focused.
928* [#11082](http://dev.ckeditor.com/ticket/11082): Fixed: Selected widget is not copied or cut when using toolbar buttons or context menu.
929* [#11083](http://dev.ckeditor.com/ticket/11083): Fixed list and div element application to block widgets.
930* [#10887](http://dev.ckeditor.com/ticket/10887): Internet Explorer 8 compatibility issues related to the Widget System.
931* [#11074](http://dev.ckeditor.com/ticket/11074): Temporarily disabled inline widget drag and drop, because of seriously buggy native `range#moveToPoint` method.
932* [#11098](http://dev.ckeditor.com/ticket/11098): Fixed: Wrong selection position after undoing widget drag and drop.
933* [#11110](http://dev.ckeditor.com/ticket/11110): Fixed: IFrame and Flash objects are being incorrectly pasted in certain conditions.
934* [#11129](http://dev.ckeditor.com/ticket/11129): Page break is lost when loading data.
935* [#11123](http://dev.ckeditor.com/ticket/11123): [Firefox] Widget is destroyed after being dragged outside of `<body>`.
936* [#11124](http://dev.ckeditor.com/ticket/11124): Fixed the [Elements Path](http://ckeditor.com/addon/elementspath) in an editor using the [Div Editing Area](http://ckeditor.com/addon/divarea).
937
938## CKEditor 4.3 Beta
939
940New Features:
941
942* [#9764](http://dev.ckeditor.com/ticket/9764): Widget System.
943 * [Widget plugin](http://ckeditor.com/addon/widget) introducing the [Widget API](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget).
944 * New [`editor.enterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-enterMode) and [`editor.shiftEnterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-shiftEnterMode) properties &ndash; normalized versions of [`config.enterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode) and [`config.shiftEnterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-shiftEnterMode).
945 * Dynamic editor settings. Starting from CKEditor 4.3 Beta, *Enter* mode values and [content filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) instances may be changed dynamically (for example when the caret was placed in an element in which editor features should be adjusted). When you are implementing a new editor feature, you should base its behavior on [dynamic](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-activeEnterMode) or [static](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-enterMode) *Enter* mode values depending on whether this feature works in selection context or globally on editor content.
946 * Dynamic *Enter* mode values &ndash; [`editor.setActiveEnterMode()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setActiveEnterMode) method, [`editor.activeEnterModeChange`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-activeEnterModeChange) event, and two properties: [`editor.activeEnterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-activeEnterMode) and [`editor.activeShiftEnterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-activeShiftEnterMode).
947 * Dynamic content filter instances &ndash; [`editor.setActiveFilter()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setActiveFilter) method, [`editor.activeFilterChange`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-activeFilterChange) event, and [`editor.activeFilter`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-activeFilter) property.
948 * "Fake" selection was introduced. It makes it possible to virtually select any element when the real selection remains hidden. See the [`selection.fake()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-fake) method.
949 * Default [`htmlParser.filter`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.filter) rules are not applied to non-editable elements (elements with `contenteditable` attribute set to `false` and their descendants) anymore. To add a rule which will be applied to all elements you need to pass an additional argument to the [`filter.addRules()`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.filter-method-addRules) method.
950 * Dozens of new methods were introduced &ndash; most interesting ones:
951 * [`document.find()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.document-method-find),
952 * [`document.findOne()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.document-method-findOne),
953 * [`editable.insertElementIntoRange()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertElementIntoRange),
954 * [`range.moveToClosestEditablePosition()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-moveToClosestEditablePosition),
955 * New methods for [`htmlParser.node`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.node) and [`htmlParser.element`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.element).
956* [#10659](http://dev.ckeditor.com/ticket/10659): New [Enhanced Image](http://ckeditor.com/addon/image2) plugin that introduces a widget with integrated image captions, an option to center images, and dynamic "click and drag" resizing.
957* [#10664](http://dev.ckeditor.com/ticket/10664): New [Mathematical Formulas](http://ckeditor.com/addon/mathjax) plugin that introduces the MathJax widget.
958* [#7987](https://dev.ckeditor.com/ticket/7987): New [Language](http://ckeditor.com/addon/language) plugin that implements Language toolbar button to support [WCAG 3.1.2 Language of Parts](http://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html).
959* [#10708](http://dev.ckeditor.com/ticket/10708): New [smileys](http://ckeditor.com/addon/smiley).
960
961## CKEditor 4.2.3
962
963Fixed Issues:
964
965* [#10994](http://dev.ckeditor.com/ticket/10994): Fixed: Loading external jQuery library when opening the [jQuery Adapter](http://docs.ckeditor.com/#!/guide/dev_jquery) sample directly from file.
966* [#10975](http://dev.ckeditor.com/ticket/10975): [IE] Fixed: Error thrown while opening the color palette.
967* [#9929](http://dev.ckeditor.com/ticket/9929): [Blink/WebKit] Fixed: A non-breaking space is created once a character is deleted and a regular space is typed.
968* [#10963](http://dev.ckeditor.com/ticket/10963): Fixed: JAWS issue with the keyboard shortcut for [Magic Line](http://ckeditor.com/addon/magicline).
969* [#11096](http://dev.ckeditor.com/ticket/11096): Fixed: TypeError: Object has no method 'is'.
970
971## CKEditor 4.2.2
972
973Fixed Issues:
974
975* [#9314](http://dev.ckeditor.com/ticket/9314): Fixed: Incorrect error message on closing a dialog window without saving changs.
976* [#10308](http://dev.ckeditor.com/ticket/10308): [IE10] Fixed: Unspecified error when deleting a row.
977* [#10945](http://dev.ckeditor.com/ticket/10945): [Chrome] Fixed: Clicking with a mouse inside the editor does not show the caret.
978* [#10912](http://dev.ckeditor.com/ticket/10912): Prevent default action when content of a non-editable link is clicked.
979* [#10913](http://dev.ckeditor.com/ticket/10913): Fixed [`CKEDITOR.plugins.addExternal()`](http://docs.ckeditor.com/#!/api/CKEDITOR.resourceManager-method-addExternal) not handling paths including file name specified.
980* [#10666](http://dev.ckeditor.com/ticket/10666): Fixed [`CKEDITOR.tools.isArray()`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-isArray) not working cross frame.
981* [#10910](http://dev.ckeditor.com/ticket/10910): [IE9] Fixed JavaScript error thrown in Compatibility Mode when clicking and/or typing in the editing area.
982* [#10868](http://dev.ckeditor.com/ticket/10868): [IE8] Prevent the browser from crashing when applying the Inline Quotation style.
983* [#10915](http://dev.ckeditor.com/ticket/10915): Fixed: Invalid CSS filter in the Kama skin.
984* [#10914](http://dev.ckeditor.com/ticket/10914): Plugins [Indent List](http://ckeditor.com/addon/indentlist) and [Indent Block](http://ckeditor.com/addon/indentblock) are now included in the build configuration.
985* [#10812](http://dev.ckeditor.com/ticket/10812): Fixed [`range.createBookmark2()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-createBookmark2) incorrectly normalizing offsets. This bug was causing many issues: [#10850](http://dev.ckeditor.com/ticket/10850), [#10842](http://dev.ckeditor.com/ticket/10842).
986* [#10951](http://dev.ckeditor.com/ticket/10951): Reviewed and optimized focus handling on panels (combo, menu buttons, color buttons, and context menu) to enhance accessibility. Fixed [#10705](http://dev.ckeditor.com/ticket/10705), [#10706](http://dev.ckeditor.com/ticket/10706) and [#10707](http://dev.ckeditor.com/ticket/10707).
987* [#10704](http://dev.ckeditor.com/ticket/10704): Fixed a JAWS issue with the Select Color dialog window title not being announced.
988* [#10753](http://dev.ckeditor.com/ticket/10753): The floating toolbar in inline instances now has a dedicated accessibility label.
989
990## CKEditor 4.2.1
991
992Fixed Issues:
993
994* [#10301](http://dev.ckeditor.com/ticket/10301): [IE9-10] Undo fails after 3+ consecutive paste actions with a JavaScript error.
995* [#10689](http://dev.ckeditor.com/ticket/10689): Save toolbar button saves only the first editor instance.
996* [#10368](http://dev.ckeditor.com/ticket/10368): Move language reading direction definition (`dir`) from main language file to core.
997* [#9330](http://dev.ckeditor.com/ticket/9330): Fixed pasting anchors from MS Word.
998* [#8103](http://dev.ckeditor.com/ticket/8103): Fixed pasting nested lists from MS Word.
999* [#9958](http://dev.ckeditor.com/ticket/9958): [IE9] Pressing the "OK" button will trigger the `onbeforeunload` event in the popup dialog.
1000* [#10662](http://dev.ckeditor.com/ticket/10662): Fixed styles from the Styles drop-down list not registering to the ACF in case when the [Shared Spaces plugin](http://ckeditor.com/addon/sharedspace) is used.
1001* [#9654](http://dev.ckeditor.com/ticket/9654): Problems with Internet Explorer 10 Quirks Mode.
1002* [#9816](http://dev.ckeditor.com/ticket/9816): Floating toolbar does not reposition vertically in several cases.
1003* [#10646](http://dev.ckeditor.com/ticket/10646): Removing a selected sublist or nested table with *Backspace/Delete* removes the parent element.
1004* [#10623](http://dev.ckeditor.com/ticket/10623): [WebKit] Page is scrolled when opening a drop-down list.
1005* [#10004](http://dev.ckeditor.com/ticket/10004): [ChromeVox] Button names are not announced.
1006* [#10731](http://dev.ckeditor.com/ticket/10731): [WebSpellChecker](http://ckeditor.com/addon/wsc) plugin breaks cloning of editor configuration.
1007* It is now possible to set per instance [WebSpellChecker](http://ckeditor.com/addon/wsc) plugin configuration instead of setting the configuration globally.
1008
1009## CKEditor 4.2
1010
1011**Important Notes:**
1012
1013* Dropped compatibility support for Internet Explorer 7 and Firefox 3.6.
1014
1015* Both the Basic and the Standard distribution packages will not contain the new [Indent Block](http://ckeditor.com/addon/indentblock) plugin. Because of this the [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) might remove block indentations from existing contents. If you want to prevent this, either [add an appropriate ACF rule to your filter](http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules) or create a custom build based on the Basic/Standard package and add the Indent Block plugin in [CKBuilder](http://ckeditor.com/builder).
1016
1017New Features:
1018
1019* [#10027](http://dev.ckeditor.com/ticket/10027): Separated list and block indentation into two plugins: [Indent List](http://ckeditor.com/addon/indentlist) and [Indent Block](http://ckeditor.com/addon/indentblock).
1020* [#8244](http://dev.ckeditor.com/ticket/8244): Use *(Shift+)Tab* to indent and outdent lists.
1021* [#10281](http://dev.ckeditor.com/ticket/10281): The [jQuery Adapter](http://docs.ckeditor.com/#!/guide/dev_jquery) is now available. Several jQuery-related issues fixed: [#8261](http://dev.ckeditor.com/ticket/8261), [#9077](http://dev.ckeditor.com/ticket/9077), [#8710](http://dev.ckeditor.com/ticket/8710), [#8530](http://dev.ckeditor.com/ticket/8530), [#9019](http://dev.ckeditor.com/ticket/9019), [#6181](http://dev.ckeditor.com/ticket/6181), [#7876](http://dev.ckeditor.com/ticket/7876), [#6906](http://dev.ckeditor.com/ticket/6906).
1022* [#10042](http://dev.ckeditor.com/ticket/10042): Introduced [`config.title`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-title) setting to change the human-readable title of the editor.
1023* [#9794](http://dev.ckeditor.com/ticket/9794): Added [`editor.change`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-change) event.
1024* [#9923](http://dev.ckeditor.com/ticket/9923): HiDPI support in the editor UI. HiDPI icons for [Moono skin](http://ckeditor.com/addon/moono) added.
1025* [#8031](http://dev.ckeditor.com/ticket/8031): Handle `required` attributes on `<textarea>` elements &mdash; introduced [`editor.required`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-required) event.
1026* [#10280](http://dev.ckeditor.com/ticket/10280): Ability to replace `<textarea>` elements with the inline editor.
1027
1028Fixed Issues:
1029
1030* [#10599](http://dev.ckeditor.com/ticket/10599): [Indent](http://ckeditor.com/addon/indent) plugin is no longer required by the [List](http://ckeditor.com/addon/list) plugin.
1031* [#10370](http://dev.ckeditor.com/ticket/10370): Inconsistency in data events between framed and inline editors.
1032* [#10438](http://dev.ckeditor.com/ticket/10438): [FF, IE] No selection is done on an editable element on executing [`editor.setData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setData).
1033
1034## CKEditor 4.1.3
1035
1036New Features:
1037
1038* Added new translation: Indonesian.
1039
1040Fixed Issues:
1041
1042* [#10644](http://dev.ckeditor.com/ticket/10644): Fixed a critical bug when pasting plain text in Blink-based browsers.
1043* [#5189](http://dev.ckeditor.com/ticket/5189): [Find/Replace](http://ckeditor.com/addon/find) dialog window: rename "Cancel" button to "Close".
1044* [#10562](http://dev.ckeditor.com/ticket/10562): [Housekeeping] Unified CSS gradient filter formats in the [Moono](http://ckeditor.com/addon/moono) skin.
1045* [#10537](http://dev.ckeditor.com/ticket/10537): Advanced Content Filter should register a default rule for [`config.shiftEnterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-shiftEnterMode).
1046* [#10610](http://dev.ckeditor.com/ticket/10610): [`CKEDITOR.dialog.addIframe()`](http://docs.ckeditor.com/#!/api/CKEDITOR.dialog-static-method-addIframe) incorrectly sets the iframe size in dialog windows.
1047
1048## CKEditor 4.1.2
1049
1050New Features:
1051
1052* Added new translation: Sinhala.
1053
1054Fixed Issues:
1055
1056* [#10339](http://dev.ckeditor.com/ticket/10339): Fixed: Error thrown when inserted data was totally stripped out after filtering and processing.
1057* [#10298](http://dev.ckeditor.com/ticket/10298): Fixed: Data processor breaks attributes containing protected parts.
1058* [#10367](http://dev.ckeditor.com/ticket/10367): Fixed: [`editable.insertText()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertText) loses characters when `RegExp` replace controls are being inserted.
1059* [#10165](http://dev.ckeditor.com/ticket/10165): [IE] Access denied error when `document.domain` has been altered.
1060* [#9761](http://dev.ckeditor.com/ticket/9761): Update the *Backspace* key state in [`keystrokeHandler.blockedKeystrokes`](http://docs.ckeditor.com/#!/api/CKEDITOR.keystrokeHandler-property-blockedKeystrokes) when calling [`editor.setReadOnly()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setReadOnly).
1061* [#6504](http://dev.ckeditor.com/ticket/6504): Fixed: Race condition while loading several [`config.customConfig`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-customConfig) files.
1062* [#10146](http://dev.ckeditor.com/ticket/10146): [Firefox] Empty lines are being removed while [`config.enterMode`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode) is [`CKEDITOR.ENTER_BR`](http://docs.ckeditor.com/#!/api/CKEDITOR-property-ENTER_BR).
1063* [#10360](http://dev.ckeditor.com/ticket/10360): Fixed: ARIA `role="application"` should not be used for dialog windows.
1064* [#10361](http://dev.ckeditor.com/ticket/10361): Fixed: ARIA `role="application"` should not be used for floating panels.
1065* [#10510](http://dev.ckeditor.com/ticket/10510): Introduced unique voice labels to differentiate between different editor instances.
1066* [#9945](http://dev.ckeditor.com/ticket/9945): [iOS] Scrolling not possible on iPad.
1067* [#10389](http://dev.ckeditor.com/ticket/10389): Fixed: Invalid HTML in the "Text and Table" template.
1068* [WebSpellChecker](http://ckeditor.com/addon/wsc) plugin user interface was changed to match CKEditor 4 style.
1069
1070## CKEditor 4.1.1
1071
1072New Features:
1073
1074* Added new translation: Albanian.
1075
1076Fixed Issues:
1077
1078* [#10172](http://dev.ckeditor.com/ticket/10172): Pressing *Delete* or *Backspace* in an empty table cell moves the cursor to the next/previous cell.
1079* [#10219](http://dev.ckeditor.com/ticket/10219): Error thrown when destroying an editor instance in parallel with a `mouseup` event.
1080* [#10265](http://dev.ckeditor.com/ticket/10265): Wrong loop type in the [File Browser](http://ckeditor.com/addon/filebrowser) plugin.
1081* [#10249](http://dev.ckeditor.com/ticket/10249): Wrong undo/redo states at start.
1082* [#10268](http://dev.ckeditor.com/ticket/10268): [Show Blocks](http://ckeditor.com/addon/showblocks) does not recover after switching to Source view.
1083* [#9995](http://dev.ckeditor.com/ticket/9995): HTML code in the `<textarea>` should not be modified by the [`htmlDataProcessor`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor).
1084* [#10320](http://dev.ckeditor.com/ticket/10320): [Justify](http://ckeditor.com/addon/justify) plugin should add elements to Advanced Content Filter based on current [Enter mode](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode).
1085* [#10260](http://dev.ckeditor.com/ticket/10260): Fixed: Advanced Content Filter blocks [`tabSpaces`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-tabSpaces). Unified `data-cke-*` attributes filtering.
1086* [#10315](http://dev.ckeditor.com/ticket/10315): [WebKit] [Undo manager](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.undo.UndoManager) should not record snapshots after a filling character was added/removed.
1087* [#10291](http://dev.ckeditor.com/ticket/10291): [WebKit] Space after a filling character should be secured.
1088* [#10330](http://dev.ckeditor.com/ticket/10330): [WebKit] The filling character is not removed on `keydown` in specific cases.
1089* [#10285](http://dev.ckeditor.com/ticket/10285): Fixed: Styled text pasted from MS Word causes an infinite loop.
1090* [#10131](http://dev.ckeditor.com/ticket/10131): Fixed: [`undoManager.update()`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.undo.UndoManager-method-update) does not refresh the command state.
1091* [#10337](http://dev.ckeditor.com/ticket/10337): Fixed: Unable to remove `<s>` using [Remove Format](http://ckeditor.com/addon/removeformat).
1092
1093## CKEditor 4.1
1094
1095Fixed Issues:
1096
1097* [#10192](http://dev.ckeditor.com/ticket/10192): Closing lists with the *Enter* key does not work with [Advanced Content Filter](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) in several cases.
1098* [#10191](http://dev.ckeditor.com/ticket/10191): Fixed allowed content rules unification, so the [`filter.allowedContent`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter-property-allowedContent) property always contains rules in the same format.
1099* [#10224](http://dev.ckeditor.com/ticket/10224): Advanced Content Filter does not remove non-empty `<a>` elements anymore.
1100* Minor issues in plugin integration with Advanced Content Filter:
1101 * [#10166](http://dev.ckeditor.com/ticket/10166): Added transformation from the `align` attribute to `float` style to preserve backward compatibility after the introduction of Advanced Content Filter.
1102 * [#10195](http://dev.ckeditor.com/ticket/10195): [Image](http://ckeditor.com/addon/image) plugin no longer registers rules for links to Advanced Content Filter.
1103 * [#10213](http://dev.ckeditor.com/ticket/10213): [Justify](http://ckeditor.com/addon/justify) plugin is now correctly registering rules to Advanced Content Filter when [`config.justifyClasses`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-justifyClasses) is defined.
1104
1105## CKEditor 4.1 RC
1106
1107New Features:
1108
1109* [#9829](http://dev.ckeditor.com/ticket/9829): Advanced Content Filter - data and features activation based on editor configuration.
1110
1111 Brand new data filtering system that works in 2 modes:
1112
1113 * Based on loaded features (toolbar items, plugins) - the data will be filtered according to what the editor in its
1114 current configuration can handle.
1115 * Based on [`config.allowedContent`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent) rules - the data
1116 will be filtered and the editor features (toolbar items, commands, keystrokes) will be enabled if they are allowed.
1117
1118 See the `datafiltering.html` sample, [guides](http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter) and [`CKEDITOR.filter` API documentation](http://docs.ckeditor.com/#!/api/CKEDITOR.filter).
1119* [#9387](http://dev.ckeditor.com/ticket/9387): Reintroduced [Shared Spaces](http://ckeditor.com/addon/sharedspace) - the ability to display toolbar and bottom editor space in selected locations and to share them by different editor instances.
1120* [#9907](http://dev.ckeditor.com/ticket/9907): Added the [`contentPreview`](http://docs.ckeditor.com/#!/api/CKEDITOR-event-contentPreview) event for preview data manipulation.
1121* [#9713](http://dev.ckeditor.com/ticket/9713): Introduced the [Source Dialog](http://ckeditor.com/addon/sourcedialog) plugin that brings raw HTML editing for inline editor instances.
1122* Included in [#9829](http://dev.ckeditor.com/ticket/9829): Introduced new events, [`toHtml`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-toHtml) and [`toDataFormat`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-toDataFormat), allowing for better integration with data processing.
1123* [#9981](http://dev.ckeditor.com/ticket/9981): Added ability to filter [`htmlParser.fragment`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.fragment), [`htmlParser.element`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.element) etc. by many [`htmlParser.filter`](http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.filter)s before writing structure to an HTML string.
1124* Included in [#10103](http://dev.ckeditor.com/ticket/10103):
1125 * Introduced the [`editor.status`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-status) property to make it easier to check the current status of the editor.
1126 * Default [`command`](http://docs.ckeditor.com/#!/api/CKEDITOR.command) state is now [`CKEDITOR.TRISTATE_DISABLE`](http://docs.ckeditor.com/#!/api/CKEDITOR-property-TRISTATE_DISABLED). It will be activated on [`editor.instanceReady`](http://docs.ckeditor.com/#!/api/CKEDITOR-event-instanceReady) or immediately after being added if the editor is already initialized.
1127* [#9796](http://dev.ckeditor.com/ticket/9796): Introduced `<s>` as a default tag for strikethrough, which replaces obsolete `<strike>` in HTML5.
1128
1129## CKEditor 4.0.3
1130
1131Fixed Issues:
1132
1133* [#10196](http://dev.ckeditor.com/ticket/10196): Fixed context menus not opening with keyboard shortcuts when [Autogrow](http://ckeditor.com/addon/autogrow) is enabled.
1134* [#10212](http://dev.ckeditor.com/ticket/10212): [IE7-10] Undo command throws errors after multiple switches between Source and WYSIWYG view.
1135* [#10219](http://dev.ckeditor.com/ticket/10219): [Inline editor] Error thrown after calling [`editor.destroy()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-destroy).
1136
1137## CKEditor 4.0.2
1138
1139Fixed Issues:
1140
1141* [#9779](http://dev.ckeditor.com/ticket/9779): Fixed overriding [`CKEDITOR.getUrl()`](http://docs.ckeditor.com/#!/api/CKEDITOR-method-getUrl) with `CKEDITOR_GETURL`.
1142* [#9772](http://dev.ckeditor.com/ticket/9772): Custom buttons in the dialog window footer have different look and size ([Moono](http://ckeditor.com/addon/moono), [Kama](http://ckeditor.com/addon/kama) skins).
1143* [#9029](http://dev.ckeditor.com/ticket/9029): Custom styles added with the [`stylesSet.add()`](http://docs.ckeditor.com/#!/api/CKEDITOR.stylesSet-method-add) are displayed in the wrong order.
1144* [#9887](http://dev.ckeditor.com/ticket/9887): Disable [Magic Line](http://ckeditor.com/addon/magicline) when [`editor.readOnly`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-readOnly) is set.
1145* [#9882](http://dev.ckeditor.com/ticket/9882): Fixed empty document title on [`editor.getData()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData) if set via the Document Properties dialog window.
1146* [#9773](http://dev.ckeditor.com/ticket/9773): Fixed rendering problems with selection fields in the Kama skin.
1147* [#9851](http://dev.ckeditor.com/ticket/9851): The [`selectionChange`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-selectionChange) event is not fired when mouse selection ended outside editable.
1148* [#9903](http://dev.ckeditor.com/ticket/9903): [Inline editor] Bad positioning of floating space with page horizontal scroll.
1149* [#9872](http://dev.ckeditor.com/ticket/9872): [`editor.checkDirty()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-checkDirty) returns `true` when called onload. Removed the obsolete `editor.mayBeDirty` flag.
1150* [#9893](http://dev.ckeditor.com/ticket/9893): [IE] Fixed broken toolbar when editing mixed direction content in Quirks mode.
1151* [#9845](http://dev.ckeditor.com/ticket/9845): Fixed TAB navigation in the [Link](http://ckeditor.com/addon/link) dialog window when the Anchor option is used and no anchors are available.
1152* [#9883](http://dev.ckeditor.com/ticket/9883): Maximizing was making the entire page editable with [divarea](http://ckeditor.com/addon/divarea)-based editors.
1153* [#9940](http://dev.ckeditor.com/ticket/9940): [Firefox] Navigating back to a page with the editor was making the entire page editable.
1154* [#9966](http://dev.ckeditor.com/ticket/9966): Fixed: Unable to type square brackets with French keyboard layout. Changed [Magic Line](http://ckeditor.com/addon/magicline) keystrokes.
1155* [#9507](http://dev.ckeditor.com/ticket/9507): [Firefox] Selection is moved before editable position when the editor is focused for the first time.
1156* [#9947](http://dev.ckeditor.com/ticket/9947): [WebKit] Editor overflows parent container in some edge cases.
1157* [#10105](http://dev.ckeditor.com/ticket/10105): Fixed: Broken [sourcearea](http://ckeditor.com/addon/sourcearea) view when an RTL language is set.
1158* [#10123](http://dev.ckeditor.com/ticket/10123): [WebKit] Fixed: Several dialog windows have broken layout since the latest WebKit release.
1159* [#10152](http://dev.ckeditor.com/ticket/10152): Fixed: Invalid ARIA property used on menu items.
1160
1161## CKEditor 4.0.1.1
1162
1163Fixed Issues:
1164
1165* Security update: Added protection against XSS attack and possible path disclosure in the PHP sample.
1166
1167## CKEditor 4.0.1
1168
1169Fixed Issues:
1170
1171* [#9655](http://dev.ckeditor.com/ticket/9655): Support for IE Quirks Mode in the new [Moono skin](http://ckeditor.com/addon/moono).
1172* Accessibility issues (mainly in inline editor): [#9364](http://dev.ckeditor.com/ticket/9364), [#9368](http://dev.ckeditor.com/ticket/9368), [#9369](http://dev.ckeditor.com/ticket/9369), [#9370](http://dev.ckeditor.com/ticket/9370), [#9541](http://dev.ckeditor.com/ticket/9541), [#9543](http://dev.ckeditor.com/ticket/9543), [#9841](http://dev.ckeditor.com/ticket/9841), [#9844](http://dev.ckeditor.com/ticket/9844).
1173* [Magic Line](http://ckeditor.com/addon/magicline) plugin:
1174 * [#9481](http://dev.ckeditor.com/ticket/9481): Added accessibility support for Magic Line.
1175 * [#9509](http://dev.ckeditor.com/ticket/9509): Added Magic Line support for forms.
1176 * [#9573](http://dev.ckeditor.com/ticket/9573): Magic Line does not disappear on `mouseout` in a specific case.
1177* [#9754](http://dev.ckeditor.com/ticket/9754): [WebKit] Cutting & pasting simple unformatted text generates an inline wrapper in WebKit browsers.
1178* [#9456](http://dev.ckeditor.com/ticket/9456): [Chrome] Properly paste bullet list style from MS Word.
1179* [#9699](http://dev.ckeditor.com/ticket/9699), [#9758](http://dev.ckeditor.com/ticket/9758): Improved selection locking when selecting by dragging.
1180* Context menu:
1181 * [#9712](http://dev.ckeditor.com/ticket/9712): Opening the context menu destroys editor focus.
1182 * [#9366](http://dev.ckeditor.com/ticket/9366): Context menu should be displayed over the floating toolbar.
1183 * [#9706](http://dev.ckeditor.com/ticket/9706): Context menu generates a JavaScript error in inline mode when the editor is attached to a header element.
1184* [#9800](http://dev.ckeditor.com/ticket/9800): Hide float panel when resizing the window.
1185* [#9721](http://dev.ckeditor.com/ticket/9721): Padding in content of div-based editor puts the editing area under the bottom UI space.
1186* [#9528](http://dev.ckeditor.com/ticket/9528): Host page `box-sizing` style should not influence the editor UI elements.
1187* [#9503](http://dev.ckeditor.com/ticket/9503): [Form Elements](http://ckeditor.com/addon/forms) plugin adds context menu listeners only on supported input types. Added support for `tel`, `email`, `search` and `url` input types.
1188* [#9769](http://dev.ckeditor.com/ticket/9769): Improved floating toolbar positioning in a narrow window.
1189* [#9875](http://dev.ckeditor.com/ticket/9875): Table dialog window does not populate width correctly.
1190* [#8675](http://dev.ckeditor.com/ticket/8675): Deleting cells in a nested table removes the outer table cell.
1191* [#9815](http://dev.ckeditor.com/ticket/9815): Cannot edit dialog window fields in an editor initialized in the jQuery UI modal dialog.
1192* [#8888](http://dev.ckeditor.com/ticket/8888): CKEditor dialog windows do not show completely in a small window.
1193* [#9360](http://dev.ckeditor.com/ticket/9360): [Inline editor] Blocks shown for a `<div>` element stay permanently even after the user exits editing the `<div>`.
1194* [#9531](http://dev.ckeditor.com/ticket/9531): [Firefox & Inline editor] Toolbar is lost when closing the Format drop-down list by clicking its button.
1195* [#9553](http://dev.ckeditor.com/ticket/9553): Table width incorrectly set when the `border-width` style is specified.
1196* [#9594](http://dev.ckeditor.com/ticket/9594): Cannot tab past CKEditor when it is in read-only mode.
1197* [#9658](http://dev.ckeditor.com/ticket/9658): [IE9] Justify not working on selected images.
1198* [#9686](http://dev.ckeditor.com/ticket/9686): Added missing contents styles for `<pre>` elements.
1199* [#9709](http://dev.ckeditor.com/ticket/9709): [Paste from Word](http://ckeditor.com/addon/pastefromword) should not depend on configuration from other styles.
1200* [#9726](http://dev.ckeditor.com/ticket/9726): Removed [Color Dialog](http://ckeditor.com/addon/colordialog) plugin dependency from [Table Tools](http://ckeditor.com/addon/tabletools).
1201* [#9765](http://dev.ckeditor.com/ticket/9765): Toolbar Collapse command documented incorrectly in the [Accessibility Instructions](http://ckeditor.com/addon/a11yhelp) dialog window.
1202* [#9771](http://dev.ckeditor.com/ticket/9771): [WebKit & Opera] Fixed scrolling issues when pasting.
1203* [#9787](http://dev.ckeditor.com/ticket/9787): [IE9] `onChange` is not fired for checkboxes in dialogs.
1204* [#9842](http://dev.ckeditor.com/ticket/9842): [Firefox 17] When opening a toolbar menu for the first time and pressing the *Down Arrow* key, focus goes to the next toolbar button instead of the menu options.
1205* [#9847](http://dev.ckeditor.com/ticket/9847): [Elements Path](http://ckeditor.com/addon/elementspath) should not be initialized in the inline editor.
1206* [#9853](http://dev.ckeditor.com/ticket/9853): [`editor.addRemoveFormatFilter()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-addRemoveFormatFilter) is exposed before it really works.
1207* [#8893](http://dev.ckeditor.com/ticket/8893): Value of the [`pasteFromWordCleanupFile`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-pasteFromWordCleanupFile) configuration option is now taken from the instance configuration.
1208* [#9693](http://dev.ckeditor.com/ticket/9693): Removed "Live Preview" checkbox from UI color picker.
1209
1210
1211## CKEditor 4.0
1212
1213The first stable release of the new CKEditor 4 code line.
1214
1215The CKEditor JavaScript API has been kept compatible with CKEditor 4, whenever
1216possible. The list of relevant changes can be found in the [API Changes page of
1217the CKEditor 4 documentation][1].
1218
1219[1]: http://docs.ckeditor.com/#!/guide/dev_api_changes "API Changes"
diff --git a/sources/LICENSE.md b/sources/LICENSE.md
new file mode 100644
index 0000000..0f50a9e
--- /dev/null
+++ b/sources/LICENSE.md
@@ -0,0 +1,1641 @@
1Software License Agreement
2==========================
3
4CKEditor - The text editor for Internet - http://ckeditor.com
5Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
6
7Licensed under the terms of any of the following licenses at your
8choice:
9
10 - GNU General Public License Version 2 or later (the "GPL")
11 http://www.gnu.org/licenses/gpl.html
12 (See Appendix A)
13
14 - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
15 http://www.gnu.org/licenses/lgpl.html
16 (See Appendix B)
17
18 - Mozilla Public License Version 1.1 or later (the "MPL")
19 http://www.mozilla.org/MPL/MPL-1.1.html
20 (See Appendix C)
21
22You are not required to, but if you want to explicitly declare the
23license you have chosen to be bound to when using, reproducing,
24modifying and distributing this software, just include a text file
25titled "legal.txt" in your version of this software, indicating your
26license choice. In any case, your choice will not restrict any
27recipient of your version of this software to use, reproduce, modify
28and distribute this software under any of the above licenses.
29
30Sources of Intellectual Property Included in CKEditor
31-----------------------------------------------------
32
33Where not otherwise indicated, all CKEditor content is authored by
34CKSource engineers and consists of CKSource-owned intellectual
35property. In some specific instances, CKEditor will incorporate work
36done by developers outside of CKSource with their express permission.
37
38The following libraries are included in CKEditor under the MIT license (see Appendix D):
39
40* CKSource Samples Framework (included in the samples) - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
41* PicoModal (included in `samples/js/sf.js`) - Copyright (c) 2012 James Frasca.
42* CodeMirror (included in the samples) - Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others.
43
44Parts of code taken from the following libraries are included in CKEditor under the MIT license (see Appendix D):
45
46* jQuery (inspired the domReady function, ckeditor_base.js) - Copyright (c) 2011 John Resig, http://jquery.com/
47
48The following libraries are included in CKEditor under the SIL Open Font License, Version 1.1 (see Appendix E):
49
50* Font Awesome (included in the toolbar configurator) - Copyright (C) 2012 by Dave Gandy.
51
52The following libraries are included in CKEditor under the BSD-3 License (see Appendix F):
53
54* highlight.js (included in the `codesnippet` plugin) - Copyright (c) 2006, Ivan Sagalaev.
55* YUI Library (included in the `uicolor` plugin) - Copyright (c) 2009, Yahoo! Inc.
56
57(Ignore this line: %REMOVE_START%)
58
59The following libraries are included only in the development version of CKEditor under the MIT license (see Appendix D):
60
61* CKBuilder - Copyright (c) 2012-2017, CKSource - Frederico Knabben.
62* CKLangTool - Copyright (c) 2012-2017, CKSource - Frederico Knabben.
63* Optimist - Copyright 2010 James Halliday (mail@substack.net).
64* Q - Copyright 2009–2014 Kristopher Michael Kowal.
65* Tmp - Copyright (c) 2014 KARASZI István.
66* Mkdirp - Copyright 2010 James Halliday (mail@substack.net).
67* Bender.js - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
68* benderjs-coverage - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
69* benderjs-jquery - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
70* benderjs-sinon - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
71* benderjs-yui - Copyright (c) 2014-2017, CKSource - Frederico Knabben.
72* Grunt - Copyright (c) 2015 "Cowboy" Ben Alman.
73* grunt-contrib-imagemin - Copyright (c) 2014 Sindre Sorhus, contributors.
74* grunt-jscs - Copyright (c) 2014 Gustavo Henke, contributors.
75* grunt-contrib-jshint - Copyright (c) 2014 "Cowboy" Ben Alman, contributors.
76* grunt-contrib-less - Copyright (c) 2014 Tyler Kellen, contributors.
77* grunt-contrib-watch - Copyright (c) 2014 "Cowboy" Ben Alman, contributors.
78* grunt-contrib-concat - Copyright (c) 2014 "Cowboy" Ben Alman, contributors.
79* grunt-jsduck - Copyright (c) 2012 Dmitry Pashkevich, contributors.
80* grunt-githooks - Copyright (c) 2013 Romaric Pascal.
81* jQuery Form Plugin (used in jquery adapter test) - Copyright (c) 2012 M. Alsup
82
83The following libraries are included only in the development version of CKEditor under the BSD-3 License (see Appendix F):
84
85* ShellJS - Copyright (c) 2012, Artur Adib <aadib@mozilla.com>.
86
87The following libraries are included only in the development version of CKEditor under the Apache License (see Appendix G):
88
89* Less.js - Copyright (c) 2009-2014 Alexis Sellier & The Core Less Team.
90
91(Ignore this line: %REMOVE_END%)
92
93Trademarks
94----------
95
96CKEditor is a trademark of CKSource - Frederico Knabben. All other brand
97and product names are trademarks, registered trademarks or service
98marks of their respective holders.
99
100---
101
102Appendix A: The GPL License
103---------------------------
104
105```
106GNU GENERAL PUBLIC LICENSE
107Version 2, June 1991
108
109 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
110 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
111 Everyone is permitted to copy and distribute verbatim copies
112 of this license document, but changing it is not allowed.
113
114Preamble
115
116 The licenses for most software are designed to take away your
117freedom to share and change it. By contrast, the GNU General Public
118License is intended to guarantee your freedom to share and change free
119software-to make sure the software is free for all its users. This
120General Public License applies to most of the Free Software
121Foundation's software and to any other program whose authors commit to
122using it. (Some other Free Software Foundation software is covered by
123the GNU Lesser General Public License instead.) You can apply it to
124your programs, too.
125
126 When we speak of free software, we are referring to freedom, not
127price. Our General Public Licenses are designed to make sure that you
128have the freedom to distribute copies of free software (and charge for
129this service if you wish), that you receive source code or can get it
130if you want it, that you can change the software or use pieces of it
131in new free programs; and that you know you can do these things.
132
133 To protect your rights, we need to make restrictions that forbid
134anyone to deny you these rights or to ask you to surrender the rights.
135These restrictions translate to certain responsibilities for you if you
136distribute copies of the software, or if you modify it.
137
138 For example, if you distribute copies of such a program, whether
139gratis or for a fee, you must give the recipients all the rights that
140you have. You must make sure that they, too, receive or can get the
141source code. And you must show them these terms so they know their
142rights.
143
144 We protect your rights with two steps: (1) copyright the software, and
145(2) offer you this license which gives you legal permission to copy,
146distribute and/or modify the software.
147
148 Also, for each author's protection and ours, we want to make certain
149that everyone understands that there is no warranty for this free
150software. If the software is modified by someone else and passed on, we
151want its recipients to know that what they have is not the original, so
152that any problems introduced by others will not reflect on the original
153authors' reputations.
154
155 Finally, any free program is threatened constantly by software
156patents. We wish to avoid the danger that redistributors of a free
157program will individually obtain patent licenses, in effect making the
158program proprietary. To prevent this, we have made it clear that any
159patent must be licensed for everyone's free use or not licensed at all.
160
161 The precise terms and conditions for copying, distribution and
162modification follow.
163
164GNU GENERAL PUBLIC LICENSE
165TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
166
167 0. This License applies to any program or other work which contains
168a notice placed by the copyright holder saying it may be distributed
169under the terms of this General Public License. The "Program", below,
170refers to any such program or work, and a "work based on the Program"
171means either the Program or any derivative work under copyright law:
172that is to say, a work containing the Program or a portion of it,
173either verbatim or with modifications and/or translated into another
174language. (Hereinafter, translation is included without limitation in
175the term "modification".) Each licensee is addressed as "you".
176
177Activities other than copying, distribution and modification are not
178covered by this License; they are outside its scope. The act of
179running the Program is not restricted, and the output from the Program
180is covered only if its contents constitute a work based on the
181Program (independent of having been made by running the Program).
182Whether that is true depends on what the Program does.
183
184 1. You may copy and distribute verbatim copies of the Program's
185source code as you receive it, in any medium, provided that you
186conspicuously and appropriately publish on each copy an appropriate
187copyright notice and disclaimer of warranty; keep intact all the
188notices that refer to this License and to the absence of any warranty;
189and give any other recipients of the Program a copy of this License
190along with the Program.
191
192You may charge a fee for the physical act of transferring a copy, and
193you may at your option offer warranty protection in exchange for a fee.
194
195 2. You may modify your copy or copies of the Program or any portion
196of it, thus forming a work based on the Program, and copy and
197distribute such modifications or work under the terms of Section 1
198above, provided that you also meet all of these conditions:
199
200 a) You must cause the modified files to carry prominent notices
201 stating that you changed the files and the date of any change.
202
203 b) You must cause any work that you distribute or publish, that in
204 whole or in part contains or is derived from the Program or any
205 part thereof, to be licensed as a whole at no charge to all third
206 parties under the terms of this License.
207
208 c) If the modified program normally reads commands interactively
209 when run, you must cause it, when started running for such
210 interactive use in the most ordinary way, to print or display an
211 announcement including an appropriate copyright notice and a
212 notice that there is no warranty (or else, saying that you provide
213 a warranty) and that users may redistribute the program under
214 these conditions, and telling the user how to view a copy of this
215 License. (Exception: if the Program itself is interactive but
216 does not normally print such an announcement, your work based on
217 the Program is not required to print an announcement.)
218
219These requirements apply to the modified work as a whole. If
220identifiable sections of that work are not derived from the Program,
221and can be reasonably considered independent and separate works in
222themselves, then this License, and its terms, do not apply to those
223sections when you distribute them as separate works. But when you
224distribute the same sections as part of a whole which is a work based
225on the Program, the distribution of the whole must be on the terms of
226this License, whose permissions for other licensees extend to the
227entire whole, and thus to each and every part regardless of who wrote it.
228
229Thus, it is not the intent of this section to claim rights or contest
230your rights to work written entirely by you; rather, the intent is to
231exercise the right to control the distribution of derivative or
232collective works based on the Program.
233
234In addition, mere aggregation of another work not based on the Program
235with the Program (or with a work based on the Program) on a volume of
236a storage or distribution medium does not bring the other work under
237the scope of this License.
238
239 3. You may copy and distribute the Program (or a work based on it,
240under Section 2) in object code or executable form under the terms of
241Sections 1 and 2 above provided that you also do one of the following:
242
243 a) Accompany it with the complete corresponding machine-readable
244 source code, which must be distributed under the terms of Sections
245 1 and 2 above on a medium customarily used for software interchange; or,
246
247 b) Accompany it with a written offer, valid for at least three
248 years, to give any third party, for a charge no more than your
249 cost of physically performing source distribution, a complete
250 machine-readable copy of the corresponding source code, to be
251 distributed under the terms of Sections 1 and 2 above on a medium
252 customarily used for software interchange; or,
253
254 c) Accompany it with the information you received as to the offer
255 to distribute corresponding source code. (This alternative is
256 allowed only for noncommercial distribution and only if you
257 received the program in object code or executable form with such
258 an offer, in accord with Subsection b above.)
259
260The source code for a work means the preferred form of the work for
261making modifications to it. For an executable work, complete source
262code means all the source code for all modules it contains, plus any
263associated interface definition files, plus the scripts used to
264control compilation and installation of the executable. However, as a
265special exception, the source code distributed need not include
266anything that is normally distributed (in either source or binary
267form) with the major components (compiler, kernel, and so on) of the
268operating system on which the executable runs, unless that component
269itself accompanies the executable.
270
271If distribution of executable or object code is made by offering
272access to copy from a designated place, then offering equivalent
273access to copy the source code from the same place counts as
274distribution of the source code, even though third parties are not
275compelled to copy the source along with the object code.
276
277 4. You may not copy, modify, sublicense, or distribute the Program
278except as expressly provided under this License. Any attempt
279otherwise to copy, modify, sublicense or distribute the Program is
280void, and will automatically terminate your rights under this License.
281However, parties who have received copies, or rights, from you under
282this License will not have their licenses terminated so long as such
283parties remain in full compliance.
284
285 5. You are not required to accept this License, since you have not
286signed it. However, nothing else grants you permission to modify or
287distribute the Program or its derivative works. These actions are
288prohibited by law if you do not accept this License. Therefore, by
289modifying or distributing the Program (or any work based on the
290Program), you indicate your acceptance of this License to do so, and
291all its terms and conditions for copying, distributing or modifying
292the Program or works based on it.
293
294 6. Each time you redistribute the Program (or any work based on the
295Program), the recipient automatically receives a license from the
296original licensor to copy, distribute or modify the Program subject to
297these terms and conditions. You may not impose any further
298restrictions on the recipients' exercise of the rights granted herein.
299You are not responsible for enforcing compliance by third parties to
300this License.
301
302 7. If, as a consequence of a court judgment or allegation of patent
303infringement or for any other reason (not limited to patent issues),
304conditions are imposed on you (whether by court order, agreement or
305otherwise) that contradict the conditions of this License, they do not
306excuse you from the conditions of this License. If you cannot
307distribute so as to satisfy simultaneously your obligations under this
308License and any other pertinent obligations, then as a consequence you
309may not distribute the Program at all. For example, if a patent
310license would not permit royalty-free redistribution of the Program by
311all those who receive copies directly or indirectly through you, then
312the only way you could satisfy both it and this License would be to
313refrain entirely from distribution of the Program.
314
315If any portion of this section is held invalid or unenforceable under
316any particular circumstance, the balance of the section is intended to
317apply and the section as a whole is intended to apply in other
318circumstances.
319
320It is not the purpose of this section to induce you to infringe any
321patents or other property right claims or to contest validity of any
322such claims; this section has the sole purpose of protecting the
323integrity of the free software distribution system, which is
324implemented by public license practices. Many people have made
325generous contributions to the wide range of software distributed
326through that system in reliance on consistent application of that
327system; it is up to the author/donor to decide if he or she is willing
328to distribute software through any other system and a licensee cannot
329impose that choice.
330
331This section is intended to make thoroughly clear what is believed to
332be a consequence of the rest of this License.
333
334 8. If the distribution and/or use of the Program is restricted in
335certain countries either by patents or by copyrighted interfaces, the
336original copyright holder who places the Program under this License
337may add an explicit geographical distribution limitation excluding
338those countries, so that distribution is permitted only in or among
339countries not thus excluded. In such case, this License incorporates
340the limitation as if written in the body of this License.
341
342 9. The Free Software Foundation may publish revised and/or new versions
343of the General Public License from time to time. Such new versions will
344be similar in spirit to the present version, but may differ in detail to
345address new problems or concerns.
346
347Each version is given a distinguishing version number. If the Program
348specifies a version number of this License which applies to it and "any
349later version", you have the option of following the terms and conditions
350either of that version or of any later version published by the Free
351Software Foundation. If the Program does not specify a version number of
352this License, you may choose any version ever published by the Free Software
353Foundation.
354
355 10. If you wish to incorporate parts of the Program into other free
356programs whose distribution conditions are different, write to the author
357to ask for permission. For software which is copyrighted by the Free
358Software Foundation, write to the Free Software Foundation; we sometimes
359make exceptions for this. Our decision will be guided by the two goals
360of preserving the free status of all derivatives of our free software and
361of promoting the sharing and reuse of software generally.
362
363NO WARRANTY
364
365 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
366FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
367OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
368PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
369OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
370MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
371TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
372PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
373REPAIR OR CORRECTION.
374
375 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
376WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
377REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
378INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
379OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
380TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
381YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
382PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
383POSSIBILITY OF SUCH DAMAGES.
384
385END OF TERMS AND CONDITIONS
386```
387
388Appendix B: The LGPL License
389----------------------------
390
391```
392GNU LESSER GENERAL PUBLIC LICENSE
393Version 2.1, February 1999
394
395 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
396 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
397 Everyone is permitted to copy and distribute verbatim copies
398 of this license document, but changing it is not allowed.
399
400[This is the first released version of the Lesser GPL. It also counts
401 as the successor of the GNU Library Public License, version 2, hence
402 the version number 2.1.]
403
404Preamble
405
406 The licenses for most software are designed to take away your
407freedom to share and change it. By contrast, the GNU General Public
408Licenses are intended to guarantee your freedom to share and change
409free software-to make sure the software is free for all its users.
410
411 This license, the Lesser General Public License, applies to some
412specially designated software packages-typically libraries-of the
413Free Software Foundation and other authors who decide to use it. You
414can use it too, but we suggest you first think carefully about whether
415this license or the ordinary General Public License is the better
416strategy to use in any particular case, based on the explanations below.
417
418 When we speak of free software, we are referring to freedom of use,
419not price. Our General Public Licenses are designed to make sure that
420you have the freedom to distribute copies of free software (and charge
421for this service if you wish); that you receive source code or can get
422it if you want it; that you can change the software and use pieces of
423it in new free programs; and that you are informed that you can do
424these things.
425
426 To protect your rights, we need to make restrictions that forbid
427distributors to deny you these rights or to ask you to surrender these
428rights. These restrictions translate to certain responsibilities for
429you if you distribute copies of the library or if you modify it.
430
431 For example, if you distribute copies of the library, whether gratis
432or for a fee, you must give the recipients all the rights that we gave
433you. You must make sure that they, too, receive or can get the source
434code. If you link other code with the library, you must provide
435complete object files to the recipients, so that they can relink them
436with the library after making changes to the library and recompiling
437it. And you must show them these terms so they know their rights.
438
439 We protect your rights with a two-step method: (1) we copyright the
440library, and (2) we offer you this license, which gives you legal
441permission to copy, distribute and/or modify the library.
442
443 To protect each distributor, we want to make it very clear that
444there is no warranty for the free library. Also, if the library is
445modified by someone else and passed on, the recipients should know
446that what they have is not the original version, so that the original
447author's reputation will not be affected by problems that might be
448introduced by others.
449
450 Finally, software patents pose a constant threat to the existence of
451any free program. We wish to make sure that a company cannot
452effectively restrict the users of a free program by obtaining a
453restrictive license from a patent holder. Therefore, we insist that
454any patent license obtained for a version of the library must be
455consistent with the full freedom of use specified in this license.
456
457 Most GNU software, including some libraries, is covered by the
458ordinary GNU General Public License. This license, the GNU Lesser
459General Public License, applies to certain designated libraries, and
460is quite different from the ordinary General Public License. We use
461this license for certain libraries in order to permit linking those
462libraries into non-free programs.
463
464 When a program is linked with a library, whether statically or using
465a shared library, the combination of the two is legally speaking a
466combined work, a derivative of the original library. The ordinary
467General Public License therefore permits such linking only if the
468entire combination fits its criteria of freedom. The Lesser General
469Public License permits more lax criteria for linking other code with
470the library.
471
472 We call this license the "Lesser" General Public License because it
473does Less to protect the user's freedom than the ordinary General
474Public License. It also provides other free software developers Less
475of an advantage over competing non-free programs. These disadvantages
476are the reason we use the ordinary General Public License for many
477libraries. However, the Lesser license provides advantages in certain
478special circumstances.
479
480 For example, on rare occasions, there may be a special need to
481encourage the widest possible use of a certain library, so that it becomes
482a de-facto standard. To achieve this, non-free programs must be
483allowed to use the library. A more frequent case is that a free
484library does the same job as widely used non-free libraries. In this
485case, there is little to gain by limiting the free library to free
486software only, so we use the Lesser General Public License.
487
488 In other cases, permission to use a particular library in non-free
489programs enables a greater number of people to use a large body of
490free software. For example, permission to use the GNU C Library in
491non-free programs enables many more people to use the whole GNU
492operating system, as well as its variant, the GNU/Linux operating
493system.
494
495 Although the Lesser General Public License is Less protective of the
496users' freedom, it does ensure that the user of a program that is
497linked with the Library has the freedom and the wherewithal to run
498that program using a modified version of the Library.
499
500 The precise terms and conditions for copying, distribution and
501modification follow. Pay close attention to the difference between a
502"work based on the library" and a "work that uses the library". The
503former contains code derived from the library, whereas the latter must
504be combined with the library in order to run.
505
506GNU LESSER GENERAL PUBLIC LICENSE
507TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
508
509 0. This License Agreement applies to any software library or other
510program which contains a notice placed by the copyright holder or
511other authorized party saying it may be distributed under the terms of
512this Lesser General Public License (also called "this License").
513Each licensee is addressed as "you".
514
515 A "library" means a collection of software functions and/or data
516prepared so as to be conveniently linked with application programs
517(which use some of those functions and data) to form executables.
518
519 The "Library", below, refers to any such software library or work
520which has been distributed under these terms. A "work based on the
521Library" means either the Library or any derivative work under
522copyright law: that is to say, a work containing the Library or a
523portion of it, either verbatim or with modifications and/or translated
524straightforwardly into another language. (Hereinafter, translation is
525included without limitation in the term "modification".)
526
527 "Source code" for a work means the preferred form of the work for
528making modifications to it. For a library, complete source code means
529all the source code for all modules it contains, plus any associated
530interface definition files, plus the scripts used to control compilation
531and installation of the library.
532
533 Activities other than copying, distribution and modification are not
534covered by this License; they are outside its scope. The act of
535running a program using the Library is not restricted, and output from
536such a program is covered only if its contents constitute a work based
537on the Library (independent of the use of the Library in a tool for
538writing it). Whether that is true depends on what the Library does
539and what the program that uses the Library does.
540
541 1. You may copy and distribute verbatim copies of the Library's
542complete source code as you receive it, in any medium, provided that
543you conspicuously and appropriately publish on each copy an
544appropriate copyright notice and disclaimer of warranty; keep intact
545all the notices that refer to this License and to the absence of any
546warranty; and distribute a copy of this License along with the
547Library.
548
549 You may charge a fee for the physical act of transferring a copy,
550and you may at your option offer warranty protection in exchange for a
551fee.
552
553 2. You may modify your copy or copies of the Library or any portion
554of it, thus forming a work based on the Library, and copy and
555distribute such modifications or work under the terms of Section 1
556above, provided that you also meet all of these conditions:
557
558 a) The modified work must itself be a software library.
559
560 b) You must cause the files modified to carry prominent notices
561 stating that you changed the files and the date of any change.
562
563 c) You must cause the whole of the work to be licensed at no
564 charge to all third parties under the terms of this License.
565
566 d) If a facility in the modified Library refers to a function or a
567 table of data to be supplied by an application program that uses
568 the facility, other than as an argument passed when the facility
569 is invoked, then you must make a good faith effort to ensure that,
570 in the event an application does not supply such function or
571 table, the facility still operates, and performs whatever part of
572 its purpose remains meaningful.
573
574 (For example, a function in a library to compute square roots has
575 a purpose that is entirely well-defined independent of the
576 application. Therefore, Subsection 2d requires that any
577 application-supplied function or table used by this function must
578 be optional: if the application does not supply it, the square
579 root function must still compute square roots.)
580
581These requirements apply to the modified work as a whole. If
582identifiable sections of that work are not derived from the Library,
583and can be reasonably considered independent and separate works in
584themselves, then this License, and its terms, do not apply to those
585sections when you distribute them as separate works. But when you
586distribute the same sections as part of a whole which is a work based
587on the Library, the distribution of the whole must be on the terms of
588this License, whose permissions for other licensees extend to the
589entire whole, and thus to each and every part regardless of who wrote
590it.
591
592Thus, it is not the intent of this section to claim rights or contest
593your rights to work written entirely by you; rather, the intent is to
594exercise the right to control the distribution of derivative or
595collective works based on the Library.
596
597In addition, mere aggregation of another work not based on the Library
598with the Library (or with a work based on the Library) on a volume of
599a storage or distribution medium does not bring the other work under
600the scope of this License.
601
602 3. You may opt to apply the terms of the ordinary GNU General Public
603License instead of this License to a given copy of the Library. To do
604this, you must alter all the notices that refer to this License, so
605that they refer to the ordinary GNU General Public License, version 2,
606instead of to this License. (If a newer version than version 2 of the
607ordinary GNU General Public License has appeared, then you can specify
608that version instead if you wish.) Do not make any other change in
609these notices.
610
611 Once this change is made in a given copy, it is irreversible for
612that copy, so the ordinary GNU General Public License applies to all
613subsequent copies and derivative works made from that copy.
614
615 This option is useful when you wish to copy part of the code of
616the Library into a program that is not a library.
617
618 4. You may copy and distribute the Library (or a portion or
619derivative of it, under Section 2) in object code or executable form
620under the terms of Sections 1 and 2 above provided that you accompany
621it with the complete corresponding machine-readable source code, which
622must be distributed under the terms of Sections 1 and 2 above on a
623medium customarily used for software interchange.
624
625 If distribution of object code is made by offering access to copy
626from a designated place, then offering equivalent access to copy the
627source code from the same place satisfies the requirement to
628distribute the source code, even though third parties are not
629compelled to copy the source along with the object code.
630
631 5. A program that contains no derivative of any portion of the
632Library, but is designed to work with the Library by being compiled or
633linked with it, is called a "work that uses the Library". Such a
634work, in isolation, is not a derivative work of the Library, and
635therefore falls outside the scope of this License.
636
637 However, linking a "work that uses the Library" with the Library
638creates an executable that is a derivative of the Library (because it
639contains portions of the Library), rather than a "work that uses the
640library". The executable is therefore covered by this License.
641Section 6 states terms for distribution of such executables.
642
643 When a "work that uses the Library" uses material from a header file
644that is part of the Library, the object code for the work may be a
645derivative work of the Library even though the source code is not.
646Whether this is true is especially significant if the work can be
647linked without the Library, or if the work is itself a library. The
648threshold for this to be true is not precisely defined by law.
649
650 If such an object file uses only numerical parameters, data
651structure layouts and accessors, and small macros and small inline
652functions (ten lines or less in length), then the use of the object
653file is unrestricted, regardless of whether it is legally a derivative
654work. (Executables containing this object code plus portions of the
655Library will still fall under Section 6.)
656
657 Otherwise, if the work is a derivative of the Library, you may
658distribute the object code for the work under the terms of Section 6.
659Any executables containing that work also fall under Section 6,
660whether or not they are linked directly with the Library itself.
661
662 6. As an exception to the Sections above, you may also combine or
663link a "work that uses the Library" with the Library to produce a
664work containing portions of the Library, and distribute that work
665under terms of your choice, provided that the terms permit
666modification of the work for the customer's own use and reverse
667engineering for debugging such modifications.
668
669 You must give prominent notice with each copy of the work that the
670Library is used in it and that the Library and its use are covered by
671this License. You must supply a copy of this License. If the work
672during execution displays copyright notices, you must include the
673copyright notice for the Library among them, as well as a reference
674directing the user to the copy of this License. Also, you must do one
675of these things:
676
677 a) Accompany the work with the complete corresponding
678 machine-readable source code for the Library including whatever
679 changes were used in the work (which must be distributed under
680 Sections 1 and 2 above); and, if the work is an executable linked
681 with the Library, with the complete machine-readable "work that
682 uses the Library", as object code and/or source code, so that the
683 user can modify the Library and then relink to produce a modified
684 executable containing the modified Library. (It is understood
685 that the user who changes the contents of definitions files in the
686 Library will not necessarily be able to recompile the application
687 to use the modified definitions.)
688
689 b) Use a suitable shared library mechanism for linking with the
690 Library. A suitable mechanism is one that (1) uses at run time a
691 copy of the library already present on the user's computer system,
692 rather than copying library functions into the executable, and (2)
693 will operate properly with a modified version of the library, if
694 the user installs one, as long as the modified version is
695 interface-compatible with the version that the work was made with.
696
697 c) Accompany the work with a written offer, valid for at
698 least three years, to give the same user the materials
699 specified in Subsection 6a, above, for a charge no more
700 than the cost of performing this distribution.
701
702 d) If distribution of the work is made by offering access to copy
703 from a designated place, offer equivalent access to copy the above
704 specified materials from the same place.
705
706 e) Verify that the user has already received a copy of these
707 materials or that you have already sent this user a copy.
708
709 For an executable, the required form of the "work that uses the
710Library" must include any data and utility programs needed for
711reproducing the executable from it. However, as a special exception,
712the materials to be distributed need not include anything that is
713normally distributed (in either source or binary form) with the major
714components (compiler, kernel, and so on) of the operating system on
715which the executable runs, unless that component itself accompanies
716the executable.
717
718 It may happen that this requirement contradicts the license
719restrictions of other proprietary libraries that do not normally
720accompany the operating system. Such a contradiction means you cannot
721use both them and the Library together in an executable that you
722distribute.
723
724 7. You may place library facilities that are a work based on the
725Library side-by-side in a single library together with other library
726facilities not covered by this License, and distribute such a combined
727library, provided that the separate distribution of the work based on
728the Library and of the other library facilities is otherwise
729permitted, and provided that you do these two things:
730
731 a) Accompany the combined library with a copy of the same work
732 based on the Library, uncombined with any other library
733 facilities. This must be distributed under the terms of the
734 Sections above.
735
736 b) Give prominent notice with the combined library of the fact
737 that part of it is a work based on the Library, and explaining
738 where to find the accompanying uncombined form of the same work.
739
740 8. You may not copy, modify, sublicense, link with, or distribute
741the Library except as expressly provided under this License. Any
742attempt otherwise to copy, modify, sublicense, link with, or
743distribute the Library is void, and will automatically terminate your
744rights under this License. However, parties who have received copies,
745or rights, from you under this License will not have their licenses
746terminated so long as such parties remain in full compliance.
747
748 9. You are not required to accept this License, since you have not
749signed it. However, nothing else grants you permission to modify or
750distribute the Library or its derivative works. These actions are
751prohibited by law if you do not accept this License. Therefore, by
752modifying or distributing the Library (or any work based on the
753Library), you indicate your acceptance of this License to do so, and
754all its terms and conditions for copying, distributing or modifying
755the Library or works based on it.
756
757 10. Each time you redistribute the Library (or any work based on the
758Library), the recipient automatically receives a license from the
759original licensor to copy, distribute, link with or modify the Library
760subject to these terms and conditions. You may not impose any further
761restrictions on the recipients' exercise of the rights granted herein.
762You are not responsible for enforcing compliance by third parties with
763this License.
764
765 11. If, as a consequence of a court judgment or allegation of patent
766infringement or for any other reason (not limited to patent issues),
767conditions are imposed on you (whether by court order, agreement or
768otherwise) that contradict the conditions of this License, they do not
769excuse you from the conditions of this License. If you cannot
770distribute so as to satisfy simultaneously your obligations under this
771License and any other pertinent obligations, then as a consequence you
772may not distribute the Library at all. For example, if a patent
773license would not permit royalty-free redistribution of the Library by
774all those who receive copies directly or indirectly through you, then
775the only way you could satisfy both it and this License would be to
776refrain entirely from distribution of the Library.
777
778If any portion of this section is held invalid or unenforceable under any
779particular circumstance, the balance of the section is intended to apply,
780and the section as a whole is intended to apply in other circumstances.
781
782It is not the purpose of this section to induce you to infringe any
783patents or other property right claims or to contest validity of any
784such claims; this section has the sole purpose of protecting the
785integrity of the free software distribution system which is
786implemented by public license practices. Many people have made
787generous contributions to the wide range of software distributed
788through that system in reliance on consistent application of that
789system; it is up to the author/donor to decide if he or she is willing
790to distribute software through any other system and a licensee cannot
791impose that choice.
792
793This section is intended to make thoroughly clear what is believed to
794be a consequence of the rest of this License.
795
796 12. If the distribution and/or use of the Library is restricted in
797certain countries either by patents or by copyrighted interfaces, the
798original copyright holder who places the Library under this License may add
799an explicit geographical distribution limitation excluding those countries,
800so that distribution is permitted only in or among countries not thus
801excluded. In such case, this License incorporates the limitation as if
802written in the body of this License.
803
804 13. The Free Software Foundation may publish revised and/or new
805versions of the Lesser General Public License from time to time.
806Such new versions will be similar in spirit to the present version,
807but may differ in detail to address new problems or concerns.
808
809Each version is given a distinguishing version number. If the Library
810specifies a version number of this License which applies to it and
811"any later version", you have the option of following the terms and
812conditions either of that version or of any later version published by
813the Free Software Foundation. If the Library does not specify a
814license version number, you may choose any version ever published by
815the Free Software Foundation.
816
817 14. If you wish to incorporate parts of the Library into other free
818programs whose distribution conditions are incompatible with these,
819write to the author to ask for permission. For software which is
820copyrighted by the Free Software Foundation, write to the Free
821Software Foundation; we sometimes make exceptions for this. Our
822decision will be guided by the two goals of preserving the free status
823of all derivatives of our free software and of promoting the sharing
824and reuse of software generally.
825
826NO WARRANTY
827
828 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
829WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
830EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
831OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
832KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
833IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
834PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
835LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
836THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
837
838 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
839WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
840AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
841FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
842CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
843LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
844RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
845FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
846SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
847DAMAGES.
848
849END OF TERMS AND CONDITIONS
850```
851
852Appendix C: The MPL License
853---------------------------
854
855```
856MOZILLA PUBLIC LICENSE
857Version 1.1
858
8591. Definitions.
860
861 1.0.1. "Commercial Use" means distribution or otherwise making the
862 Covered Code available to a third party.
863
864 1.1. "Contributor" means each entity that creates or contributes to
865 the creation of Modifications.
866
867 1.2. "Contributor Version" means the combination of the Original
868 Code, prior Modifications used by a Contributor, and the Modifications
869 made by that particular Contributor.
870
871 1.3. "Covered Code" means the Original Code or Modifications or the
872 combination of the Original Code and Modifications, in each case
873 including portions thereof.
874
875 1.4. "Electronic Distribution Mechanism" means a mechanism generally
876 accepted in the software development community for the electronic
877 transfer of data.
878
879 1.5. "Executable" means Covered Code in any form other than Source
880 Code.
881
882 1.6. "Initial Developer" means the individual or entity identified
883 as the Initial Developer in the Source Code notice required by Exhibit
884 A.
885
886 1.7. "Larger Work" means a work which combines Covered Code or
887 portions thereof with code not governed by the terms of this License.
888
889 1.8. "License" means this document.
890
891 1.8.1. "Licensable" means having the right to grant, to the maximum
892 extent possible, whether at the time of the initial grant or
893 subsequently acquired, any and all of the rights conveyed herein.
894
895 1.9. "Modifications" means any addition to or deletion from the
896 substance or structure of either the Original Code or any previous
897 Modifications. When Covered Code is released as a series of files, a
898 Modification is:
899 A. Any addition to or deletion from the contents of a file
900 containing Original Code or previous Modifications.
901
902 B. Any new file that contains any part of the Original Code or
903 previous Modifications.
904
905 1.10. "Original Code" means Source Code of computer software code
906 which is described in the Source Code notice required by Exhibit A as
907 Original Code, and which, at the time of its release under this
908 License is not already Covered Code governed by this License.
909
910 1.10.1. "Patent Claims" means any patent claim(s), now owned or
911 hereafter acquired, including without limitation, method, process,
912 and apparatus claims, in any patent Licensable by grantor.
913
914 1.11. "Source Code" means the preferred form of the Covered Code for
915 making modifications to it, including all modules it contains, plus
916 any associated interface definition files, scripts used to control
917 compilation and installation of an Executable, or source code
918 differential comparisons against either the Original Code or another
919 well known, available Covered Code of the Contributor's choice. The
920 Source Code can be in a compressed or archival form, provided the
921 appropriate decompression or de-archiving software is widely available
922 for no charge.
923
924 1.12. "You" (or "Your") means an individual or a legal entity
925 exercising rights under, and complying with all of the terms of, this
926 License or a future version of this License issued under Section 6.1.
927 For legal entities, "You" includes any entity which controls, is
928 controlled by, or is under common control with You. For purposes of
929 this definition, "control" means (a) the power, direct or indirect,
930 to cause the direction or management of such entity, whether by
931 contract or otherwise, or (b) ownership of more than fifty percent
932 (50%) of the outstanding shares or beneficial ownership of such
933 entity.
934
9352. Source Code License.
936
937 2.1. The Initial Developer Grant.
938 The Initial Developer hereby grants You a world-wide, royalty-free,
939 non-exclusive license, subject to third party intellectual property
940 claims:
941 (a) under intellectual property rights (other than patent or
942 trademark) Licensable by Initial Developer to use, reproduce,
943 modify, display, perform, sublicense and distribute the Original
944 Code (or portions thereof) with or without Modifications, and/or
945 as part of a Larger Work; and
946
947 (b) under Patents Claims infringed by the making, using or
948 selling of Original Code, to make, have made, use, practice,
949 sell, and offer for sale, and/or otherwise dispose of the
950 Original Code (or portions thereof).
951
952 (c) the licenses granted in this Section 2.1(a) and (b) are
953 effective on the date Initial Developer first distributes
954 Original Code under the terms of this License.
955
956 (d) Notwithstanding Section 2.1(b) above, no patent license is
957 granted: 1) for code that You delete from the Original Code; 2)
958 separate from the Original Code; or 3) for infringements caused
959 by: i) the modification of the Original Code or ii) the
960 combination of the Original Code with other software or devices.
961
962 2.2. Contributor Grant.
963 Subject to third party intellectual property claims, each Contributor
964 hereby grants You a world-wide, royalty-free, non-exclusive license
965
966 (a) under intellectual property rights (other than patent or
967 trademark) Licensable by Contributor, to use, reproduce, modify,
968 display, perform, sublicense and distribute the Modifications
969 created by such Contributor (or portions thereof) either on an
970 unmodified basis, with other Modifications, as Covered Code
971 and/or as part of a Larger Work; and
972
973 (b) under Patent Claims infringed by the making, using, or
974 selling of Modifications made by that Contributor either alone
975 and/or in combination with its Contributor Version (or portions
976 of such combination), to make, use, sell, offer for sale, have
977 made, and/or otherwise dispose of: 1) Modifications made by that
978 Contributor (or portions thereof); and 2) the combination of
979 Modifications made by that Contributor with its Contributor
980 Version (or portions of such combination).
981
982 (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
983 effective on the date Contributor first makes Commercial Use of
984 the Covered Code.
985
986 (d) Notwithstanding Section 2.2(b) above, no patent license is
987 granted: 1) for any code that Contributor has deleted from the
988 Contributor Version; 2) separate from the Contributor Version;
989 3) for infringements caused by: i) third party modifications of
990 Contributor Version or ii) the combination of Modifications made
991 by that Contributor with other software (except as part of the
992 Contributor Version) or other devices; or 4) under Patent Claims
993 infringed by Covered Code in the absence of Modifications made by
994 that Contributor.
995
9963. Distribution Obligations.
997
998 3.1. Application of License.
999 The Modifications which You create or to which You contribute are
1000 governed by the terms of this License, including without limitation
1001 Section 2.2. The Source Code version of Covered Code may be
1002 distributed only under the terms of this License or a future version
1003 of this License released under Section 6.1, and You must include a
1004 copy of this License with every copy of the Source Code You
1005 distribute. You may not offer or impose any terms on any Source Code
1006 version that alters or restricts the applicable version of this
1007 License or the recipients' rights hereunder. However, You may include
1008 an additional document offering the additional rights described in
1009 Section 3.5.
1010
1011 3.2. Availability of Source Code.
1012 Any Modification which You create or to which You contribute must be
1013 made available in Source Code form under the terms of this License
1014 either on the same media as an Executable version or via an accepted
1015 Electronic Distribution Mechanism to anyone to whom you made an
1016 Executable version available; and if made available via Electronic
1017 Distribution Mechanism, must remain available for at least twelve (12)
1018 months after the date it initially became available, or at least six
1019 (6) months after a subsequent version of that particular Modification
1020 has been made available to such recipients. You are responsible for
1021 ensuring that the Source Code version remains available even if the
1022 Electronic Distribution Mechanism is maintained by a third party.
1023
1024 3.3. Description of Modifications.
1025 You must cause all Covered Code to which You contribute to contain a
1026 file documenting the changes You made to create that Covered Code and
1027 the date of any change. You must include a prominent statement that
1028 the Modification is derived, directly or indirectly, from Original
1029 Code provided by the Initial Developer and including the name of the
1030 Initial Developer in (a) the Source Code, and (b) in any notice in an
1031 Executable version or related documentation in which You describe the
1032 origin or ownership of the Covered Code.
1033
1034 3.4. Intellectual Property Matters
1035 (a) Third Party Claims.
1036 If Contributor has knowledge that a license under a third party's
1037 intellectual property rights is required to exercise the rights
1038 granted by such Contributor under Sections 2.1 or 2.2,
1039 Contributor must include a text file with the Source Code
1040 distribution titled "LEGAL" which describes the claim and the
1041 party making the claim in sufficient detail that a recipient will
1042 know whom to contact. If Contributor obtains such knowledge after
1043 the Modification is made available as described in Section 3.2,
1044 Contributor shall promptly modify the LEGAL file in all copies
1045 Contributor makes available thereafter and shall take other steps
1046 (such as notifying appropriate mailing lists or newsgroups)
1047 reasonably calculated to inform those who received the Covered
1048 Code that new knowledge has been obtained.
1049
1050 (b) Contributor APIs.
1051 If Contributor's Modifications include an application programming
1052 interface and Contributor has knowledge of patent licenses which
1053 are reasonably necessary to implement that API, Contributor must
1054 also include this information in the LEGAL file.
1055
1056 (c) Representations.
1057 Contributor represents that, except as disclosed pursuant to
1058 Section 3.4(a) above, Contributor believes that Contributor's
1059 Modifications are Contributor's original creation(s) and/or
1060 Contributor has sufficient rights to grant the rights conveyed by
1061 this License.
1062
1063 3.5. Required Notices.
1064 You must duplicate the notice in Exhibit A in each file of the Source
1065 Code. If it is not possible to put such notice in a particular Source
1066 Code file due to its structure, then You must include such notice in a
1067 location (such as a relevant directory) where a user would be likely
1068 to look for such a notice. If You created one or more Modification(s)
1069 You may add your name as a Contributor to the notice described in
1070 Exhibit A. You must also duplicate this License in any documentation
1071 for the Source Code where You describe recipients' rights or ownership
1072 rights relating to Covered Code. You may choose to offer, and to
1073 charge a fee for, warranty, support, indemnity or liability
1074 obligations to one or more recipients of Covered Code. However, You
1075 may do so only on Your own behalf, and not on behalf of the Initial
1076 Developer or any Contributor. You must make it absolutely clear than
1077 any such warranty, support, indemnity or liability obligation is
1078 offered by You alone, and You hereby agree to indemnify the Initial
1079 Developer and every Contributor for any liability incurred by the
1080 Initial Developer or such Contributor as a result of warranty,
1081 support, indemnity or liability terms You offer.
1082
1083 3.6. Distribution of Executable Versions.
1084 You may distribute Covered Code in Executable form only if the
1085 requirements of Section 3.1-3.5 have been met for that Covered Code,
1086 and if You include a notice stating that the Source Code version of
1087 the Covered Code is available under the terms of this License,
1088 including a description of how and where You have fulfilled the
1089 obligations of Section 3.2. The notice must be conspicuously included
1090 in any notice in an Executable version, related documentation or
1091 collateral in which You describe recipients' rights relating to the
1092 Covered Code. You may distribute the Executable version of Covered
1093 Code or ownership rights under a license of Your choice, which may
1094 contain terms different from this License, provided that You are in
1095 compliance with the terms of this License and that the license for the
1096 Executable version does not attempt to limit or alter the recipient's
1097 rights in the Source Code version from the rights set forth in this
1098 License. If You distribute the Executable version under a different
1099 license You must make it absolutely clear that any terms which differ
1100 from this License are offered by You alone, not by the Initial
1101 Developer or any Contributor. You hereby agree to indemnify the
1102 Initial Developer and every Contributor for any liability incurred by
1103 the Initial Developer or such Contributor as a result of any such
1104 terms You offer.
1105
1106 3.7. Larger Works.
1107 You may create a Larger Work by combining Covered Code with other code
1108 not governed by the terms of this License and distribute the Larger
1109 Work as a single product. In such a case, You must make sure the
1110 requirements of this License are fulfilled for the Covered Code.
1111
11124. Inability to Comply Due to Statute or Regulation.
1113
1114 If it is impossible for You to comply with any of the terms of this
1115 License with respect to some or all of the Covered Code due to
1116 statute, judicial order, or regulation then You must: (a) comply with
1117 the terms of this License to the maximum extent possible; and (b)
1118 describe the limitations and the code they affect. Such description
1119 must be included in the LEGAL file described in Section 3.4 and must
1120 be included with all distributions of the Source Code. Except to the
1121 extent prohibited by statute or regulation, such description must be
1122 sufficiently detailed for a recipient of ordinary skill to be able to
1123 understand it.
1124
11255. Application of this License.
1126
1127 This License applies to code to which the Initial Developer has
1128 attached the notice in Exhibit A and to related Covered Code.
1129
11306. Versions of the License.
1131
1132 6.1. New Versions.
1133 Netscape Communications Corporation ("Netscape") may publish revised
1134 and/or new versions of the License from time to time. Each version
1135 will be given a distinguishing version number.
1136
1137 6.2. Effect of New Versions.
1138 Once Covered Code has been published under a particular version of the
1139 License, You may always continue to use it under the terms of that
1140 version. You may also choose to use such Covered Code under the terms
1141 of any subsequent version of the License published by Netscape. No one
1142 other than Netscape has the right to modify the terms applicable to
1143 Covered Code created under this License.
1144
1145 6.3. Derivative Works.
1146 If You create or use a modified version of this License (which you may
1147 only do in order to apply it to code which is not already Covered Code
1148 governed by this License), You must (a) rename Your license so that
1149 the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
1150 "MPL", "NPL" or any confusingly similar phrase do not appear in your
1151 license (except to note that your license differs from this License)
1152 and (b) otherwise make it clear that Your version of the license
1153 contains terms which differ from the Mozilla Public License and
1154 Netscape Public License. (Filling in the name of the Initial
1155 Developer, Original Code or Contributor in the notice described in
1156 Exhibit A shall not of themselves be deemed to be modifications of
1157 this License.)
1158
11597. DISCLAIMER OF WARRANTY.
1160
1161 COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
1162 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
1163 WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
1164 DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
1165 THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
1166 IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
1167 YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
1168 COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
1169 OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
1170 ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
1171
11728. TERMINATION.
1173
1174 8.1. This License and the rights granted hereunder will terminate
1175 automatically if You fail to comply with terms herein and fail to cure
1176 such breach within 30 days of becoming aware of the breach. All
1177 sublicenses to the Covered Code which are properly granted shall
1178 survive any termination of this License. Provisions which, by their
1179 nature, must remain in effect beyond the termination of this License
1180 shall survive.
1181
1182 8.2. If You initiate litigation by asserting a patent infringement
1183 claim (excluding declatory judgment actions) against Initial Developer
1184 or a Contributor (the Initial Developer or Contributor against whom
1185 You file such action is referred to as "Participant") alleging that:
1186
1187 (a) such Participant's Contributor Version directly or indirectly
1188 infringes any patent, then any and all rights granted by such
1189 Participant to You under Sections 2.1 and/or 2.2 of this License
1190 shall, upon 60 days notice from Participant terminate prospectively,
1191 unless if within 60 days after receipt of notice You either: (i)
1192 agree in writing to pay Participant a mutually agreeable reasonable
1193 royalty for Your past and future use of Modifications made by such
1194 Participant, or (ii) withdraw Your litigation claim with respect to
1195 the Contributor Version against such Participant. If within 60 days
1196 of notice, a reasonable royalty and payment arrangement are not
1197 mutually agreed upon in writing by the parties or the litigation claim
1198 is not withdrawn, the rights granted by Participant to You under
1199 Sections 2.1 and/or 2.2 automatically terminate at the expiration of
1200 the 60 day notice period specified above.
1201
1202 (b) any software, hardware, or device, other than such Participant's
1203 Contributor Version, directly or indirectly infringes any patent, then
1204 any rights granted to You by such Participant under Sections 2.1(b)
1205 and 2.2(b) are revoked effective as of the date You first made, used,
1206 sold, distributed, or had made, Modifications made by that
1207 Participant.
1208
1209 8.3. If You assert a patent infringement claim against Participant
1210 alleging that such Participant's Contributor Version directly or
1211 indirectly infringes any patent where such claim is resolved (such as
1212 by license or settlement) prior to the initiation of patent
1213 infringement litigation, then the reasonable value of the licenses
1214 granted by such Participant under Sections 2.1 or 2.2 shall be taken
1215 into account in determining the amount or value of any payment or
1216 license.
1217
1218 8.4. In the event of termination under Sections 8.1 or 8.2 above,
1219 all end user license agreements (excluding distributors and resellers)
1220 which have been validly granted by You or any distributor hereunder
1221 prior to termination shall survive termination.
1222
12239. LIMITATION OF LIABILITY.
1224
1225 UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
1226 (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
1227 DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
1228 OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
1229 ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
1230 CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
1231 WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
1232 COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
1233 INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
1234 LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
1235 RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
1236 PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
1237 EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
1238 THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
1239
124010. U.S. GOVERNMENT END USERS.
1241
1242 The Covered Code is a "commercial item," as that term is defined in
1243 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
1244 software" and "commercial computer software documentation," as such
1245 terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
1246 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
1247 all U.S. Government End Users acquire Covered Code with only those
1248 rights set forth herein.
1249
125011. MISCELLANEOUS.
1251
1252 This License represents the complete agreement concerning subject
1253 matter hereof. If any provision of this License is held to be
1254 unenforceable, such provision shall be reformed only to the extent
1255 necessary to make it enforceable. This License shall be governed by
1256 California law provisions (except to the extent applicable law, if
1257 any, provides otherwise), excluding its conflict-of-law provisions.
1258 With respect to disputes in which at least one party is a citizen of,
1259 or an entity chartered or registered to do business in the United
1260 States of America, any litigation relating to this License shall be
1261 subject to the jurisdiction of the Federal Courts of the Northern
1262 District of California, with venue lying in Santa Clara County,
1263 California, with the losing party responsible for costs, including
1264 without limitation, court costs and reasonable attorneys' fees and
1265 expenses. The application of the United Nations Convention on
1266 Contracts for the International Sale of Goods is expressly excluded.
1267 Any law or regulation which provides that the language of a contract
1268 shall be construed against the drafter shall not apply to this
1269 License.
1270
127112. RESPONSIBILITY FOR CLAIMS.
1272
1273 As between Initial Developer and the Contributors, each party is
1274 responsible for claims and damages arising, directly or indirectly,
1275 out of its utilization of rights under this License and You agree to
1276 work with Initial Developer and Contributors to distribute such
1277 responsibility on an equitable basis. Nothing herein is intended or
1278 shall be deemed to constitute any admission of liability.
1279
128013. MULTIPLE-LICENSED CODE.
1281
1282 Initial Developer may designate portions of the Covered Code as
1283 "Multiple-Licensed". "Multiple-Licensed" means that the Initial
1284 Developer permits you to utilize portions of the Covered Code under
1285 Your choice of the NPL or the alternative licenses, if any, specified
1286 by the Initial Developer in the file described in Exhibit A.
1287
1288EXHIBIT A -Mozilla Public License.
1289
1290 ``The contents of this file are subject to the Mozilla Public License
1291 Version 1.1 (the "License"); you may not use this file except in
1292 compliance with the License. You may obtain a copy of the License at
1293 http://www.mozilla.org/MPL/
1294
1295 Software distributed under the License is distributed on an "AS IS"
1296 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
1297 License for the specific language governing rights and limitations
1298 under the License.
1299
1300 The Original Code is ______________________________________.
1301
1302 The Initial Developer of the Original Code is ________________________.
1303 Portions created by ______________________ are Copyright (C) ______
1304 _______________________. All Rights Reserved.
1305
1306 Contributor(s): ______________________________________.
1307
1308 Alternatively, the contents of this file may be used under the terms
1309 of the _____ license (the "[___] License"), in which case the
1310 provisions of [______] License are applicable instead of those
1311 above. If you wish to allow use of your version of this file only
1312 under the terms of the [____] License and not to allow others to use
1313 your version of this file under the MPL, indicate your decision by
1314 deleting the provisions above and replace them with the notice and
1315 other provisions required by the [___] License. If you do not delete
1316 the provisions above, a recipient may use your version of this file
1317 under either the MPL or the [___] License."
1318
1319 [NOTE: The text of this Exhibit A may differ slightly from the text of
1320 the notices in the Source Code files of the Original Code. You should
1321 use the text of this Exhibit A rather than the text found in the
1322 Original Code Source Code for Your Modifications.]
1323```
1324
1325Appendix D: The MIT License
1326---------------------------
1327
1328```
1329The MIT License (MIT)
1330
1331Permission is hereby granted, free of charge, to any person obtaining a copy
1332of this software and associated documentation files (the "Software"), to deal
1333in the Software without restriction, including without limitation the rights
1334to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1335copies of the Software, and to permit persons to whom the Software is
1336furnished to do so, subject to the following conditions:
1337
1338The above copyright notice and this permission notice shall be included in
1339all copies or substantial portions of the Software.
1340
1341THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1342IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1343FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1344AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1345LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1346OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1347THE SOFTWARE.
1348```
1349
1350Appendix E: The SIL Open Font License Version 1.1
1351---------------------------------------------
1352
1353```
1354SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
1355-----------------------------------------------------------
1356
1357PREAMBLE
1358The goals of the Open Font License (OFL) are to stimulate worldwide
1359development of collaborative font projects, to support the font creation
1360efforts of academic and linguistic communities, and to provide a free and
1361open framework in which fonts may be shared and improved in partnership
1362with others.
1363
1364The OFL allows the licensed fonts to be used, studied, modified and
1365redistributed freely as long as they are not sold by themselves. The
1366fonts, including any derivative works, can be bundled, embedded,
1367redistributed and/or sold with any software provided that any reserved
1368names are not used by derivative works. The fonts and derivatives,
1369however, cannot be released under any other type of license. The
1370requirement for fonts to remain under this license does not apply
1371to any document created using the fonts or their derivatives.
1372
1373DEFINITIONS
1374"Font Software" refers to the set of files released by the Copyright
1375Holder(s) under this license and clearly marked as such. This may
1376include source files, build scripts and documentation.
1377
1378"Reserved Font Name" refers to any names specified as such after the
1379copyright statement(s).
1380
1381"Original Version" refers to the collection of Font Software components as
1382distributed by the Copyright Holder(s).
1383
1384"Modified Version" refers to any derivative made by adding to, deleting,
1385or substituting -- in part or in whole -- any of the components of the
1386Original Version, by changing formats or by porting the Font Software to a
1387new environment.
1388
1389"Author" refers to any designer, engineer, programmer, technical
1390writer or other person who contributed to the Font Software.
1391
1392PERMISSION & CONDITIONS
1393Permission is hereby granted, free of charge, to any person obtaining
1394a copy of the Font Software, to use, study, copy, merge, embed, modify,
1395redistribute, and sell modified and unmodified copies of the Font
1396Software, subject to the following conditions:
1397
13981) Neither the Font Software nor any of its individual components,
1399in Original or Modified Versions, may be sold by itself.
1400
14012) Original or Modified Versions of the Font Software may be bundled,
1402redistributed and/or sold with any software, provided that each copy
1403contains the above copyright notice and this license. These can be
1404included either as stand-alone text files, human-readable headers or
1405in the appropriate machine-readable metadata fields within text or
1406binary files as long as those fields can be easily viewed by the user.
1407
14083) No Modified Version of the Font Software may use the Reserved Font
1409Name(s) unless explicit written permission is granted by the corresponding
1410Copyright Holder. This restriction only applies to the primary font name as
1411presented to the users.
1412
14134) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
1414Software shall not be used to promote, endorse or advertise any
1415Modified Version, except to acknowledge the contribution(s) of the
1416Copyright Holder(s) and the Author(s) or with their explicit written
1417permission.
1418
14195) The Font Software, modified or unmodified, in part or in whole,
1420must be distributed entirely under this license, and must not be
1421distributed under any other license. The requirement for fonts to
1422remain under this license does not apply to any document created
1423using the Font Software.
1424
1425TERMINATION
1426This license becomes null and void if any of the above conditions are
1427not met.
1428
1429DISCLAIMER
1430THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1431EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
1432MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
1433OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
1434COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1435INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
1436DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1437FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
1438OTHER DEALINGS IN THE FONT SOFTWARE.
1439```
1440
1441Appendix F: The BSD-3 License
1442-----------------------------
1443
1444```
1445Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1446
14471. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
1448
14492. 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.
1450
14513. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
1452
1453THIS 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.
1454```
1455
1456(Ignore this line: %REMOVE_START%)
1457
1458Appendix G: The Apache License
1459------------------------------
1460
1461```
1462
1463 Apache License
1464 Version 2.0, January 2004
1465 http://www.apache.org/licenses/
1466
1467TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1468
14691. Definitions.
1470
1471 "License" shall mean the terms and conditions for use, reproduction,
1472 and distribution as defined by Sections 1 through 9 of this document.
1473
1474 "Licensor" shall mean the copyright owner or entity authorized by
1475 the copyright owner that is granting the License.
1476
1477 "Legal Entity" shall mean the union of the acting entity and all
1478 other entities that control, are controlled by, or are under common
1479 control with that entity. For the purposes of this definition,
1480 "control" means (i) the power, direct or indirect, to cause the
1481 direction or management of such entity, whether by contract or
1482 otherwise, or (ii) ownership of fifty percent (50%) or more of the
1483 outstanding shares, or (iii) beneficial ownership of such entity.
1484
1485 "You" (or "Your") shall mean an individual or Legal Entity
1486 exercising permissions granted by this License.
1487
1488 "Source" form shall mean the preferred form for making modifications,
1489 including but not limited to software source code, documentation
1490 source, and configuration files.
1491
1492 "Object" form shall mean any form resulting from mechanical
1493 transformation or translation of a Source form, including but
1494 not limited to compiled object code, generated documentation,
1495 and conversions to other media types.
1496
1497 "Work" shall mean the work of authorship, whether in Source or
1498 Object form, made available under the License, as indicated by a
1499 copyright notice that is included in or attached to the work
1500 (an example is provided in the Appendix below).
1501
1502 "Derivative Works" shall mean any work, whether in Source or Object
1503 form, that is based on (or derived from) the Work and for which the
1504 editorial revisions, annotations, elaborations, or other modifications
1505 represent, as a whole, an original work of authorship. For the purposes
1506 of this License, Derivative Works shall not include works that remain
1507 separable from, or merely link (or bind by name) to the interfaces of,
1508 the Work and Derivative Works thereof.
1509
1510 "Contribution" shall mean any work of authorship, including
1511 the original version of the Work and any modifications or additions
1512 to that Work or Derivative Works thereof, that is intentionally
1513 submitted to Licensor for inclusion in the Work by the copyright owner
1514 or by an individual or Legal Entity authorized to submit on behalf of
1515 the copyright owner. For the purposes of this definition, "submitted"
1516 means any form of electronic, verbal, or written communication sent
1517 to the Licensor or its representatives, including but not limited to
1518 communication on electronic mailing lists, source code control systems,
1519 and issue tracking systems that are managed by, or on behalf of, the
1520 Licensor for the purpose of discussing and improving the Work, but
1521 excluding communication that is conspicuously marked or otherwise
1522 designated in writing by the copyright owner as "Not a Contribution."
1523
1524 "Contributor" shall mean Licensor and any individual or Legal Entity
1525 on behalf of whom a Contribution has been received by Licensor and
1526 subsequently incorporated within the Work.
1527
15282. Grant of Copyright License. Subject to the terms and conditions of
1529 this License, each Contributor hereby grants to You a perpetual,
1530 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1531 copyright license to reproduce, prepare Derivative Works of,
1532 publicly display, publicly perform, sublicense, and distribute the
1533 Work and such Derivative Works in Source or Object form.
1534
15353. Grant of Patent License. Subject to the terms and conditions of
1536 this License, each Contributor hereby grants to You a perpetual,
1537 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1538 (except as stated in this section) patent license to make, have made,
1539 use, offer to sell, sell, import, and otherwise transfer the Work,
1540 where such license applies only to those patent claims licensable
1541 by such Contributor that are necessarily infringed by their
1542 Contribution(s) alone or by combination of their Contribution(s)
1543 with the Work to which such Contribution(s) was submitted. If You
1544 institute patent litigation against any entity (including a
1545 cross-claim or counterclaim in a lawsuit) alleging that the Work
1546 or a Contribution incorporated within the Work constitutes direct
1547 or contributory patent infringement, then any patent licenses
1548 granted to You under this License for that Work shall terminate
1549 as of the date such litigation is filed.
1550
15514. Redistribution. You may reproduce and distribute copies of the
1552 Work or Derivative Works thereof in any medium, with or without
1553 modifications, and in Source or Object form, provided that You
1554 meet the following conditions:
1555
1556 (a) You must give any other recipients of the Work or
1557 Derivative Works a copy of this License; and
1558
1559 (b) You must cause any modified files to carry prominent notices
1560 stating that You changed the files; and
1561
1562 (c) You must retain, in the Source form of any Derivative Works
1563 that You distribute, all copyright, patent, trademark, and
1564 attribution notices from the Source form of the Work,
1565 excluding those notices that do not pertain to any part of
1566 the Derivative Works; and
1567
1568 (d) If the Work includes a "NOTICE" text file as part of its
1569 distribution, then any Derivative Works that You distribute must
1570 include a readable copy of the attribution notices contained
1571 within such NOTICE file, excluding those notices that do not
1572 pertain to any part of the Derivative Works, in at least one
1573 of the following places: within a NOTICE text file distributed
1574 as part of the Derivative Works; within the Source form or
1575 documentation, if provided along with the Derivative Works; or,
1576 within a display generated by the Derivative Works, if and
1577 wherever such third-party notices normally appear. The contents
1578 of the NOTICE file are for informational purposes only and
1579 do not modify the License. You may add Your own attribution
1580 notices within Derivative Works that You distribute, alongside
1581 or as an addendum to the NOTICE text from the Work, provided
1582 that such additional attribution notices cannot be construed
1583 as modifying the License.
1584
1585 You may add Your own copyright statement to Your modifications and
1586 may provide additional or different license terms and conditions
1587 for use, reproduction, or distribution of Your modifications, or
1588 for any such Derivative Works as a whole, provided Your use,
1589 reproduction, and distribution of the Work otherwise complies with
1590 the conditions stated in this License.
1591
15925. Submission of Contributions. Unless You explicitly state otherwise,
1593 any Contribution intentionally submitted for inclusion in the Work
1594 by You to the Licensor shall be under the terms and conditions of
1595 this License, without any additional terms or conditions.
1596 Notwithstanding the above, nothing herein shall supersede or modify
1597 the terms of any separate license agreement you may have executed
1598 with Licensor regarding such Contributions.
1599
16006. Trademarks. This License does not grant permission to use the trade
1601 names, trademarks, service marks, or product names of the Licensor,
1602 except as required for reasonable and customary use in describing the
1603 origin of the Work and reproducing the content of the NOTICE file.
1604
16057. Disclaimer of Warranty. Unless required by applicable law or
1606 agreed to in writing, Licensor provides the Work (and each
1607 Contributor provides its Contributions) on an "AS IS" BASIS,
1608 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1609 implied, including, without limitation, any warranties or conditions
1610 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
1611 PARTICULAR PURPOSE. You are solely responsible for determining the
1612 appropriateness of using or redistributing the Work and assume any
1613 risks associated with Your exercise of permissions under this License.
1614
16158. Limitation of Liability. In no event and under no legal theory,
1616 whether in tort (including negligence), contract, or otherwise,
1617 unless required by applicable law (such as deliberate and grossly
1618 negligent acts) or agreed to in writing, shall any Contributor be
1619 liable to You for damages, including any direct, indirect, special,
1620 incidental, or consequential damages of any character arising as a
1621 result of this License or out of the use or inability to use the
1622 Work (including but not limited to damages for loss of goodwill,
1623 work stoppage, computer failure or malfunction, or any and all
1624 other commercial damages or losses), even if such Contributor
1625 has been advised of the possibility of such damages.
1626
16279. Accepting Warranty or Additional Liability. While redistributing
1628 the Work or Derivative Works thereof, You may choose to offer,
1629 and charge a fee for, acceptance of support, warranty, indemnity,
1630 or other liability obligations and/or rights consistent with this
1631 License. However, in accepting such obligations, You may act only
1632 on Your own behalf and on Your sole responsibility, not on behalf
1633 of any other Contributor, and only if You agree to indemnify,
1634 defend, and hold each Contributor harmless for any liability
1635 incurred by, or claims asserted against, such Contributor by reason
1636 of your accepting any such warranty or additional liability.
1637
1638END OF TERMS AND CONDITIONS
1639```
1640
1641(Ignore this line: %REMOVE_END%)
diff --git a/sources/README.md b/sources/README.md
new file mode 100644
index 0000000..d18d4a1
--- /dev/null
+++ b/sources/README.md
@@ -0,0 +1,39 @@
1CKEditor 4
2==========
3
4Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
5http://ckeditor.com - See LICENSE.md for license information.
6
7CKEditor is a text editor to be used inside web pages. It's not a replacement
8for desktop text editors like Word or OpenOffice, but a component to be used as
9part of web applications and websites.
10
11## Documentation
12
13The full editor documentation is available online at the following address:
14http://docs.ckeditor.com
15
16## Installation
17
18Installing CKEditor is an easy task. Just follow these simple steps:
19
20 1. **Download** the latest version from the CKEditor website:
21 http://ckeditor.com. You should have already completed this step, but be
22 sure you have the very latest version.
23 2. **Extract** (decompress) the downloaded file into the root of your website.
24
25**Note:** CKEditor is by default installed in the `ckeditor` folder. You can
26place the files in whichever you want though.
27
28## Checking Your Installation
29
30The editor comes with a few sample pages that can be used to verify that
31installation proceeded properly. Take a look at the `samples` directory.
32
33To test your installation, just call the following page at your website:
34
35 http://<your site>/<CKEditor installation path>/samples/index.html
36
37For example:
38
39 http://www.example.com/ckeditor/samples/index.html
diff --git a/sources/adapters/jquery.js b/sources/adapters/jquery.js
new file mode 100644
index 0000000..4a7796b
--- /dev/null
+++ b/sources/adapters/jquery.js
@@ -0,0 +1,379 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR_Adapters.jQuery jQuery Adapter}.
8 */
9
10/**
11 * @class CKEDITOR_Adapters.jQuery
12 * @singleton
13 *
14 * The jQuery Adapter allows for easy use of basic CKEditor functions and access to the internal API.
15 * To find more information about the jQuery Adapter, go to the [jQuery Adapter section](#!/guide/dev_jquery)
16 * of the Developer's Guide or see the "Create Editors with jQuery" sample.
17 *
18 * @aside guide dev_jquery
19 */
20
21( function( $ ) {
22 if ( typeof $ == 'undefined' ) {
23 throw new Error( 'jQuery should be loaded before CKEditor jQuery adapter.' );
24 }
25
26 if ( typeof CKEDITOR == 'undefined' ) {
27 throw new Error( 'CKEditor should be loaded before CKEditor jQuery adapter.' );
28 }
29
30 /**
31 * Allows CKEditor to override `jQuery.fn.val()`. When set to `true`, the `val()` function
32 * used on textarea elements replaced with CKEditor uses the CKEditor API.
33 *
34 * This configuration option is global and is executed during the loading of the jQuery Adapter.
35 * It cannot be customized across editor instances.
36 *
37 * Read more in the [documentation](#!/guide/dev_jquery).
38 *
39 * <script>
40 * CKEDITOR.config.jqueryOverrideVal = true;
41 * </script>
42 *
43 * <!-- Important: The jQuery Adapter is loaded *after* setting jqueryOverrideVal. -->
44 * <script src="/ckeditor/adapters/jquery.js"></script>
45 *
46 * <script>
47 * $( 'textarea' ).ckeditor();
48 * // ...
49 * $( 'textarea' ).val( 'New content' );
50 * </script>
51 *
52 * @cfg {Boolean} [jqueryOverrideVal=true]
53 * @member CKEDITOR.config
54 */
55 CKEDITOR.config.jqueryOverrideVal =
56 typeof CKEDITOR.config.jqueryOverrideVal == 'undefined' ? true : CKEDITOR.config.jqueryOverrideVal;
57
58 // jQuery object methods.
59 $.extend( $.fn, {
60 /**
61 * Returns an existing CKEditor instance for the first matched element.
62 * Allows to easily use the internal API. Does not return a jQuery object.
63 *
64 * Raises an exception if the editor does not exist or is not ready yet.
65 *
66 * @returns CKEDITOR.editor
67 * @deprecated Use {@link #editor editor property} instead.
68 */
69 ckeditorGet: function() {
70 var instance = this.eq( 0 ).data( 'ckeditorInstance' );
71
72 if ( !instance )
73 throw 'CKEditor is not initialized yet, use ckeditor() with a callback.';
74
75 return instance;
76 },
77
78 /**
79 * A jQuery function which triggers the creation of CKEditor with `<textarea>` and
80 * {@link CKEDITOR.dtd#$editable editable} elements.
81 * Every `<textarea>` element will be converted to a classic (`iframe`-based) editor,
82 * while any other supported element will be converted to an inline editor.
83 * This method binds the callback to the `instanceReady` event of all instances.
84 * If the editor has already been created, the callback is fired straightaway.
85 * You can also create multiple editors at once by using `$( '.className' ).ckeditor();`.
86 *
87 * **Note**: jQuery chaining and mixed parameter order is allowed.
88 *
89 * @param {Function} callback
90 * Function to be run on the editor instance. Callback takes the source element as a parameter.
91 *
92 * $( 'textarea' ).ckeditor( function( textarea ) {
93 * // Callback function code.
94 * } );
95 *
96 * @param {Object} config
97 * Configuration options for new instance(s) if not already created.
98 *
99 * $( 'textarea' ).ckeditor( {
100 * uiColor: '#9AB8F3'
101 * } );
102 *
103 * @returns jQuery.fn
104 */
105 ckeditor: function( callback, config ) {
106 if ( !CKEDITOR.env.isCompatible )
107 throw new Error( 'The environment is incompatible.' );
108
109 // Reverse the order of arguments if the first one isn't a function.
110 if ( !$.isFunction( callback ) ) {
111 var tmp = config;
112 config = callback;
113 callback = tmp;
114 }
115
116 // An array of instanceReady callback promises.
117 var promises = [];
118
119 config = config || {};
120
121 // Iterate over the collection.
122 this.each( function() {
123 var $element = $( this ),
124 editor = $element.data( 'ckeditorInstance' ),
125 instanceLock = $element.data( '_ckeditorInstanceLock' ),
126 element = this,
127 dfd = new $.Deferred();
128
129 promises.push( dfd.promise() );
130
131 if ( editor && !instanceLock ) {
132 if ( callback )
133 callback.apply( editor, [ this ] );
134
135 dfd.resolve();
136 } else if ( !instanceLock ) {
137 // CREATE NEW INSTANCE
138
139 // Handle config.autoUpdateElement inside this plugin if desired.
140 if ( config.autoUpdateElement || ( typeof config.autoUpdateElement == 'undefined' && CKEDITOR.config.autoUpdateElement ) ) {
141 config.autoUpdateElementJquery = true;
142 }
143
144 // Always disable config.autoUpdateElement.
145 config.autoUpdateElement = false;
146 $element.data( '_ckeditorInstanceLock', true );
147
148 // Set instance reference in element's data.
149 if ( $( this ).is( 'textarea' ) )
150 editor = CKEDITOR.replace( element, config );
151 else
152 editor = CKEDITOR.inline( element, config );
153
154 $element.data( 'ckeditorInstance', editor );
155
156 // Register callback.
157 editor.on( 'instanceReady', function( evt ) {
158 var editor = evt.editor;
159
160 setTimeout( function() {
161 // Delay bit more if editor is still not ready.
162 if ( !editor.element ) {
163 setTimeout( arguments.callee, 100 );
164 return;
165 }
166
167 // Remove this listener. Triggered when new instance is ready.
168 evt.removeListener();
169
170 /**
171 * Forwards the CKEditor {@link CKEDITOR.editor#event-dataReady dataReady event} as a jQuery event.
172 *
173 * @event dataReady
174 * @param {CKEDITOR.editor} editor Editor instance.
175 */
176 editor.on( 'dataReady', function() {
177 $element.trigger( 'dataReady.ckeditor', [ editor ] );
178 } );
179
180 /**
181 * Forwards the CKEditor {@link CKEDITOR.editor#event-setData setData event} as a jQuery event.
182 *
183 * @event setData
184 * @param {CKEDITOR.editor} editor Editor instance.
185 * @param data
186 * @param {String} data.dataValue The data that will be used.
187 */
188 editor.on( 'setData', function( evt ) {
189 $element.trigger( 'setData.ckeditor', [ editor, evt.data ] );
190 } );
191
192 /**
193 * Forwards the CKEditor {@link CKEDITOR.editor#event-getData getData event} as a jQuery event.
194 *
195 * @event getData
196 * @param {CKEDITOR.editor} editor Editor instance.
197 * @param data
198 * @param {String} data.dataValue The data that will be returned.
199 */
200 editor.on( 'getData', function( evt ) {
201 $element.trigger( 'getData.ckeditor', [ editor, evt.data ] );
202 }, 999 );
203
204 /**
205 * Forwards the CKEditor {@link CKEDITOR.editor#event-destroy destroy event} as a jQuery event.
206 *
207 * @event destroy
208 * @param {CKEDITOR.editor} editor Editor instance.
209 */
210 editor.on( 'destroy', function() {
211 $element.trigger( 'destroy.ckeditor', [ editor ] );
212 } );
213
214 // Overwrite save button to call jQuery submit instead of javascript submit.
215 // Otherwise jQuery.forms does not work properly
216 editor.on( 'save', function() {
217 $( element.form ).submit();
218 return false;
219 }, null, null, 20 );
220
221 // Integrate with form submit.
222 if ( editor.config.autoUpdateElementJquery && $element.is( 'textarea' ) && $( element.form ).length ) {
223 var onSubmit = function() {
224 $element.ckeditor( function() {
225 editor.updateElement();
226 } );
227 };
228
229 // Bind to submit event.
230 $( element.form ).submit( onSubmit );
231
232 // Bind to form-pre-serialize from jQuery Forms plugin.
233 $( element.form ).bind( 'form-pre-serialize', onSubmit );
234
235 // Unbind when editor destroyed.
236 $element.bind( 'destroy.ckeditor', function() {
237 $( element.form ).unbind( 'submit', onSubmit );
238 $( element.form ).unbind( 'form-pre-serialize', onSubmit );
239 } );
240 }
241
242 // Garbage collect on destroy.
243 editor.on( 'destroy', function() {
244 $element.removeData( 'ckeditorInstance' );
245 } );
246
247 // Remove lock.
248 $element.removeData( '_ckeditorInstanceLock' );
249
250 /**
251 * Forwards the CKEditor {@link CKEDITOR.editor#event-instanceReady instanceReady event} as a jQuery event.
252 *
253 * @event instanceReady
254 * @param {CKEDITOR.editor} editor Editor instance.
255 */
256 $element.trigger( 'instanceReady.ckeditor', [ editor ] );
257
258 // Run given (first) code.
259 if ( callback )
260 callback.apply( editor, [ element ] );
261
262 dfd.resolve();
263 }, 0 );
264 }, null, null, 9999 );
265 } else {
266 // Editor is already during creation process, bind our code to the event.
267 editor.once( 'instanceReady', function() {
268 setTimeout( function() {
269 // Delay bit more if editor is still not ready.
270 if ( !editor.element ) {
271 setTimeout( arguments.callee, 100 );
272 return;
273 }
274
275 // Run given code.
276 if ( editor.element.$ == element && callback )
277 callback.apply( editor, [ element ] );
278
279 dfd.resolve();
280 }, 0 );
281 }, null, null, 9999 );
282 }
283 } );
284
285 /**
286 * The [jQuery Promise object]((http://api.jquery.com/promise/)) that handles the asynchronous constructor.
287 * This promise will be resolved after **all** of the constructors.
288 *
289 * @property {Function} promise
290 */
291 var dfd = new $.Deferred();
292
293 this.promise = dfd.promise();
294
295 $.when.apply( this, promises ).then( function() {
296 dfd.resolve();
297 } );
298
299 /**
300 * Existing CKEditor instance. Allows to easily use the internal API.
301 *
302 * **Note**: This is not a jQuery object.
303 *
304 * var editor = $( 'textarea' ).ckeditor().editor;
305 *
306 * @property {CKEDITOR.editor} editor
307 */
308 this.editor = this.eq( 0 ).data( 'ckeditorInstance' );
309
310 return this;
311 }
312 } );
313
314 /**
315 * Overwritten jQuery `val()` method for `<textarea>` elements that have bound CKEditor instances.
316 * This method gets or sets editor content by using the {@link CKEDITOR.editor#method-getData editor.getData()}
317 * or {@link CKEDITOR.editor#method-setData editor.setData()} methods. To handle
318 * the {@link CKEDITOR.editor#method-setData editor.setData()} callback (as `setData` is asynchronous),
319 * `val( 'some data' )` will return a [jQuery Promise object](http://api.jquery.com/promise/).
320 *
321 * @method val
322 * @returns String|Number|Array|jQuery.fn|function(jQuery Promise)
323 */
324 if ( CKEDITOR.config.jqueryOverrideVal ) {
325 $.fn.val = CKEDITOR.tools.override( $.fn.val, function( oldValMethod ) {
326 return function( value ) {
327 // Setter, i.e. .val( "some data" );
328 if ( arguments.length ) {
329 var _this = this,
330 promises = [], //use promise to handle setData callback
331
332 result = this.each( function() {
333 var $elem = $( this ),
334 editor = $elem.data( 'ckeditorInstance' );
335
336 // Handle .val for CKEditor.
337 if ( $elem.is( 'textarea' ) && editor ) {
338 var dfd = new $.Deferred();
339
340 editor.setData( value, function() {
341 dfd.resolve();
342 } );
343
344 promises.push( dfd.promise() );
345 return true;
346 // Call default .val function for rest of elements
347 } else {
348 return oldValMethod.call( $elem, value );
349 }
350 } );
351
352 // If there is no promise return default result (jQuery object of chaining).
353 if ( !promises.length )
354 return result;
355 // Create one promise which will be resolved when all of promises will be done.
356 else {
357 var dfd = new $.Deferred();
358
359 $.when.apply( this, promises ).done( function() {
360 dfd.resolveWith( _this );
361 } );
362
363 return dfd.promise();
364 }
365 }
366 // Getter .val();
367 else {
368 var $elem = $( this ).eq( 0 ),
369 editor = $elem.data( 'ckeditorInstance' );
370
371 if ( $elem.is( 'textarea' ) && editor )
372 return editor.getData();
373 else
374 return oldValMethod.call( $elem );
375 }
376 };
377 } );
378 }
379} )( window.jQuery );
diff --git a/sources/ckeditor.js b/sources/ckeditor.js
new file mode 100644
index 0000000..8dc999b
--- /dev/null
+++ b/sources/ckeditor.js
@@ -0,0 +1,48 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6// Compressed version of core/ckeditor_base.js. See original for instructions.
7/* jshint ignore:start */
8/* jscs:disable */
9window.CKEDITOR||(window.CKEDITOR=function(){var e=/(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i,b={timestamp:"",version:"%VERSION%",revision:"%REV%",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:e},status:"unloaded",basePath:function(){var a=window.CKEDITOR_BASEPATH||"";if(!a)for(var b=document.getElementsByTagName("script"),c=0;c<b.length;c++){var f=b[c].src.match(e);if(f){a=f[1];break}}-1==a.indexOf(":/")&&"//"!=a.slice(0,2)&&(a=0===a.indexOf("/")?location.href.match(/^.*?:\/\/[^\/]*/)[0]+
10a:location.href.match(/^[^\?]*\/(?:)/)[0]+a);if(!a)throw'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';return a}(),getUrl:function(a){-1==a.indexOf(":/")&&0!==a.indexOf("/")&&(a=this.basePath+a);this.timestamp&&"/"!=a.charAt(a.length-1)&&!/[&?]t=/.test(a)&&(a+=(0<=a.indexOf("?")?"&":"?")+"t="+this.timestamp);return a},domReady:function(){function a(){try{document.addEventListener?(document.removeEventListener("DOMContentLoaded",
11a,!1),b()):document.attachEvent&&"complete"===document.readyState&&(document.detachEvent("onreadystatechange",a),b())}catch(f){}}function b(){for(var a;a=c.shift();)a()}var c=[];return function(b){c.push(b);"complete"===document.readyState&&setTimeout(a,1);if(1==c.length)if(document.addEventListener)document.addEventListener("DOMContentLoaded",a,!1),window.addEventListener("load",a,!1);else if(document.attachEvent){document.attachEvent("onreadystatechange",a);window.attachEvent("onload",a);b=!1;try{b=
12!window.frameElement}catch(e){}if(document.documentElement.doScroll&&b){var d=function(){try{document.documentElement.doScroll("left")}catch(b){setTimeout(d,1);return}a()};d()}}}}()},d=window.CKEDITOR_GETURL;if(d){var g=b.getUrl;b.getUrl=function(a){return d.call(b,a)||g.call(b,a)}}return b}());
13/* jscs:enable */
14/* jshint ignore:end */
15
16if ( CKEDITOR.loader )
17 CKEDITOR.loader.load( 'ckeditor' );
18else {
19 // Set the script name to be loaded by the loader.
20 CKEDITOR._autoLoad = 'ckeditor';
21
22 // Include the loader script.
23 if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) {
24 var script = document.createElement( 'script' );
25 script.type = 'text/javascript';
26 script.src = CKEDITOR.getUrl( 'core/loader.js' );
27 document.body.appendChild( script );
28 } else {
29 document.write( '<script type="text/javascript" src="' + CKEDITOR.getUrl( 'core/loader.js' ) + '"></script>' );
30 }
31
32}
33
34/**
35 * The skin to load for all created instances, it may be the name of the skin
36 * folder inside the editor installation path, or the name and the path separated
37 * by a comma.
38 *
39 * **Note:** This is a global configuration that applies to all instances.
40 *
41 * CKEDITOR.skinName = 'moono';
42 *
43 * CKEDITOR.skinName = 'myskin,/customstuff/myskin/';
44 *
45 * @cfg {String} [skinName='moono-lisa']
46 * @member CKEDITOR
47 */
48CKEDITOR.skinName = 'moono-lisa';
diff --git a/sources/config.js b/sources/config.js
new file mode 100644
index 0000000..c3716d1
--- /dev/null
+++ b/sources/config.js
@@ -0,0 +1,17 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.editorConfig = function( config ) {
7
8 // %REMOVE_START%
9 // The configuration options below are needed when running CKEditor from source files.
10 config.plugins = 'dialogui,dialog,a11yhelp,dialogadvtab,basicstyles,panel,floatpanel,menu,contextmenu,resize,button,toolbar,elementspath,enterkey,entities,popup,filebrowser,floatingspace,listblock,richcombo,format,horizontalrule,htmlwriter,fakeobjects,iframe,wysiwygarea,image,indent,indentblock,indentlist,justify,link,list,liststyle,magicline,maximize,removeformat,showborders,sourcearea,tab,lineutils,clipboard,widgetselection,widget,oembed';
11 config.skin = 'moono';
12 // %REMOVE_END%
13
14 // Define changes to default configuration here. For example:
15 // config.language = 'fr';
16 // config.uiColor = '#AADC6E';
17};
diff --git a/sources/contents.css b/sources/contents.css
new file mode 100644
index 0000000..8571059
--- /dev/null
+++ b/sources/contents.css
@@ -0,0 +1,208 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6body
7{
8 /* Font */
9 font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
10 font-size: 12px;
11
12 /* Text color */
13 color: #333;
14
15 /* Remove the background color to make it transparent */
16 background-color: #fff;
17
18 margin: 20px;
19}
20
21.cke_editable
22{
23 font-size: 13px;
24 line-height: 1.6;
25
26 /* Fix for missing scrollbars with RTL texts. (#10488) */
27 word-wrap: break-word;
28}
29
30blockquote
31{
32 font-style: italic;
33 font-family: Georgia, Times, "Times New Roman", serif;
34 padding: 2px 0;
35 border-style: solid;
36 border-color: #ccc;
37 border-width: 0;
38}
39
40.cke_contents_ltr blockquote
41{
42 padding-left: 20px;
43 padding-right: 8px;
44 border-left-width: 5px;
45}
46
47.cke_contents_rtl blockquote
48{
49 padding-left: 8px;
50 padding-right: 20px;
51 border-right-width: 5px;
52}
53
54a
55{
56 color: #0782C1;
57}
58
59ol,ul,dl
60{
61 /* IE7: reset rtl list margin. (#7334) */
62 *margin-right: 0px;
63 /* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/
64 padding: 0 40px;
65}
66
67h1,h2,h3,h4,h5,h6
68{
69 font-weight: normal;
70 line-height: 1.2;
71}
72
73hr
74{
75 border: 0px;
76 border-top: 1px solid #ccc;
77}
78
79img.right
80{
81 border: 1px solid #ccc;
82 float: right;
83 margin-left: 15px;
84 padding: 5px;
85}
86
87img.left
88{
89 border: 1px solid #ccc;
90 float: left;
91 margin-right: 15px;
92 padding: 5px;
93}
94
95pre
96{
97 white-space: pre-wrap; /* CSS 2.1 */
98 word-wrap: break-word; /* IE7 */
99 -moz-tab-size: 4;
100 tab-size: 4;
101}
102
103.marker
104{
105 background-color: Yellow;
106}
107
108span[lang]
109{
110 font-style: italic;
111}
112
113figure
114{
115 text-align: center;
116 border: solid 1px #ccc;
117 border-radius: 2px;
118 background: rgba(0,0,0,0.05);
119 padding: 10px;
120 margin: 10px 20px;
121 display: inline-block;
122}
123
124figure > figcaption
125{
126 text-align: center;
127 display: block; /* For IE8 */
128}
129
130a > img {
131 padding: 1px;
132 margin: 1px;
133 border: none;
134 outline: 1px solid #0782C1;
135}
136
137/* Widget Styles */
138.code-featured
139{
140 border: 5px solid red;
141}
142
143.math-featured
144{
145 padding: 20px;
146 box-shadow: 0 0 2px rgba(200, 0, 0, 1);
147 background-color: rgba(255, 0, 0, 0.05);
148 margin: 10px;
149}
150
151.image-clean
152{
153 border: 0;
154 background: none;
155 padding: 0;
156}
157
158.image-clean > figcaption
159{
160 font-size: .9em;
161 text-align: right;
162}
163
164.image-grayscale
165{
166 background-color: white;
167 color: #666;
168}
169
170.image-grayscale img, img.image-grayscale
171{
172 filter: grayscale(100%);
173}
174
175.embed-240p
176{
177 max-width: 426px;
178 max-height: 240px;
179 margin:0 auto;
180}
181
182.embed-360p
183{
184 max-width: 640px;
185 max-height: 360px;
186 margin:0 auto;
187}
188
189.embed-480p
190{
191 max-width: 854px;
192 max-height: 480px;
193 margin:0 auto;
194}
195
196.embed-720p
197{
198 max-width: 1280px;
199 max-height: 720px;
200 margin:0 auto;
201}
202
203.embed-1080p
204{
205 max-width: 1920px;
206 max-height: 1080px;
207 margin:0 auto;
208}
diff --git a/sources/core/_bootstrap.js b/sources/core/_bootstrap.js
new file mode 100644
index 0000000..0163912
--- /dev/null
+++ b/sources/core/_bootstrap.js
@@ -0,0 +1,74 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview API initialization code.
8 */
9
10( function() {
11 // Disable HC detection in WebKit. (#5429)
12 if ( CKEDITOR.env.webkit )
13 CKEDITOR.env.hc = false;
14 else {
15 // Check whether high contrast is active by creating a colored border.
16 var hcDetect = CKEDITOR.dom.element.createFromHtml( '<div style="width:0;height:0;position:absolute;left:-10000px;' +
17 'border:1px solid;border-color:red blue"></div>', CKEDITOR.document );
18
19 hcDetect.appendTo( CKEDITOR.document.getHead() );
20
21 // Update CKEDITOR.env.
22 // Catch exception needed sometimes for FF. (#4230)
23 try {
24 var top = hcDetect.getComputedStyle( 'border-top-color' ),
25 right = hcDetect.getComputedStyle( 'border-right-color' );
26
27 // We need to check if getComputedStyle returned any value, because on FF
28 // it returnes empty string if CKEditor is loaded in hidden iframe. (#11121)
29 CKEDITOR.env.hc = !!( top && top == right );
30 } catch ( e ) {
31 CKEDITOR.env.hc = false;
32 }
33
34 hcDetect.remove();
35 }
36
37 if ( CKEDITOR.env.hc )
38 CKEDITOR.env.cssClass += ' cke_hc';
39
40 // Initially hide UI spaces when relevant skins are loading, later restored by skin css.
41 CKEDITOR.document.appendStyleText( '.cke{visibility:hidden;}' );
42
43 // Mark the editor as fully loaded.
44 CKEDITOR.status = 'loaded';
45 CKEDITOR.fireOnce( 'loaded' );
46
47 // Process all instances created by the "basic" implementation.
48 var pending = CKEDITOR._.pending;
49 if ( pending ) {
50 delete CKEDITOR._.pending;
51
52 for ( var i = 0; i < pending.length; i++ ) {
53 CKEDITOR.editor.prototype.constructor.apply( pending[ i ][ 0 ], pending[ i ][ 1 ] );
54 CKEDITOR.add( pending[ i ][ 0 ] );
55 }
56 }
57} )();
58
59/**
60 * Indicates that CKEditor is running on a High Contrast environment.
61 *
62 * if ( CKEDITOR.env.hc )
63 * alert( 'You\'re running on High Contrast mode. The editor interface will get adapted to provide you a better experience.' );
64 *
65 * @property {Boolean} hc
66 * @member CKEDITOR.env
67 */
68
69/**
70 * Fired when a CKEDITOR core object is fully loaded and ready for interaction.
71 *
72 * @event loaded
73 * @member CKEDITOR
74 */
diff --git a/sources/core/ckeditor.js b/sources/core/ckeditor.js
new file mode 100644
index 0000000..2756204
--- /dev/null
+++ b/sources/core/ckeditor.js
@@ -0,0 +1,204 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Contains the third and last part of the {@link CKEDITOR} object
8 * definition.
9 */
10
11/** @class CKEDITOR */
12
13// Remove the CKEDITOR.loadFullCore reference defined on ckeditor_basic.
14delete CKEDITOR.loadFullCore;
15
16/**
17 * Stores references to all editor instances created. The name of the properties
18 * in this object correspond to instance names, and their values contain the
19 * {@link CKEDITOR.editor} object representing them.
20 *
21 * alert( CKEDITOR.instances.editor1.name ); // 'editor1'
22 *
23 * @property {Object}
24 */
25CKEDITOR.instances = {};
26
27/**
28 * The document of the window storing the CKEDITOR object.
29 *
30 * alert( CKEDITOR.document.getBody().getName() ); // 'body'
31 *
32 * @property {CKEDITOR.dom.document}
33 */
34CKEDITOR.document = new CKEDITOR.dom.document( document );
35
36/**
37 * Adds an editor instance to the global {@link CKEDITOR} object. This function
38 * is available for internal use mainly.
39 *
40 * @param {CKEDITOR.editor} editor The editor instance to be added.
41 */
42CKEDITOR.add = function( editor ) {
43 CKEDITOR.instances[ editor.name ] = editor;
44
45 editor.on( 'focus', function() {
46 if ( CKEDITOR.currentInstance != editor ) {
47 CKEDITOR.currentInstance = editor;
48 CKEDITOR.fire( 'currentInstance' );
49 }
50 } );
51
52 editor.on( 'blur', function() {
53 if ( CKEDITOR.currentInstance == editor ) {
54 CKEDITOR.currentInstance = null;
55 CKEDITOR.fire( 'currentInstance' );
56 }
57 } );
58
59 CKEDITOR.fire( 'instance', null, editor );
60};
61
62/**
63 * Removes an editor instance from the global {@link CKEDITOR} object. This function
64 * is available for internal use only. External code must use {@link CKEDITOR.editor#method-destroy}.
65 *
66 * @private
67 * @param {CKEDITOR.editor} editor The editor instance to be removed.
68 */
69CKEDITOR.remove = function( editor ) {
70 delete CKEDITOR.instances[ editor.name ];
71};
72
73( function() {
74 var tpls = {};
75
76 /**
77 * Adds a named {@link CKEDITOR.template} instance to be reused among all editors.
78 * This will return the existing one if a template with same name is already
79 * defined. Additionally, it fires the "template" event to allow template source customization.
80 *
81 * @param {String} name The name which identifies a UI template.
82 * @param {String} source The source string for constructing this template.
83 * @returns {CKEDITOR.template} The created template instance.
84 */
85 CKEDITOR.addTemplate = function( name, source ) {
86 var tpl = tpls[ name ];
87 if ( tpl )
88 return tpl;
89
90 // Make it possible to customize the template through event.
91 var params = { name: name, source: source };
92 CKEDITOR.fire( 'template', params );
93
94 return ( tpls[ name ] = new CKEDITOR.template( params.source ) );
95 };
96
97 /**
98 * Retrieves a defined template created with {@link CKEDITOR#addTemplate}.
99 *
100 * @param {String} name The template name.
101 */
102 CKEDITOR.getTemplate = function( name ) {
103 return tpls[ name ];
104 };
105} )();
106
107( function() {
108 var styles = [];
109
110 /**
111 * Adds CSS rules to be appended to the editor document.
112 * This method is mostly used by plugins to add custom styles to the editor
113 * document. For basic content styling the `contents.css` file should be
114 * used instead.
115 *
116 * **Note:** This function should be called before the creation of editor instances.
117 *
118 * // Add styles for all headings inside editable contents.
119 * CKEDITOR.addCss( '.cke_editable h1,.cke_editable h2,.cke_editable h3 { border-bottom: 1px dotted red }' );
120 *
121 * @param {String} css The style rules to be appended.
122 * @see CKEDITOR.config#contentsCss
123 */
124 CKEDITOR.addCss = function( css ) {
125 styles.push( css );
126 };
127
128 /**
129 * Returns a string will all CSS rules passed to the {@link CKEDITOR#addCss} method.
130 *
131 * @returns {String} A string containing CSS rules.
132 */
133 CKEDITOR.getCss = function() {
134 return styles.join( '\n' );
135 };
136} )();
137
138// Perform global clean up to free as much memory as possible
139// when there are no instances left
140CKEDITOR.on( 'instanceDestroyed', function() {
141 if ( CKEDITOR.tools.isEmpty( this.instances ) )
142 CKEDITOR.fire( 'reset' );
143} );
144
145// Load the bootstrap script.
146CKEDITOR.loader.load( '_bootstrap' ); // %REMOVE_LINE%
147
148// Tri-state constants.
149/**
150 * Used to indicate the ON or ACTIVE state.
151 *
152 * @readonly
153 * @property {Number} [=1]
154 */
155CKEDITOR.TRISTATE_ON = 1;
156
157/**
158 * Used to indicate the OFF or INACTIVE state.
159 *
160 * @readonly
161 * @property {Number} [=2]
162 */
163CKEDITOR.TRISTATE_OFF = 2;
164
165/**
166 * Used to indicate the DISABLED state.
167 *
168 * @readonly
169 * @property {Number} [=0]
170 */
171CKEDITOR.TRISTATE_DISABLED = 0;
172
173/**
174 * The editor which is currently active (has user focus).
175 *
176 * function showCurrentEditorName() {
177 * if ( CKEDITOR.currentInstance )
178 * alert( CKEDITOR.currentInstance.name );
179 * else
180 * alert( 'Please focus an editor first.' );
181 * }
182 *
183 * @property {CKEDITOR.editor} currentInstance
184 * @see CKEDITOR#event-currentInstance
185 */
186
187/**
188 * Fired when the CKEDITOR.currentInstance object reference changes. This may
189 * happen when setting the focus on different editor instances in the page.
190 *
191 * var editor; // A variable to store a reference to the current editor.
192 * CKEDITOR.on( 'currentInstance', function() {
193 * editor = CKEDITOR.currentInstance;
194 * } );
195 *
196 * @event currentInstance
197 */
198
199/**
200 * Fired when the last instance has been destroyed. This event is used to perform
201 * global memory cleanup.
202 *
203 * @event reset
204 */
diff --git a/sources/core/ckeditor_base.js b/sources/core/ckeditor_base.js
new file mode 100644
index 0000000..8c36b11
--- /dev/null
+++ b/sources/core/ckeditor_base.js
@@ -0,0 +1,318 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Contains the first and essential part of the {@link CKEDITOR}
8 * object definition.
9 */
10
11// #### Compressed Code
12// Compressed code in ckeditor.js must be be updated on changes in the script.
13// The Closure Compiler online service should be used when updating this manually:
14// http://closure-compiler.appspot.com/
15
16// #### Raw code
17// ATTENTION: read the above "Compressed Code" notes when changing this code.
18
19if ( !window.CKEDITOR ) {
20 /**
21 * This is the API entry point. The entire CKEditor code runs under this object.
22 * @class CKEDITOR
23 * @singleton
24 */
25 window.CKEDITOR = ( function() {
26 var basePathSrcPattern = /(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i;
27
28 var CKEDITOR = {
29
30 /**
31 * A constant string unique for each release of CKEditor. Its value
32 * is used, by default, to build the URL for all resources loaded
33 * by the editor code, guaranteeing clean cache results when
34 * upgrading.
35 *
36 * **Note:** There is [a known issue where "icons.png" does not include
37 * timestamp](http://dev.ckeditor.com/ticket/10685) and might get cached.
38 * We are working on having it fixed.
39 *
40 * alert( CKEDITOR.timestamp ); // e.g. '87dm'
41 */
42 timestamp: '', // %REMOVE_LINE%
43 /* // %REMOVE_LINE%
44 // The production implementation contains a fixed timestamp, unique
45 // for each release and generated by the releaser.
46 // (Base 36 value of each component of YYMMDDHH - 4 chars total - e.g. 87bm == 08071122)
47 timestamp: '%TIMESTAMP%',
48 // %REMOVE_LINE% */
49
50 /**
51 * Contains the CKEditor version number.
52 *
53 * alert( CKEDITOR.version ); // e.g. 'CKEditor 3.4.1'
54 */
55 version: '%VERSION%',
56
57 /**
58 * Contains the CKEditor revision number.
59 * The revision number is incremented automatically, following each
60 * modification to the CKEditor source code.
61 *
62 * alert( CKEDITOR.revision ); // e.g. '3975'
63 */
64 revision: '%REV%',
65
66 /**
67 * A 3-digit random integer, valid for the entire life of the CKEDITOR object.
68 *
69 * alert( CKEDITOR.rnd ); // e.g. 319
70 *
71 * @property {Number}
72 */
73 rnd: Math.floor( Math.random() * ( 999 /*Max*/ - 100 /*Min*/ + 1 ) ) + 100 /*Min*/,
74
75 /**
76 * Private object used to hold core stuff. It should not be used outside of
77 * the API code as properties defined here may change at any time
78 * without notice.
79 *
80 * @private
81 */
82 _: {
83 pending: [],
84 basePathSrcPattern: basePathSrcPattern
85 },
86
87 /**
88 * Indicates the API loading status. The following statuses are available:
89 *
90 * * **unloaded**: the API is not yet loaded.
91 * * **basic_loaded**: the basic API features are available.
92 * * **basic_ready**: the basic API is ready to load the full core code.
93 * * **loaded**: the API can be fully used.
94 *
95 * Example:
96 *
97 * if ( CKEDITOR.status == 'loaded' ) {
98 * // The API can now be fully used.
99 * doSomething();
100 * } else {
101 * // Wait for the full core to be loaded and fire its loading.
102 * CKEDITOR.on( 'load', doSomething );
103 * CKEDITOR.loadFullCore && CKEDITOR.loadFullCore();
104 * }
105 */
106 status: 'unloaded',
107
108 /**
109 * The full URL for the CKEditor installation directory.
110 * It is possible to manually provide the base path by setting a
111 * global variable named `CKEDITOR_BASEPATH`. This global variable
112 * must be set **before** the editor script loading.
113 *
114 * alert( CKEDITOR.basePath ); // e.g. 'http://www.example.com/ckeditor/'
115 *
116 * @property {String}
117 */
118 basePath: ( function() {
119 // Find out the editor directory path, based on its <script> tag.
120 var path = window.CKEDITOR_BASEPATH || '';
121
122 if ( !path ) {
123 var scripts = document.getElementsByTagName( 'script' );
124
125 for ( var i = 0; i < scripts.length; i++ ) {
126 var match = scripts[ i ].src.match( basePathSrcPattern );
127
128 if ( match ) {
129 path = match[ 1 ];
130 break;
131 }
132 }
133 }
134
135 // In IE (only) the script.src string is the raw value entered in the
136 // HTML source. Other browsers return the full resolved URL instead.
137 if ( path.indexOf( ':/' ) == -1 && path.slice( 0, 2 ) != '//' ) {
138 // Absolute path.
139 if ( path.indexOf( '/' ) === 0 )
140 path = location.href.match( /^.*?:\/\/[^\/]*/ )[ 0 ] + path;
141 // Relative path.
142 else
143 path = location.href.match( /^[^\?]*\/(?:)/ )[ 0 ] + path;
144 }
145
146 if ( !path )
147 throw 'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';
148
149 return path;
150 } )(),
151
152 /**
153 * Gets the full URL for CKEditor resources. By default, URLs
154 * returned by this function contain a querystring parameter ("t")
155 * set to the {@link CKEDITOR#timestamp} value.
156 *
157 * It is possible to provide a custom implementation of this
158 * function by setting a global variable named `CKEDITOR_GETURL`.
159 * This global variable must be set **before** the editor script
160 * loading. If the custom implementation returns nothing (`==null`), the
161 * default implementation is used.
162 *
163 * // e.g. 'http://www.example.com/ckeditor/skins/default/editor.css?t=87dm'
164 * alert( CKEDITOR.getUrl( 'skins/default/editor.css' ) );
165 *
166 * // e.g. 'http://www.example.com/skins/default/editor.css?t=87dm'
167 * alert( CKEDITOR.getUrl( '/skins/default/editor.css' ) );
168 *
169 * // e.g. 'http://www.somesite.com/skins/default/editor.css?t=87dm'
170 * alert( CKEDITOR.getUrl( 'http://www.somesite.com/skins/default/editor.css' ) );
171 *
172 * @param {String} resource The resource whose full URL we want to get.
173 * It may be a full, absolute, or relative URL.
174 * @returns {String} The full URL.
175 */
176 getUrl: function( resource ) {
177 // If this is not a full or absolute path.
178 if ( resource.indexOf( ':/' ) == -1 && resource.indexOf( '/' ) !== 0 )
179 resource = this.basePath + resource;
180
181 // Add the timestamp, except for directories.
182 if ( this.timestamp && resource.charAt( resource.length - 1 ) != '/' && !( /[&?]t=/ ).test( resource ) )
183 resource += ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + this.timestamp;
184
185 return resource;
186 },
187
188 /**
189 * Specify a function to execute when the DOM is fully loaded.
190 *
191 * If called after the DOM has been initialized, the function passed in will
192 * be executed immediately.
193 *
194 * @method
195 * @todo
196 */
197 domReady: ( function() {
198 // Based on the original jQuery code (available under the MIT license, see LICENSE.md).
199
200 var callbacks = [];
201
202 function onReady() {
203 try {
204 // Cleanup functions for the document ready method
205 if ( document.addEventListener ) {
206 document.removeEventListener( 'DOMContentLoaded', onReady, false );
207 executeCallbacks();
208 }
209 // Make sure body exists, at least, in case IE gets a little overzealous.
210 else if ( document.attachEvent && document.readyState === 'complete' ) {
211 document.detachEvent( 'onreadystatechange', onReady );
212 executeCallbacks();
213 }
214 } catch ( er ) {}
215 }
216
217 function executeCallbacks() {
218 var i;
219 while ( ( i = callbacks.shift() ) )
220 i();
221 }
222
223 return function( fn ) {
224 callbacks.push( fn );
225
226 // Catch cases where this is called after the
227 // browser event has already occurred.
228 if ( document.readyState === 'complete' )
229 // Handle it asynchronously to allow scripts the opportunity to delay ready
230 setTimeout( onReady, 1 );
231
232 // Run below once on demand only.
233 if ( callbacks.length != 1 )
234 return;
235
236 // For IE>8, Firefox, Opera and Webkit.
237 if ( document.addEventListener ) {
238 // Use the handy event callback
239 document.addEventListener( 'DOMContentLoaded', onReady, false );
240
241 // A fallback to window.onload, that will always work
242 window.addEventListener( 'load', onReady, false );
243
244 }
245 // If old IE event model is used
246 else if ( document.attachEvent ) {
247 // ensure firing before onload,
248 // maybe late but safe also for iframes
249 document.attachEvent( 'onreadystatechange', onReady );
250
251 // A fallback to window.onload, that will always work
252 window.attachEvent( 'onload', onReady );
253
254 // If IE and not a frame
255 // continually check to see if the document is ready
256 // use the trick by Diego Perini
257 // http://javascript.nwbox.com/IEContentLoaded/
258 var toplevel = false;
259
260 try {
261 toplevel = !window.frameElement;
262 } catch ( e ) {}
263
264 if ( document.documentElement.doScroll && toplevel ) {
265 scrollCheck();
266 }
267 }
268
269 function scrollCheck() {
270 try {
271 document.documentElement.doScroll( 'left' );
272 } catch ( e ) {
273 setTimeout( scrollCheck, 1 );
274 return;
275 }
276 onReady();
277 }
278 };
279
280 } )()
281 };
282
283 // Make it possible to override the "url" function with a custom
284 // implementation pointing to a global named CKEDITOR_GETURL.
285 var newGetUrl = window.CKEDITOR_GETURL;
286 if ( newGetUrl ) {
287 var originalGetUrl = CKEDITOR.getUrl;
288 CKEDITOR.getUrl = function( resource ) {
289 return newGetUrl.call( CKEDITOR, resource ) || originalGetUrl.call( CKEDITOR, resource );
290 };
291 }
292
293 return CKEDITOR;
294 } )();
295}
296
297/**
298 * Function called upon loading a custom configuration file that can
299 * modify the editor instance configuration ({@link CKEDITOR.editor#config}).
300 * It is usually defined inside the custom configuration files that can
301 * include developer defined settings.
302 *
303 * // This is supposed to be placed in the config.js file.
304 * CKEDITOR.editorConfig = function( config ) {
305 * // Define changes to default configuration here. For example:
306 * config.language = 'fr';
307 * config.uiColor = '#AADC6E';
308 * };
309 *
310 * @method editorConfig
311 * @param {CKEDITOR.config} config A configuration object containing the
312 * settings defined for a {@link CKEDITOR.editor} instance up to this
313 * function call. Note that not all settings may still be available. See
314 * [Configuration Loading Order](http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Setting_Configurations#Configuration_Loading_Order)
315 * for details.
316 */
317
318// PACKAGER_RENAME( CKEDITOR )
diff --git a/sources/core/ckeditor_basic.js b/sources/core/ckeditor_basic.js
new file mode 100644
index 0000000..c07e4d9
--- /dev/null
+++ b/sources/core/ckeditor_basic.js
@@ -0,0 +1,94 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Contains the second part of the {@link CKEDITOR} object
8 * definition, which defines the basic editor features to be available in
9 * the root ckeditor_basic.js file.
10 */
11
12if ( CKEDITOR.status == 'unloaded' ) {
13 ( function() {
14 CKEDITOR.event.implementOn( CKEDITOR );
15
16 /**
17 * Forces the full CKEditor core code, in the case only the basic code has been
18 * loaded (`ckeditor_basic.js`). This method self-destroys (becomes undefined) in
19 * the first call or as soon as the full code is available.
20 *
21 * // Check if the full core code has been loaded and load it.
22 * if ( CKEDITOR.loadFullCore )
23 * CKEDITOR.loadFullCore();
24 *
25 * @member CKEDITOR
26 */
27 CKEDITOR.loadFullCore = function() {
28 // If the basic code is not ready, just mark it to be loaded.
29 if ( CKEDITOR.status != 'basic_ready' ) {
30 CKEDITOR.loadFullCore._load = 1;
31 return;
32 }
33
34 // Destroy this function.
35 delete CKEDITOR.loadFullCore;
36
37 // Append the script to the head.
38 var script = document.createElement( 'script' );
39 script.type = 'text/javascript';
40 script.src = CKEDITOR.basePath + 'ckeditor.js';
41 script.src = CKEDITOR.basePath + 'ckeditor_source.js'; // %REMOVE_LINE%
42
43 document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
44 };
45
46 /**
47 * The time to wait (in seconds) to load the full editor code after the
48 * page load, if the "ckeditor_basic" file is used. If set to zero, the
49 * editor is loaded on demand, as soon as an instance is created.
50 *
51 * This value must be set on the page before the page load completion.
52 *
53 * // Loads the full source after five seconds.
54 * CKEDITOR.loadFullCoreTimeout = 5;
55 *
56 * @property
57 * @member CKEDITOR
58 */
59 CKEDITOR.loadFullCoreTimeout = 0;
60
61 // Documented at ckeditor.js.
62 CKEDITOR.add = function( editor ) {
63 // For now, just put the editor in the pending list. It will be
64 // processed as soon as the full code gets loaded.
65 var pending = this._.pending || ( this._.pending = [] );
66 pending.push( editor );
67 };
68
69 ( function() {
70 var onload = function() {
71 var loadFullCore = CKEDITOR.loadFullCore,
72 loadFullCoreTimeout = CKEDITOR.loadFullCoreTimeout;
73
74 if ( !loadFullCore )
75 return;
76
77 CKEDITOR.status = 'basic_ready';
78
79 if ( loadFullCore && loadFullCore._load )
80 loadFullCore();
81 else if ( loadFullCoreTimeout ) {
82 setTimeout( function() {
83 if ( CKEDITOR.loadFullCore )
84 CKEDITOR.loadFullCore();
85 }, loadFullCoreTimeout * 1000 );
86 }
87 };
88
89 CKEDITOR.domReady( onload );
90 } )();
91
92 CKEDITOR.status = 'basic_loaded';
93 } )();
94}
diff --git a/sources/core/command.js b/sources/core/command.js
new file mode 100644
index 0000000..0446d24
--- /dev/null
+++ b/sources/core/command.js
@@ -0,0 +1,275 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Represents a command that can be executed on an editor instance.
8 *
9 * var command = new CKEDITOR.command( editor, {
10 * exec: function( editor ) {
11 * alert( editor.document.getBody().getHtml() );
12 * }
13 * } );
14 *
15 * @class
16 * @extends CKEDITOR.commandDefinition
17 * @mixins CKEDITOR.event
18 * @constructor Creates a command class instance.
19 * @param {CKEDITOR.editor} editor The editor instance this command will be
20 * related to.
21 * @param {CKEDITOR.commandDefinition} commandDefinition The command
22 * definition.
23 */
24CKEDITOR.command = function( editor, commandDefinition ) {
25 /**
26 * Lists UI items that are associated to this command. This list can be
27 * used to interact with the UI on command execution (by the execution code
28 * itself, for example).
29 *
30 * alert( 'Number of UI items associated to this command: ' + command.uiItems.length );
31 */
32 this.uiItems = [];
33
34 /**
35 * Executes the command.
36 *
37 * command.exec(); // The command gets executed.
38 *
39 * **Note:** You should use the {@link CKEDITOR.editor#execCommand} method instead of calling
40 * `command.exec()` directly.
41 *
42 * @param {Object} [data] Any data to pass to the command. Depends on the
43 * command implementation and requirements.
44 * @returns {Boolean} A boolean indicating that the command has been successfully executed.
45 */
46 this.exec = function( data ) {
47 if ( this.state == CKEDITOR.TRISTATE_DISABLED || !this.checkAllowed() )
48 return false;
49
50 if ( this.editorFocus ) // Give editor focus if necessary (#4355).
51 editor.focus();
52
53 if ( this.fire( 'exec' ) === false )
54 return true;
55
56 return ( commandDefinition.exec.call( this, editor, data ) !== false );
57 };
58
59 /**
60 * Explicitly update the status of the command, by firing the {@link CKEDITOR.command#event-refresh} event,
61 * as well as invoke the {@link CKEDITOR.commandDefinition#refresh} method if defined, this method
62 * is to allow different parts of the editor code to contribute in command status resolution.
63 *
64 * @param {CKEDITOR.editor} editor The editor instance.
65 * @param {CKEDITOR.dom.elementPath} path
66 */
67 this.refresh = function( editor, path ) {
68 // Do nothing is we're on read-only and this command doesn't support it.
69 // We don't need to disabled the command explicitely here, because this
70 // is already done by the "readOnly" event listener.
71 if ( !this.readOnly && editor.readOnly )
72 return true;
73
74 // Disable commands that are not allowed in the current selection path context.
75 if ( this.context && !path.isContextFor( this.context ) ) {
76 this.disable();
77 return true;
78 }
79
80 // Disable commands that are not allowed by the active filter.
81 if ( !this.checkAllowed( true ) ) {
82 this.disable();
83 return true;
84 }
85
86 // Make the "enabled" state a default for commands enabled from start.
87 if ( !this.startDisabled )
88 this.enable();
89
90 // Disable commands which shouldn't be enabled in this mode.
91 if ( this.modes && !this.modes[ editor.mode ] )
92 this.disable();
93
94 if ( this.fire( 'refresh', { editor: editor, path: path } ) === false )
95 return true;
96
97 return ( commandDefinition.refresh && commandDefinition.refresh.apply( this, arguments ) !== false );
98 };
99
100 var allowed;
101
102 /**
103 * Checks whether this command is allowed by the active allowed
104 * content filter ({@link CKEDITOR.editor#activeFilter}). This means
105 * that if command implements {@link CKEDITOR.feature} interface it will be tested
106 * by the {@link CKEDITOR.filter#checkFeature} method.
107 *
108 * @since 4.1
109 * @param {Boolean} [noCache] Skip cache for example due to active filter change. Since CKEditor 4.2.
110 * @returns {Boolean} Whether this command is allowed.
111 */
112 this.checkAllowed = function( noCache ) {
113 if ( !noCache && typeof allowed == 'boolean' )
114 return allowed;
115
116 return allowed = editor.activeFilter.checkFeature( this );
117 };
118
119 CKEDITOR.tools.extend( this, commandDefinition, {
120 /**
121 * The editor modes within which the command can be executed. The
122 * execution will have no action if the current mode is not listed
123 * in this property.
124 *
125 * // Enable the command in both WYSIWYG and Source modes.
126 * command.modes = { wysiwyg:1,source:1 };
127 *
128 * // Enable the command in Source mode only.
129 * command.modes = { source:1 };
130 *
131 * @see CKEDITOR.editor#mode
132 */
133 modes: { wysiwyg: 1 },
134
135 /**
136 * Indicates that the editor will get the focus before executing
137 * the command.
138 *
139 * // Do not force the editor to have focus when executing the command.
140 * command.editorFocus = false;
141 *
142 * @property {Boolean} [=true]
143 */
144 editorFocus: 1,
145
146 /**
147 * Indicates that this command is sensible to the selection context.
148 * If `true`, the {@link CKEDITOR.command#method-refresh} method will be
149 * called for this command on the {@link CKEDITOR.editor#event-selectionChange} event.
150 *
151 * @property {Boolean} [=false]
152 */
153 contextSensitive: !!commandDefinition.context,
154
155 /**
156 * Indicates the editor state. Possible values are:
157 *
158 * * {@link CKEDITOR#TRISTATE_DISABLED}: the command is
159 * disabled. It's execution will have no effect. Same as {@link #disable}.
160 * * {@link CKEDITOR#TRISTATE_ON}: the command is enabled
161 * and currently active in the editor (for context sensitive commands, for example).
162 * * {@link CKEDITOR#TRISTATE_OFF}: the command is enabled
163 * and currently inactive in the editor (for context sensitive commands, for example).
164 *
165 * Do not set this property directly, using the {@link #setState} method instead.
166 *
167 * if ( command.state == CKEDITOR.TRISTATE_DISABLED )
168 * alert( 'This command is disabled' );
169 *
170 * @property {Number} [=CKEDITOR.TRISTATE_DISABLED]
171 */
172 state: CKEDITOR.TRISTATE_DISABLED
173 } );
174
175 // Call the CKEDITOR.event constructor to initialize this instance.
176 CKEDITOR.event.call( this );
177};
178
179CKEDITOR.command.prototype = {
180 /**
181 * Enables the command for execution. The command state (see
182 * {@link CKEDITOR.command#property-state}) available before disabling it is restored.
183 *
184 * command.enable();
185 * command.exec(); // Execute the command.
186 */
187 enable: function() {
188 if ( this.state == CKEDITOR.TRISTATE_DISABLED && this.checkAllowed() )
189 this.setState( ( !this.preserveState || ( typeof this.previousState == 'undefined' ) ) ? CKEDITOR.TRISTATE_OFF : this.previousState );
190 },
191
192 /**
193 * Disables the command for execution. The command state (see
194 * {@link CKEDITOR.command#property-state}) will be set to {@link CKEDITOR#TRISTATE_DISABLED}.
195 *
196 * command.disable();
197 * command.exec(); // "false" - Nothing happens.
198 */
199 disable: function() {
200 this.setState( CKEDITOR.TRISTATE_DISABLED );
201 },
202
203 /**
204 * Sets the command state.
205 *
206 * command.setState( CKEDITOR.TRISTATE_ON );
207 * command.exec(); // Execute the command.
208 * command.setState( CKEDITOR.TRISTATE_DISABLED );
209 * command.exec(); // 'false' - Nothing happens.
210 * command.setState( CKEDITOR.TRISTATE_OFF );
211 * command.exec(); // Execute the command.
212 *
213 * @param {Number} newState The new state. See {@link #property-state}.
214 * @returns {Boolean} Returns `true` if the command state changed.
215 */
216 setState: function( newState ) {
217 // Do nothing if there is no state change.
218 if ( this.state == newState )
219 return false;
220
221 if ( newState != CKEDITOR.TRISTATE_DISABLED && !this.checkAllowed() )
222 return false;
223
224 this.previousState = this.state;
225
226 // Set the new state.
227 this.state = newState;
228
229 // Fire the "state" event, so other parts of the code can react to the
230 // change.
231 this.fire( 'state' );
232
233 return true;
234 },
235
236 /**
237 * Toggles the on/off (active/inactive) state of the command. This is
238 * mainly used internally by context sensitive commands.
239 *
240 * command.toggleState();
241 */
242 toggleState: function() {
243 if ( this.state == CKEDITOR.TRISTATE_OFF )
244 this.setState( CKEDITOR.TRISTATE_ON );
245 else if ( this.state == CKEDITOR.TRISTATE_ON )
246 this.setState( CKEDITOR.TRISTATE_OFF );
247 }
248};
249
250CKEDITOR.event.implementOn( CKEDITOR.command.prototype );
251
252/**
253 * Indicates the previous command state.
254 *
255 * alert( command.previousState );
256 *
257 * @property {Number} previousState
258 * @see #state
259 */
260
261/**
262 * Fired when the command state changes.
263 *
264 * command.on( 'state', function() {
265 * // Alerts the new state.
266 * alert( this.state );
267 * } );
268 *
269 * @event state
270 */
271
272 /**
273 * @event refresh
274 * @todo
275 */
diff --git a/sources/core/commanddefinition.js b/sources/core/commanddefinition.js
new file mode 100644
index 0000000..10a040f
--- /dev/null
+++ b/sources/core/commanddefinition.js
@@ -0,0 +1,162 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the "virtual" {@link CKEDITOR.commandDefinition} class
8 * which contains the defintion of a command. This file is for
9 * documentation purposes only.
10 */
11
12/**
13 * Virtual class that illustrates the features of command objects to be
14 * passed to the {@link CKEDITOR.editor#addCommand} function.
15 *
16 * @class CKEDITOR.commandDefinition
17 * @abstract
18 */
19
20/**
21 * The function to be fired when the commend is executed.
22 *
23 * editorInstance.addCommand( 'sample', {
24 * exec: function( editor ) {
25 * alert( 'Executing a command for the editor name "' + editor.name + '"!' );
26 * }
27 * } );
28 *
29 * @method exec
30 * @param {CKEDITOR.editor} editor The editor within which to run the command.
31 * @param {Object} [data] Additional data to be used to execute the command.
32 * @returns {Boolean} Whether the command has been successfully executed.
33 * Defaults to `true` if nothing is returned.
34 */
35
36/**
37 * Whether the command needs to be hooked into the redo/undo system.
38 *
39 * editorInstance.addCommand( 'alertName', {
40 * exec: function( editor ) {
41 * alert( editor.name );
42 * },
43 * canUndo: false // No support for undo/redo.
44 * } );
45 *
46 * @property {Boolean} [canUndo=true]
47 */
48
49/**
50 * Whether the command is asynchronous, which means that the
51 * {@link CKEDITOR.editor#event-afterCommandExec} event will be fired by the
52 * command itself manually, and that the return value of this command is not to
53 * be returned by the {@link #exec} function.
54 *
55 * editorInstance.addCommand( 'loadoptions', {
56 * exec: function( editor ) {
57 * var cmd = this;
58 * // Asynchronous operation below.
59 * CKEDITOR.ajax.loadXml( 'data.xml', function() {
60 * editor.fire( 'afterCommandExec', {
61 * name: 'loadoptions',
62 * command: cmd
63 * } );
64 * } );
65 * },
66 * async: true // The command needs some time to complete after the exec function returns.
67 * } );
68 *
69 * @property {Boolean} [async=false]
70 */
71
72/**
73 * Whether the command should give focus to the editor before execution.
74 *
75 * editorInstance.addCommand( 'maximize', {
76 * exec: function( editor ) {
77 * // ...
78 * },
79 * editorFocus: false // The command does not require focusing the editing document.
80 * } );
81 *
82 * See also {@link CKEDITOR.command#editorFocus}.
83 *
84 * @property {Boolean} [editorFocus=true]
85 */
86
87
88/**
89 * Whether the command state should be set to {@link CKEDITOR#TRISTATE_DISABLED} on startup.
90 *
91 * editorInstance.addCommand( 'unlink', {
92 * exec: function( editor ) {
93 * // ...
94 * },
95 * startDisabled: true // The command is unavailable until the selection is inside a link.
96 * } );
97 *
98 * @property {Boolean} [startDisabled=false]
99 */
100
101/**
102 * Indicates that this command is sensitive to the selection context.
103 * If `true`, the {@link CKEDITOR.command#method-refresh} method will be
104 * called for this command on selection changes, with a single parameter
105 * representing the current elements path.
106 *
107 * @property {Boolean} [contextSensitive=true]
108 */
109
110/**
111 * Defined by the command definition, a function to determine the command state. It will be invoked
112 * when the editor has its `states` or `selection` changed.
113 *
114 * **Note:** The function provided must be calling {@link CKEDITOR.command#setState} in all circumstances
115 * if it is intended to update the command state.
116 *
117 * @method refresh
118 * @param {CKEDITOR.editor} editor
119 * @param {CKEDITOR.dom.elementPath} path
120 */
121
122/**
123 * Sets the element name used to reflect the command state on selection changes.
124 * If the selection is in a place where the element is not allowed, the command
125 * will be disabled.
126 * Setting this property overrides {@link #contextSensitive} to `true`.
127 *
128 * @property {Boolean} [context=true]
129 */
130
131/**
132 * The editor modes within which the command can be executed. The execution
133 * will have no action if the current mode is not listed in this property.
134 *
135 * editorInstance.addCommand( 'link', {
136 * exec: function( editor ) {
137 * // ...
138 * },
139 * modes: { wysiwyg:1 } // The command is available in wysiwyg mode only.
140 * } );
141 *
142 * See also {@link CKEDITOR.command#modes}.
143 *
144 * @property {Object} [modes={ wysiwyg:1 }]
145 */
146
147/**
148 * Whether the command should be enabled in the {@link CKEDITOR.editor#setReadOnly read-only mode}.
149 *
150 * @since 4.0
151 * @property {Boolean} [readOnly=false]
152 */
153
154/**
155 * A property that should be set when a command has no keystroke assigned by {@link CKEDITOR.editor#setKeystroke}, but
156 * the keystroke is still supported. For example: `cut`, `copy` and `paste` commands are handled that way.
157 * This property is used when displaying keystroke information in tooltips and context menus. It is used by
158 * {@link CKEDITOR.editor#getCommandKeystroke}.
159 *
160 * @since 4.6.0
161 * @property {Number} fakeKeystroke
162 */
diff --git a/sources/core/config.js b/sources/core/config.js
new file mode 100644
index 0000000..f0f4aec
--- /dev/null
+++ b/sources/core/config.js
@@ -0,0 +1,451 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.config} object that stores the
8 * default configuration settings.
9 */
10
11/**
12 * Used in conjunction with the {@link CKEDITOR.config#enterMode}
13 * and {@link CKEDITOR.config#shiftEnterMode} configuration
14 * settings to make the editor produce `<p>` tags when
15 * using the <kbd>Enter</kbd> key.
16 *
17 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
18 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
19 *
20 * @readonly
21 * @property {Number} [=1]
22 * @member CKEDITOR
23 */
24CKEDITOR.ENTER_P = 1;
25
26/**
27 * Used in conjunction with the {@link CKEDITOR.config#enterMode}
28 * and {@link CKEDITOR.config#shiftEnterMode} configuration
29 * settings to make the editor produce `<br>` tags when
30 * using the <kbd>Enter</kbd> key.
31 *
32 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
33 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
34 *
35 * @readonly
36 * @property {Number} [=2]
37 * @member CKEDITOR
38 */
39CKEDITOR.ENTER_BR = 2;
40
41/**
42 * Used in conjunction with the {@link CKEDITOR.config#enterMode}
43 * and {@link CKEDITOR.config#shiftEnterMode} configuration
44 * settings to make the editor produce `<div>` tags when
45 * using the <kbd>Enter</kbd> key.
46 *
47 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
48 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
49 *
50 * @readonly
51 * @property {Number} [=3]
52 * @member CKEDITOR
53 */
54CKEDITOR.ENTER_DIV = 3;
55
56/**
57 * Stores default configuration settings. Changes to this object are
58 * reflected in all editor instances, if not specified otherwise for a particular
59 * instance.
60 *
61 * Read more about setting CKEditor configuration in the
62 * [documentation](#!/guide/dev_configuration).
63 *
64 * @class
65 * @singleton
66 */
67CKEDITOR.config = {
68 /**
69 * The URL path to the custom configuration file to be loaded. If not
70 * overwritten with inline configuration, it defaults to the `config.js`
71 * file present in the root of the CKEditor installation directory.
72 *
73 * CKEditor will recursively load custom configuration files defined inside
74 * other custom configuration files.
75 *
76 * Read more about setting CKEditor configuration in the
77 * [documentation](#!/guide/dev_configuration).
78 *
79 * // Load a specific configuration file.
80 * CKEDITOR.replace( 'myfield', { customConfig: '/myconfig.js' } );
81 *
82 * // Do not load any custom configuration file.
83 * CKEDITOR.replace( 'myfield', { customConfig: '' } );
84 *
85 * @cfg {String} [="<CKEditor folder>/config.js"]
86 */
87 customConfig: 'config.js',
88
89 /**
90 * Whether the element replaced by the editor (usually a `<textarea>`)
91 * is to be updated automatically when posting the form containing the editor.
92 *
93 * @cfg
94 */
95 autoUpdateElement: true,
96
97 /**
98 * The user interface language localization to use. If left empty, the editor
99 * will automatically be localized to the user language. If the user language is not supported,
100 * the language specified in the {@link CKEDITOR.config#defaultLanguage}
101 * configuration setting is used.
102 *
103 * Read more in the [documentation](#!/guide/dev_uilanguage) and see the
104 * [SDK sample](http://sdk.ckeditor.com/samples/uilanguages.html).
105 *
106 * // Load the German interface.
107 * config.language = 'de';
108 *
109 * @cfg
110 */
111 language: '',
112
113 /**
114 * The language to be used if the {@link CKEDITOR.config#language}
115 * setting is left empty and it is not possible to localize the editor to the user language.
116 *
117 * Read more in the [documentation](#!/guide/dev_uilanguage) and see the
118 * [SDK sample](http://sdk.ckeditor.com/samples/uilanguages.html).
119 *
120 * config.defaultLanguage = 'it';
121 *
122 * @cfg
123 */
124 defaultLanguage: 'en',
125
126 /**
127 * The writing direction of the language which is used to create editor content.
128 * Allowed values are:
129 *
130 * * `''` (an empty string) &ndash; Indicates that content direction will be the same as either
131 * the editor UI direction or the page element direction depending on the editor type:
132 * * [Classic editor](#!/guide/dev_framed) &ndash; The same as the user interface language direction.
133 * * [Inline editor](#!/guide/dev_inline)&ndash; The same as the editable element text direction.
134 * * `'ltr'` &ndash; Indicates a Left-To-Right text direction (like in English).
135 * * `'rtl'` &ndash; Indicates a Right-To-Left text direction (like in Arabic).
136 *
137 * See the [SDK sample](http://sdk.ckeditor.com/samples/language.html).
138 *
139 * Example:
140 *
141 * config.contentsLangDirection = 'rtl';
142 *
143 * @cfg
144 */
145 contentsLangDirection: '',
146
147 /**
148 * Sets the behavior of the <kbd>Enter</kbd> key. It also determines other behavior
149 * rules of the editor, like whether the `<br>` element is to be used
150 * as a paragraph separator when indenting text.
151 * The allowed values are the following constants that cause the behavior outlined below:
152 *
153 * * {@link CKEDITOR#ENTER_P} (1) &ndash; New `<p>` paragraphs are created.
154 * * {@link CKEDITOR#ENTER_BR} (2) &ndash; Lines are broken with `<br>` elements.
155 * * {@link CKEDITOR#ENTER_DIV} (3) &ndash; New `<div>` blocks are created.
156 *
157 * **Note**: It is recommended to use the {@link CKEDITOR#ENTER_P} setting because of
158 * its semantic value and correctness. The editor is optimized for this setting.
159 *
160 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
161 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
162 *
163 * // Not recommended.
164 * config.enterMode = CKEDITOR.ENTER_BR;
165 *
166 * @cfg {Number} [=CKEDITOR.ENTER_P]
167 */
168 enterMode: CKEDITOR.ENTER_P,
169
170 /**
171 * Forces the use of {@link CKEDITOR.config#enterMode} as line break regardless
172 * of the context. If, for example, {@link CKEDITOR.config#enterMode} is set
173 * to {@link CKEDITOR#ENTER_P}, pressing the <kbd>Enter</kbd> key inside a
174 * `<div>` element will create a new paragraph with a `<p>`
175 * instead of a `<div>`.
176 *
177 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
178 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
179 *
180 * // Not recommended.
181 * config.forceEnterMode = true;
182 *
183 * @since 3.2.1
184 * @cfg
185 */
186 forceEnterMode: false,
187
188 /**
189 * Similarly to the {@link CKEDITOR.config#enterMode} setting, it defines the behavior
190 * of the <kbd>Shift+Enter</kbd> key combination.
191 *
192 * The allowed values are the following constants that cause the behavior outlined below:
193 *
194 * * {@link CKEDITOR#ENTER_P} (1) &ndash; New `<p>` paragraphs are created.
195 * * {@link CKEDITOR#ENTER_BR} (2) &ndash; Lines are broken with `<br>` elements.
196 * * {@link CKEDITOR#ENTER_DIV} (3) &ndash; New `<div>` blocks are created.
197 *
198 * Read more in the [documentation](#!/guide/dev_enterkey) and see the
199 * [SDK sample](http://sdk.ckeditor.com/samples/enterkey.html).
200 *
201 * Example:
202 *
203 * config.shiftEnterMode = CKEDITOR.ENTER_P;
204 *
205 * @cfg {Number} [=CKEDITOR.ENTER_BR]
206 */
207 shiftEnterMode: CKEDITOR.ENTER_BR,
208
209 /**
210 * Sets the `DOCTYPE` to be used when loading the editor content as HTML.
211 *
212 * // Set the DOCTYPE to the HTML 4 (Quirks) mode.
213 * config.docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
214 *
215 * @cfg
216 */
217 docType: '<!DOCTYPE html>',
218
219 /**
220 * Sets the `id` attribute to be used on the `body` element
221 * of the editing area. This can be useful when you intend to reuse the original CSS
222 * file you are using on your live website and want to assign the editor the same ID
223 * as the section that will include the contents. In this way ID-specific CSS rules will
224 * be enabled.
225 *
226 * config.bodyId = 'contents_id';
227 *
228 * @since 3.1
229 * @cfg
230 */
231 bodyId: '',
232
233 /**
234 * Sets the `class` attribute to be used on the `body` element
235 * of the editing area. This can be useful when you intend to reuse the original CSS
236 * file you are using on your live website and want to assign the editor the same class
237 * as the section that will include the contents. In this way class-specific CSS rules will
238 * be enabled.
239 *
240 * config.bodyClass = 'contents';
241 *
242 * **Note:** The editor needs to load stylesheets containing contents styles. You can either
243 * copy them to the `contents.css` file that the editor loads by default or set the {@link #contentsCss}
244 * option.
245 *
246 * **Note:** This setting only applies to [classic editor](#!/guide/dev_framed) (the one that uses `iframe`).
247 *
248 * @since 3.1
249 * @cfg
250 */
251 bodyClass: '',
252
253 /**
254 * Indicates whether the content to be edited is being input as a full HTML page.
255 * A full page includes the `<html>`, `<head>`, and `<body>` elements.
256 * The final output will also reflect this setting, including the
257 * `<body>` content only if this setting is disabled.
258 *
259 * Read more in the [documentation](#!/guide/dev_fullpage) and see the
260 * [SDK sample](http://sdk.ckeditor.com/samples/fullpage.html).
261 *
262 * config.fullPage = true;
263 *
264 * @since 3.1
265 * @cfg
266 */
267 fullPage: false,
268
269 /**
270 * The height of the editing area that includes the editor content. This configuration
271 * option accepts an integer (to denote a value in pixels) or any CSS-defined length unit
272 * except percent (`%`) values which are not supported.
273 *
274 * **Note:** This configuration option is ignored by [inline editor](#!/guide/dev_inline).
275 *
276 * Read more in the [documentation](#!/guide/dev_size) and see the
277 * [SDK sample](http://sdk.ckeditor.com/samples/size.html).
278 *
279 * config.height = 500; // 500 pixels.
280 * config.height = '25em'; // CSS length.
281 * config.height = '300px'; // CSS length.
282 *
283 * @cfg {Number/String}
284 */
285 height: 200,
286
287 /**
288 * The CSS file(s) to be used to apply style to editor content. It should
289 * reflect the CSS used in the target pages where the content is to be
290 * displayed.
291 *
292 * **Note:** This configuration value is ignored by [inline editor](#!/guide/dev_inline)
293 * as it uses the styles that come directly from the page that CKEditor is
294 * rendered on. It is also ignored in the {@link #fullPage full page mode} in
295 * which the developer has full control over the page HTML code.
296 *
297 * Read more in the [documentation](#!/guide/dev_styles) and see the
298 * [SDK sample](http://sdk.ckeditor.com/samples/styles.html).
299 *
300 * config.contentsCss = '/css/mysitestyles.css';
301 * config.contentsCss = [ '/css/mysitestyles.css', '/css/anotherfile.css' ];
302 *
303 * @cfg {String/Array} [contentsCss=CKEDITOR.getUrl( 'contents.css' )]
304 */
305 contentsCss: CKEDITOR.getUrl( 'contents.css' ),
306
307 /**
308 * Comma-separated list of plugins to be used in an editor instance. Note that
309 * the actual plugins that are to be loaded could still be affected by two other settings:
310 * {@link CKEDITOR.config#extraPlugins} and {@link CKEDITOR.config#removePlugins}.
311 *
312 * @cfg {String} [="<default list of plugins>"]
313 */
314 plugins: '', // %REMOVE_LINE%
315
316 /**
317 * A list of additional plugins to be loaded. This setting makes it easier
318 * to add new plugins without having to touch the {@link CKEDITOR.config#plugins} setting.
319 *
320 * **Note:** The most recommended way to
321 * [add CKEditor plugins](http://docs.ckeditor.com/#!/guide/dev_plugins) is through
322 * [CKEditor Builder](http://ckeditor.com/builder). Read more in the
323 * [documentation](#!/guide/dev_plugins).
324 *
325 * config.extraPlugins = 'myplugin,anotherplugin';
326 *
327 * @cfg
328 */
329 extraPlugins: '',
330
331 /**
332 * A list of plugins that must not be loaded. This setting makes it possible
333 * to avoid loading some plugins defined in the {@link CKEDITOR.config#plugins}
334 * setting without having to touch it.
335 *
336 * **Note:** A plugin required by another plugin cannot be removed and will cause
337 * an error to be thrown. So for example if `contextmenu` is required by `tabletools`,
338 * it can only be removed if `tabletools` is not loaded.
339 *
340 * config.removePlugins = 'elementspath,save,font';
341 *
342 * @cfg
343 */
344 removePlugins: '',
345
346 /**
347 * A list of regular expressions to be executed on input HTML,
348 * indicating HTML source code that when matched, must **not** be available in the WYSIWYG
349 * mode for editing.
350 *
351 * config.protectedSource.push( /<\?[\s\S]*?\?>/g ); // PHP code
352 * config.protectedSource.push( /<%[\s\S]*?%>/g ); // ASP code
353 * config.protectedSource.push( /(<asp:[^\>]+>[\s|\S]*?<\/asp:[^\>]+>)|(<asp:[^\>]+\/>)/gi ); // ASP.NET code
354 *
355 * @cfg
356 */
357 protectedSource: [],
358
359 /**
360 * The editor `tabindex` value.
361 *
362 * Read more in the [documentation](#!/guide/dev_tabindex) and see the
363 * [SDK sample](http://sdk.ckeditor.com/samples/tabindex.html).
364 *
365 * config.tabIndex = 1;
366 *
367 * @cfg
368 */
369 tabIndex: 0,
370
371 /**
372 * The editor UI outer width. This configuration option accepts an integer
373 * (to denote a value in pixels) or any CSS-defined length unit.
374 *
375 * Unlike the {@link CKEDITOR.config#height} setting, this
376 * one will set the outer width of the entire editor UI, not for the
377 * editing area only.
378 *
379 * **Note:** This configuration option is ignored by [inline editor](#!/guide/dev_inline).
380 *
381 * Read more in the [documentation](#!/guide/dev_size) and see the
382 * [SDK sample](http://sdk.ckeditor.com/samples/size.html).
383 *
384 * config.width = 850; // 850 pixels wide.
385 * config.width = '75%'; // CSS unit.
386 *
387 * @cfg {String/Number}
388 */
389 width: '',
390
391 /**
392 * The base Z-index for floating dialog windows and popups.
393 *
394 * config.baseFloatZIndex = 2000;
395 *
396 * @cfg
397 */
398 baseFloatZIndex: 10000,
399
400 /**
401 * The keystrokes that are blocked by default as the browser implementation
402 * is buggy. These default keystrokes are handled by the editor.
403 *
404 * // Default setting.
405 * config.blockedKeystrokes = [
406 * CKEDITOR.CTRL + 66, // Ctrl+B
407 * CKEDITOR.CTRL + 73, // Ctrl+I
408 * CKEDITOR.CTRL + 85 // Ctrl+U
409 * ];
410 *
411 * @cfg {Array} [blockedKeystrokes=see example]
412 */
413 blockedKeystrokes: [
414 CKEDITOR.CTRL + 66, // Ctrl+B
415 CKEDITOR.CTRL + 73, // Ctrl+I
416 CKEDITOR.CTRL + 85 // Ctrl+U
417 ]
418};
419
420/**
421 * Indicates that some of the editor features, like alignment and text
422 * direction, should use the "computed value" of the feature to indicate its
423 * on/off state instead of using the "real value".
424 *
425 * If enabled in a Left-To-Right written document, the "Left Justify"
426 * alignment button will be shown as active, even if the alignment style is not
427 * explicitly applied to the current paragraph in the editor.
428 *
429 * config.useComputedState = false;
430 *
431 * @since 3.4
432 * @cfg {Boolean} [useComputedState=true]
433 */
434
435/**
436 * The base user interface color to be used by the editor. Not all skins are
437 * [compatible with this setting](#!/guide/skin_sdk_chameleon).
438 *
439 * Read more in the [documentation](#!/guide/dev_uicolor) and see the
440 * [SDK sample](http://sdk.ckeditor.com/samples/uicolor.html).
441 *
442 * // Using a color code.
443 * config.uiColor = '#AADC6E';
444 *
445 * // Using an HTML color name.
446 * config.uiColor = 'Gold';
447 *
448 * @cfg {String} uiColor
449 */
450
451// PACKAGER_RENAME( CKEDITOR.config )
diff --git a/sources/core/creators/inline.js b/sources/core/creators/inline.js
new file mode 100644
index 0000000..adb402f
--- /dev/null
+++ b/sources/core/creators/inline.js
@@ -0,0 +1,157 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 /** @class CKEDITOR */
8
9 /**
10 * Turns a DOM element with the `contenteditable` attribute set to `true` into a
11 * CKEditor instance. Check {@link CKEDITOR.dtd#$editable} for a list of
12 * allowed element names.
13 *
14 * **Note:** If the DOM element for which inline editing is being enabled does not have
15 * the `contenteditable` attribute set to `true`, the editor will start in read-only mode.
16 *
17 * <div contenteditable="true" id="content">...</div>
18 * ...
19 * CKEDITOR.inline( 'content' );
20 *
21 * It is also possible to create an inline editor from the `<textarea>` element.
22 * If you do so, an additional `<div>` element with editable content will be created
23 * directly after the `<textarea>` element and the `<textarea>` element will be hidden.
24 *
25 * @param {Object/String} element The DOM element or its ID.
26 * @param {Object} [instanceConfig] The specific configurations to apply to this editor instance.
27 * See {@link CKEDITOR.config}.
28 * @returns {CKEDITOR.editor} The editor instance created.
29 */
30 CKEDITOR.inline = function( element, instanceConfig ) {
31 if ( !CKEDITOR.env.isCompatible )
32 return null;
33
34 element = CKEDITOR.dom.element.get( element );
35
36 // Avoid multiple inline editor instances on the same element.
37 if ( element.getEditor() )
38 throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.';
39
40 var editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE ),
41 textarea = element.is( 'textarea' ) ? element : null;
42
43 if ( textarea ) {
44 editor.setData( textarea.getValue(), null, true );
45
46 //Change element from textarea to div
47 element = CKEDITOR.dom.element.createFromHtml(
48 '<div contenteditable="' + !!editor.readOnly + '" class="cke_textarea_inline">' +
49 textarea.getValue() +
50 '</div>',
51 CKEDITOR.document );
52
53 element.insertAfter( textarea );
54 textarea.hide();
55
56 // Attaching the concrete form.
57 if ( textarea.$.form )
58 editor._attachToForm();
59 } else {
60 // Initial editor data is simply loaded from the page element content to make
61 // data retrieval possible immediately after the editor creation.
62 editor.setData( element.getHtml(), null, true );
63 }
64
65 // Once the editor is loaded, start the UI.
66 editor.on( 'loaded', function() {
67 editor.fire( 'uiReady' );
68
69 // Enable editing on the element.
70 editor.editable( element );
71
72 // Editable itself is the outermost element.
73 editor.container = element;
74 editor.ui.contentsElement = element;
75
76 // Load and process editor data.
77 editor.setData( editor.getData( 1 ) );
78
79 // Clean on startup.
80 editor.resetDirty();
81
82 editor.fire( 'contentDom' );
83
84 // Inline editing defaults to "wysiwyg" mode, so plugins don't
85 // need to make special handling for this "mode-less" environment.
86 editor.mode = 'wysiwyg';
87 editor.fire( 'mode' );
88
89 // The editor is completely loaded for interaction.
90 editor.status = 'ready';
91 editor.fireOnce( 'instanceReady' );
92 CKEDITOR.fire( 'instanceReady', null, editor );
93
94 // give priority to plugins that relay on editor#loaded for bootstrapping.
95 }, null, null, 10000 );
96
97 // Handle editor destroying.
98 editor.on( 'destroy', function() {
99 // Remove container from DOM if inline-textarea editor.
100 // Show <textarea> back again.
101 if ( textarea ) {
102 editor.container.clearCustomData();
103 editor.container.remove();
104 textarea.show();
105 }
106
107 editor.element.clearCustomData();
108
109 delete editor.element;
110 } );
111
112 return editor;
113 };
114
115 /**
116 * Calls {@link CKEDITOR#inline} for all page elements with
117 * the `contenteditable` attribute set to `true`.
118 *
119 */
120 CKEDITOR.inlineAll = function() {
121 var el, data;
122
123 for ( var name in CKEDITOR.dtd.$editable ) {
124 var elements = CKEDITOR.document.getElementsByTag( name );
125
126 for ( var i = 0, len = elements.count(); i < len; i++ ) {
127 el = elements.getItem( i );
128
129 if ( el.getAttribute( 'contenteditable' ) == 'true' ) {
130 // Fire the "inline" event, making it possible to customize
131 // the instance settings and eventually cancel the creation.
132
133 data = {
134 element: el,
135 config: {}
136 };
137
138 if ( CKEDITOR.fire( 'inline', data ) !== false )
139 CKEDITOR.inline( el, data.config );
140 }
141 }
142 }
143 };
144
145 CKEDITOR.domReady( function() {
146 !CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
147 } );
148} )();
149
150/**
151 * Disables creating the inline editor automatically for elements with
152 * the `contenteditable` attribute set to `true`.
153 *
154 * CKEDITOR.disableAutoInline = true;
155 *
156 * @cfg {Boolean} [disableAutoInline=false]
157 */
diff --git a/sources/core/creators/themedui.js b/sources/core/creators/themedui.js
new file mode 100644
index 0000000..04927d0
--- /dev/null
+++ b/sources/core/creators/themedui.js
@@ -0,0 +1,541 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 /** @class CKEDITOR */
7
8/**
9 * The class name used to identify `<textarea>` elements to be replaced
10 * by CKEditor instances. Set it to empty/`null` to disable this feature.
11 *
12 * CKEDITOR.replaceClass = 'rich_editor';
13 *
14 * @cfg {String} [replaceClass='ckeditor']
15 */
16CKEDITOR.replaceClass = 'ckeditor';
17
18( function() {
19 /**
20 * Replaces a `<textarea>` or a DOM element (`<div>`) with a CKEditor
21 * instance. For textareas, the initial value in the editor will be the
22 * textarea value. For DOM elements, their `innerHTML` will be used
23 * instead. It is recommended to use `<textarea>` and `<div>` elements only.
24 *
25 * <textarea id="myfield" name="myfield"></textarea>
26 * ...
27 * CKEDITOR.replace( 'myfield' );
28 *
29 * var textarea = document.body.appendChild( document.createElement( 'textarea' ) );
30 * CKEDITOR.replace( textarea );
31 *
32 * @param {Object/String} element The DOM element (textarea), its ID, or name.
33 * @param {Object} [config] The specific configuration to apply to this
34 * editor instance. Configuration set here will override the global CKEditor settings
35 * (see {@link CKEDITOR.config}).
36 * @returns {CKEDITOR.editor} The editor instance created.
37 */
38 CKEDITOR.replace = function( element, config ) {
39 return createInstance( element, config, null, CKEDITOR.ELEMENT_MODE_REPLACE );
40 };
41
42 /**
43 * Creates a new editor instance at the end of a specific DOM element.
44 *
45 * <!DOCTYPE html>
46 * <html>
47 * <head>
48 * <meta charset="utf-8">
49 * <title>CKEditor</title>
50 * <!-- Make sure the path to CKEditor is correct. -->
51 * <script src="/ckeditor/ckeditor.js"></script>
52 * </head>
53 * <body>
54 * <div id="editorSpace"></div>
55 * <script>
56 * CKEDITOR.appendTo( 'editorSpace' );
57 * </script>
58 * </body>
59 * </html>
60 *
61 * @param {Object/String} element The DOM element, its ID, or name.
62 * @param {Object} [config] The specific configuration to apply to this
63 * editor instance. Configuration set here will override the global CKEditor settings
64 * (see {@link CKEDITOR.config}).
65 * @param {String} [data] Since 3.3. Initial value for the instance.
66 * @returns {CKEDITOR.editor} The editor instance created.
67 */
68 CKEDITOR.appendTo = function( element, config, data ) {
69 return createInstance( element, config, data, CKEDITOR.ELEMENT_MODE_APPENDTO );
70 };
71
72 /**
73 * Replaces all `<textarea>` elements available in the document with
74 * editor instances.
75 *
76 * // Replace all <textarea> elements in the page.
77 * CKEDITOR.replaceAll();
78 *
79 * // Replace all <textarea class="myClassName"> elements in the page.
80 * CKEDITOR.replaceAll( 'myClassName' );
81 *
82 * // Selectively replace <textarea> elements, based on a custom evaluation function.
83 * CKEDITOR.replaceAll( function( textarea, config ) {
84 * // A function that needs to be evaluated for the <textarea>
85 * // to be replaced. It must explicitly return "false" to ignore a
86 * // specific <textarea>.
87 * // You can also customize the editor instance by having the function
88 * // modify the "config" parameter.
89 * } );
90 *
91 * // Full page example where three <textarea> elements are replaced.
92 * <!DOCTYPE html>
93 * <html>
94 * <head>
95 * <meta charset="utf-8">
96 * <title>CKEditor</title>
97 * <!-- Make sure the path to CKEditor is correct. -->
98 * <script src="/ckeditor/ckeditor.js"></script>
99 * </head>
100 * <body>
101 * <textarea name="editor1"></textarea>
102 * <textarea name="editor2"></textarea>
103 * <textarea name="editor3"></textarea>
104 * <script>
105 * // Replace all three <textarea> elements above with CKEditor instances.
106 * CKEDITOR.replaceAll();
107 * </script>
108 * </body>
109 * </html>
110 *
111 * @param {String} [className] The `<textarea>` class name.
112 * @param {Function} [evaluator] An evaluation function that must return `true` for a `<textarea>`
113 * to be replaced with the editor. If the function returns `false`, the `<textarea>` element
114 * will not be replaced.
115 */
116 CKEDITOR.replaceAll = function() {
117 var textareas = document.getElementsByTagName( 'textarea' );
118
119 for ( var i = 0; i < textareas.length; i++ ) {
120 var config = null,
121 textarea = textareas[ i ];
122
123 // The "name" and/or "id" attribute must exist.
124 if ( !textarea.name && !textarea.id )
125 continue;
126
127 if ( typeof arguments[ 0 ] == 'string' ) {
128 // The textarea class name could be passed as the function
129 // parameter.
130
131 var classRegex = new RegExp( '(?:^|\\s)' + arguments[ 0 ] + '(?:$|\\s)' );
132
133 if ( !classRegex.test( textarea.className ) )
134 continue;
135 } else if ( typeof arguments[ 0 ] == 'function' ) {
136 // An evaluation function could be passed as the function parameter.
137 // It must explicitly return "false" to ignore a specific <textarea>.
138 config = {};
139 if ( arguments[ 0 ]( textarea, config ) === false )
140 continue;
141 }
142
143 this.replace( textarea, config );
144 }
145 };
146
147 /** @class CKEDITOR.editor */
148
149 /**
150 * Registers an editing mode. This function is to be used mainly by plugins.
151 *
152 * @param {String} mode The mode name.
153 * @param {Function} exec The function that performs the actual mode change.
154 */
155 CKEDITOR.editor.prototype.addMode = function( mode, exec ) {
156 ( this._.modes || ( this._.modes = {} ) )[ mode ] = exec;
157 };
158
159 /**
160 * Changes the editing mode of this editor instance.
161 *
162 * **Note:** The mode switch could be asynchronous depending on the mode provider.
163 * Use the `callback` to hook subsequent code.
164 *
165 * // Switch to "source" view.
166 * CKEDITOR.instances.editor1.setMode( 'source' );
167 * // Switch to "wysiwyg" view and be notified on completion.
168 * CKEDITOR.instances.editor1.setMode( 'wysiwyg', function() { alert( 'wysiwyg mode loaded!' ); } );
169 *
170 * @param {String} [newMode] If not specified, the {@link CKEDITOR.config#startupMode} will be used.
171 * @param {Function} [callback] Optional callback function which is invoked once the mode switch has succeeded.
172 */
173 CKEDITOR.editor.prototype.setMode = function( newMode, callback ) {
174 var editor = this;
175
176 var modes = this._.modes;
177
178 // Mode loading quickly fails.
179 if ( newMode == editor.mode || !modes || !modes[ newMode ] )
180 return;
181
182 editor.fire( 'beforeSetMode', newMode );
183
184 if ( editor.mode ) {
185 var isDirty = editor.checkDirty(),
186 previousModeData = editor._.previousModeData,
187 currentData,
188 unlockSnapshot = 0;
189
190 editor.fire( 'beforeModeUnload' );
191
192 // Detach the current editable. While detaching editable will set
193 // cached editor's data (with internal setData call). We use this
194 // data below to avoid two getData() calls in a row.
195 editor.editable( 0 );
196
197 editor._.previousMode = editor.mode;
198 // Get cached data, which was set while detaching editable.
199 editor._.previousModeData = currentData = editor.getData( 1 );
200
201 // If data has not been modified in the mode which we are currently leaving,
202 // avoid making snapshot right after initializing new mode.
203 // http://dev.ckeditor.com/ticket/5217#comment:20
204 // Tested by:
205 // 'test switch mode with unrecoreded, inner HTML specific content (boguses)'
206 // 'test switch mode with unrecoreded, inner HTML specific content (boguses) plus changes in source mode'
207 if ( editor.mode == 'source' && previousModeData == currentData ) {
208 // We need to make sure that unlockSnapshot will update the last snapshot
209 // (will not create new one) if lockSnapshot is not called on outdated snapshots stack.
210 // Additionally, forceUpdate prevents from making content image now, which is useless
211 // (because it equals editor data not inner HTML).
212 editor.fire( 'lockSnapshot', { forceUpdate: true } );
213 unlockSnapshot = 1;
214 }
215
216 // Clear up the mode space.
217 editor.ui.space( 'contents' ).setHtml( '' );
218
219 editor.mode = '';
220 } else {
221 editor._.previousModeData = editor.getData( 1 );
222 }
223
224 // Fire the mode handler.
225 this._.modes[ newMode ]( function() {
226 // Set the current mode.
227 editor.mode = newMode;
228
229 if ( isDirty !== undefined )
230 !isDirty && editor.resetDirty();
231
232 if ( unlockSnapshot )
233 editor.fire( 'unlockSnapshot' );
234 // Since snapshot made on dataReady (which normally catches changes done by setData)
235 // won't work because editor.mode was not set yet (it's set in this function), we need
236 // to make special snapshot for changes done in source mode here.
237 else if ( newMode == 'wysiwyg' )
238 editor.fire( 'saveSnapshot' );
239
240 // Delay to avoid race conditions (setMode inside setMode).
241 setTimeout( function() {
242 editor.fire( 'mode' );
243 callback && callback.call( editor );
244 }, 0 );
245 } );
246 };
247
248 /**
249 * Resizes the editor interface.
250 *
251 * editor.resize( 900, 300 );
252 *
253 * editor.resize( '100%', 450, true );
254 *
255 * @param {Number/String} width The new width. It can be an integer denoting a value
256 * in pixels or a CSS size value with unit.
257 * @param {Number/String} height The new height. It can be an integer denoting a value
258 * in pixels or a CSS size value with unit.
259 * @param {Boolean} [isContentHeight] Indicates that the provided height is to
260 * be applied to the editor content area, and not to the entire editor
261 * interface. Defaults to `false`.
262 * @param {Boolean} [resizeInner] Indicates that it is the inner interface
263 * element that must be resized, not the outer element. The default theme
264 * defines the editor interface inside a pair of `<span>` elements
265 * (`<span><span>...</span></span>`). By default the first,
266 * outer `<span>` element receives the sizes. If this parameter is set to
267 * `true`, the second, inner `<span>` is resized instead.
268 */
269 CKEDITOR.editor.prototype.resize = function( width, height, isContentHeight, resizeInner ) {
270 var container = this.container,
271 contents = this.ui.space( 'contents' ),
272 contentsFrame = CKEDITOR.env.webkit && this.document && this.document.getWindow().$.frameElement,
273 outer;
274
275 if ( resizeInner ) {
276 outer = this.container.getFirst( function( node ) {
277 return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_inner' );
278 } );
279 } else {
280 outer = container;
281 }
282
283 // Set as border box width. (#5353)
284 outer.setSize( 'width', width, true );
285
286 // WebKit needs to refresh the iframe size to avoid rendering issues. (1/2) (#8348)
287 contentsFrame && ( contentsFrame.style.width = '1%' );
288
289 // Get the height delta between the outer table and the content area.
290 var contentsOuterDelta = ( outer.$.offsetHeight || 0 ) - ( contents.$.clientHeight || 0 ),
291
292 // If we're setting the content area's height, then we don't need the delta.
293 resultContentsHeight = Math.max( height - ( isContentHeight ? 0 : contentsOuterDelta ), 0 ),
294 resultOuterHeight = ( isContentHeight ? height + contentsOuterDelta : height );
295
296 contents.setStyle( 'height', resultContentsHeight + 'px' );
297
298 // WebKit needs to refresh the iframe size to avoid rendering issues. (2/2) (#8348)
299 contentsFrame && ( contentsFrame.style.width = '100%' );
300
301 // Emit a resize event.
302 this.fire( 'resize', {
303 outerHeight: resultOuterHeight,
304 contentsHeight: resultContentsHeight,
305 // Sometimes width is not provided.
306 outerWidth: width || outer.getSize( 'width' )
307 } );
308 };
309
310 /**
311 * Gets the element that can be used to check the editor size. This method
312 * is mainly used by the [Editor Resize](http://ckeditor.com/addon/resize) plugin, which adds
313 * a UI handle that can be used to resize the editor.
314 *
315 * @param {Boolean} forContents Whether to return the "contents" part of the theme instead of the container.
316 * @returns {CKEDITOR.dom.element} The resizable element.
317 */
318 CKEDITOR.editor.prototype.getResizable = function( forContents ) {
319 return forContents ? this.ui.space( 'contents' ) : this.container;
320 };
321
322 function createInstance( element, config, data, mode ) {
323 if ( !CKEDITOR.env.isCompatible )
324 return null;
325
326 element = CKEDITOR.dom.element.get( element );
327
328 // Avoid multiple inline editor instances on the same element.
329 if ( element.getEditor() )
330 throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.';
331
332 // Create the editor instance.
333 var editor = new CKEDITOR.editor( config, element, mode );
334
335 if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
336 // Do not replace the textarea right now, just hide it. The effective
337 // replacement will be done later in the editor creation lifecycle.
338 element.setStyle( 'visibility', 'hidden' );
339
340 // #8031 Remember if textarea was required and remove the attribute.
341 editor._.required = element.hasAttribute( 'required' );
342 element.removeAttribute( 'required' );
343 }
344
345 data && editor.setData( data, null, true );
346
347 // Once the editor is loaded, start the UI.
348 editor.on( 'loaded', function() {
349 loadTheme( editor );
350
351 if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE && editor.config.autoUpdateElement && element.$.form )
352 editor._attachToForm();
353
354 editor.setMode( editor.config.startupMode, function() {
355 // Clean on startup.
356 editor.resetDirty();
357
358 // Editor is completely loaded for interaction.
359 editor.status = 'ready';
360 editor.fireOnce( 'instanceReady' );
361 CKEDITOR.fire( 'instanceReady', null, editor );
362 } );
363 } );
364
365 editor.on( 'destroy', destroy );
366 return editor;
367 }
368
369 function destroy() {
370 var editor = this,
371 container = editor.container,
372 element = editor.element;
373
374 if ( container ) {
375 container.clearCustomData();
376 container.remove();
377 }
378
379 if ( element ) {
380 element.clearCustomData();
381 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
382 element.show();
383 if ( editor._.required )
384 element.setAttribute( 'required', 'required' );
385 }
386 delete editor.element;
387 }
388 }
389
390 function loadTheme( editor ) {
391 var name = editor.name,
392 element = editor.element,
393 elementMode = editor.elementMode;
394
395 // Get the HTML for the predefined spaces.
396 var topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html;
397 var bottomHtml = editor.fire( 'uiSpace', { space: 'bottom', html: '' } ).html;
398
399 var themedTpl = new CKEDITOR.template(
400 '<{outerEl}' +
401 ' id="cke_{name}"' +
402 ' class="{id} cke cke_reset cke_chrome cke_editor_{name} cke_{langDir} ' + CKEDITOR.env.cssClass + '" ' +
403 ' dir="{langDir}"' +
404 ' lang="{langCode}"' +
405 ' role="application"' +
406 ( editor.title ? ' aria-labelledby="cke_{name}_arialbl"' : '' ) +
407 '>' +
408 ( editor.title ? '<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' : '' ) +
409 '<{outerEl} class="cke_inner cke_reset" role="presentation">' +
410 '{topHtml}' +
411 '<{outerEl} id="{contentId}" class="cke_contents cke_reset" role="presentation"></{outerEl}>' +
412 '{bottomHtml}' +
413 '</{outerEl}>' +
414 '</{outerEl}>' );
415
416 var container = CKEDITOR.dom.element.createFromHtml( themedTpl.output( {
417 id: editor.id,
418 name: name,
419 langDir: editor.lang.dir,
420 langCode: editor.langCode,
421 voiceLabel: editor.title,
422 topHtml: topHtml ? '<span id="' + editor.ui.spaceId( 'top' ) + '" class="cke_top cke_reset_all" role="presentation" style="height:auto">' + topHtml + '</span>' : '',
423 contentId: editor.ui.spaceId( 'contents' ),
424 bottomHtml: bottomHtml ? '<span id="' + editor.ui.spaceId( 'bottom' ) + '" class="cke_bottom cke_reset_all" role="presentation">' + bottomHtml + '</span>' : '',
425 outerEl: CKEDITOR.env.ie ? 'span' : 'div' // #9571
426 } ) );
427
428 if ( elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
429 element.hide();
430 container.insertAfter( element );
431 } else {
432 element.append( container );
433 }
434
435 editor.container = container;
436 editor.ui.contentsElement = editor.ui.space( 'contents' );
437
438 // Make top and bottom spaces unelectable, but not content space,
439 // otherwise the editable area would be affected.
440 topHtml && editor.ui.space( 'top' ).unselectable();
441 bottomHtml && editor.ui.space( 'bottom' ).unselectable();
442
443 var width = editor.config.width, height = editor.config.height;
444 if ( width )
445 container.setStyle( 'width', CKEDITOR.tools.cssLength( width ) );
446
447 // The editor height is applied to the contents space.
448 if ( height )
449 editor.ui.space( 'contents' ).setStyle( 'height', CKEDITOR.tools.cssLength( height ) );
450
451 // Disable browser context menu for editor's chrome.
452 container.disableContextMenu();
453
454 // Redirect the focus into editor for webkit. (#5713)
455 CKEDITOR.env.webkit && container.on( 'focus', function() {
456 editor.focus();
457 } );
458
459 editor.fireOnce( 'uiReady' );
460 }
461
462 // Replace all textareas with the default class name.
463 CKEDITOR.domReady( function() {
464 CKEDITOR.replaceClass && CKEDITOR.replaceAll( CKEDITOR.replaceClass );
465 } );
466} )();
467
468/**
469 * The current editing mode. An editing mode basically provides
470 * different ways of editing or viewing the editor content.
471 *
472 * alert( CKEDITOR.instances.editor1.mode ); // (e.g.) 'wysiwyg'
473 *
474 * @readonly
475 * @property {String} mode
476 */
477
478/**
479 * The mode to load at the editor startup. It depends on the plugins
480 * loaded. By default, the `wysiwyg` and `source` modes are available.
481 *
482 * config.startupMode = 'source';
483 *
484 * @cfg {String} [startupMode='wysiwyg']
485 * @member CKEDITOR.config
486 */
487CKEDITOR.config.startupMode = 'wysiwyg';
488
489/**
490 * Fired after the editor instance is resized through
491 * the {@link CKEDITOR.editor#method-resize CKEDITOR.resize} method.
492 *
493 * @event resize
494 * @param {CKEDITOR.editor} editor This editor instance.
495 * @param {Object} data Available since CKEditor 4.5.
496 * @param {Number} data.outerHeight The height of the entire area that the editor covers.
497 * @param {Number} data.contentsHeight Editable area height in pixels.
498 * @param {Number} data.outerWidth The width of the entire area that the editor covers.
499 */
500
501/**
502 * Fired before changing the editing mode. See also
503 * {@link #beforeSetMode} and {@link #event-mode}.
504 *
505 * @event beforeModeUnload
506 * @param {CKEDITOR.editor} editor This editor instance.
507 */
508
509/**
510 * Fired before the editor mode is set. See also
511 * {@link #event-mode} and {@link #beforeModeUnload}.
512 *
513 * @since 3.5.3
514 * @event beforeSetMode
515 * @param {CKEDITOR.editor} editor This editor instance.
516 * @param {String} data The name of the mode which is about to be set.
517 */
518
519/**
520 * Fired after setting the editing mode. See also {@link #beforeSetMode} and {@link #beforeModeUnload}
521 *
522 * @event mode
523 * @param {CKEDITOR.editor} editor This editor instance.
524 */
525
526/**
527 * Fired when the editor (replacing a `<textarea>` which has a `required` attribute) is empty during form submission.
528 *
529 * This event replaces native required fields validation that the browsers cannot
530 * perform when CKEditor replaces `<textarea>` elements.
531 *
532 * You can cancel this event to prevent the page from submitting data.
533 *
534 * editor.on( 'required', function( evt ) {
535 * alert( 'Article content is required.' );
536 * evt.cancel();
537 * } );
538 *
539 * @event required
540 * @param {CKEDITOR.editor} editor This editor instance.
541 */
diff --git a/sources/core/dataprocessor.js b/sources/core/dataprocessor.js
new file mode 100644
index 0000000..c42eab4
--- /dev/null
+++ b/sources/core/dataprocessor.js
@@ -0,0 +1,70 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the "virtual" {@link CKEDITOR.dataProcessor} class, which
8 * defines the basic structure of data processor objects to be
9 * set to {@link CKEDITOR.editor.dataProcessor}.
10 */
11
12/**
13 * If defined, points to the data processor which is responsible for translating
14 * and transforming the editor data on input and output.
15 * Generally it will point to an instance of {@link CKEDITOR.htmlDataProcessor},
16 * which handles HTML data. The editor may also handle other data formats by
17 * using different data processors provided by specific plugins.
18 *
19 * @property {CKEDITOR.dataProcessor} dataProcessor
20 * @member CKEDITOR.editor
21 */
22
23/**
24 * Represents a data processor which is responsible for translating and
25 * transforming the editor data on input and output.
26 *
27 * This class is here for documentation purposes only and is not really part of
28 * the API. It serves as the base ("interface") for data processor implementations.
29 *
30 * @class CKEDITOR.dataProcessor
31 * @abstract
32 */
33
34/**
35 * Transforms input data into HTML to be loaded into the editor.
36 * While the editor is able to handle non-HTML data (like BBCode), it can only
37 * handle HTML data at runtime. The role of the data processor is to transform
38 * the input data into HTML through this function.
39 *
40 * // Tranforming BBCode data, with a custom BBCode data processor available.
41 * var data = 'This is [b]an example[/b].';
42 * var html = editor.dataProcessor.toHtml( data ); // '<p>This is <b>an example</b>.</p>'
43 *
44 * @method toHtml
45 * @param {String} data The input data to be transformed.
46 * @param {String} [fixForBody] The tag name to be used if the data must be
47 * fixed because it is supposed to be loaded direcly into the `<body>`
48 * tag. This is generally not used by non-HTML data processors.
49 * @todo fixForBody type - compare to htmlDataProcessor.
50 */
51
52/**
53 * Transforms HTML into data to be output by the editor, in the format
54 * expected by the data processor.
55 *
56 * While the editor is able to handle non-HTML data (like BBCode), it can only
57 * handle HTML data at runtime. The role of the data processor is to transform
58 * the HTML data containined by the editor into a specific data format through
59 * this function.
60 *
61 * // Tranforming into BBCode data, with a custom BBCode data processor available.
62 * var html = '<p>This is <b>an example</b>.</p>';
63 * var data = editor.dataProcessor.toDataFormat( html ); // 'This is [b]an example[/b].'
64 *
65 * @method toDataFormat
66 * @param {String} html The HTML to be transformed.
67 * @param {String} fixForBody The tag name to be used if the output data is
68 * coming from the `<body>` element and may be eventually fixed for it. This is
69 * generally not used by non-HTML data processors.
70 */
diff --git a/sources/core/dom.js b/sources/core/dom.js
new file mode 100644
index 0000000..84aa21d
--- /dev/null
+++ b/sources/core/dom.js
@@ -0,0 +1,13 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom} object, which contains DOM
8 * manipulation objects and function.
9 */
10
11CKEDITOR.dom = {};
12
13// PACKAGER_RENAME( CKEDITOR.dom )
diff --git a/sources/core/dom/comment.js b/sources/core/dom/comment.js
new file mode 100644
index 0000000..4abb453
--- /dev/null
+++ b/sources/core/dom/comment.js
@@ -0,0 +1,53 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents
8 * a DOM comment node.
9 */
10
11/**
12 * Represents a DOM comment node.
13 *
14 * var nativeNode = document.createComment( 'Example' );
15 * var comment = new CKEDITOR.dom.comment( nativeNode );
16 *
17 * var comment = new CKEDITOR.dom.comment( 'Example' );
18 *
19 * @class
20 * @extends CKEDITOR.dom.node
21 * @constructor Creates a comment class instance.
22 * @param {Object/String} comment A native DOM comment node or a string containing
23 * the text to use to create a new comment node.
24 * @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
25 * the node in case of new node creation. Defaults to the current document.
26 */
27CKEDITOR.dom.comment = function( comment, ownerDocument ) {
28 if ( typeof comment == 'string' )
29 comment = ( ownerDocument ? ownerDocument.$ : document ).createComment( comment );
30
31 CKEDITOR.dom.domObject.call( this, comment );
32};
33
34CKEDITOR.dom.comment.prototype = new CKEDITOR.dom.node();
35
36CKEDITOR.tools.extend( CKEDITOR.dom.comment.prototype, {
37 /**
38 * The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
39 *
40 * @readonly
41 * @property {Number} [=CKEDITOR.NODE_COMMENT]
42 */
43 type: CKEDITOR.NODE_COMMENT,
44
45 /**
46 * Gets the outer HTML of this comment.
47 *
48 * @returns {String} The HTML `<!-- comment value -->`.
49 */
50 getOuterHtml: function() {
51 return '<!--' + this.$.nodeValue + '-->';
52 }
53} );
diff --git a/sources/core/dom/document.js b/sources/core/dom/document.js
new file mode 100644
index 0000000..51c5b19
--- /dev/null
+++ b/sources/core/dom/document.js
@@ -0,0 +1,326 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.document} class which
8 * represents a DOM document.
9 */
10
11/**
12 * Represents a DOM document.
13 *
14 * var document = new CKEDITOR.dom.document( document );
15 *
16 * @class
17 * @extends CKEDITOR.dom.domObject
18 * @constructor Creates a document class instance.
19 * @param {Object} domDocument A native DOM document.
20 */
21CKEDITOR.dom.document = function( domDocument ) {
22 CKEDITOR.dom.domObject.call( this, domDocument );
23};
24
25// PACKAGER_RENAME( CKEDITOR.dom.document )
26
27CKEDITOR.dom.document.prototype = new CKEDITOR.dom.domObject();
28
29CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, {
30 /**
31 * The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT}.
32 *
33 * @readonly
34 * @property {Number} [=CKEDITOR.NODE_DOCUMENT]
35 */
36 type: CKEDITOR.NODE_DOCUMENT,
37
38 /**
39 * Appends a CSS file to the document.
40 *
41 * CKEDITOR.document.appendStyleSheet( '/mystyles.css' );
42 *
43 * @param {String} cssFileUrl The CSS file URL.
44 */
45 appendStyleSheet: function( cssFileUrl ) {
46 if ( this.$.createStyleSheet )
47 this.$.createStyleSheet( cssFileUrl );
48 else {
49 var link = new CKEDITOR.dom.element( 'link' );
50 link.setAttributes( {
51 rel: 'stylesheet',
52 type: 'text/css',
53 href: cssFileUrl
54 } );
55
56 this.getHead().append( link );
57 }
58 },
59
60 /**
61 * Creates a CSS stylesheet and inserts it into the document.
62 *
63 * @param cssStyleText {String} CSS style text.
64 * @returns {Object} The created DOM native stylesheet object.
65 */
66 appendStyleText: function( cssStyleText ) {
67 if ( this.$.createStyleSheet ) {
68 var styleSheet = this.$.createStyleSheet( '' );
69 styleSheet.cssText = cssStyleText;
70 } else {
71 var style = new CKEDITOR.dom.element( 'style', this );
72 style.append( new CKEDITOR.dom.text( cssStyleText, this ) );
73 this.getHead().append( style );
74 }
75
76 return styleSheet || style.$.sheet;
77 },
78
79 /**
80 * Creates a {@link CKEDITOR.dom.element} instance in this document.
81 *
82 * @param {String} name The name of the element.
83 * @param {Object} [attributesAndStyles]
84 * @param {Object} [attributesAndStyles.attributes] Attributes that will be set.
85 * @param {Object} [attributesAndStyles.styles] Styles that will be set.
86 * @returns {CKEDITOR.dom.element}
87 */
88 createElement: function( name, attribsAndStyles ) {
89 var element = new CKEDITOR.dom.element( name, this );
90
91 if ( attribsAndStyles ) {
92 if ( attribsAndStyles.attributes )
93 element.setAttributes( attribsAndStyles.attributes );
94
95 if ( attribsAndStyles.styles )
96 element.setStyles( attribsAndStyles.styles );
97 }
98
99 return element;
100 },
101
102 /**
103 * Creates a {@link CKEDITOR.dom.text} instance in this document.
104 *
105 * @param {String} text Value of the text node.
106 * @returns {CKEDITOR.dom.element}
107 */
108 createText: function( text ) {
109 return new CKEDITOR.dom.text( text, this );
110 },
111
112 /**
113 * Moves the selection focus to this document's window.
114 */
115 focus: function() {
116 this.getWindow().focus();
117 },
118
119 /**
120 * Returns the element that is currently designated as the active element in the document.
121 *
122 * **Note:** Only one element can be active at a time in a document.
123 * An active element does not necessarily have focus,
124 * but an element with focus is always the active element in a document.
125 *
126 * @returns {CKEDITOR.dom.element} Active element or `null` if an IE8-9 bug is encountered.
127 * See [#10030](http://dev.ckeditor.com/ticket/10030).
128 */
129 getActive: function() {
130 var $active;
131 try {
132 $active = this.$.activeElement;
133 } catch ( e ) {
134 return null;
135 }
136 return new CKEDITOR.dom.element( $active );
137 },
138
139 /**
140 * Gets an element based on its ID.
141 *
142 * var element = CKEDITOR.document.getById( 'myElement' );
143 * alert( element.getId() ); // 'myElement'
144 *
145 * @param {String} elementId The element ID.
146 * @returns {CKEDITOR.dom.element} The element instance, or `null` if not found.
147 */
148 getById: function( elementId ) {
149 var $ = this.$.getElementById( elementId );
150 return $ ? new CKEDITOR.dom.element( $ ) : null;
151 },
152
153 /**
154 * Gets a node based on its address. See {@link CKEDITOR.dom.node#getAddress}.
155 *
156 * @param {Array} address
157 * @param {Boolean} [normalized=false]
158 */
159 getByAddress: function( address, normalized ) {
160 var $ = this.$.documentElement;
161
162 for ( var i = 0; $ && i < address.length; i++ ) {
163 var target = address[ i ];
164
165 if ( !normalized ) {
166 $ = $.childNodes[ target ];
167 continue;
168 }
169
170 var currentIndex = -1;
171
172 for ( var j = 0; j < $.childNodes.length; j++ ) {
173 var candidate = $.childNodes[ j ];
174
175 if ( normalized === true && candidate.nodeType == 3 && candidate.previousSibling && candidate.previousSibling.nodeType == 3 )
176 continue;
177
178 currentIndex++;
179
180 if ( currentIndex == target ) {
181 $ = candidate;
182 break;
183 }
184 }
185 }
186
187 return $ ? new CKEDITOR.dom.node( $ ) : null;
188 },
189
190 /**
191 * Gets elements list based on a given tag name.
192 *
193 * @param {String} tagName The element tag name.
194 * @returns {CKEDITOR.dom.nodeList} The nodes list.
195 */
196 getElementsByTag: function( tagName, namespace ) {
197 if ( !( CKEDITOR.env.ie && ( document.documentMode <= 8 ) ) && namespace )
198 tagName = namespace + ':' + tagName;
199 return new CKEDITOR.dom.nodeList( this.$.getElementsByTagName( tagName ) );
200 },
201
202 /**
203 * Gets the `<head>` element for this document.
204 *
205 * var element = CKEDITOR.document.getHead();
206 * alert( element.getName() ); // 'head'
207 *
208 * @returns {CKEDITOR.dom.element} The `<head>` element.
209 */
210 getHead: function() {
211 var head = this.$.getElementsByTagName( 'head' )[ 0 ];
212 if ( !head )
213 head = this.getDocumentElement().append( new CKEDITOR.dom.element( 'head' ), true );
214 else
215 head = new CKEDITOR.dom.element( head );
216
217 return head;
218 },
219
220 /**
221 * Gets the `<body>` element for this document.
222 *
223 * var element = CKEDITOR.document.getBody();
224 * alert( element.getName() ); // 'body'
225 *
226 * @returns {CKEDITOR.dom.element} The `<body>` element.
227 */
228 getBody: function() {
229 return new CKEDITOR.dom.element( this.$.body );
230 },
231
232 /**
233 * Gets the DOM document element for this document.
234 *
235 * @returns {CKEDITOR.dom.element} The DOM document element.
236 */
237 getDocumentElement: function() {
238 return new CKEDITOR.dom.element( this.$.documentElement );
239 },
240
241 /**
242 * Gets the window object that stores this document.
243 *
244 * @returns {CKEDITOR.dom.window} The window object.
245 */
246 getWindow: function() {
247 return new CKEDITOR.dom.window( this.$.parentWindow || this.$.defaultView );
248 },
249
250 /**
251 * Defines the document content through `document.write`. Note that the
252 * previous document content will be lost (cleaned).
253 *
254 * document.write(
255 * '<html>' +
256 * '<head><title>Sample Document</title></head>' +
257 * '<body>Document content created by code.</body>' +
258 * '</html>'
259 * );
260 *
261 * @since 3.5
262 * @param {String} html The HTML defining the document content.
263 */
264 write: function( html ) {
265 // Don't leave any history log in IE. (#5657)
266 this.$.open( 'text/html', 'replace' );
267
268 // Support for custom document.domain in IE.
269 //
270 // The script must be appended because if placed before the
271 // doctype, IE will go into quirks mode and mess with
272 // the editable, e.g. by changing its default height.
273 if ( CKEDITOR.env.ie )
274 html = html.replace( /(?:^\s*<!DOCTYPE[^>]*?>)|^/i, '$&\n<script data-cke-temp="1">(' + CKEDITOR.tools.fixDomain + ')();</script>' );
275
276 this.$.write( html );
277 this.$.close();
278 },
279
280 /**
281 * Wrapper for `querySelectorAll`. Returns a list of elements within this document that match
282 * the specified `selector`.
283 *
284 * **Note:** The returned list is not a live collection (like the result of native `querySelectorAll`).
285 *
286 * @since 4.3
287 * @param {String} selector
288 * @returns {CKEDITOR.dom.nodeList}
289 */
290 find: function( selector ) {
291 return new CKEDITOR.dom.nodeList( this.$.querySelectorAll( selector ) );
292 },
293
294 /**
295 * Wrapper for `querySelector`. Returns the first element within this document that matches
296 * the specified `selector`.
297 *
298 * @since 4.3
299 * @param {String} selector
300 * @returns {CKEDITOR.dom.element}
301 */
302 findOne: function( selector ) {
303 var el = this.$.querySelector( selector );
304
305 return el ? new CKEDITOR.dom.element( el ) : null;
306 },
307
308 /**
309 * Internet Explorer 8 only method. It returns a document fragment which has all HTML5 elements enabled.
310 *
311 * @since 4.3
312 * @private
313 * @returns DocumentFragment
314 */
315 _getHtml5ShivFrag: function() {
316 var $frag = this.getCustomData( 'html5ShivFrag' );
317
318 if ( !$frag ) {
319 $frag = this.$.createDocumentFragment();
320 CKEDITOR.tools.enableHtml5Elements( $frag, true );
321 this.setCustomData( 'html5ShivFrag', $frag );
322 }
323
324 return $frag;
325 }
326} );
diff --git a/sources/core/dom/documentfragment.js b/sources/core/dom/documentfragment.js
new file mode 100644
index 0000000..1058144
--- /dev/null
+++ b/sources/core/dom/documentfragment.js
@@ -0,0 +1,62 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * DocumentFragment is a "lightweight" or "minimal" Document object. It is
8 * commonly used to extract a portion of a document's tree or to create a new
9 * fragment of a document. Various operations may take document fragment objects
10 * as arguments and result in all the child nodes of the document fragment being
11 * moved to the child list of this node.
12 *
13 * @class
14 * @constructor Creates a document fragment class instance.
15 * @param {CKEDITOR.dom.document/DocumentFragment} [nodeOrDoc=CKEDITOR.document]
16 */
17CKEDITOR.dom.documentFragment = function( nodeOrDoc ) {
18 nodeOrDoc = nodeOrDoc || CKEDITOR.document;
19
20 if ( nodeOrDoc.type == CKEDITOR.NODE_DOCUMENT )
21 this.$ = nodeOrDoc.$.createDocumentFragment();
22 else
23 this.$ = nodeOrDoc;
24};
25
26CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype, CKEDITOR.dom.element.prototype, {
27 /**
28 * The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
29 *
30 * @readonly
31 * @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
32 */
33 type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
34
35 /**
36 * Inserts the document fragment content after the specified node.
37 *
38 * @param {CKEDITOR.dom.node} node
39 */
40 insertAfterNode: function( node ) {
41 node = node.$;
42 node.parentNode.insertBefore( this.$, node.nextSibling );
43 },
44
45 /**
46 * Gets HTML of this document fragment's children.
47 *
48 * @since 4.5
49 * @returns {String} The HTML of this document fragment's children.
50 */
51 getHtml: function() {
52 var container = new CKEDITOR.dom.element( 'div' );
53
54 this.clone( 1, 1 ).appendTo( container );
55
56 return container.getHtml().replace( /\s*data-cke-expando=".*?"/g, '' );
57 }
58}, true, {
59 'append': 1, 'appendBogus': 1, 'clone': 1, 'getFirst': 1, 'getHtml': 1, 'getLast': 1, 'getParent': 1, 'getNext': 1, 'getPrevious': 1,
60 'appendTo': 1, 'moveChildren': 1, 'insertBefore': 1, 'insertAfterNode': 1, 'replace': 1, 'trim': 1, 'type': 1,
61 'ltrim': 1, 'rtrim': 1, 'getDocument': 1, 'getChildCount': 1, 'getChild': 1, 'getChildren': 1
62} );
diff --git a/sources/core/dom/domobject.js b/sources/core/dom/domobject.js
new file mode 100644
index 0000000..4c593ff
--- /dev/null
+++ b/sources/core/dom/domobject.js
@@ -0,0 +1,266 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base
8 * for other classes representing DOM objects.
9 */
10
11/**
12 * Represents a DOM object. This class is not intended to be used directly. It
13 * serves as the base class for other classes representing specific DOM
14 * objects.
15 *
16 * @class
17 * @mixins CKEDITOR.event
18 * @constructor Creates a domObject class instance.
19 * @param {Object} nativeDomObject A native DOM object.
20 */
21CKEDITOR.dom.domObject = function( nativeDomObject ) {
22 if ( nativeDomObject ) {
23 /**
24 * The native DOM object represented by this class instance.
25 *
26 * var element = new CKEDITOR.dom.element( 'span' );
27 * alert( element.$.nodeType ); // '1'
28 *
29 * @readonly
30 * @property {Object}
31 */
32 this.$ = nativeDomObject;
33 }
34};
35
36CKEDITOR.dom.domObject.prototype = ( function() {
37 // Do not define other local variables here. We want to keep the native
38 // listener closures as clean as possible.
39
40 var getNativeListener = function( domObject, eventName ) {
41 return function( domEvent ) {
42 // In FF, when reloading the page with the editor focused, it may
43 // throw an error because the CKEDITOR global is not anymore
44 // available. So, we check it here first. (#2923)
45 if ( typeof CKEDITOR != 'undefined' )
46 domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );
47 };
48 };
49
50 return {
51
52 /**
53 * Gets the private `_` object which is bound to the native
54 * DOM object using {@link #getCustomData}.
55 *
56 * var elementA = new CKEDITOR.dom.element( nativeElement );
57 * elementA.getPrivate().value = 1;
58 * ...
59 * var elementB = new CKEDITOR.dom.element( nativeElement );
60 * elementB.getPrivate().value; // 1
61 *
62 * @returns {Object} The private object.
63 */
64 getPrivate: function() {
65 var priv;
66
67 // Get the main private object from the custom data. Create it if not defined.
68 if ( !( priv = this.getCustomData( '_' ) ) )
69 this.setCustomData( '_', ( priv = {} ) );
70
71 return priv;
72 },
73
74 // Docs inherited from event.
75 on: function( eventName ) {
76 // We customize the "on" function here. The basic idea is that we'll have
77 // only one listener for a native event, which will then call all listeners
78 // set to the event.
79
80 // Get the listeners holder object.
81 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
82
83 if ( !nativeListeners ) {
84 nativeListeners = {};
85 this.setCustomData( '_cke_nativeListeners', nativeListeners );
86 }
87
88 // Check if we have a listener for that event.
89 if ( !nativeListeners[ eventName ] ) {
90 var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );
91
92 if ( this.$.addEventListener )
93 this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );
94 else if ( this.$.attachEvent )
95 this.$.attachEvent( 'on' + eventName, listener );
96 }
97
98 // Call the original implementation.
99 return CKEDITOR.event.prototype.on.apply( this, arguments );
100 },
101
102 // Docs inherited from event.
103 removeListener: function( eventName ) {
104 // Call the original implementation.
105 CKEDITOR.event.prototype.removeListener.apply( this, arguments );
106
107 // If we don't have listeners for this event, clean the DOM up.
108 if ( !this.hasListeners( eventName ) ) {
109 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
110 var listener = nativeListeners && nativeListeners[ eventName ];
111 if ( listener ) {
112 if ( this.$.removeEventListener )
113 this.$.removeEventListener( eventName, listener, false );
114 else if ( this.$.detachEvent )
115 this.$.detachEvent( 'on' + eventName, listener );
116
117 delete nativeListeners[ eventName ];
118 }
119 }
120 },
121
122 /**
123 * Removes any listener set on this object.
124 *
125 * To avoid memory leaks we must assure that there are no
126 * references left after the object is no longer needed.
127 */
128 removeAllListeners: function() {
129 var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
130 for ( var eventName in nativeListeners ) {
131 var listener = nativeListeners[ eventName ];
132 if ( this.$.detachEvent )
133 this.$.detachEvent( 'on' + eventName, listener );
134 else if ( this.$.removeEventListener )
135 this.$.removeEventListener( eventName, listener, false );
136
137 delete nativeListeners[ eventName ];
138 }
139
140 // Remove events from events object so fire() method will not call
141 // listeners (#11400).
142 CKEDITOR.event.prototype.removeAllListeners.call( this );
143 }
144 };
145} )();
146
147( function( domObjectProto ) {
148 var customData = {};
149
150 CKEDITOR.on( 'reset', function() {
151 customData = {};
152 } );
153
154 /**
155 * Determines whether the specified object is equal to the current object.
156 *
157 * var doc = new CKEDITOR.dom.document( document );
158 * alert( doc.equals( CKEDITOR.document ) ); // true
159 * alert( doc == CKEDITOR.document ); // false
160 *
161 * @param {Object} object The object to compare with the current object.
162 * @returns {Boolean} `true` if the object is equal.
163 */
164 domObjectProto.equals = function( object ) {
165 // Try/Catch to avoid IE permission error when object is from different document.
166 try {
167 return ( object && object.$ === this.$ );
168 } catch ( er ) {
169 return false;
170 }
171 };
172
173 /**
174 * Sets a data slot value for this object. These values are shared by all
175 * instances pointing to that same DOM object.
176 *
177 * **Note:** The created data slot is only guaranteed to be available on this unique DOM node,
178 * thus any wish to continue access to it from other element clones (either created by
179 * clone node or from `innerHtml`) will fail. For such usage please use
180 * {@link CKEDITOR.dom.element#setAttribute} instead.
181 *
182 * **Note**: This method does not work on text nodes prior to Internet Explorer 9.
183 *
184 * var element = new CKEDITOR.dom.element( 'span' );
185 * element.setCustomData( 'hasCustomData', true );
186 *
187 * @param {String} key A key used to identify the data slot.
188 * @param {Object} value The value to set to the data slot.
189 * @returns {CKEDITOR.dom.domObject} This DOM object instance.
190 * @chainable
191 */
192 domObjectProto.setCustomData = function( key, value ) {
193 var expandoNumber = this.getUniqueId(),
194 dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );
195
196 dataSlot[ key ] = value;
197
198 return this;
199 };
200
201 /**
202 * Gets the value set to a data slot in this object.
203 *
204 * var element = new CKEDITOR.dom.element( 'span' );
205 * alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
206 * alert( element.getCustomData( 'nonExistingKey' ) ); // null
207 *
208 * @param {String} key The key used to identify the data slot.
209 * @returns {Object} This value set to the data slot.
210 */
211 domObjectProto.getCustomData = function( key ) {
212 var expandoNumber = this.$[ 'data-cke-expando' ],
213 dataSlot = expandoNumber && customData[ expandoNumber ];
214
215 return ( dataSlot && key in dataSlot ) ? dataSlot[ key ] : null;
216 };
217
218 /**
219 * Removes the value in the data slot under the given `key`.
220 *
221 * @param {String} key
222 * @returns {Object} Removed value or `null` if not found.
223 */
224 domObjectProto.removeCustomData = function( key ) {
225 var expandoNumber = this.$[ 'data-cke-expando' ],
226 dataSlot = expandoNumber && customData[ expandoNumber ],
227 retval, hadKey;
228
229 if ( dataSlot ) {
230 retval = dataSlot[ key ];
231 hadKey = key in dataSlot;
232 delete dataSlot[ key ];
233 }
234
235 return hadKey ? retval : null;
236 };
237
238 /**
239 * Removes any data stored in this object.
240 * To avoid memory leaks we must assure that there are no
241 * references left after the object is no longer needed.
242 */
243 domObjectProto.clearCustomData = function() {
244 // Clear all event listeners
245 this.removeAllListeners();
246
247 var expandoNumber = this.$[ 'data-cke-expando' ];
248 expandoNumber && delete customData[ expandoNumber ];
249 };
250
251 /**
252 * Gets an ID that can be used to identify this DOM object in
253 * the running session.
254 *
255 * **Note**: This method does not work on text nodes prior to Internet Explorer 9.
256 *
257 * @returns {Number} A unique ID.
258 */
259 domObjectProto.getUniqueId = function() {
260 return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() );
261 };
262
263 // Implement CKEDITOR.event.
264 CKEDITOR.event.implementOn( domObjectProto );
265
266} )( CKEDITOR.dom.domObject.prototype );
diff --git a/sources/core/dom/element.js b/sources/core/dom/element.js
new file mode 100644
index 0000000..e02ff17
--- /dev/null
+++ b/sources/core/dom/element.js
@@ -0,0 +1,2183 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.element} class, which
8 * represents a DOM element.
9 */
10
11/**
12 * Represents a DOM element.
13 *
14 * // Create a new <span> element.
15 * var element = new CKEDITOR.dom.element( 'span' );
16 *
17 * // Create an element based on a native DOM element.
18 * var element = new CKEDITOR.dom.element( document.getElementById( 'myId' ) );
19 *
20 * @class
21 * @extends CKEDITOR.dom.node
22 * @constructor Creates an element class instance.
23 * @param {Object/String} element A native DOM element or the element name for
24 * new elements.
25 * @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
26 * the element in case of element creation.
27 */
28CKEDITOR.dom.element = function( element, ownerDocument ) {
29 if ( typeof element == 'string' )
30 element = ( ownerDocument ? ownerDocument.$ : document ).createElement( element );
31
32 // Call the base constructor (we must not call CKEDITOR.dom.node).
33 CKEDITOR.dom.domObject.call( this, element );
34};
35
36// PACKAGER_RENAME( CKEDITOR.dom.element )
37/**
38 * The the {@link CKEDITOR.dom.element} representing and element. If the
39 * element is a native DOM element, it will be transformed into a valid
40 * CKEDITOR.dom.element object.
41 *
42 * var element = new CKEDITOR.dom.element( 'span' );
43 * alert( element == CKEDITOR.dom.element.get( element ) ); // true
44 *
45 * var element = document.getElementById( 'myElement' );
46 * alert( CKEDITOR.dom.element.get( element ).getName() ); // (e.g.) 'p'
47 *
48 * @static
49 * @param {String/Object} element Element's id or name or native DOM element.
50 * @returns {CKEDITOR.dom.element} The transformed element.
51 */
52CKEDITOR.dom.element.get = function( element ) {
53 var el = typeof element == 'string' ? document.getElementById( element ) || document.getElementsByName( element )[ 0 ] : element;
54
55 return el && ( el.$ ? el : new CKEDITOR.dom.element( el ) );
56};
57
58CKEDITOR.dom.element.prototype = new CKEDITOR.dom.node();
59
60/**
61 * Creates an instance of the {@link CKEDITOR.dom.element} class based on the
62 * HTML representation of an element.
63 *
64 * var element = CKEDITOR.dom.element.createFromHtml( '<strong class="anyclass">My element</strong>' );
65 * alert( element.getName() ); // 'strong'
66 *
67 * @static
68 * @param {String} html The element HTML. It should define only one element in
69 * the "root" level. The "root" element can have child nodes, but not siblings.
70 * @returns {CKEDITOR.dom.element} The element instance.
71 */
72CKEDITOR.dom.element.createFromHtml = function( html, ownerDocument ) {
73 var temp = new CKEDITOR.dom.element( 'div', ownerDocument );
74 temp.setHtml( html );
75
76 // When returning the node, remove it from its parent to detach it.
77 return temp.getFirst().remove();
78};
79
80/**
81 * Sets {@link CKEDITOR.dom.element#setCustomData custom data} on an element in a way that it is later
82 * possible to {@link #clearAllMarkers clear all data} set on all elements sharing the same database.
83 *
84 * This mechanism is very useful when processing some portion of DOM. All markers can later be removed
85 * by calling the {@link #clearAllMarkers} method, hence markers will not leak to second pass of this algorithm.
86 *
87 * var database = {};
88 * CKEDITOR.dom.element.setMarker( database, element1, 'foo', 'bar' );
89 * CKEDITOR.dom.element.setMarker( database, element2, 'oof', [ 1, 2, 3 ] );
90 *
91 * element1.getCustomData( 'foo' ); // 'bar'
92 * element2.getCustomData( 'oof' ); // [ 1, 2, 3 ]
93 *
94 * CKEDITOR.dom.element.clearAllMarkers( database );
95 *
96 * element1.getCustomData( 'foo' ); // null
97 *
98 * @static
99 * @param {Object} database
100 * @param {CKEDITOR.dom.element} element
101 * @param {String} name
102 * @param {Object} value
103 * @returns {CKEDITOR.dom.element} The element.
104 */
105CKEDITOR.dom.element.setMarker = function( database, element, name, value ) {
106 var id = element.getCustomData( 'list_marker_id' ) || ( element.setCustomData( 'list_marker_id', CKEDITOR.tools.getNextNumber() ).getCustomData( 'list_marker_id' ) ),
107 markerNames = element.getCustomData( 'list_marker_names' ) || ( element.setCustomData( 'list_marker_names', {} ).getCustomData( 'list_marker_names' ) );
108 database[ id ] = element;
109 markerNames[ name ] = 1;
110
111 return element.setCustomData( name, value );
112};
113
114/**
115 * Removes all markers added using this database. See the {@link #setMarker} method for more information.
116 *
117 * @param {Object} database
118 * @static
119 */
120CKEDITOR.dom.element.clearAllMarkers = function( database ) {
121 for ( var i in database )
122 CKEDITOR.dom.element.clearMarkers( database, database[ i ], 1 );
123};
124
125/**
126 * Removes all markers added to this element and removes it from the database if
127 * `removeFromDatabase` was passed. See the {@link #setMarker} method for more information.
128 *
129 * var database = {};
130 * CKEDITOR.dom.element.setMarker( database, element1, 'foo', 'bar' );
131 * CKEDITOR.dom.element.setMarker( database, element2, 'oof', [ 1, 2, 3 ] );
132 *
133 * element1.getCustomData( 'foo' ); // 'bar'
134 * element2.getCustomData( 'oof' ); // [ 1, 2, 3 ]
135 *
136 * CKEDITOR.dom.element.clearMarkers( database, element1, true );
137 *
138 * element1.getCustomData( 'foo' ); // null
139 * element2.getCustomData( 'oof' ); // [ 1, 2, 3 ]
140 *
141 * @param {Object} database
142 * @static
143 */
144CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatabase ) {
145 var names = element.getCustomData( 'list_marker_names' ),
146 id = element.getCustomData( 'list_marker_id' );
147 for ( var i in names )
148 element.removeCustomData( i );
149 element.removeCustomData( 'list_marker_names' );
150 if ( removeFromDatabase ) {
151 element.removeCustomData( 'list_marker_id' );
152 delete database[ id ];
153 }
154};
155
156( function() {
157 var elementsClassList = document.createElement( '_' ).classList,
158 supportsClassLists = typeof elementsClassList !== 'undefined' && String( elementsClassList.add ).match( /\[Native code\]/gi ) !== null,
159 rclass = /[\n\t\r]/g;
160
161 function hasClass( classNames, className ) {
162 // Source: jQuery.
163 return ( ' ' + classNames + ' ' ).replace( rclass, ' ' ).indexOf( ' ' + className + ' ' ) > -1;
164 }
165
166 CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype, {
167 /**
168 * The node type. This is a constant value set to {@link CKEDITOR#NODE_ELEMENT}.
169 *
170 * @readonly
171 * @property {Number} [=CKEDITOR.NODE_ELEMENT]
172 */
173 type: CKEDITOR.NODE_ELEMENT,
174
175 /**
176 * Adds a CSS class to the element. It appends the class to the
177 * already existing names.
178 *
179 * var element = new CKEDITOR.dom.element( 'div' );
180 * element.addClass( 'classA' ); // <div class="classA">
181 * element.addClass( 'classB' ); // <div class="classA classB">
182 * element.addClass( 'classA' ); // <div class="classA classB">
183 *
184 * **Note:** Since CKEditor 4.5 this method cannot be used with multiple classes (`'classA classB'`).
185 *
186 * @chainable
187 * @method addClass
188 * @param {String} className The name of the class to be added.
189 */
190 addClass: supportsClassLists ?
191 function( className ) {
192 this.$.classList.add( className );
193
194 return this;
195 } : function( className ) {
196 var c = this.$.className;
197 if ( c ) {
198 if ( !hasClass( c, className ) )
199 c += ' ' + className;
200 }
201 this.$.className = c || className;
202
203 return this;
204 },
205
206 /**
207 * Removes a CSS class name from the elements classes. Other classes
208 * remain untouched.
209 *
210 * var element = new CKEDITOR.dom.element( 'div' );
211 * element.addClass( 'classA' ); // <div class="classA">
212 * element.addClass( 'classB' ); // <div class="classA classB">
213 * element.removeClass( 'classA' ); // <div class="classB">
214 * element.removeClass( 'classB' ); // <div>
215 *
216 * @chainable
217 * @method removeClass
218 * @param {String} className The name of the class to remove.
219 */
220 removeClass: supportsClassLists ?
221 function( className ) {
222 var $ = this.$;
223 $.classList.remove( className );
224
225 if ( !$.className )
226 $.removeAttribute( 'class' );
227
228 return this;
229 } : function( className ) {
230 var c = this.getAttribute( 'class' );
231 if ( c && hasClass( c, className ) ) {
232 c = c
233 .replace( new RegExp( '(?:^|\\s+)' + className + '(?=\\s|$)' ), '' )
234 .replace( /^\s+/, '' );
235
236 if ( c )
237 this.setAttribute( 'class', c );
238 else
239 this.removeAttribute( 'class' );
240 }
241
242 return this;
243 },
244
245 /**
246 * Checks if element has class name.
247 *
248 * @param {String} className
249 * @returns {Boolean}
250 */
251 hasClass: function( className ) {
252 return hasClass( this.$.className, className );
253 },
254
255 /**
256 * Append a node as a child of this element.
257 *
258 * var p = new CKEDITOR.dom.element( 'p' );
259 *
260 * var strong = new CKEDITOR.dom.element( 'strong' );
261 * p.append( strong );
262 *
263 * var em = p.append( 'em' );
264 *
265 * // Result: '<p><strong></strong><em></em></p>'
266 *
267 * @param {CKEDITOR.dom.node/String} node The node or element name to be appended.
268 * @param {Boolean} [toStart=false] Indicates that the element is to be appended at the start.
269 * @returns {CKEDITOR.dom.node} The appended node.
270 */
271 append: function( node, toStart ) {
272 if ( typeof node == 'string' )
273 node = this.getDocument().createElement( node );
274
275 if ( toStart )
276 this.$.insertBefore( node.$, this.$.firstChild );
277 else
278 this.$.appendChild( node.$ );
279
280 return node;
281 },
282
283 /**
284 * Append HTML as a child(ren) of this element.
285 *
286 * @param {String} html
287 */
288 appendHtml: function( html ) {
289 if ( !this.$.childNodes.length )
290 this.setHtml( html );
291 else {
292 var temp = new CKEDITOR.dom.element( 'div', this.getDocument() );
293 temp.setHtml( html );
294 temp.moveChildren( this );
295 }
296 },
297
298 /**
299 * Append text to this element.
300 *
301 * var p = new CKEDITOR.dom.element( 'p' );
302 * p.appendText( 'This is' );
303 * p.appendText( ' some text' );
304 *
305 * // Result: '<p>This is some text</p>'
306 *
307 * @param {String} text The text to be appended.
308 */
309 appendText: function( text ) {
310 // On IE8 it is impossible to append node to script tag, so we use its text.
311 // On the contrary, on Safari the text property is unpredictable in links. (#13232)
312 if ( this.$.text != null && CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
313 this.$.text += text;
314 else
315 this.append( new CKEDITOR.dom.text( text ) );
316 },
317
318 /**
319 * Appends a `<br>` filler element to this element if the filler is not present already.
320 * By default filler is appended only if {@link CKEDITOR.env#needsBrFiller} is `true`,
321 * however when `force` is set to `true` filler will be appended regardless of the environment.
322 *
323 * @param {Boolean} [force] Append filler regardless of the environment.
324 */
325 appendBogus: function( force ) {
326 if ( !force && !CKEDITOR.env.needsBrFiller )
327 return;
328
329 var lastChild = this.getLast();
330
331 // Ignore empty/spaces text.
332 while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.rtrim( lastChild.getText() ) )
333 lastChild = lastChild.getPrevious();
334 if ( !lastChild || !lastChild.is || !lastChild.is( 'br' ) ) {
335 var bogus = this.getDocument().createElement( 'br' );
336
337 CKEDITOR.env.gecko && bogus.setAttribute( 'type', '_moz' );
338
339 this.append( bogus );
340 }
341 },
342
343 /**
344 * Breaks one of the ancestor element in the element position, moving
345 * this element between the broken parts.
346 *
347 * // Before breaking:
348 * // <b>This <i>is some<span /> sample</i> test text</b>
349 * // If "element" is <span /> and "parent" is <i>:
350 * // <b>This <i>is some</i><span /><i> sample</i> test text</b>
351 * element.breakParent( parent );
352 *
353 * // Before breaking:
354 * // <b>This <i>is some<span /> sample</i> test text</b>
355 * // If "element" is <span /> and "parent" is <b>:
356 * // <b>This <i>is some</i></b><span /><b><i> sample</i> test text</b>
357 * element.breakParent( parent );
358 *
359 * @param {CKEDITOR.dom.element} parent The anscestor element to get broken.
360 * @param {Boolean} [cloneId=false] Whether to preserve ancestor ID attributes while breaking.
361 */
362 breakParent: function( parent, cloneId ) {
363 var range = new CKEDITOR.dom.range( this.getDocument() );
364
365 // We'll be extracting part of this element, so let's use our
366 // range to get the correct piece.
367 range.setStartAfter( this );
368 range.setEndAfter( parent );
369
370 // Extract it.
371 var docFrag = range.extractContents( false, cloneId || false ),
372 tmpElement,
373 current;
374
375 // Move the element outside the broken element.
376 range.insertNode( this.remove() );
377
378 // In case of Internet Explorer, we must check if there is no background-color
379 // added to the element. In such case, we have to overwrite it to prevent "switching it off"
380 // by a browser (#14667).
381 if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
382 tmpElement = new CKEDITOR.dom.element( 'div' );
383
384 while ( current = docFrag.getFirst() ) {
385 if ( current.$.style.backgroundColor ) {
386 // This is a necessary hack to make sure that IE will track backgroundColor CSS property, see
387 // http://dev.ckeditor.com/ticket/14667#comment:8 for more details.
388 current.$.style.backgroundColor = current.$.style.backgroundColor;
389 }
390
391 tmpElement.append( current );
392 }
393
394 // Re-insert the extracted piece after the element.
395 tmpElement.insertAfter( this );
396 tmpElement.remove( true );
397 } else {
398 // Re-insert the extracted piece after the element.
399 docFrag.insertAfterNode( this );
400 }
401 },
402
403 /**
404 * Checks if this element contains given node.
405 *
406 * @method
407 * @param {CKEDITOR.dom.node} node
408 * @returns {Boolean}
409 */
410 contains: !document.compareDocumentPosition ?
411 function( node ) {
412 var $ = this.$;
413
414 return node.type != CKEDITOR.NODE_ELEMENT ? $.contains( node.getParent().$ ) : $ != node.$ && $.contains( node.$ );
415 } : function( node ) {
416 return !!( this.$.compareDocumentPosition( node.$ ) & 16 );
417 },
418
419 /**
420 * Moves the selection focus to this element.
421 *
422 * var element = CKEDITOR.document.getById( 'myTextarea' );
423 * element.focus();
424 *
425 * @method
426 * @param {Boolean} defer Whether to asynchronously defer the
427 * execution by 100 ms.
428 */
429 focus: ( function() {
430 function exec() {
431 // IE throws error if the element is not visible.
432 try {
433 this.$.focus();
434 } catch ( e ) {}
435 }
436
437 return function( defer ) {
438 if ( defer )
439 CKEDITOR.tools.setTimeout( exec, 100, this );
440 else
441 exec.call( this );
442 };
443 } )(),
444
445 /**
446 * Gets the inner HTML of this element.
447 *
448 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b></div>' );
449 * alert( element.getHtml() ); // '<b>Example</b>'
450 *
451 * @returns {String} The inner HTML of this element.
452 */
453 getHtml: function() {
454 var retval = this.$.innerHTML;
455 // Strip <?xml:namespace> tags in IE. (#3341).
456 return CKEDITOR.env.ie ? retval.replace( /<\?[^>]*>/g, '' ) : retval;
457 },
458
459 /**
460 * Gets the outer (inner plus tags) HTML of this element.
461 *
462 * var element = CKEDITOR.dom.element.createFromHtml( '<div class="bold"><b>Example</b></div>' );
463 * alert( element.getOuterHtml() ); // '<div class="bold"><b>Example</b></div>'
464 *
465 * @returns {String} The outer HTML of this element.
466 */
467 getOuterHtml: function() {
468 if ( this.$.outerHTML ) {
469 // IE includes the <?xml:namespace> tag in the outerHTML of
470 // namespaced element. So, we must strip it here. (#3341)
471 return this.$.outerHTML.replace( /<\?[^>]*>/, '' );
472 }
473
474 var tmpDiv = this.$.ownerDocument.createElement( 'div' );
475 tmpDiv.appendChild( this.$.cloneNode( true ) );
476 return tmpDiv.innerHTML;
477 },
478
479 /**
480 * Retrieve the bounding rectangle of the current element, in pixels,
481 * relative to the upper-left corner of the browser's client area.
482 *
483 * @returns {Object} The dimensions of the DOM element including
484 * `left`, `top`, `right`, `bottom`, `width` and `height`.
485 */
486 getClientRect: function() {
487 // http://help.dottoro.com/ljvmcrrn.php
488 var rect = CKEDITOR.tools.extend( {}, this.$.getBoundingClientRect() );
489
490 !rect.width && ( rect.width = rect.right - rect.left );
491 !rect.height && ( rect.height = rect.bottom - rect.top );
492
493 return rect;
494 },
495
496 /**
497 * Sets the inner HTML of this element.
498 *
499 * var p = new CKEDITOR.dom.element( 'p' );
500 * p.setHtml( '<b>Inner</b> HTML' );
501 *
502 * // Result: '<p><b>Inner</b> HTML</p>'
503 *
504 * @method
505 * @param {String} html The HTML to be set for this element.
506 * @returns {String} The inserted HTML.
507 */
508 setHtml: ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) ?
509 // old IEs throws error on HTML manipulation (through the "innerHTML" property)
510 // on the element which resides in an DTD invalid position, e.g. <span><div></div></span>
511 // fortunately it can be worked around with DOM manipulation.
512 function( html ) {
513 try {
514 var $ = this.$;
515
516 // Fix the case when setHtml is called on detached element.
517 // HTML5 shiv used for document in which this element was created
518 // won't affect that detached element. So get document fragment with
519 // all HTML5 elements enabled and set innerHTML while this element is appended to it.
520 if ( this.getParent() )
521 return ( $.innerHTML = html );
522 else {
523 var $frag = this.getDocument()._getHtml5ShivFrag();
524 $frag.appendChild( $ );
525 $.innerHTML = html;
526 $frag.removeChild( $ );
527
528 return html;
529 }
530 }
531 catch ( e ) {
532 this.$.innerHTML = '';
533
534 var temp = new CKEDITOR.dom.element( 'body', this.getDocument() );
535 temp.$.innerHTML = html;
536
537 var children = temp.getChildren();
538 while ( children.count() )
539 this.append( children.getItem( 0 ) );
540
541 return html;
542 }
543 } : function( html ) {
544 return ( this.$.innerHTML = html );
545 },
546
547 /**
548 * Sets the element contents as plain text.
549 *
550 * var element = new CKEDITOR.dom.element( 'div' );
551 * element.setText( 'A > B & C < D' );
552 * alert( element.innerHTML ); // 'A &gt; B &amp; C &lt; D'
553 *
554 * @param {String} text The text to be set.
555 * @returns {String} The inserted text.
556 */
557 setText: ( function() {
558 var supportsTextContent = document.createElement( 'p' );
559 supportsTextContent.innerHTML = 'x';
560 supportsTextContent = supportsTextContent.textContent;
561
562 return function( text ) {
563 this.$[ supportsTextContent ? 'textContent' : 'innerText' ] = text;
564 };
565 } )(),
566
567 /**
568 * Gets the value of an element attribute.
569 *
570 * var element = CKEDITOR.dom.element.createFromHtml( '<input type="text" />' );
571 * alert( element.getAttribute( 'type' ) ); // 'text'
572 *
573 * @method
574 * @param {String} name The attribute name.
575 * @returns {String} The attribute value or null if not defined.
576 */
577 getAttribute: ( function() {
578 var standard = function( name ) {
579 return this.$.getAttribute( name, 2 );
580 };
581
582 if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks ) ) {
583 return function( name ) {
584 switch ( name ) {
585 case 'class':
586 name = 'className';
587 break;
588
589 case 'http-equiv':
590 name = 'httpEquiv';
591 break;
592
593 case 'name':
594 return this.$.name;
595
596 case 'tabindex':
597 var tabIndex = standard.call( this, name );
598
599 // IE returns tabIndex=0 by default for all
600 // elements. For those elements,
601 // getAtrribute( 'tabindex', 2 ) returns 32768
602 // instead. So, we must make this check to give a
603 // uniform result among all browsers.
604 if ( tabIndex !== 0 && this.$.tabIndex === 0 )
605 tabIndex = null;
606
607 return tabIndex;
608
609 case 'checked':
610 var attr = this.$.attributes.getNamedItem( name ),
611 attrValue = attr.specified ? attr.nodeValue // For value given by parser.
612 : this.$.checked; // For value created via DOM interface.
613
614 return attrValue ? 'checked' : null;
615
616 case 'hspace':
617 case 'value':
618 return this.$[ name ];
619
620 case 'style':
621 // IE does not return inline styles via getAttribute(). See #2947.
622 return this.$.style.cssText;
623
624 case 'contenteditable':
625 case 'contentEditable':
626 return this.$.attributes.getNamedItem( 'contentEditable' ).specified ? this.$.getAttribute( 'contentEditable' ) : null;
627 }
628
629 return standard.call( this, name );
630 };
631 } else {
632 return standard;
633 }
634 } )(),
635
636 /**
637 * Gets the values of all element attributes.
638 *
639 * @param {Array} exclude The names of attributes to be excluded from the returned object.
640 * @return {Object} An object containing all element attributes with their values.
641 */
642 getAttributes: function( exclude ) {
643 var attributes = {},
644 attrDefs = this.$.attributes,
645 i;
646
647 exclude = CKEDITOR.tools.isArray( exclude ) ? exclude : [];
648
649 for ( i = 0; i < attrDefs.length; i++ ) {
650 if ( CKEDITOR.tools.indexOf( exclude, attrDefs[ i ].name ) === -1 ) {
651 attributes[ attrDefs[ i ].name ] = attrDefs[ i ].value;
652 }
653 }
654
655 return attributes;
656 },
657
658 /**
659 * Gets the nodes list containing all children of this element.
660 *
661 * @returns {CKEDITOR.dom.nodeList}
662 */
663 getChildren: function() {
664 return new CKEDITOR.dom.nodeList( this.$.childNodes );
665 },
666
667 /**
668 * Gets the current computed value of one of the element CSS style
669 * properties.
670 *
671 * var element = new CKEDITOR.dom.element( 'span' );
672 * alert( element.getComputedStyle( 'display' ) ); // 'inline'
673 *
674 * @method
675 * @param {String} propertyName The style property name.
676 * @returns {String} The property value.
677 */
678 getComputedStyle: ( document.defaultView && document.defaultView.getComputedStyle ) ?
679 function( propertyName ) {
680 var style = this.getWindow().$.getComputedStyle( this.$, null );
681
682 // Firefox may return null if we call the above on a hidden iframe. (#9117)
683 return style ? style.getPropertyValue( propertyName ) : '';
684 } : function( propertyName ) {
685 return this.$.currentStyle[ CKEDITOR.tools.cssStyleToDomStyle( propertyName ) ];
686 },
687
688 /**
689 * Gets the DTD entries for this element.
690 *
691 * @returns {Object} An object containing the list of elements accepted
692 * by this element.
693 */
694 getDtd: function() {
695 var dtd = CKEDITOR.dtd[ this.getName() ];
696
697 this.getDtd = function() {
698 return dtd;
699 };
700
701 return dtd;
702 },
703
704 /**
705 * Gets all this element's descendants having given tag name.
706 *
707 * @method
708 * @param {String} tagName
709 */
710 getElementsByTag: CKEDITOR.dom.document.prototype.getElementsByTag,
711
712 /**
713 * Gets the computed tabindex for this element.
714 *
715 * var element = CKEDITOR.document.getById( 'myDiv' );
716 * alert( element.getTabIndex() ); // (e.g.) '-1'
717 *
718 * @method
719 * @returns {Number} The tabindex value.
720 */
721 getTabIndex: function() {
722 var tabIndex = this.$.tabIndex;
723
724 // IE returns tabIndex=0 by default for all elements. In
725 // those cases we must check that the element really has
726 // the tabindex attribute set to zero, or it is one of
727 // those element that should have zero by default.
728 if ( tabIndex === 0 && !CKEDITOR.dtd.$tabIndex[ this.getName() ] && parseInt( this.getAttribute( 'tabindex' ), 10 ) !== 0 )
729 return -1;
730
731 return tabIndex;
732 },
733
734 /**
735 * Gets the text value of this element.
736 *
737 * Only in IE (which uses innerText), `<br>` will cause linebreaks,
738 * and sucessive whitespaces (including line breaks) will be reduced to
739 * a single space. This behavior is ok for us, for now. It may change
740 * in the future.
741 *
742 * var element = CKEDITOR.dom.element.createFromHtml( '<div>Sample <i>text</i>.</div>' );
743 * alert( <b>element.getText()</b> ); // 'Sample text.'
744 *
745 * @returns {String} The text value.
746 */
747 getText: function() {
748 return this.$.textContent || this.$.innerText || '';
749 },
750
751 /**
752 * Gets the window object that contains this element.
753 *
754 * @returns {CKEDITOR.dom.window} The window object.
755 */
756 getWindow: function() {
757 return this.getDocument().getWindow();
758 },
759
760 /**
761 * Gets the value of the `id` attribute of this element.
762 *
763 * var element = CKEDITOR.dom.element.createFromHtml( '<p id="myId"></p>' );
764 * alert( element.getId() ); // 'myId'
765 *
766 * @returns {String} The element id, or null if not available.
767 */
768 getId: function() {
769 return this.$.id || null;
770 },
771
772 /**
773 * Gets the value of the `name` attribute of this element.
774 *
775 * var element = CKEDITOR.dom.element.createFromHtml( '<input name="myName"></input>' );
776 * alert( <b>element.getNameAtt()</b> ); // 'myName'
777 *
778 * @returns {String} The element name, or null if not available.
779 */
780 getNameAtt: function() {
781 return this.$.name || null;
782 },
783
784 /**
785 * Gets the element name (tag name). The returned name is guaranteed to
786 * be always full lowercased.
787 *
788 * var element = new CKEDITOR.dom.element( 'span' );
789 * alert( element.getName() ); // 'span'
790 *
791 * @returns {String} The element name.
792 */
793 getName: function() {
794 // Cache the lowercased name inside a closure.
795 var nodeName = this.$.nodeName.toLowerCase();
796
797 if ( CKEDITOR.env.ie && ( document.documentMode <= 8 ) ) {
798 var scopeName = this.$.scopeName;
799 if ( scopeName != 'HTML' )
800 nodeName = scopeName.toLowerCase() + ':' + nodeName;
801 }
802
803 this.getName = function() {
804 return nodeName;
805 };
806
807 return this.getName();
808 },
809
810 /**
811 * Gets the value set to this element. This value is usually available
812 * for form field elements.
813 *
814 * @returns {String} The element value.
815 */
816 getValue: function() {
817 return this.$.value;
818 },
819
820 /**
821 * Gets the first child node of this element.
822 *
823 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b></div>' );
824 * var first = element.getFirst();
825 * alert( first.getName() ); // 'b'
826 *
827 * @param {Function} evaluator Filtering the result node.
828 * @returns {CKEDITOR.dom.node} The first child node or null if not available.
829 */
830 getFirst: function( evaluator ) {
831 var first = this.$.firstChild,
832 retval = first && new CKEDITOR.dom.node( first );
833 if ( retval && evaluator && !evaluator( retval ) )
834 retval = retval.getNext( evaluator );
835
836 return retval;
837 },
838
839 /**
840 * See {@link #getFirst}.
841 *
842 * @param {Function} evaluator Filtering the result node.
843 * @returns {CKEDITOR.dom.node}
844 */
845 getLast: function( evaluator ) {
846 var last = this.$.lastChild,
847 retval = last && new CKEDITOR.dom.node( last );
848 if ( retval && evaluator && !evaluator( retval ) )
849 retval = retval.getPrevious( evaluator );
850
851 return retval;
852 },
853
854 /**
855 * Gets CSS style value.
856 *
857 * @param {String} name The CSS property name.
858 * @returns {String} Style value.
859 */
860 getStyle: function( name ) {
861 return this.$.style[ CKEDITOR.tools.cssStyleToDomStyle( name ) ];
862 },
863
864 /**
865 * Checks if the element name matches the specified criteria.
866 *
867 * var element = new CKEDITOR.element( 'span' );
868 * alert( element.is( 'span' ) ); // true
869 * alert( element.is( 'p', 'span' ) ); // true
870 * alert( element.is( 'p' ) ); // false
871 * alert( element.is( 'p', 'div' ) ); // false
872 * alert( element.is( { p:1,span:1 } ) ); // true
873 *
874 * @param {String.../Object} name One or more names to be checked, or a {@link CKEDITOR.dtd} object.
875 * @returns {Boolean} `true` if the element name matches any of the names.
876 */
877 is: function() {
878 var name = this.getName();
879
880 // Check against the specified DTD liternal.
881 if ( typeof arguments[ 0 ] == 'object' )
882 return !!arguments[ 0 ][ name ];
883
884 // Check for tag names
885 for ( var i = 0; i < arguments.length; i++ ) {
886 if ( arguments[ i ] == name )
887 return true;
888 }
889 return false;
890 },
891
892 /**
893 * Decide whether one element is able to receive cursor.
894 *
895 * @param {Boolean} [textCursor=true] Only consider element that could receive text child.
896 */
897 isEditable: function( textCursor ) {
898 var name = this.getName();
899
900 if ( this.isReadOnly() || this.getComputedStyle( 'display' ) == 'none' ||
901 this.getComputedStyle( 'visibility' ) == 'hidden' ||
902 CKEDITOR.dtd.$nonEditable[ name ] ||
903 CKEDITOR.dtd.$empty[ name ] ||
904 ( this.is( 'a' ) &&
905 ( this.data( 'cke-saved-name' ) || this.hasAttribute( 'name' ) ) &&
906 !this.getChildCount()
907 ) ) {
908 return false;
909 }
910
911 if ( textCursor !== false ) {
912 // Get the element DTD (defaults to span for unknown elements).
913 var dtd = CKEDITOR.dtd[ name ] || CKEDITOR.dtd.span;
914 // In the DTD # == text node.
915 return !!( dtd && dtd[ '#' ] );
916 }
917
918 return true;
919 },
920
921 /**
922 * Compare this element's inner html, tag name, attributes, etc. with other one.
923 *
924 * See [W3C's DOM Level 3 spec - node#isEqualNode](http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-isEqualNode)
925 * for more details.
926 *
927 * @param {CKEDITOR.dom.element} otherElement Element to compare.
928 * @returns {Boolean}
929 */
930 isIdentical: function( otherElement ) {
931 // do shallow clones, but with IDs
932 var thisEl = this.clone( 0, 1 ),
933 otherEl = otherElement.clone( 0, 1 );
934
935 // Remove distractions.
936 thisEl.removeAttributes( [ '_moz_dirty', 'data-cke-expando', 'data-cke-saved-href', 'data-cke-saved-name' ] );
937 otherEl.removeAttributes( [ '_moz_dirty', 'data-cke-expando', 'data-cke-saved-href', 'data-cke-saved-name' ] );
938
939 // Native comparison available.
940 if ( thisEl.$.isEqualNode ) {
941 // Styles order matters.
942 thisEl.$.style.cssText = CKEDITOR.tools.normalizeCssText( thisEl.$.style.cssText );
943 otherEl.$.style.cssText = CKEDITOR.tools.normalizeCssText( otherEl.$.style.cssText );
944 return thisEl.$.isEqualNode( otherEl.$ );
945 } else {
946 thisEl = thisEl.getOuterHtml();
947 otherEl = otherEl.getOuterHtml();
948
949 // Fix tiny difference between link href in older IEs.
950 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && this.is( 'a' ) ) {
951 var parent = this.getParent();
952 if ( parent.type == CKEDITOR.NODE_ELEMENT ) {
953 var el = parent.clone();
954 el.setHtml( thisEl ), thisEl = el.getHtml();
955 el.setHtml( otherEl ), otherEl = el.getHtml();
956 }
957 }
958
959 return thisEl == otherEl;
960 }
961 },
962
963 /**
964 * Checks if this element is visible. May not work if the element is
965 * child of an element with visibility set to `hidden`, but works well
966 * on the great majority of cases.
967 *
968 * @returns {Boolean} True if the element is visible.
969 */
970 isVisible: function() {
971 var isVisible = ( this.$.offsetHeight || this.$.offsetWidth ) && this.getComputedStyle( 'visibility' ) != 'hidden',
972 elementWindow, elementWindowFrame;
973
974 // Webkit and Opera report non-zero offsetHeight despite that
975 // element is inside an invisible iframe. (#4542)
976 if ( isVisible && CKEDITOR.env.webkit ) {
977 elementWindow = this.getWindow();
978
979 if ( !elementWindow.equals( CKEDITOR.document.getWindow() ) && ( elementWindowFrame = elementWindow.$.frameElement ) )
980 isVisible = new CKEDITOR.dom.element( elementWindowFrame ).isVisible();
981
982 }
983
984 return !!isVisible;
985 },
986
987 /**
988 * Whether it's an empty inline elements which has no visual impact when removed.
989 *
990 * @returns {Boolean}
991 */
992 isEmptyInlineRemoveable: function() {
993 if ( !CKEDITOR.dtd.$removeEmpty[ this.getName() ] )
994 return false;
995
996 var children = this.getChildren();
997 for ( var i = 0, count = children.count(); i < count; i++ ) {
998 var child = children.getItem( i );
999
1000 if ( child.type == CKEDITOR.NODE_ELEMENT && child.data( 'cke-bookmark' ) )
1001 continue;
1002
1003 if ( child.type == CKEDITOR.NODE_ELEMENT && !child.isEmptyInlineRemoveable() || child.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.trim( child.getText() ) )
1004 return false;
1005
1006 }
1007 return true;
1008 },
1009
1010 /**
1011 * Checks if the element has any defined attributes.
1012 *
1013 * var element = CKEDITOR.dom.element.createFromHtml( '<div title="Test">Example</div>' );
1014 * alert( element.hasAttributes() ); // true
1015 *
1016 * var element = CKEDITOR.dom.element.createFromHtml( '<div>Example</div>' );
1017 * alert( element.hasAttributes() ); // false
1018 *
1019 * @method
1020 * @returns {Boolean} True if the element has attributes.
1021 */
1022 hasAttributes: CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks ) ?
1023 function() {
1024 var attributes = this.$.attributes;
1025
1026 for ( var i = 0; i < attributes.length; i++ ) {
1027 var attribute = attributes[ i ];
1028
1029 switch ( attribute.nodeName ) {
1030 case 'class':
1031 // IE has a strange bug. If calling removeAttribute('className'),
1032 // the attributes collection will still contain the "class"
1033 // attribute, which will be marked as "specified", even if the
1034 // outerHTML of the element is not displaying the class attribute.
1035 // Note : I was not able to reproduce it outside the editor,
1036 // but I've faced it while working on the TC of #1391.
1037 if ( this.getAttribute( 'class' ) ) {
1038 return true;
1039 }
1040
1041 // Attributes to be ignored.
1042 /* falls through */
1043 case 'data-cke-expando':
1044 continue;
1045
1046
1047 /* falls through */
1048 default:
1049 if ( attribute.specified ) {
1050 return true;
1051 }
1052 }
1053 }
1054
1055 return false;
1056 } : function() {
1057 var attrs = this.$.attributes,
1058 attrsNum = attrs.length;
1059
1060 // The _moz_dirty attribute might get into the element after pasting (#5455)
1061 var execludeAttrs = { 'data-cke-expando': 1, _moz_dirty: 1 };
1062
1063 return attrsNum > 0 && ( attrsNum > 2 || !execludeAttrs[ attrs[ 0 ].nodeName ] || ( attrsNum == 2 && !execludeAttrs[ attrs[ 1 ].nodeName ] ) );
1064 },
1065
1066 /**
1067 * Checks if the specified attribute is defined for this element.
1068 *
1069 * @method
1070 * @param {String} name The attribute name.
1071 * @returns {Boolean} `true` if the specified attribute is defined.
1072 */
1073 hasAttribute: ( function() {
1074 function ieHasAttribute( name ) {
1075 var $attr = this.$.attributes.getNamedItem( name );
1076
1077 if ( this.getName() == 'input' ) {
1078 switch ( name ) {
1079 case 'class':
1080 return this.$.className.length > 0;
1081 case 'checked':
1082 return !!this.$.checked;
1083 case 'value':
1084 var type = this.getAttribute( 'type' );
1085 return type == 'checkbox' || type == 'radio' ? this.$.value != 'on' : !!this.$.value;
1086 }
1087 }
1088
1089 if ( !$attr )
1090 return false;
1091
1092 return $attr.specified;
1093 }
1094
1095 if ( CKEDITOR.env.ie ) {
1096 if ( CKEDITOR.env.version < 8 ) {
1097 return function( name ) {
1098 // On IE < 8 the name attribute cannot be retrieved
1099 // right after the element creation and setting the
1100 // name with setAttribute.
1101 if ( name == 'name' )
1102 return !!this.$.name;
1103
1104 return ieHasAttribute.call( this, name );
1105 };
1106 } else {
1107 return ieHasAttribute;
1108 }
1109 } else {
1110 return function( name ) {
1111 // On other browsers specified property is deprecated and return always true,
1112 // but fortunately $.attributes contains only specified attributes.
1113 return !!this.$.attributes.getNamedItem( name );
1114 };
1115 }
1116 } )(),
1117
1118 /**
1119 * Hides this element (sets `display: none`).
1120 *
1121 * var element = CKEDITOR.document.getById( 'myElement' );
1122 * element.hide();
1123 */
1124 hide: function() {
1125 this.setStyle( 'display', 'none' );
1126 },
1127
1128 /**
1129 * Moves this element's children to the target element.
1130 *
1131 * @param {CKEDITOR.dom.element} target
1132 * @param {Boolean} [toStart=false] Insert moved children at the
1133 * beginning of the target element.
1134 */
1135 moveChildren: function( target, toStart ) {
1136 var $ = this.$;
1137 target = target.$;
1138
1139 if ( $ == target )
1140 return;
1141
1142 var child;
1143
1144 if ( toStart ) {
1145 while ( ( child = $.lastChild ) )
1146 target.insertBefore( $.removeChild( child ), target.firstChild );
1147 } else {
1148 while ( ( child = $.firstChild ) )
1149 target.appendChild( $.removeChild( child ) );
1150 }
1151 },
1152
1153 /**
1154 * Merges sibling elements that are identical to this one.
1155 *
1156 * Identical child elements are also merged. For example:
1157 *
1158 * <b><i></i></b><b><i></i></b> => <b><i></i></b>
1159 *
1160 * @method
1161 * @param {Boolean} [inlineOnly=true] Allow only inline elements to be merged.
1162 */
1163 mergeSiblings: ( function() {
1164 function mergeElements( element, sibling, isNext ) {
1165 if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT ) {
1166 // Jumping over bookmark nodes and empty inline elements, e.g. <b><i></i></b>,
1167 // queuing them to be moved later. (#5567)
1168 var pendingNodes = [];
1169
1170 while ( sibling.data( 'cke-bookmark' ) || sibling.isEmptyInlineRemoveable() ) {
1171 pendingNodes.push( sibling );
1172 sibling = isNext ? sibling.getNext() : sibling.getPrevious();
1173 if ( !sibling || sibling.type != CKEDITOR.NODE_ELEMENT )
1174 return;
1175 }
1176
1177 if ( element.isIdentical( sibling ) ) {
1178 // Save the last child to be checked too, to merge things like
1179 // <b><i></i></b><b><i></i></b> => <b><i></i></b>
1180 var innerSibling = isNext ? element.getLast() : element.getFirst();
1181
1182 // Move pending nodes first into the target element.
1183 while ( pendingNodes.length )
1184 pendingNodes.shift().move( element, !isNext );
1185
1186 sibling.moveChildren( element, !isNext );
1187 sibling.remove();
1188
1189 // Now check the last inner child (see two comments above).
1190 if ( innerSibling && innerSibling.type == CKEDITOR.NODE_ELEMENT )
1191 innerSibling.mergeSiblings();
1192 }
1193 }
1194 }
1195
1196 return function( inlineOnly ) {
1197 // Merge empty links and anchors also. (#5567)
1198 if ( !( inlineOnly === false || CKEDITOR.dtd.$removeEmpty[ this.getName() ] || this.is( 'a' ) ) ) {
1199 return;
1200 }
1201
1202 mergeElements( this, this.getNext(), true );
1203 mergeElements( this, this.getPrevious() );
1204 };
1205 } )(),
1206
1207 /**
1208 * Shows this element (displays it).
1209 *
1210 * var element = CKEDITOR.document.getById( 'myElement' );
1211 * element.show();
1212 */
1213 show: function() {
1214 this.setStyles( {
1215 display: '',
1216 visibility: ''
1217 } );
1218 },
1219
1220 /**
1221 * Sets the value of an element attribute.
1222 *
1223 * var element = CKEDITOR.document.getById( 'myElement' );
1224 * element.setAttribute( 'class', 'myClass' );
1225 * element.setAttribute( 'title', 'This is an example' );
1226 *
1227 * @method
1228 * @param {String} name The name of the attribute.
1229 * @param {String} value The value to be set to the attribute.
1230 * @returns {CKEDITOR.dom.element} This element instance.
1231 */
1232 setAttribute: ( function() {
1233 var standard = function( name, value ) {
1234 this.$.setAttribute( name, value );
1235 return this;
1236 };
1237
1238 if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks ) ) {
1239 return function( name, value ) {
1240 if ( name == 'class' )
1241 this.$.className = value;
1242 else if ( name == 'style' )
1243 this.$.style.cssText = value;
1244 else if ( name == 'tabindex' ) // Case sensitive.
1245 this.$.tabIndex = value;
1246 else if ( name == 'checked' )
1247 this.$.checked = value;
1248 else if ( name == 'contenteditable' )
1249 standard.call( this, 'contentEditable', value );
1250 else
1251 standard.apply( this, arguments );
1252 return this;
1253 };
1254 } else if ( CKEDITOR.env.ie8Compat && CKEDITOR.env.secure ) {
1255 return function( name, value ) {
1256 // IE8 throws error when setting src attribute to non-ssl value. (#7847)
1257 if ( name == 'src' && value.match( /^http:\/\// ) ) {
1258 try {
1259 standard.apply( this, arguments );
1260 } catch ( e ) {}
1261 } else {
1262 standard.apply( this, arguments );
1263 }
1264 return this;
1265 };
1266 } else {
1267 return standard;
1268 }
1269 } )(),
1270
1271 /**
1272 * Sets the value of several element attributes.
1273 *
1274 * var element = CKEDITOR.document.getById( 'myElement' );
1275 * element.setAttributes( {
1276 * 'class': 'myClass',
1277 * title: 'This is an example'
1278 * } );
1279 *
1280 * @chainable
1281 * @param {Object} attributesPairs An object containing the names and
1282 * values of the attributes.
1283 * @returns {CKEDITOR.dom.element} This element instance.
1284 */
1285 setAttributes: function( attributesPairs ) {
1286 for ( var name in attributesPairs )
1287 this.setAttribute( name, attributesPairs[ name ] );
1288 return this;
1289 },
1290
1291 /**
1292 * Sets the element value. This function is usually used with form
1293 * field element.
1294 *
1295 * @chainable
1296 * @param {String} value The element value.
1297 * @returns {CKEDITOR.dom.element} This element instance.
1298 */
1299 setValue: function( value ) {
1300 this.$.value = value;
1301 return this;
1302 },
1303
1304 /**
1305 * Removes an attribute from the element.
1306 *
1307 * var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA"></div>' );
1308 * element.removeAttribute( 'class' );
1309 *
1310 * @method
1311 * @param {String} name The attribute name.
1312 */
1313 removeAttribute: ( function() {
1314 var standard = function( name ) {
1315 this.$.removeAttribute( name );
1316 };
1317
1318 if ( CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.quirks ) ) {
1319 return function( name ) {
1320 if ( name == 'class' )
1321 name = 'className';
1322 else if ( name == 'tabindex' )
1323 name = 'tabIndex';
1324 else if ( name == 'contenteditable' )
1325 name = 'contentEditable';
1326 standard.call( this, name );
1327 };
1328 } else {
1329 return standard;
1330 }
1331 } )(),
1332
1333 /**
1334 * Removes all element's attributes or just given ones.
1335 *
1336 * @param {Array} [attributes] The array with attributes names.
1337 */
1338 removeAttributes: function( attributes ) {
1339 if ( CKEDITOR.tools.isArray( attributes ) ) {
1340 for ( var i = 0; i < attributes.length; i++ ) {
1341 this.removeAttribute( attributes[ i ] );
1342 }
1343 } else {
1344 attributes = attributes || this.getAttributes();
1345
1346 for ( var attr in attributes ) {
1347 attributes.hasOwnProperty( attr ) && this.removeAttribute( attr );
1348 }
1349 }
1350 },
1351
1352 /**
1353 * Removes a style from the element.
1354 *
1355 * var element = CKEDITOR.dom.element.createFromHtml( '<div style="display:none"></div>' );
1356 * element.removeStyle( 'display' );
1357 *
1358 * @method
1359 * @param {String} name The style name.
1360 */
1361 removeStyle: function( name ) {
1362 // Removes the specified property from the current style object.
1363 var $ = this.$.style;
1364
1365 // "removeProperty" need to be specific on the following styles.
1366 if ( !$.removeProperty && ( name == 'border' || name == 'margin' || name == 'padding' ) ) {
1367 var names = expandedRules( name );
1368 for ( var i = 0 ; i < names.length ; i++ )
1369 this.removeStyle( names[ i ] );
1370 return;
1371 }
1372
1373 $.removeProperty ? $.removeProperty( name ) : $.removeAttribute( CKEDITOR.tools.cssStyleToDomStyle( name ) );
1374
1375 // Eventually remove empty style attribute.
1376 if ( !this.$.style.cssText )
1377 this.removeAttribute( 'style' );
1378 },
1379
1380 /**
1381 * Sets the value of an element style.
1382 *
1383 * var element = CKEDITOR.document.getById( 'myElement' );
1384 * element.setStyle( 'background-color', '#ff0000' );
1385 * element.setStyle( 'margin-top', '10px' );
1386 * element.setStyle( 'float', 'right' );
1387 *
1388 * @param {String} name The name of the style. The CSS naming notation
1389 * must be used (e.g. `background-color`).
1390 * @param {String} value The value to be set to the style.
1391 * @returns {CKEDITOR.dom.element} This element instance.
1392 */
1393 setStyle: function( name, value ) {
1394 this.$.style[ CKEDITOR.tools.cssStyleToDomStyle( name ) ] = value;
1395 return this;
1396 },
1397
1398 /**
1399 * Sets the value of several element styles.
1400 *
1401 * var element = CKEDITOR.document.getById( 'myElement' );
1402 * element.setStyles( {
1403 * position: 'absolute',
1404 * float: 'right'
1405 * } );
1406 *
1407 * @param {Object} stylesPairs An object containing the names and
1408 * values of the styles.
1409 * @returns {CKEDITOR.dom.element} This element instance.
1410 */
1411 setStyles: function( stylesPairs ) {
1412 for ( var name in stylesPairs )
1413 this.setStyle( name, stylesPairs[ name ] );
1414 return this;
1415 },
1416
1417 /**
1418 * Sets the opacity of an element.
1419 *
1420 * var element = CKEDITOR.document.getById( 'myElement' );
1421 * element.setOpacity( 0.75 );
1422 *
1423 * @param {Number} opacity A number within the range `[0.0, 1.0]`.
1424 */
1425 setOpacity: function( opacity ) {
1426 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
1427 opacity = Math.round( opacity * 100 );
1428 this.setStyle( 'filter', opacity >= 100 ? '' : 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')' );
1429 } else {
1430 this.setStyle( 'opacity', opacity );
1431 }
1432 },
1433
1434 /**
1435 * Makes the element and its children unselectable.
1436 *
1437 * var element = CKEDITOR.document.getById( 'myElement' );
1438 * element.unselectable();
1439 *
1440 * @method
1441 */
1442 unselectable: function() {
1443 // CSS unselectable.
1444 this.setStyles( CKEDITOR.tools.cssVendorPrefix( 'user-select', 'none' ) );
1445
1446 // For IE/Opera which doesn't support for the above CSS style,
1447 // the unselectable="on" attribute only specifies the selection
1448 // process cannot start in the element itself, and it doesn't inherit.
1449 if ( CKEDITOR.env.ie ) {
1450 this.setAttribute( 'unselectable', 'on' );
1451
1452 var element,
1453 elements = this.getElementsByTag( '*' );
1454
1455 for ( var i = 0, count = elements.count() ; i < count ; i++ ) {
1456 element = elements.getItem( i );
1457 element.setAttribute( 'unselectable', 'on' );
1458 }
1459 }
1460 },
1461
1462 /**
1463 * Gets closest positioned (`position != static`) ancestor.
1464 *
1465 * @returns {CKEDITOR.dom.element} Positioned ancestor or `null`.
1466 */
1467 getPositionedAncestor: function() {
1468 var current = this;
1469 while ( current.getName() != 'html' ) {
1470 if ( current.getComputedStyle( 'position' ) != 'static' )
1471 return current;
1472
1473 current = current.getParent();
1474 }
1475 return null;
1476 },
1477
1478 /**
1479 * Gets this element's position in document.
1480 *
1481 * @param {CKEDITOR.dom.document} [refDocument]
1482 * @returns {Object} Element's position.
1483 * @returns {Number} return.x
1484 * @returns {Number} return.y
1485 * @todo refDocument
1486 */
1487 getDocumentPosition: function( refDocument ) {
1488 var x = 0,
1489 y = 0,
1490 doc = this.getDocument(),
1491 body = doc.getBody(),
1492 quirks = doc.$.compatMode == 'BackCompat';
1493
1494 if ( document.documentElement.getBoundingClientRect &&
1495 ( CKEDITOR.env.ie ? CKEDITOR.env.version !== 8 : true ) ) {
1496 var box = this.$.getBoundingClientRect(),
1497 $doc = doc.$,
1498 $docElem = $doc.documentElement;
1499
1500 var clientTop = $docElem.clientTop || body.$.clientTop || 0,
1501 clientLeft = $docElem.clientLeft || body.$.clientLeft || 0,
1502 needAdjustScrollAndBorders = true;
1503
1504 // #3804: getBoundingClientRect() works differently on IE and non-IE
1505 // browsers, regarding scroll positions.
1506 //
1507 // On IE, the top position of the <html> element is always 0, no matter
1508 // how much you scrolled down.
1509 //
1510 // On other browsers, the top position of the <html> element is negative
1511 // scrollTop.
1512 if ( CKEDITOR.env.ie ) {
1513 var inDocElem = doc.getDocumentElement().contains( this ),
1514 inBody = doc.getBody().contains( this );
1515
1516 needAdjustScrollAndBorders = ( quirks && inBody ) || ( !quirks && inDocElem );
1517 }
1518
1519 // #12747.
1520 if ( needAdjustScrollAndBorders ) {
1521 var scrollRelativeLeft,
1522 scrollRelativeTop;
1523
1524 // See #12758 to know more about document.(documentElement|body).scroll(Left|Top) in Webkit.
1525 if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version >= 12 ) ) {
1526 scrollRelativeLeft = body.$.scrollLeft || $docElem.scrollLeft;
1527 scrollRelativeTop = body.$.scrollTop || $docElem.scrollTop;
1528 } else {
1529 var scrollRelativeElement = quirks ? body.$ : $docElem;
1530
1531 scrollRelativeLeft = scrollRelativeElement.scrollLeft;
1532 scrollRelativeTop = scrollRelativeElement.scrollTop;
1533 }
1534
1535 x = box.left + scrollRelativeLeft - clientLeft;
1536 y = box.top + scrollRelativeTop - clientTop;
1537 }
1538 } else {
1539 var current = this,
1540 previous = null,
1541 offsetParent;
1542 while ( current && !( current.getName() == 'body' || current.getName() == 'html' ) ) {
1543 x += current.$.offsetLeft - current.$.scrollLeft;
1544 y += current.$.offsetTop - current.$.scrollTop;
1545
1546 // Opera includes clientTop|Left into offsetTop|Left.
1547 if ( !current.equals( this ) ) {
1548 x += ( current.$.clientLeft || 0 );
1549 y += ( current.$.clientTop || 0 );
1550 }
1551
1552 var scrollElement = previous;
1553 while ( scrollElement && !scrollElement.equals( current ) ) {
1554 x -= scrollElement.$.scrollLeft;
1555 y -= scrollElement.$.scrollTop;
1556 scrollElement = scrollElement.getParent();
1557 }
1558
1559 previous = current;
1560 current = ( offsetParent = current.$.offsetParent ) ? new CKEDITOR.dom.element( offsetParent ) : null;
1561 }
1562 }
1563
1564 if ( refDocument ) {
1565 var currentWindow = this.getWindow(),
1566 refWindow = refDocument.getWindow();
1567
1568 if ( !currentWindow.equals( refWindow ) && currentWindow.$.frameElement ) {
1569 var iframePosition = ( new CKEDITOR.dom.element( currentWindow.$.frameElement ) ).getDocumentPosition( refDocument );
1570
1571 x += iframePosition.x;
1572 y += iframePosition.y;
1573 }
1574 }
1575
1576 if ( !document.documentElement.getBoundingClientRect ) {
1577 // In Firefox, we'll endup one pixel before the element positions,
1578 // so we must add it here.
1579 if ( CKEDITOR.env.gecko && !quirks ) {
1580 x += this.$.clientLeft ? 1 : 0;
1581 y += this.$.clientTop ? 1 : 0;
1582 }
1583 }
1584
1585 return { x: x, y: y };
1586 },
1587
1588 /**
1589 * Make any page element visible inside the browser viewport.
1590 *
1591 * @param {Boolean} [alignToTop=false]
1592 */
1593 scrollIntoView: function( alignToTop ) {
1594 var parent = this.getParent();
1595 if ( !parent )
1596 return;
1597
1598 // Scroll the element into parent container from the inner out.
1599 do {
1600 // Check ancestors that overflows.
1601 var overflowed =
1602 parent.$.clientWidth && parent.$.clientWidth < parent.$.scrollWidth ||
1603 parent.$.clientHeight && parent.$.clientHeight < parent.$.scrollHeight;
1604
1605 // Skip body element, which will report wrong clientHeight when containing
1606 // floated content. (#9523)
1607 if ( overflowed && !parent.is( 'body' ) )
1608 this.scrollIntoParent( parent, alignToTop, 1 );
1609
1610 // Walk across the frame.
1611 if ( parent.is( 'html' ) ) {
1612 var win = parent.getWindow();
1613
1614 // Avoid security error.
1615 try {
1616 var iframe = win.$.frameElement;
1617 iframe && ( parent = new CKEDITOR.dom.element( iframe ) );
1618 } catch ( er ) {}
1619 }
1620 }
1621 while ( ( parent = parent.getParent() ) );
1622 },
1623
1624 /**
1625 * Make any page element visible inside one of the ancestors by scrolling the parent.
1626 *
1627 * @param {CKEDITOR.dom.element/CKEDITOR.dom.window} parent The container to scroll into.
1628 * @param {Boolean} [alignToTop] Align the element's top side with the container's
1629 * when `true` is specified; align the bottom with viewport bottom when
1630 * `false` is specified. Otherwise scroll on either side with the minimum
1631 * amount to show the element.
1632 * @param {Boolean} [hscroll] Whether horizontal overflow should be considered.
1633 */
1634 scrollIntoParent: function( parent, alignToTop, hscroll ) {
1635 !parent && ( parent = this.getWindow() );
1636
1637 var doc = parent.getDocument();
1638 var isQuirks = doc.$.compatMode == 'BackCompat';
1639
1640 // On window <html> is scrolled while quirks scrolls <body>.
1641 if ( parent instanceof CKEDITOR.dom.window )
1642 parent = isQuirks ? doc.getBody() : doc.getDocumentElement();
1643
1644 // Scroll the parent by the specified amount.
1645 function scrollBy( x, y ) {
1646 // Webkit doesn't support "scrollTop/scrollLeft"
1647 // on documentElement/body element.
1648 if ( /body|html/.test( parent.getName() ) )
1649 parent.getWindow().$.scrollBy( x, y );
1650 else {
1651 parent.$.scrollLeft += x;
1652 parent.$.scrollTop += y;
1653 }
1654 }
1655
1656 // Figure out the element position relative to the specified window.
1657 function screenPos( element, refWin ) {
1658 var pos = { x: 0, y: 0 };
1659
1660 if ( !( element.is( isQuirks ? 'body' : 'html' ) ) ) {
1661 var box = element.$.getBoundingClientRect();
1662 pos.x = box.left, pos.y = box.top;
1663 }
1664
1665 var win = element.getWindow();
1666 if ( !win.equals( refWin ) ) {
1667 var outerPos = screenPos( CKEDITOR.dom.element.get( win.$.frameElement ), refWin );
1668 pos.x += outerPos.x, pos.y += outerPos.y;
1669 }
1670
1671 return pos;
1672 }
1673
1674 // calculated margin size.
1675 function margin( element, side ) {
1676 return parseInt( element.getComputedStyle( 'margin-' + side ) || 0, 10 ) || 0;
1677 }
1678
1679 // [WebKit] Reset stored scrollTop value to not break scrollIntoView() method flow.
1680 // Scrolling breaks when range.select() is used right after element.scrollIntoView(). (#14659)
1681 if ( CKEDITOR.env.webkit ) {
1682 var editor = this.getEditor( false );
1683
1684 if ( editor ) {
1685 editor._.previousScrollTop = null;
1686 }
1687 }
1688
1689 var win = parent.getWindow();
1690
1691 var thisPos = screenPos( this, win ),
1692 parentPos = screenPos( parent, win ),
1693 eh = this.$.offsetHeight,
1694 ew = this.$.offsetWidth,
1695 ch = parent.$.clientHeight,
1696 cw = parent.$.clientWidth,
1697 lt, br;
1698
1699 // Left-top margins.
1700 lt = {
1701 x: thisPos.x - margin( this, 'left' ) - parentPos.x || 0,
1702 y: thisPos.y - margin( this, 'top' ) - parentPos.y || 0
1703 };
1704
1705 // Bottom-right margins.
1706 br = {
1707 x: thisPos.x + ew + margin( this, 'right' ) - ( ( parentPos.x ) + cw ) || 0,
1708 y: thisPos.y + eh + margin( this, 'bottom' ) - ( ( parentPos.y ) + ch ) || 0
1709 };
1710
1711 // 1. Do the specified alignment as much as possible;
1712 // 2. Otherwise be smart to scroll only the minimum amount;
1713 // 3. Never cut at the top;
1714 // 4. DO NOT scroll when already visible.
1715 if ( lt.y < 0 || br.y > 0 )
1716 scrollBy( 0, alignToTop === true ? lt.y : alignToTop === false ? br.y : lt.y < 0 ? lt.y : br.y );
1717
1718 if ( hscroll && ( lt.x < 0 || br.x > 0 ) )
1719 scrollBy( lt.x < 0 ? lt.x : br.x, 0 );
1720 },
1721
1722 /**
1723 * Switch the `class` attribute to reflect one of the triple states of an
1724 * element in one of {@link CKEDITOR#TRISTATE_ON}, {@link CKEDITOR#TRISTATE_OFF}
1725 * or {@link CKEDITOR#TRISTATE_DISABLED}.
1726 *
1727 * link.setState( CKEDITOR.TRISTATE_ON );
1728 * // <a class="cke_on" aria-pressed="true">...</a>
1729 * link.setState( CKEDITOR.TRISTATE_OFF );
1730 * // <a class="cke_off">...</a>
1731 * link.setState( CKEDITOR.TRISTATE_DISABLED );
1732 * // <a class="cke_disabled" aria-disabled="true">...</a>
1733 *
1734 * span.setState( CKEDITOR.TRISTATE_ON, 'cke_button' );
1735 * // <span class="cke_button_on">...</span>
1736 *
1737 * @param {Number} state Indicate the element state. One of {@link CKEDITOR#TRISTATE_ON},
1738 * {@link CKEDITOR#TRISTATE_OFF}, {@link CKEDITOR#TRISTATE_DISABLED}.
1739 * @param [base='cke'] The prefix apply to each of the state class name.
1740 * @param [useAria=true] Whether toggle the ARIA state attributes besides of class name change.
1741 */
1742 setState: function( state, base, useAria ) {
1743 base = base || 'cke';
1744
1745 switch ( state ) {
1746 case CKEDITOR.TRISTATE_ON:
1747 this.addClass( base + '_on' );
1748 this.removeClass( base + '_off' );
1749 this.removeClass( base + '_disabled' );
1750 useAria && this.setAttribute( 'aria-pressed', true );
1751 useAria && this.removeAttribute( 'aria-disabled' );
1752 break;
1753
1754 case CKEDITOR.TRISTATE_DISABLED:
1755 this.addClass( base + '_disabled' );
1756 this.removeClass( base + '_off' );
1757 this.removeClass( base + '_on' );
1758 useAria && this.setAttribute( 'aria-disabled', true );
1759 useAria && this.removeAttribute( 'aria-pressed' );
1760 break;
1761
1762 default:
1763 this.addClass( base + '_off' );
1764 this.removeClass( base + '_on' );
1765 this.removeClass( base + '_disabled' );
1766 useAria && this.removeAttribute( 'aria-pressed' );
1767 useAria && this.removeAttribute( 'aria-disabled' );
1768 break;
1769 }
1770 },
1771
1772 /**
1773 * Returns the inner document of this `<iframe>` element.
1774 *
1775 * @returns {CKEDITOR.dom.document} The inner document.
1776 */
1777 getFrameDocument: function() {
1778 var $ = this.$;
1779
1780 try {
1781 // In IE, with custom document.domain, it may happen that
1782 // the iframe is not yet available, resulting in "Access
1783 // Denied" for the following property access.
1784 $.contentWindow.document;
1785 } catch ( e ) {
1786 // Trick to solve this issue, forcing the iframe to get ready
1787 // by simply setting its "src" property.
1788 $.src = $.src;
1789 }
1790
1791 return $ && new CKEDITOR.dom.document( $.contentWindow.document );
1792 },
1793
1794 /**
1795 * Copy all the attributes from one node to the other, kinda like a clone
1796 * skipAttributes is an object with the attributes that must **not** be copied.
1797 *
1798 * @param {CKEDITOR.dom.element} dest The destination element.
1799 * @param {Object} skipAttributes A dictionary of attributes to skip.
1800 */
1801 copyAttributes: function( dest, skipAttributes ) {
1802 var attributes = this.$.attributes;
1803 skipAttributes = skipAttributes || {};
1804
1805 for ( var n = 0; n < attributes.length; n++ ) {
1806 var attribute = attributes[ n ];
1807
1808 // Lowercase attribute name hard rule is broken for
1809 // some attribute on IE, e.g. CHECKED.
1810 var attrName = attribute.nodeName.toLowerCase(),
1811 attrValue;
1812
1813 // We can set the type only once, so do it with the proper value, not copying it.
1814 if ( attrName in skipAttributes )
1815 continue;
1816
1817 if ( attrName == 'checked' && ( attrValue = this.getAttribute( attrName ) ) )
1818 dest.setAttribute( attrName, attrValue );
1819 // IE contains not specified attributes in $.attributes so we need to check
1820 // if elements attribute is specified using hasAttribute.
1821 else if ( !CKEDITOR.env.ie || this.hasAttribute( attrName ) ) {
1822 attrValue = this.getAttribute( attrName );
1823 if ( attrValue === null )
1824 attrValue = attribute.nodeValue;
1825
1826 dest.setAttribute( attrName, attrValue );
1827 }
1828 }
1829
1830 // The style:
1831 if ( this.$.style.cssText !== '' )
1832 dest.$.style.cssText = this.$.style.cssText;
1833 },
1834
1835 /**
1836 * Changes the tag name of the current element.
1837 *
1838 * @param {String} newTag The new tag for the element.
1839 */
1840 renameNode: function( newTag ) {
1841 // If it's already correct exit here.
1842 if ( this.getName() == newTag )
1843 return;
1844
1845 var doc = this.getDocument();
1846
1847 // Create the new node.
1848 var newNode = new CKEDITOR.dom.element( newTag, doc );
1849
1850 // Copy all attributes.
1851 this.copyAttributes( newNode );
1852
1853 // Move children to the new node.
1854 this.moveChildren( newNode );
1855
1856 // Replace the node.
1857 this.getParent( true ) && this.$.parentNode.replaceChild( newNode.$, this.$ );
1858 newNode.$[ 'data-cke-expando' ] = this.$[ 'data-cke-expando' ];
1859 this.$ = newNode.$;
1860 // Bust getName's cache. (#8663)
1861 delete this.getName;
1862 },
1863
1864 /**
1865 * Gets a DOM tree descendant under the current node.
1866 *
1867 * var strong = p.getChild( 0 );
1868 *
1869 * @method
1870 * @param {Array/Number} indices The child index or array of child indices under the node.
1871 * @returns {CKEDITOR.dom.node} The specified DOM child under the current node. Null if child does not exist.
1872 */
1873 getChild: ( function() {
1874 function getChild( rawNode, index ) {
1875 var childNodes = rawNode.childNodes;
1876
1877 if ( index >= 0 && index < childNodes.length )
1878 return childNodes[ index ];
1879 }
1880
1881 return function( indices ) {
1882 var rawNode = this.$;
1883
1884 if ( !indices.slice )
1885 rawNode = getChild( rawNode, indices );
1886 else {
1887 indices = indices.slice();
1888 while ( indices.length > 0 && rawNode )
1889 rawNode = getChild( rawNode, indices.shift() );
1890 }
1891
1892 return rawNode ? new CKEDITOR.dom.node( rawNode ) : null;
1893 };
1894 } )(),
1895
1896 /**
1897 * Gets number of element's children.
1898 *
1899 * @returns {Number}
1900 */
1901 getChildCount: function() {
1902 return this.$.childNodes.length;
1903 },
1904
1905 /**
1906 * Disables browser's context menu in this element.
1907 */
1908 disableContextMenu: function() {
1909 this.on( 'contextmenu', function( evt ) {
1910 // Cancel the browser context menu.
1911 if ( !evt.data.getTarget().getAscendant( enablesContextMenu, true ) )
1912 evt.data.preventDefault();
1913 } );
1914
1915 function enablesContextMenu( node ) {
1916 return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_enable_context_menu' );
1917 }
1918 },
1919
1920 /**
1921 * Gets element's direction. Supports both CSS `direction` prop and `dir` attr.
1922 */
1923 getDirection: function( useComputed ) {
1924 if ( useComputed ) {
1925 return this.getComputedStyle( 'direction' ) ||
1926 this.getDirection() ||
1927 this.getParent() && this.getParent().getDirection( 1 ) ||
1928 this.getDocument().$.dir ||
1929 'ltr';
1930 }
1931 else {
1932 return this.getStyle( 'direction' ) || this.getAttribute( 'dir' );
1933 }
1934 },
1935
1936 /**
1937 * Gets, sets and removes custom data to be stored as HTML5 data-* attributes.
1938 *
1939 * element.data( 'extra-info', 'test' ); // Appended the attribute data-extra-info="test" to the element.
1940 * alert( element.data( 'extra-info' ) ); // 'test'
1941 * element.data( 'extra-info', false ); // Remove the data-extra-info attribute from the element.
1942 *
1943 * @param {String} name The name of the attribute, excluding the `data-` part.
1944 * @param {String} [value] The value to set. If set to false, the attribute will be removed.
1945 */
1946 data: function( name, value ) {
1947 name = 'data-' + name;
1948 if ( value === undefined )
1949 return this.getAttribute( name );
1950 else if ( value === false )
1951 this.removeAttribute( name );
1952 else
1953 this.setAttribute( name, value );
1954
1955 return null;
1956 },
1957
1958 /**
1959 * Retrieves an editor instance which is based on this element (if any).
1960 * It basically loops over {@link CKEDITOR#instances} in search for an instance
1961 * that uses the element.
1962 *
1963 * var element = new CKEDITOR.dom.element( 'div' );
1964 * element.appendTo( CKEDITOR.document.getBody() );
1965 * CKEDITOR.replace( element );
1966 * alert( element.getEditor().name ); // 'editor1'
1967 *
1968 * By default this method considers only original DOM elements upon which the editor
1969 * was created. Setting `optimized` parameter to `false` will consider editor editable
1970 * and its children.
1971 *
1972 * @param {Boolean} [optimized=true] If set to `false` it will scan every editor editable.
1973 * @returns {CKEDITOR.editor} An editor instance or null if nothing has been found.
1974 */
1975 getEditor: function( optimized ) {
1976 var instances = CKEDITOR.instances,
1977 name, instance, editable;
1978
1979 optimized = optimized || optimized === undefined;
1980
1981 for ( name in instances ) {
1982 instance = instances[ name ];
1983
1984 if ( instance.element.equals( this ) && instance.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO )
1985 return instance;
1986
1987 if ( !optimized ) {
1988 editable = instance.editable();
1989
1990 if ( editable && ( editable.equals( this ) || editable.contains( this ) ) ) {
1991 return instance;
1992 }
1993 }
1994 }
1995
1996 return null;
1997 },
1998
1999 /**
2000 * Returns list of elements within this element that match specified `selector`.
2001 *
2002 * **Notes:**
2003 *
2004 * * Not available in IE7.
2005 * * Returned list is not a live collection (like a result of native `querySelectorAll`).
2006 * * Unlike native `querySelectorAll` this method ensures selector contextualization. This is:
2007 *
2008 * HTML: '<body><div><i>foo</i></div></body>'
2009 * Native: div.querySelectorAll( 'body i' ) // -> [ <i>foo</i> ]
2010 * Method: div.find( 'body i' ) // -> []
2011 * div.find( 'i' ) // -> [ <i>foo</i> ]
2012 *
2013 * @since 4.3
2014 * @param {String} selector
2015 * @returns {CKEDITOR.dom.nodeList}
2016 */
2017 find: function( selector ) {
2018 var removeTmpId = createTmpId( this ),
2019 list = new CKEDITOR.dom.nodeList(
2020 this.$.querySelectorAll( getContextualizedSelector( this, selector ) )
2021 );
2022
2023 removeTmpId();
2024
2025 return list;
2026 },
2027
2028 /**
2029 * Returns first element within this element that matches specified `selector`.
2030 *
2031 * **Notes:**
2032 *
2033 * * Not available in IE7.
2034 * * Unlike native `querySelectorAll` this method ensures selector contextualization. This is:
2035 *
2036 * HTML: '<body><div><i>foo</i></div></body>'
2037 * Native: div.querySelector( 'body i' ) // -> <i>foo</i>
2038 * Method: div.findOne( 'body i' ) // -> null
2039 * div.findOne( 'i' ) // -> <i>foo</i>
2040 *
2041 * @since 4.3
2042 * @param {String} selector
2043 * @returns {CKEDITOR.dom.element}
2044 */
2045 findOne: function( selector ) {
2046 var removeTmpId = createTmpId( this ),
2047 found = this.$.querySelector( getContextualizedSelector( this, selector ) );
2048
2049 removeTmpId();
2050
2051 return found ? new CKEDITOR.dom.element( found ) : null;
2052 },
2053
2054 /**
2055 * Traverse the DOM of this element (inclusive), executing a callback for
2056 * each node.
2057 *
2058 * var element = CKEDITOR.dom.element.createFromHtml( '<div><p>foo<b>bar</b>bom</p></div>' );
2059 * element.forEach( function( node ) {
2060 * console.log( node );
2061 * } );
2062 * // Will log:
2063 * // 1. <div> element,
2064 * // 2. <p> element,
2065 * // 3. "foo" text node,
2066 * // 4. <b> element,
2067 * // 5. "bar" text node,
2068 * // 6. "bom" text node.
2069 *
2070 * @since 4.3
2071 * @param {Function} callback Function to be executed on every node.
2072 * If `callback` returns `false` descendants of the node will be ignored.
2073 * @param {CKEDITOR.htmlParser.node} callback.node Node passed as argument.
2074 * @param {Number} [type] If specified `callback` will be executed only on
2075 * nodes of this type.
2076 * @param {Boolean} [skipRoot] Don't execute `callback` on this element.
2077 */
2078 forEach: function( callback, type, skipRoot ) {
2079 if ( !skipRoot && ( !type || this.type == type ) )
2080 var ret = callback( this );
2081
2082 // Do not filter children if callback returned false.
2083 if ( ret === false )
2084 return;
2085
2086 var children = this.getChildren(),
2087 node,
2088 i = 0;
2089
2090 // We do not cache the size, because the live list of nodes may be changed by the callback.
2091 for ( ; i < children.count(); i++ ) {
2092 node = children.getItem( i );
2093 if ( node.type == CKEDITOR.NODE_ELEMENT )
2094 node.forEach( callback, type );
2095 else if ( !type || node.type == type )
2096 callback( node );
2097 }
2098 }
2099 } );
2100
2101 function createTmpId( element ) {
2102 var hadId = true;
2103
2104 if ( !element.$.id ) {
2105 element.$.id = 'cke_tmp_' + CKEDITOR.tools.getNextNumber();
2106 hadId = false;
2107 }
2108
2109 return function() {
2110 if ( !hadId )
2111 element.removeAttribute( 'id' );
2112 };
2113 }
2114
2115 function getContextualizedSelector( element, selector ) {
2116 var id = CKEDITOR.tools.escapeCss( element.$.id );
2117 return '#' + id + ' ' + selector.split( /,\s*/ ).join( ', #' + id + ' ' );
2118 }
2119
2120 var sides = {
2121 width: [ 'border-left-width', 'border-right-width', 'padding-left', 'padding-right' ],
2122 height: [ 'border-top-width', 'border-bottom-width', 'padding-top', 'padding-bottom' ]
2123 };
2124
2125 // Generate list of specific style rules, applicable to margin/padding/border.
2126 function expandedRules( style ) {
2127 var sides = [ 'top', 'left', 'right', 'bottom' ], components;
2128
2129 if ( style == 'border' )
2130 components = [ 'color', 'style', 'width' ];
2131
2132 var styles = [];
2133 for ( var i = 0 ; i < sides.length ; i++ ) {
2134
2135 if ( components ) {
2136 for ( var j = 0 ; j < components.length ; j++ )
2137 styles.push( [ style, sides[ i ], components[ j ] ].join( '-' ) );
2138 } else {
2139 styles.push( [ style, sides[ i ] ].join( '-' ) );
2140 }
2141 }
2142
2143 return styles;
2144 }
2145
2146 function marginAndPaddingSize( type ) {
2147 var adjustment = 0;
2148 for ( var i = 0, len = sides[ type ].length; i < len; i++ )
2149 adjustment += parseFloat( this.getComputedStyle( sides[ type ][ i ] ) || 0, 10 ) || 0;
2150 return adjustment;
2151 }
2152
2153 /**
2154 * Sets the element size considering the box model.
2155 *
2156 * @param {'width'/'height'} type The dimension to set.
2157 * @param {Number} size The length unit in px.
2158 * @param {Boolean} isBorderBox Apply the size based on the border box model.
2159 */
2160 CKEDITOR.dom.element.prototype.setSize = function( type, size, isBorderBox ) {
2161 if ( typeof size == 'number' ) {
2162 if ( isBorderBox && !( CKEDITOR.env.ie && CKEDITOR.env.quirks ) )
2163 size -= marginAndPaddingSize.call( this, type );
2164
2165 this.setStyle( type, size + 'px' );
2166 }
2167 };
2168
2169 /**
2170 * Gets the element size, possibly considering the box model.
2171 *
2172 * @param {'width'/'height'} type The dimension to get.
2173 * @param {Boolean} isBorderBox Get the size based on the border box model.
2174 */
2175 CKEDITOR.dom.element.prototype.getSize = function( type, isBorderBox ) {
2176 var size = Math.max( this.$[ 'offset' + CKEDITOR.tools.capitalize( type ) ], this.$[ 'client' + CKEDITOR.tools.capitalize( type ) ] ) || 0;
2177
2178 if ( isBorderBox )
2179 size -= marginAndPaddingSize.call( this, type );
2180
2181 return size;
2182 };
2183} )();
diff --git a/sources/core/dom/elementpath.js b/sources/core/dom/elementpath.js
new file mode 100644
index 0000000..1a3aed0
--- /dev/null
+++ b/sources/core/dom/elementpath.js
@@ -0,0 +1,251 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8( function() {
9
10 var pathBlockLimitElements = {},
11 pathBlockElements = {},
12 tag;
13
14 // Elements that are considered the "Block limit" in an element path.
15 for ( tag in CKEDITOR.dtd.$blockLimit ) {
16 // Exclude from list roots.
17 if ( !( tag in CKEDITOR.dtd.$list ) )
18 pathBlockLimitElements[ tag ] = 1;
19 }
20
21 // Elements that are considered the "End level Block" in an element path.
22 for ( tag in CKEDITOR.dtd.$block ) {
23 // Exclude block limits, and empty block element, e.g. hr.
24 if ( !( tag in CKEDITOR.dtd.$blockLimit || tag in CKEDITOR.dtd.$empty ) )
25 pathBlockElements[ tag ] = 1;
26 }
27
28 // Check if an element contains any block element.
29 function checkHasBlock( element ) {
30 var childNodes = element.getChildren();
31
32 for ( var i = 0, count = childNodes.count(); i < count; i++ ) {
33 var child = childNodes.getItem( i );
34
35 if ( child.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$block[ child.getName() ] )
36 return true;
37 }
38
39 return false;
40 }
41
42 /**
43 * Retrieve the list of nodes walked from the start node up to the editable element of the editor.
44 *
45 * @class
46 * @constructor Creates an element path class instance.
47 * @param {CKEDITOR.dom.element} startNode From which the path should start.
48 * @param {CKEDITOR.dom.element} root To which element the path should stop, defaults to the `body` element.
49 */
50 CKEDITOR.dom.elementPath = function( startNode, root ) {
51 var block = null,
52 blockLimit = null,
53 elements = [],
54 e = startNode,
55 elementName;
56
57 // Backward compact.
58 root = root || startNode.getDocument().getBody();
59
60 do {
61 if ( e.type == CKEDITOR.NODE_ELEMENT ) {
62 elements.push( e );
63
64 if ( !this.lastElement ) {
65 this.lastElement = e;
66
67 // If an object or non-editable element is fully selected at the end of the element path,
68 // it must not become the block limit.
69 if ( e.is( CKEDITOR.dtd.$object ) || e.getAttribute( 'contenteditable' ) == 'false' )
70 continue;
71 }
72
73 if ( e.equals( root ) )
74 break;
75
76 if ( !blockLimit ) {
77 elementName = e.getName();
78
79 // First editable element becomes a block limit, because it cannot be split.
80 if ( e.getAttribute( 'contenteditable' ) == 'true' )
81 blockLimit = e;
82 // "Else" because element cannot be both - block and block levelimit.
83 else if ( !block && pathBlockElements[ elementName ] )
84 block = e;
85
86 if ( pathBlockLimitElements[ elementName ] ) {
87 // End level DIV is considered as the block, if no block is available. (#525)
88 // But it must NOT be the root element (checked above).
89 if ( !block && elementName == 'div' && !checkHasBlock( e ) )
90 block = e;
91 else
92 blockLimit = e;
93 }
94 }
95 }
96 }
97 while ( ( e = e.getParent() ) );
98
99 // Block limit defaults to root.
100 if ( !blockLimit )
101 blockLimit = root;
102
103 /**
104 * First non-empty block element which:
105 *
106 * * is not a {@link CKEDITOR.dtd#$blockLimit},
107 * * or is a `div` which does not contain block elements and is not a `root`.
108 *
109 * This means a first, splittable block in elements path.
110 *
111 * @readonly
112 * @property {CKEDITOR.dom.element}
113 */
114 this.block = block;
115
116 /**
117 * See the {@link CKEDITOR.dtd#$blockLimit} description.
118 *
119 * @readonly
120 * @property {CKEDITOR.dom.element}
121 */
122 this.blockLimit = blockLimit;
123
124 /**
125 * The root of the elements path - `root` argument passed to class constructor or a `body` element.
126 *
127 * @readonly
128 * @property {CKEDITOR.dom.element}
129 */
130 this.root = root;
131
132 /**
133 * An array of elements (from `startNode` to `root`) in the path.
134 *
135 * @readonly
136 * @property {CKEDITOR.dom.element[]}
137 */
138 this.elements = elements;
139
140 /**
141 * The last element of the elements path - `startNode` or its parent.
142 *
143 * @readonly
144 * @property {CKEDITOR.dom.element} lastElement
145 */
146 };
147
148} )();
149
150CKEDITOR.dom.elementPath.prototype = {
151 /**
152 * Compares this element path with another one.
153 *
154 * @param {CKEDITOR.dom.elementPath} otherPath The elementPath object to be
155 * compared with this one.
156 * @returns {Boolean} `true` if the paths are equal, containing the same
157 * number of elements and the same elements in the same order.
158 */
159 compare: function( otherPath ) {
160 var thisElements = this.elements;
161 var otherElements = otherPath && otherPath.elements;
162
163 if ( !otherElements || thisElements.length != otherElements.length )
164 return false;
165
166 for ( var i = 0; i < thisElements.length; i++ ) {
167 if ( !thisElements[ i ].equals( otherElements[ i ] ) )
168 return false;
169 }
170
171 return true;
172 },
173
174 /**
175 * Search the path elements that meets the specified criteria.
176 *
177 * @param {String/Array/Function/Object/CKEDITOR.dom.element} query The criteria that can be
178 * either a tag name, list (array and object) of tag names, element or an node evaluator function.
179 * @param {Boolean} [excludeRoot] Not taking path root element into consideration.
180 * @param {Boolean} [fromTop] Search start from the topmost element instead of bottom.
181 * @returns {CKEDITOR.dom.element} The first matched dom element or `null`.
182 */
183 contains: function( query, excludeRoot, fromTop ) {
184 var evaluator;
185 if ( typeof query == 'string' )
186 evaluator = function( node ) {
187 return node.getName() == query;
188 };
189 if ( query instanceof CKEDITOR.dom.element )
190 evaluator = function( node ) {
191 return node.equals( query );
192 };
193 else if ( CKEDITOR.tools.isArray( query ) )
194 evaluator = function( node ) {
195 return CKEDITOR.tools.indexOf( query, node.getName() ) > -1;
196 };
197 else if ( typeof query == 'function' )
198 evaluator = query;
199 else if ( typeof query == 'object' )
200 evaluator = function( node ) {
201 return node.getName() in query;
202 };
203
204 var elements = this.elements,
205 length = elements.length;
206 excludeRoot && length--;
207
208 if ( fromTop ) {
209 elements = Array.prototype.slice.call( elements, 0 );
210 elements.reverse();
211 }
212
213 for ( var i = 0; i < length; i++ ) {
214 if ( evaluator( elements[ i ] ) )
215 return elements[ i ];
216 }
217
218 return null;
219 },
220
221 /**
222 * Check whether the elements path is the proper context for the specified
223 * tag name in the DTD.
224 *
225 * @param {String} tag The tag name.
226 * @returns {Boolean}
227 */
228 isContextFor: function( tag ) {
229 var holder;
230
231 // Check for block context.
232 if ( tag in CKEDITOR.dtd.$block ) {
233 // Indeterminate elements which are not subjected to be splitted or surrounded must be checked first.
234 var inter = this.contains( CKEDITOR.dtd.$intermediate );
235 holder = inter || ( this.root.equals( this.block ) && this.block ) || this.blockLimit;
236 return !!holder.getDtd()[ tag ];
237 }
238
239 return true;
240 },
241
242 /**
243 * Retrieve the text direction for this elements path.
244 *
245 * @returns {'ltr'/'rtl'}
246 */
247 direction: function() {
248 var directionNode = this.block || this.blockLimit || this.root;
249 return directionNode.getDirection( 1 );
250 }
251};
diff --git a/sources/core/dom/event.js b/sources/core/dom/event.js
new file mode 100644
index 0000000..8b1193a
--- /dev/null
+++ b/sources/core/dom/event.js
@@ -0,0 +1,208 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.event} class, which
8 * represents the a native DOM event object.
9 */
10
11/**
12 * Represents a native DOM event object.
13 *
14 * @class
15 * @constructor Creates an event class instance.
16 * @param {Object} domEvent A native DOM event object.
17 */
18CKEDITOR.dom.event = function( domEvent ) {
19 /**
20 * The native DOM event object represented by this class instance.
21 *
22 * @readonly
23 */
24 this.$ = domEvent;
25};
26
27CKEDITOR.dom.event.prototype = {
28 /**
29 * Gets the key code associated to the event.
30 *
31 * alert( event.getKey() ); // '65' is 'a' has been pressed
32 *
33 * @returns {Number} The key code.
34 */
35 getKey: function() {
36 return this.$.keyCode || this.$.which;
37 },
38
39 /**
40 * Gets a number represeting the combination of the keys pressed during the
41 * event. It is the sum with the current key code and the {@link CKEDITOR#CTRL},
42 * {@link CKEDITOR#SHIFT} and {@link CKEDITOR#ALT} constants.
43 *
44 * alert( event.getKeystroke() == 65 ); // 'a' key
45 * alert( event.getKeystroke() == CKEDITOR.CTRL + 65 ); // CTRL + 'a' key
46 * alert( event.getKeystroke() == CKEDITOR.CTRL + CKEDITOR.SHIFT + 65 ); // CTRL + SHIFT + 'a' key
47 *
48 * @returns {Number} The number representing the keys combination.
49 */
50 getKeystroke: function() {
51 var keystroke = this.getKey();
52
53 if ( this.$.ctrlKey || this.$.metaKey )
54 keystroke += CKEDITOR.CTRL;
55
56 if ( this.$.shiftKey )
57 keystroke += CKEDITOR.SHIFT;
58
59 if ( this.$.altKey )
60 keystroke += CKEDITOR.ALT;
61
62 return keystroke;
63 },
64
65 /**
66 * Prevents the original behavior of the event to happen. It can optionally
67 * stop propagating the event in the event chain.
68 *
69 * var element = CKEDITOR.document.getById( 'myElement' );
70 * element.on( 'click', function( ev ) {
71 * // The DOM event object is passed by the 'data' property.
72 * var domEvent = ev.data;
73 * // Prevent the click to chave any effect in the element.
74 * domEvent.preventDefault();
75 * } );
76 *
77 * @param {Boolean} [stopPropagation=false] Stop propagating this event in the
78 * event chain.
79 */
80 preventDefault: function( stopPropagation ) {
81 var $ = this.$;
82 if ( $.preventDefault )
83 $.preventDefault();
84 else
85 $.returnValue = false;
86
87 if ( stopPropagation )
88 this.stopPropagation();
89 },
90
91 /**
92 * Stops this event propagation in the event chain.
93 */
94 stopPropagation: function() {
95 var $ = this.$;
96 if ( $.stopPropagation )
97 $.stopPropagation();
98 else
99 $.cancelBubble = true;
100 },
101
102 /**
103 * Returns the DOM node where the event was targeted to.
104 *
105 * var element = CKEDITOR.document.getById( 'myElement' );
106 * element.on( 'click', function( ev ) {
107 * // The DOM event object is passed by the 'data' property.
108 * var domEvent = ev.data;
109 * // Add a CSS class to the event target.
110 * domEvent.getTarget().addClass( 'clicked' );
111 * } );
112 *
113 * @returns {CKEDITOR.dom.node} The target DOM node.
114 */
115 getTarget: function() {
116 var rawNode = this.$.target || this.$.srcElement;
117 return rawNode ? new CKEDITOR.dom.node( rawNode ) : null;
118 },
119
120 /**
121 * Returns an integer value that indicates the current processing phase of an event.
122 * For browsers that doesn't support event phase, {@link CKEDITOR#EVENT_PHASE_AT_TARGET} is always returned.
123 *
124 * @returns {Number} One of {@link CKEDITOR#EVENT_PHASE_CAPTURING},
125 * {@link CKEDITOR#EVENT_PHASE_AT_TARGET}, or {@link CKEDITOR#EVENT_PHASE_BUBBLING}.
126 */
127 getPhase: function() {
128 return this.$.eventPhase || 2;
129 },
130
131 /**
132 * Retrieves the coordinates of the mouse pointer relative to the top-left
133 * corner of the document, in mouse related event.
134 *
135 * element.on( 'mousemouse', function( ev ) {
136 * var pageOffset = ev.data.getPageOffset();
137 * alert( pageOffset.x ); // page offset X
138 * alert( pageOffset.y ); // page offset Y
139 * } );
140 *
141 * @returns {Object} The object contains the position.
142 * @returns {Number} return.x
143 * @returns {Number} return.y
144 */
145 getPageOffset: function() {
146 var doc = this.getTarget().getDocument().$;
147 var pageX = this.$.pageX || this.$.clientX + ( doc.documentElement.scrollLeft || doc.body.scrollLeft );
148 var pageY = this.$.pageY || this.$.clientY + ( doc.documentElement.scrollTop || doc.body.scrollTop );
149 return { x: pageX, y: pageY };
150 }
151};
152
153// For the followind constants, we need to go over the Unicode boundaries
154// (0x10FFFF) to avoid collision.
155
156/**
157 * CTRL key (0x110000).
158 *
159 * @readonly
160 * @property {Number} [=0x110000]
161 * @member CKEDITOR
162 */
163CKEDITOR.CTRL = 0x110000;
164
165/**
166 * SHIFT key (0x220000).
167 *
168 * @readonly
169 * @property {Number} [=0x220000]
170 * @member CKEDITOR
171 */
172CKEDITOR.SHIFT = 0x220000;
173
174/**
175 * ALT key (0x440000).
176 *
177 * @readonly
178 * @property {Number} [=0x440000]
179 * @member CKEDITOR
180 */
181CKEDITOR.ALT = 0x440000;
182
183/**
184 * Capturing phase.
185 *
186 * @readonly
187 * @property {Number} [=1]
188 * @member CKEDITOR
189 */
190CKEDITOR.EVENT_PHASE_CAPTURING = 1;
191
192/**
193 * Event at target.
194 *
195 * @readonly
196 * @property {Number} [=2]
197 * @member CKEDITOR
198 */
199CKEDITOR.EVENT_PHASE_AT_TARGET = 2;
200
201/**
202 * Bubbling phase.
203 *
204 * @readonly
205 * @property {Number} [=3]
206 * @member CKEDITOR
207 */
208CKEDITOR.EVENT_PHASE_BUBBLING = 3;
diff --git a/sources/core/dom/iterator.js b/sources/core/dom/iterator.js
new file mode 100644
index 0000000..50056ec
--- /dev/null
+++ b/sources/core/dom/iterator.js
@@ -0,0 +1,565 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @ignore
8 * File overview: DOM iterator which iterates over list items, lines and paragraphs.
9 */
10
11'use strict';
12
13( function() {
14 /**
15 * Represents the iterator class. It can be used to iterate
16 * over all elements (or even text nodes in case of {@link #enlargeBr} set to `false`)
17 * which establish "paragraph-like" spaces within the passed range.
18 *
19 * // <h1>[foo</h1><p>bar]</p>
20 * var iterator = range.createIterator();
21 * iterator.getNextParagraph(); // h1 element
22 * iterator.getNextParagraph(); // p element
23 *
24 * // <ul><li>[foo</li><li>bar]</li>
25 * // With enforceRealBlocks set to false the iterator will return two list item elements.
26 * // With enforceRealBlocks set to true the iterator will return two paragraphs and the DOM will be changed to:
27 * // <ul><li><p>foo</p></li><li><p>bar</p></li>
28 *
29 * @class CKEDITOR.dom.iterator
30 * @constructor Creates an iterator class instance.
31 * @param {CKEDITOR.dom.range} range
32 */
33 function iterator( range ) {
34 if ( arguments.length < 1 )
35 return;
36
37 /**
38 * @readonly
39 * @property {CKEDITOR.dom.range}
40 */
41 this.range = range;
42
43 /**
44 * @property {Boolean} [forceBrBreak=false]
45 */
46 this.forceBrBreak = 0;
47
48 // (#3730).
49 /**
50 * Whether to include `<br>` elements in the enlarged range. Should be
51 * set to `false` when using the iterator in the {@link CKEDITOR#ENTER_BR} mode.
52 *
53 * @property {Boolean} [enlargeBr=true]
54 */
55 this.enlargeBr = 1;
56
57 /**
58 * Whether the iterator should create a transformable block
59 * if the current one contains text and cannot be transformed.
60 * For example new blocks will be established in elements like
61 * `<li>` or `<td>`.
62 *
63 * @property {Boolean} [enforceRealBlocks=false]
64 */
65 this.enforceRealBlocks = 0;
66
67 this._ || ( this._ = {} );
68 }
69
70 /**
71 * Default iterator's filter. It is set only for nested iterators.
72 *
73 * @since 4.3
74 * @readonly
75 * @property {CKEDITOR.filter} filter
76 */
77
78 /**
79 * Iterator's active filter. It is set by the {@link #getNextParagraph} method
80 * when it enters a nested editable.
81 *
82 * @since 4.3
83 * @readonly
84 * @property {CKEDITOR.filter} activeFilter
85 */
86
87 var beginWhitespaceRegex = /^[\r\n\t ]+$/,
88 // Ignore bookmark nodes.(#3783)
89 bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ),
90 whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ),
91 skipGuard = function( node ) {
92 return bookmarkGuard( node ) && whitespacesGuard( node );
93 },
94 listItemNames = { dd: 1, dt: 1, li: 1 };
95
96 iterator.prototype = {
97 /**
98 * Returns the next paragraph-like element or `null` if the end of a range is reached.
99 *
100 * @param {String} [blockTag='p'] Name of a block element which will be established by
101 * the iterator in block-less elements (see {@link #enforceRealBlocks}).
102 */
103 getNextParagraph: function( blockTag ) {
104 // The block element to be returned.
105 var block;
106
107 // The range object used to identify the paragraph contents.
108 var range;
109
110 // Indicats that the current element in the loop is the last one.
111 var isLast;
112
113 // Instructs to cleanup remaining BRs.
114 var removePreviousBr, removeLastBr;
115
116 blockTag = blockTag || 'p';
117
118 // We're iterating over nested editable.
119 if ( this._.nestedEditable ) {
120 // Get next block from nested iterator and returns it if was found.
121 block = this._.nestedEditable.iterator.getNextParagraph( blockTag );
122 if ( block ) {
123 // Inherit activeFilter from the nested iterator.
124 this.activeFilter = this._.nestedEditable.iterator.activeFilter;
125 return block;
126 }
127
128 // No block in nested iterator means that we reached the end of the nested editable.
129 // Reset the active filter to the default filter (or undefined if this iterator didn't have it).
130 this.activeFilter = this.filter;
131
132 // Try to find next nested editable or get back to parent (this) iterator.
133 if ( startNestedEditableIterator( this, blockTag, this._.nestedEditable.container, this._.nestedEditable.remaining ) ) {
134 // Inherit activeFilter from the nested iterator.
135 this.activeFilter = this._.nestedEditable.iterator.activeFilter;
136 return this._.nestedEditable.iterator.getNextParagraph( blockTag );
137 } else {
138 this._.nestedEditable = null;
139 }
140 }
141
142 // Block-less range should be checked first.
143 if ( !this.range.root.getDtd()[ blockTag ] )
144 return null;
145
146 // This is the first iteration. Let's initialize it.
147 if ( !this._.started )
148 range = startIterator.call( this );
149
150 var currentNode = this._.nextNode,
151 lastNode = this._.lastNode;
152
153 this._.nextNode = null;
154 while ( currentNode ) {
155 // closeRange indicates that a paragraph boundary has been found,
156 // so the range can be closed.
157 var closeRange = 0,
158 parentPre = currentNode.hasAscendant( 'pre' );
159
160 // includeNode indicates that the current node is good to be part
161 // of the range. By default, any non-element node is ok for it.
162 var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
163 continueFromSibling = 0;
164
165 // If it is an element node, let's check if it can be part of the range.
166 if ( !includeNode ) {
167 var nodeName = currentNode.getName();
168
169 // Non-editable block was found - return it and move to processing
170 // its nested editables if they exist.
171 if ( CKEDITOR.dtd.$block[ nodeName ] && currentNode.getAttribute( 'contenteditable' ) == 'false' ) {
172 block = currentNode;
173
174 // Setup iterator for first of nested editables.
175 // If there's no editable, then algorithm will move to next element after current block.
176 startNestedEditableIterator( this, blockTag, block );
177
178 // Gets us straight to the end of getParagraph() because block variable is set.
179 break;
180 } else if ( currentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
181 // <br> boundaries must be part of the range. It will
182 // happen only if ForceBrBreak.
183 if ( nodeName == 'br' )
184 includeNode = 1;
185 else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' ) {
186 // If we have found an empty block, and haven't started
187 // the range yet, it means we must return this block.
188 block = currentNode;
189 isLast = currentNode.equals( lastNode );
190 break;
191 }
192
193 // The range must finish right before the boundary,
194 // including possibly skipped empty spaces. (#1603)
195 if ( range ) {
196 range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
197
198 // The found boundary must be set as the next one at this
199 // point. (#1717)
200 if ( nodeName != 'br' ) {
201 this._.nextNode = currentNode;
202 }
203 }
204
205 closeRange = 1;
206 } else {
207 // If we have child nodes, let's check them.
208 if ( currentNode.getFirst() ) {
209 // If we don't have a range yet, let's start it.
210 if ( !range ) {
211 range = this.range.clone();
212 range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
213 }
214
215 currentNode = currentNode.getFirst();
216 continue;
217 }
218 includeNode = 1;
219 }
220 } else if ( currentNode.type == CKEDITOR.NODE_TEXT ) {
221 // Ignore normal whitespaces (i.e. not including &nbsp; or
222 // other unicode whitespaces) before/after a block node.
223 if ( beginWhitespaceRegex.test( currentNode.getText() ) )
224 includeNode = 0;
225 }
226
227 // The current node is good to be part of the range and we are
228 // starting a new range, initialize it first.
229 if ( includeNode && !range ) {
230 range = this.range.clone();
231 range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
232 }
233
234 // The last node has been found.
235 isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
236
237 // If we are in an element boundary, let's check if it is time
238 // to close the range, otherwise we include the parent within it.
239 if ( range && !closeRange ) {
240 while ( !currentNode.getNext( skipGuard ) && !isLast ) {
241 var parentNode = currentNode.getParent();
242
243 if ( parentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
244 closeRange = 1;
245 includeNode = 0;
246 isLast = isLast || ( parentNode.equals( lastNode ) );
247 // Make sure range includes bookmarks at the end of the block. (#7359)
248 range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END );
249 break;
250 }
251
252 currentNode = parentNode;
253 includeNode = 1;
254 isLast = ( currentNode.equals( lastNode ) );
255 continueFromSibling = 1;
256 }
257 }
258
259 // Now finally include the node.
260 if ( includeNode )
261 range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
262
263 currentNode = this._getNextSourceNode( currentNode, continueFromSibling, lastNode );
264 isLast = !currentNode;
265
266 // We have found a block boundary. Let's close the range and move out of the
267 // loop.
268 if ( isLast || ( closeRange && range ) )
269 break;
270 }
271
272 // Now, based on the processed range, look for (or create) the block to be returned.
273 if ( !block ) {
274 // If no range has been found, this is the end.
275 if ( !range ) {
276 this._.docEndMarker && this._.docEndMarker.remove();
277 this._.nextNode = null;
278 return null;
279 }
280
281 var startPath = new CKEDITOR.dom.elementPath( range.startContainer, range.root );
282 var startBlockLimit = startPath.blockLimit,
283 checkLimits = { div: 1, th: 1, td: 1 };
284 block = startPath.block;
285
286 if ( !block && startBlockLimit && !this.enforceRealBlocks && checkLimits[ startBlockLimit.getName() ] &&
287 range.checkStartOfBlock() && range.checkEndOfBlock() && !startBlockLimit.equals( range.root ) ) {
288 block = startBlockLimit;
289 } else if ( !block || ( this.enforceRealBlocks && block.is( listItemNames ) ) ) {
290 // Create the fixed block.
291 block = this.range.document.createElement( blockTag );
292
293 // Move the contents of the temporary range to the fixed block.
294 range.extractContents().appendTo( block );
295 block.trim();
296
297 // Insert the fixed block into the DOM.
298 range.insertNode( block );
299
300 removePreviousBr = removeLastBr = true;
301 } else if ( block.getName() != 'li' ) {
302 // If the range doesn't includes the entire contents of the
303 // block, we must split it, isolating the range in a dedicated
304 // block.
305 if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() ) {
306 // The resulting block will be a clone of the current one.
307 block = block.clone( false );
308
309 // Extract the range contents, moving it to the new block.
310 range.extractContents().appendTo( block );
311 block.trim();
312
313 // Split the block. At this point, the range will be in the
314 // right position for our intents.
315 var splitInfo = range.splitBlock();
316
317 removePreviousBr = !splitInfo.wasStartOfBlock;
318 removeLastBr = !splitInfo.wasEndOfBlock;
319
320 // Insert the new block into the DOM.
321 range.insertNode( block );
322 }
323 } else if ( !isLast ) {
324 // LIs are returned as is, with all their children (due to the
325 // nested lists). But, the next node is the node right after
326 // the current range, which could be an <li> child (nested
327 // lists) or the next sibling <li>.
328
329 this._.nextNode = ( block.equals( lastNode ) ? null : this._getNextSourceNode( range.getBoundaryNodes().endNode, 1, lastNode ) );
330 }
331 }
332
333 if ( removePreviousBr ) {
334 var previousSibling = block.getPrevious();
335 if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT ) {
336 if ( previousSibling.getName() == 'br' )
337 previousSibling.remove();
338 else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
339 previousSibling.getLast().remove();
340 }
341 }
342
343 if ( removeLastBr ) {
344 var lastChild = block.getLast();
345 if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' ) {
346 // Remove br filler on browser which do not need it.
347 if ( !CKEDITOR.env.needsBrFiller || lastChild.getPrevious( bookmarkGuard ) || lastChild.getNext( bookmarkGuard ) )
348 lastChild.remove();
349 }
350 }
351
352 // Get a reference for the next element. This is important because the
353 // above block can be removed or changed, so we can rely on it for the
354 // next interation.
355 if ( !this._.nextNode ) {
356 this._.nextNode = ( isLast || block.equals( lastNode ) || !lastNode ) ? null : this._getNextSourceNode( block, 1, lastNode );
357 }
358
359 return block;
360 },
361
362 /**
363 * Gets the next element to check or `null` when the `lastNode` or the
364 * {@link #range}'s {@link CKEDITOR.dom.range#root root} is reached. Bookmarks are skipped.
365 *
366 * @since 4.4.6
367 * @private
368 * @param {CKEDITOR.dom.node} node
369 * @param {Boolean} startFromSibling
370 * @param {CKEDITOR.dom.node} lastNode
371 * @returns {CKEDITOR.dom.node}
372 */
373 _getNextSourceNode: function( node, startFromSibling, lastNode ) {
374 var rootNode = this.range.root,
375 next;
376
377 // Here we are checking in guard function whether current element
378 // reach lastNode(default behaviour) and root node to prevent against
379 // getting out of editor instance root DOM object.
380 // #12484
381 function guardFunction( node ) {
382 return !( node.equals( lastNode ) || node.equals( rootNode ) );
383 }
384
385 next = node.getNextSourceNode( startFromSibling, null, guardFunction );
386 while ( !bookmarkGuard( next ) ) {
387 next = next.getNextSourceNode( startFromSibling, null, guardFunction );
388 }
389 return next;
390 }
391 };
392
393 // @context CKEDITOR.dom.iterator
394 // @returns Collapsed range which will be reused when during furter processing.
395 function startIterator() {
396 var range = this.range.clone(),
397 // Indicate at least one of the range boundaries is inside a preformat block.
398 touchPre,
399
400 // (#12178)
401 // Remember if following situation takes place:
402 // * startAtInnerBoundary: <p>foo[</p>...
403 // * endAtInnerBoundary: ...<p>]bar</p>
404 // Because information about line break will be lost when shrinking range.
405 // Note that we test only if path block exist, because we must properly shrink
406 // range containing table and/or table cells.
407 // Note: When range is collapsed there's no way it can be shrinked.
408 // By checking if range is collapsed we also prevent #12308.
409 startPath = range.startPath(),
410 endPath = range.endPath(),
411 startAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, startPath.block ),
412 endAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, endPath.block, 1 );
413
414 // Shrink the range to exclude harmful "noises" (#4087, #4450, #5435).
415 range.shrink( CKEDITOR.SHRINK_ELEMENT, true );
416
417 if ( startAtInnerBoundary )
418 range.setStartAt( startPath.block, CKEDITOR.POSITION_BEFORE_END );
419 if ( endAtInnerBoundary )
420 range.setEndAt( endPath.block, CKEDITOR.POSITION_AFTER_START );
421
422 touchPre = range.endContainer.hasAscendant( 'pre', true ) || range.startContainer.hasAscendant( 'pre', true );
423
424 range.enlarge( this.forceBrBreak && !touchPre || !this.enlargeBr ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
425
426 if ( !range.collapsed ) {
427 var walker = new CKEDITOR.dom.walker( range.clone() ),
428 ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
429 // Avoid anchor inside bookmark inner text.
430 walker.evaluator = ignoreBookmarkTextEvaluator;
431 this._.nextNode = walker.next();
432 // TODO: It's better to have walker.reset() used here.
433 walker = new CKEDITOR.dom.walker( range.clone() );
434 walker.evaluator = ignoreBookmarkTextEvaluator;
435 var lastNode = walker.previous();
436 this._.lastNode = lastNode.getNextSourceNode( true, null, range.root );
437
438 // We may have an empty text node at the end of block due to [3770].
439 // If that node is the lastNode, it would cause our logic to leak to the
440 // next block.(#3887)
441 if ( this._.lastNode && this._.lastNode.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( this._.lastNode.getText() ) && this._.lastNode.getParent().isBlockBoundary() ) {
442 var testRange = this.range.clone();
443 testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END );
444 if ( testRange.checkEndOfBlock() ) {
445 var path = new CKEDITOR.dom.elementPath( testRange.endContainer, testRange.root ),
446 lastBlock = path.block || path.blockLimit;
447 this._.lastNode = lastBlock.getNextSourceNode( true );
448 }
449 }
450
451 // The end of document or range.root was reached, so we need a marker node inside.
452 if ( !this._.lastNode || !range.root.contains( this._.lastNode ) ) {
453 this._.lastNode = this._.docEndMarker = range.document.createText( '' );
454 this._.lastNode.insertAfter( lastNode );
455 }
456
457 // Let's reuse this variable.
458 range = null;
459 }
460
461 this._.started = 1;
462
463 return range;
464 }
465
466 // Does a nested editables lookup inside editablesContainer.
467 // If remainingEditables is set will lookup inside this array.
468 // @param {CKEDITOR.dom.element} editablesContainer
469 // @param {CKEDITOR.dom.element[]} [remainingEditables]
470 function getNestedEditableIn( editablesContainer, remainingEditables ) {
471 if ( remainingEditables == null )
472 remainingEditables = findNestedEditables( editablesContainer );
473
474 var editable;
475
476 while ( ( editable = remainingEditables.shift() ) ) {
477 if ( isIterableEditable( editable ) )
478 return { element: editable, remaining: remainingEditables };
479 }
480
481 return null;
482 }
483
484 // Checkes whether we can iterate over this editable.
485 function isIterableEditable( editable ) {
486 // Reject blockless editables.
487 return editable.getDtd().p;
488 }
489
490 // Finds nested editables within container. Does not return
491 // editables nested in another editable (twice).
492 function findNestedEditables( container ) {
493 var editables = [];
494
495 container.forEach( function( element ) {
496 if ( element.getAttribute( 'contenteditable' ) == 'true' ) {
497 editables.push( element );
498 return false; // Skip children.
499 }
500 }, CKEDITOR.NODE_ELEMENT, true );
501
502 return editables;
503 }
504
505 // Looks for a first nested editable after previousEditable (if passed) and creates
506 // nested iterator for it.
507 function startNestedEditableIterator( parentIterator, blockTag, editablesContainer, remainingEditables ) {
508 var editable = getNestedEditableIn( editablesContainer, remainingEditables );
509
510 if ( !editable )
511 return 0;
512
513 var filter = CKEDITOR.filter.instances[ editable.element.data( 'cke-filter' ) ];
514
515 // If current editable has a filter and this filter does not allow for block tag,
516 // search for next nested editable in remaining ones.
517 if ( filter && !filter.check( blockTag ) )
518 return startNestedEditableIterator( parentIterator, blockTag, editablesContainer, editable.remaining );
519
520 var range = new CKEDITOR.dom.range( editable.element );
521 range.selectNodeContents( editable.element );
522
523 var iterator = range.createIterator();
524 // This setting actually does not change anything in this case,
525 // because entire range contents is selected, so there're no <br>s to be included.
526 // But it seems right to copy it too.
527 iterator.enlargeBr = parentIterator.enlargeBr;
528 // Inherit configuration from parent iterator.
529 iterator.enforceRealBlocks = parentIterator.enforceRealBlocks;
530 // Set the activeFilter (which can be overriden when this iteator will start nested iterator)
531 // and the default filter, which will make it possible to reset to
532 // current iterator's activeFilter after leaving nested editable.
533 iterator.activeFilter = iterator.filter = filter;
534
535 parentIterator._.nestedEditable = {
536 element: editable.element,
537 container: editablesContainer,
538 remaining: editable.remaining,
539 iterator: iterator
540 };
541
542 return 1;
543 }
544
545 // Checks whether range starts or ends at inner block boundary.
546 // See usage comments to learn more.
547 function rangeAtInnerBlockBoundary( range, block, checkEnd ) {
548 if ( !block )
549 return false;
550
551 var testRange = range.clone();
552 testRange.collapse( !checkEnd );
553 return testRange.checkBoundaryOfElement( block, checkEnd ? CKEDITOR.START : CKEDITOR.END );
554 }
555
556 /**
557 * Creates a {@link CKEDITOR.dom.iterator} instance for this range.
558 *
559 * @member CKEDITOR.dom.range
560 * @returns {CKEDITOR.dom.iterator}
561 */
562 CKEDITOR.dom.range.prototype.createIterator = function() {
563 return new iterator( this );
564 };
565} )();
diff --git a/sources/core/dom/node.js b/sources/core/dom/node.js
new file mode 100644
index 0000000..51bba18
--- /dev/null
+++ b/sources/core/dom/node.js
@@ -0,0 +1,902 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.node} class which is the base
8 * class for classes that represent DOM nodes.
9 */
10
11/**
12 * Base class for classes representing DOM nodes. This constructor may return
13 * an instance of a class that inherits from this class, like
14 * {@link CKEDITOR.dom.element} or {@link CKEDITOR.dom.text}.
15 *
16 * @class
17 * @extends CKEDITOR.dom.domObject
18 * @constructor Creates a node class instance.
19 * @param {Object} domNode A native DOM node.
20 * @see CKEDITOR.dom.element
21 * @see CKEDITOR.dom.text
22 */
23CKEDITOR.dom.node = function( domNode ) {
24 if ( domNode ) {
25 var type =
26 domNode.nodeType == CKEDITOR.NODE_DOCUMENT ? 'document' :
27 domNode.nodeType == CKEDITOR.NODE_ELEMENT ? 'element' :
28 domNode.nodeType == CKEDITOR.NODE_TEXT ? 'text' :
29 domNode.nodeType == CKEDITOR.NODE_COMMENT ? 'comment' :
30 domNode.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 'documentFragment' :
31 'domObject'; // Call the base constructor otherwise.
32
33 return new CKEDITOR.dom[ type ]( domNode );
34 }
35
36 return this;
37};
38
39CKEDITOR.dom.node.prototype = new CKEDITOR.dom.domObject();
40
41/**
42 * Element node type.
43 *
44 * @readonly
45 * @property {Number} [=1]
46 * @member CKEDITOR
47 */
48CKEDITOR.NODE_ELEMENT = 1;
49
50/**
51 * Document node type.
52 *
53 * @readonly
54 * @property {Number} [=9]
55 * @member CKEDITOR
56 */
57CKEDITOR.NODE_DOCUMENT = 9;
58
59/**
60 * Text node type.
61 *
62 * @readonly
63 * @property {Number} [=3]
64 * @member CKEDITOR
65 */
66CKEDITOR.NODE_TEXT = 3;
67
68/**
69 * Comment node type.
70 *
71 * @readonly
72 * @property {Number} [=8]
73 * @member CKEDITOR
74 */
75CKEDITOR.NODE_COMMENT = 8;
76
77/**
78 * Document fragment node type.
79 *
80 * @readonly
81 * @property {Number} [=11]
82 * @member CKEDITOR
83 */
84CKEDITOR.NODE_DOCUMENT_FRAGMENT = 11;
85
86/**
87 * Indicates that positions of both nodes are identical (this is the same node). See {@link CKEDITOR.dom.node#getPosition}.
88 *
89 * @readonly
90 * @property {Number} [=0]
91 * @member CKEDITOR
92 */
93CKEDITOR.POSITION_IDENTICAL = 0;
94
95/**
96 * Indicates that nodes are in different (detached) trees. See {@link CKEDITOR.dom.node#getPosition}.
97 *
98 * @readonly
99 * @property {Number} [=1]
100 * @member CKEDITOR
101 */
102CKEDITOR.POSITION_DISCONNECTED = 1;
103
104/**
105 * Indicates that the context node follows the other node. See {@link CKEDITOR.dom.node#getPosition}.
106 *
107 * @readonly
108 * @property {Number} [=2]
109 * @member CKEDITOR
110 */
111CKEDITOR.POSITION_FOLLOWING = 2;
112
113/**
114 * Indicates that the context node precedes the other node. See {@link CKEDITOR.dom.node#getPosition}.
115 *
116 * @readonly
117 * @property {Number} [=4]
118 * @member CKEDITOR
119 */
120CKEDITOR.POSITION_PRECEDING = 4;
121
122/**
123 * Indicates that the context node is a descendant of the other node. See {@link CKEDITOR.dom.node#getPosition}.
124 *
125 * @readonly
126 * @property {Number} [=8]
127 * @member CKEDITOR
128 */
129CKEDITOR.POSITION_IS_CONTAINED = 8;
130
131/**
132 * Indicates that the context node contains the other node. See {@link CKEDITOR.dom.node#getPosition}.
133 *
134 * @readonly
135 * @property {Number} [=16]
136 * @member CKEDITOR
137 */
138CKEDITOR.POSITION_CONTAINS = 16;
139
140CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, {
141 /**
142 * Makes this node a child of another element.
143 *
144 * var p = new CKEDITOR.dom.element( 'p' );
145 * var strong = new CKEDITOR.dom.element( 'strong' );
146 * strong.appendTo( p );
147 *
148 * // Result: '<p><strong></strong></p>'.
149 *
150 * @param {CKEDITOR.dom.element} element The target element to which this node will be appended.
151 * @returns {CKEDITOR.dom.element} The target element.
152 */
153 appendTo: function( element, toStart ) {
154 element.append( this, toStart );
155 return element;
156 },
157
158 /**
159 * Clones this node.
160 *
161 * **Note**: Values set by {#setCustomData} will not be available in the clone.
162 *
163 * @param {Boolean} [includeChildren=false] If `true` then all node's
164 * children will be cloned recursively.
165 * @param {Boolean} [cloneId=false] Whether ID attributes should be cloned, too.
166 * @returns {CKEDITOR.dom.node} Clone of this node.
167 */
168 clone: function( includeChildren, cloneId ) {
169 var $clone = this.$.cloneNode( includeChildren );
170
171 // The "id" attribute should never be cloned to avoid duplication.
172 removeIds( $clone );
173
174 var node = new CKEDITOR.dom.node( $clone );
175
176 // On IE8 we need to fixed HTML5 node name, see details below.
177 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 &&
178 ( this.type == CKEDITOR.NODE_ELEMENT || this.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) ) {
179 renameNodes( node );
180 }
181
182 return node;
183
184 function removeIds( node ) {
185 // Reset data-cke-expando only when has been cloned (IE and only for some types of objects).
186 if ( node[ 'data-cke-expando' ] )
187 node[ 'data-cke-expando' ] = false;
188
189 if ( node.nodeType != CKEDITOR.NODE_ELEMENT && node.nodeType != CKEDITOR.NODE_DOCUMENT_FRAGMENT )
190 return;
191
192 if ( !cloneId && node.nodeType == CKEDITOR.NODE_ELEMENT )
193 node.removeAttribute( 'id', false );
194
195 if ( includeChildren ) {
196 var childs = node.childNodes;
197 for ( var i = 0; i < childs.length; i++ )
198 removeIds( childs[ i ] );
199 }
200 }
201
202 // IE8 rename HTML5 nodes by adding `:` at the begging of the tag name when the node is cloned,
203 // so `<figure>` will be `<:figure>` after 'cloneNode'. We need to fix it (#13101).
204 function renameNodes( node ) {
205 if ( node.type != CKEDITOR.NODE_ELEMENT && node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT )
206 return;
207
208 if ( node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT ) {
209 var name = node.getName();
210 if ( name[ 0 ] == ':' ) {
211 node.renameNode( name.substring( 1 ) );
212 }
213 }
214
215 if ( includeChildren ) {
216 for ( var i = 0; i < node.getChildCount(); i++ )
217 renameNodes( node.getChild( i ) );
218 }
219 }
220 },
221
222 /**
223 * Checks if the node is preceded by any sibling.
224 *
225 * @returns {Boolean}
226 */
227 hasPrevious: function() {
228 return !!this.$.previousSibling;
229 },
230
231 /**
232 * Checks if the node is succeeded by any sibling.
233 *
234 * @returns {Boolean}
235 */
236 hasNext: function() {
237 return !!this.$.nextSibling;
238 },
239
240 /**
241 * Inserts this element after a node.
242 *
243 * var em = new CKEDITOR.dom.element( 'em' );
244 * var strong = new CKEDITOR.dom.element( 'strong' );
245 * strong.insertAfter( em );
246 *
247 * // Result: '<em></em><strong></strong>'
248 *
249 * @param {CKEDITOR.dom.node} node The node that will precede this element.
250 * @returns {CKEDITOR.dom.node} The node preceding this one after insertion.
251 */
252 insertAfter: function( node ) {
253 node.$.parentNode.insertBefore( this.$, node.$.nextSibling );
254 return node;
255 },
256
257 /**
258 * Inserts this element before a node.
259 *
260 * var em = new CKEDITOR.dom.element( 'em' );
261 * var strong = new CKEDITOR.dom.element( 'strong' );
262 * strong.insertBefore( em );
263 *
264 * // result: '<strong></strong><em></em>'
265 *
266 * @param {CKEDITOR.dom.node} node The node that will succeed this element.
267 * @returns {CKEDITOR.dom.node} The node being inserted.
268 */
269 insertBefore: function( node ) {
270 node.$.parentNode.insertBefore( this.$, node.$ );
271 return node;
272 },
273
274 /**
275 * Inserts a node before this node.
276 *
277 * var em = new CKEDITOR.dom.element( 'em' );
278 * var strong = new CKEDITOR.dom.element( 'strong' );
279 * strong.insertBeforeMe( em );
280 *
281 * // result: '<em></em><strong></strong>'
282 *
283 * @param {CKEDITOR.dom.node} node The node that will preceed this element.
284 * @returns {CKEDITOR.dom.node} The node being inserted.
285 */
286 insertBeforeMe: function( node ) {
287 this.$.parentNode.insertBefore( node.$, this.$ );
288 return node;
289 },
290
291 /**
292 * Retrieves a uniquely identifiable tree address for this node.
293 * The tree address returned is an array of integers, with each integer
294 * indicating a child index of a DOM node, starting from
295 * `document.documentElement`.
296 *
297 * For example, assuming `<body>` is the second child
298 * of `<html>` (`<head>` being the first),
299 * and we would like to address the third child under the
300 * fourth child of `<body>`, the tree address returned would be:
301 * `[1, 3, 2]`.
302 *
303 * The tree address cannot be used for finding back the DOM tree node once
304 * the DOM tree structure has been modified.
305 *
306 * @param {Boolean} [normalized=false] See {@link #getIndex}.
307 * @returns {Array} The address.
308 */
309 getAddress: function( normalized ) {
310 var address = [];
311 var $documentElement = this.getDocument().$.documentElement;
312 var node = this.$;
313
314 while ( node && node != $documentElement ) {
315 var parentNode = node.parentNode;
316
317 if ( parentNode ) {
318 // Get the node index. For performance, call getIndex
319 // directly, instead of creating a new node object.
320 address.unshift( this.getIndex.call( { $: node }, normalized ) );
321 }
322
323 node = parentNode;
324 }
325
326 return address;
327 },
328
329 /**
330 * Gets the document containing this element.
331 *
332 * var element = CKEDITOR.document.getById( 'example' );
333 * alert( element.getDocument().equals( CKEDITOR.document ) ); // true
334 *
335 * @returns {CKEDITOR.dom.document} The document.
336 */
337 getDocument: function() {
338 return new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument );
339 },
340
341 /**
342 * Gets the index of a node in an array of its `parent.childNodes`.
343 * Returns `-1` if a node does not have a parent or when the `normalized` argument is set to `true`
344 * and the text node is empty and will be removed during the normalization.
345 *
346 * Let us assume having the following `childNodes` array:
347 *
348 * [ emptyText, element1, text, text, element2, emptyText2 ]
349 *
350 * emptyText.getIndex() // 0
351 * emptyText.getIndex( true ) // -1
352 * element1.getIndex(); // 1
353 * element1.getIndex( true ); // 0
354 * element2.getIndex(); // 4
355 * element2.getIndex( true ); // 2
356 * emptyText2.getIndex(); // 5
357 * emptyText2.getIndex( true ); // -1
358 *
359 * @param {Boolean} normalized When `true`, adjacent text nodes are merged and empty text nodes are removed.
360 * @returns {Number} Index of a node or `-1` if a node does not have a parent or is removed during the normalization.
361 */
362 getIndex: function( normalized ) {
363 // Attention: getAddress depends on this.$
364 // getIndex is called on a plain object: { $ : node }
365
366 var current = this.$,
367 index = -1,
368 isNormalizing;
369
370 if ( !this.$.parentNode )
371 return -1;
372
373 // The idea is - all empty text nodes will be virtually merged into their adjacent text nodes.
374 // If an empty text node does not have an adjacent non-empty text node we can return -1 straight away,
375 // because it and all its sibling text nodes will be merged into an empty text node and then totally ignored.
376 if ( normalized && current.nodeType == CKEDITOR.NODE_TEXT && isEmpty( current ) ) {
377 var adjacent = getAdjacentNonEmptyTextNode( current ) || getAdjacentNonEmptyTextNode( current, true );
378
379 if ( !adjacent )
380 return -1;
381 }
382
383 do {
384 // Bypass blank node and adjacent text nodes.
385 if ( normalized && current != this.$ && current.nodeType == CKEDITOR.NODE_TEXT && ( isNormalizing || isEmpty( current ) ) )
386 continue;
387
388 index++;
389 isNormalizing = current.nodeType == CKEDITOR.NODE_TEXT;
390 }
391 while ( ( current = current.previousSibling ) );
392
393 return index;
394
395 function getAdjacentNonEmptyTextNode( node, lookForward ) {
396 var sibling = lookForward ? node.nextSibling : node.previousSibling;
397
398 if ( !sibling || sibling.nodeType != CKEDITOR.NODE_TEXT ) {
399 return null;
400 }
401
402 // If found a non-empty text node, then return it.
403 // If not, then continue search.
404 return isEmpty( sibling ) ? getAdjacentNonEmptyTextNode( sibling, lookForward ) : sibling;
405 }
406
407 // Checks whether a text node is empty or is FCSeq string (which will be totally removed when normalizing).
408 function isEmpty( textNode ) {
409 return !textNode.nodeValue || textNode.nodeValue == CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE;
410 }
411 },
412
413 /**
414 * @todo
415 */
416 getNextSourceNode: function( startFromSibling, nodeType, guard ) {
417 // If "guard" is a node, transform it in a function.
418 if ( guard && !guard.call ) {
419 var guardNode = guard;
420 guard = function( node ) {
421 return !node.equals( guardNode );
422 };
423 }
424
425 var node = ( !startFromSibling && this.getFirst && this.getFirst() ),
426 parent;
427
428 // Guarding when we're skipping the current element( no children or 'startFromSibling' ).
429 // send the 'moving out' signal even we don't actually dive into.
430 if ( !node ) {
431 if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
432 return null;
433 node = this.getNext();
434 }
435
436 while ( !node && ( parent = ( parent || this ).getParent() ) ) {
437 // The guard check sends the "true" paramenter to indicate that
438 // we are moving "out" of the element.
439 if ( guard && guard( parent, true ) === false )
440 return null;
441
442 node = parent.getNext();
443 }
444
445 if ( !node )
446 return null;
447
448 if ( guard && guard( node ) === false )
449 return null;
450
451 if ( nodeType && nodeType != node.type )
452 return node.getNextSourceNode( false, nodeType, guard );
453
454 return node;
455 },
456
457 /**
458 * @todo
459 */
460 getPreviousSourceNode: function( startFromSibling, nodeType, guard ) {
461 if ( guard && !guard.call ) {
462 var guardNode = guard;
463 guard = function( node ) {
464 return !node.equals( guardNode );
465 };
466 }
467
468 var node = ( !startFromSibling && this.getLast && this.getLast() ),
469 parent;
470
471 // Guarding when we're skipping the current element( no children or 'startFromSibling' ).
472 // send the 'moving out' signal even we don't actually dive into.
473 if ( !node ) {
474 if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
475 return null;
476 node = this.getPrevious();
477 }
478
479 while ( !node && ( parent = ( parent || this ).getParent() ) ) {
480 // The guard check sends the "true" paramenter to indicate that
481 // we are moving "out" of the element.
482 if ( guard && guard( parent, true ) === false )
483 return null;
484
485 node = parent.getPrevious();
486 }
487
488 if ( !node )
489 return null;
490
491 if ( guard && guard( node ) === false )
492 return null;
493
494 if ( nodeType && node.type != nodeType )
495 return node.getPreviousSourceNode( false, nodeType, guard );
496
497 return node;
498 },
499
500 /**
501 * Gets the node that preceeds this element in its parent's child list.
502 *
503 * var element = CKEDITOR.dom.element.createFromHtml( '<div><i>prev</i><b>Example</b></div>' );
504 * var first = element.getLast().getPrev();
505 * alert( first.getName() ); // 'i'
506 *
507 * @param {Function} [evaluator] Filtering the result node.
508 * @returns {CKEDITOR.dom.node} The previous node or null if not available.
509 */
510 getPrevious: function( evaluator ) {
511 var previous = this.$,
512 retval;
513 do {
514 previous = previous.previousSibling;
515
516 // Avoid returning the doc type node.
517 // http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-412266927
518 retval = previous && previous.nodeType != 10 && new CKEDITOR.dom.node( previous );
519 }
520 while ( retval && evaluator && !evaluator( retval ) );
521 return retval;
522 },
523
524 /**
525 * Gets the node that follows this element in its parent's child list.
526 *
527 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b><i>next</i></div>' );
528 * var last = element.getFirst().getNext();
529 * alert( last.getName() ); // 'i'
530 *
531 * @param {Function} [evaluator] Filtering the result node.
532 * @returns {CKEDITOR.dom.node} The next node or null if not available.
533 */
534 getNext: function( evaluator ) {
535 var next = this.$,
536 retval;
537 do {
538 next = next.nextSibling;
539 retval = next && new CKEDITOR.dom.node( next );
540 }
541 while ( retval && evaluator && !evaluator( retval ) );
542 return retval;
543 },
544
545 /**
546 * Gets the parent element for this node.
547 *
548 * var node = editor.document.getBody().getFirst();
549 * var parent = node.getParent();
550 * alert( parent.getName() ); // 'body'
551 *
552 * @param {Boolean} [allowFragmentParent=false] Consider also parent node that is of
553 * fragment type {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
554 * @returns {CKEDITOR.dom.element} The parent element.
555 */
556 getParent: function( allowFragmentParent ) {
557 var parent = this.$.parentNode;
558 return ( parent && ( parent.nodeType == CKEDITOR.NODE_ELEMENT || allowFragmentParent && parent.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) ) ? new CKEDITOR.dom.node( parent ) : null;
559 },
560
561 /**
562 * Returns an array containing node parents and the node itself. By default nodes are in _descending_ order.
563 *
564 * // Assuming that body has paragraph as the first child.
565 * var node = editor.document.getBody().getFirst();
566 * var parents = node.getParents();
567 * alert( parents[ 0 ].getName() + ',' + parents[ 2 ].getName() ); // 'html,p'
568 *
569 * @param {Boolean} [closerFirst=false] Determines the order of returned nodes.
570 * @returns {Array} Returns an array of {@link CKEDITOR.dom.node}.
571 */
572 getParents: function( closerFirst ) {
573 var node = this;
574 var parents = [];
575
576 do {
577 parents[ closerFirst ? 'push' : 'unshift' ]( node );
578 }
579 while ( ( node = node.getParent() ) );
580
581 return parents;
582 },
583
584 /**
585 * @todo
586 */
587 getCommonAncestor: function( node ) {
588 if ( node.equals( this ) )
589 return this;
590
591 if ( node.contains && node.contains( this ) )
592 return node;
593
594 var start = this.contains ? this : this.getParent();
595
596 do {
597 if ( start.contains( node ) ) return start;
598 }
599 while ( ( start = start.getParent() ) );
600
601 return null;
602 },
603
604 /**
605 * Determines the position relation between this node and the given {@link CKEDITOR.dom.node} in the document.
606 * This node can be preceding ({@link CKEDITOR#POSITION_PRECEDING}) or following ({@link CKEDITOR#POSITION_FOLLOWING})
607 * the given node. This node can also contain ({@link CKEDITOR#POSITION_CONTAINS}) or be contained by
608 * ({@link CKEDITOR#POSITION_IS_CONTAINED}) the given node. The function returns a bitmask of constants
609 * listed above or {@link CKEDITOR#POSITION_IDENTICAL} if the given node is the same as this node.
610 *
611 * @param {CKEDITOR.dom.node} otherNode A node to check relation with.
612 * @returns {Number} Position relation between this node and given node.
613 */
614 getPosition: function( otherNode ) {
615 var $ = this.$;
616 var $other = otherNode.$;
617
618 if ( $.compareDocumentPosition )
619 return $.compareDocumentPosition( $other );
620
621 // IE and Safari have no support for compareDocumentPosition.
622
623 if ( $ == $other )
624 return CKEDITOR.POSITION_IDENTICAL;
625
626 // Only element nodes support contains and sourceIndex.
627 if ( this.type == CKEDITOR.NODE_ELEMENT && otherNode.type == CKEDITOR.NODE_ELEMENT ) {
628 if ( $.contains ) {
629 if ( $.contains( $other ) )
630 return CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING;
631
632 if ( $other.contains( $ ) )
633 return CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
634 }
635
636 if ( 'sourceIndex' in $ )
637 return ( $.sourceIndex < 0 || $other.sourceIndex < 0 ) ? CKEDITOR.POSITION_DISCONNECTED : ( $.sourceIndex < $other.sourceIndex ) ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
638
639 }
640
641 // For nodes that don't support compareDocumentPosition, contains
642 // or sourceIndex, their "address" is compared.
643
644 var addressOfThis = this.getAddress(),
645 addressOfOther = otherNode.getAddress(),
646 minLevel = Math.min( addressOfThis.length, addressOfOther.length );
647
648 // Determinate preceding/following relationship.
649 for ( var i = 0; i < minLevel; i++ ) {
650 if ( addressOfThis[ i ] != addressOfOther[ i ] ) {
651 return addressOfThis[ i ] < addressOfOther[ i ] ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
652 }
653 }
654
655 // Determinate contains/contained relationship.
656 return ( addressOfThis.length < addressOfOther.length ) ? CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
657 },
658
659 /**
660 * Gets the closest ancestor node of this node, specified by its name or using an evaluator function.
661 *
662 * // Suppose we have the following HTML structure:
663 * // <div id="outer"><div id="inner"><p><b>Some text</b></p></div></div>
664 * // If node == <b>
665 * ascendant = node.getAscendant( 'div' ); // ascendant == <div id="inner">
666 * ascendant = node.getAscendant( 'b' ); // ascendant == null
667 * ascendant = node.getAscendant( 'b', true ); // ascendant == <b>
668 * ascendant = node.getAscendant( { div:1, p:1 } ); // Searches for the first 'div' or 'p': ascendant == <div id="inner">
669 *
670 * // Using custom evaluator:
671 * ascendant = node.getAscendant( function( el ) {
672 * return el.getId() == 'inner';
673 * } );
674 * // ascendant == <div id="inner">
675 *
676 * @since 3.6.1
677 * @param {String/Function/Object} query The name of the ancestor node to search or
678 * an object with the node names to search for or an evaluator function.
679 * @param {Boolean} [includeSelf] Whether to include the current
680 * node in the search.
681 * @returns {CKEDITOR.dom.node} The located ancestor node or `null` if not found.
682 */
683 getAscendant: function( query, includeSelf ) {
684 var $ = this.$,
685 evaluator,
686 isCustomEvaluator;
687
688 if ( !includeSelf ) {
689 $ = $.parentNode;
690 }
691
692 // Custom checker provided in an argument.
693 if ( typeof query == 'function' ) {
694 isCustomEvaluator = true;
695 evaluator = query;
696 } else {
697 // Predefined tag name checker.
698 isCustomEvaluator = false;
699 evaluator = function( $ ) {
700 var name = ( typeof $.nodeName == 'string' ? $.nodeName.toLowerCase() : '' );
701
702 return ( typeof query == 'string' ? name == query : name in query );
703 };
704 }
705
706 while ( $ ) {
707 // For user provided checker we use CKEDITOR.dom.node.
708 if ( evaluator( isCustomEvaluator ? new CKEDITOR.dom.node( $ ) : $ ) ) {
709 return new CKEDITOR.dom.node( $ );
710 }
711
712 try {
713 $ = $.parentNode;
714 } catch ( e ) {
715 $ = null;
716 }
717 }
718
719 return null;
720 },
721
722 /**
723 * @todo
724 */
725 hasAscendant: function( name, includeSelf ) {
726 var $ = this.$;
727
728 if ( !includeSelf )
729 $ = $.parentNode;
730
731 while ( $ ) {
732 if ( $.nodeName && $.nodeName.toLowerCase() == name )
733 return true;
734
735 $ = $.parentNode;
736 }
737 return false;
738 },
739
740 /**
741 * @todo
742 */
743 move: function( target, toStart ) {
744 target.append( this.remove(), toStart );
745 },
746
747 /**
748 * Removes this node from the document DOM.
749 *
750 * var element = CKEDITOR.document.getById( 'MyElement' );
751 * element.remove();
752 *
753 * @param {Boolean} [preserveChildren=false] Indicates that the children
754 * elements must remain in the document, removing only the outer tags.
755 */
756 remove: function( preserveChildren ) {
757 var $ = this.$;
758 var parent = $.parentNode;
759
760 if ( parent ) {
761 if ( preserveChildren ) {
762 // Move all children before the node.
763 for ( var child;
764 ( child = $.firstChild ); ) {
765 parent.insertBefore( $.removeChild( child ), $ );
766 }
767 }
768
769 parent.removeChild( $ );
770 }
771
772 return this;
773 },
774
775 /**
776 * @todo
777 */
778 replace: function( nodeToReplace ) {
779 this.insertBefore( nodeToReplace );
780 nodeToReplace.remove();
781 },
782
783 /**
784 * @todo
785 */
786 trim: function() {
787 this.ltrim();
788 this.rtrim();
789 },
790
791 /**
792 * @todo
793 */
794 ltrim: function() {
795 var child;
796 while ( this.getFirst && ( child = this.getFirst() ) ) {
797 if ( child.type == CKEDITOR.NODE_TEXT ) {
798 var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
799 originalLength = child.getLength();
800
801 if ( !trimmed ) {
802 child.remove();
803 continue;
804 } else if ( trimmed.length < originalLength ) {
805 child.split( originalLength - trimmed.length );
806
807 // IE BUG: child.remove() may raise JavaScript errors here. (#81)
808 this.$.removeChild( this.$.firstChild );
809 }
810 }
811 break;
812 }
813 },
814
815 /**
816 * @todo
817 */
818 rtrim: function() {
819 var child;
820 while ( this.getLast && ( child = this.getLast() ) ) {
821 if ( child.type == CKEDITOR.NODE_TEXT ) {
822 var trimmed = CKEDITOR.tools.rtrim( child.getText() ),
823 originalLength = child.getLength();
824
825 if ( !trimmed ) {
826 child.remove();
827 continue;
828 } else if ( trimmed.length < originalLength ) {
829 child.split( trimmed.length );
830
831 // IE BUG: child.getNext().remove() may raise JavaScript errors here.
832 // (#81)
833 this.$.lastChild.parentNode.removeChild( this.$.lastChild );
834 }
835 }
836 break;
837 }
838
839 if ( CKEDITOR.env.needsBrFiller ) {
840 child = this.$.lastChild;
841
842 if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' ) {
843 // Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
844 child.parentNode.removeChild( child );
845 }
846 }
847 },
848
849 /**
850 * Checks if this node is read-only (should not be changed).
851 *
852 * // For the following HTML:
853 * // <b>foo</b><div contenteditable="false"><i>bar</i></div>
854 *
855 * elB.isReadOnly(); // -> false
856 * foo.isReadOnly(); // -> false
857 * elDiv.isReadOnly(); // -> true
858 * elI.isReadOnly(); // -> true
859 *
860 * This method works in two modes depending on browser support for the `element.isContentEditable` property and
861 * the value of the `checkOnlyAttributes` parameter. The `element.isContentEditable` check is faster, but it is known
862 * to malfunction in hidden or detached nodes. Additionally, when processing some detached DOM tree you may want to imitate
863 * that this happens inside an editable container (like it would happen inside the {@link CKEDITOR.editable}). To do so,
864 * you can temporarily attach this tree to an element with the `data-cke-editable` attribute and use the
865 * `checkOnlyAttributes` mode.
866 *
867 * @since 3.5
868 * @param {Boolean} [checkOnlyAttributes=false] If `true`, only attributes will be checked, native methods will not
869 * be used. This parameter needs to be `true` to check hidden or detached elements. Introduced in 4.5.
870 * @returns {Boolean}
871 */
872 isReadOnly: function( checkOnlyAttributes ) {
873 var element = this;
874 if ( this.type != CKEDITOR.NODE_ELEMENT )
875 element = this.getParent();
876
877 // Prevent Edge crash (#13609, #13919).
878 if ( CKEDITOR.env.edge && element && element.is( 'textarea', 'input' ) ) {
879 checkOnlyAttributes = true;
880 }
881
882 if ( !checkOnlyAttributes && element && typeof element.$.isContentEditable != 'undefined' ) {
883 return !( element.$.isContentEditable || element.data( 'cke-editable' ) );
884 }
885 else {
886 // Degrade for old browsers which don't support "isContentEditable", e.g. FF3
887
888 while ( element ) {
889 if ( element.data( 'cke-editable' ) ) {
890 return false;
891 } else if ( element.hasAttribute( 'contenteditable' ) ) {
892 return element.getAttribute( 'contenteditable' ) == 'false';
893 }
894
895 element = element.getParent();
896 }
897
898 // Reached the root of DOM tree, no editable found.
899 return true;
900 }
901 }
902} );
diff --git a/sources/core/dom/nodelist.js b/sources/core/dom/nodelist.js
new file mode 100644
index 0000000..165a415
--- /dev/null
+++ b/sources/core/dom/nodelist.js
@@ -0,0 +1,43 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Represents a list of {@link CKEDITOR.dom.node} objects.
8 * It's a wrapper for native nodes list.
9 *
10 * var nodeList = CKEDITOR.document.getBody().getChildren();
11 * alert( nodeList.count() ); // number [0;N]
12 *
13 * @class
14 * @constructor Creates a document class instance.
15 * @param {Object} nativeList
16 */
17CKEDITOR.dom.nodeList = function( nativeList ) {
18 this.$ = nativeList;
19};
20
21CKEDITOR.dom.nodeList.prototype = {
22 /**
23 * Get count of nodes in this list.
24 *
25 * @returns {Number}
26 */
27 count: function() {
28 return this.$.length;
29 },
30
31 /**
32 * Get node from the list.
33 *
34 * @returns {CKEDITOR.dom.node}
35 */
36 getItem: function( index ) {
37 if ( index < 0 || index >= this.$.length )
38 return null;
39
40 var $node = this.$[ index ];
41 return $node ? new CKEDITOR.dom.node( $node ) : null;
42 }
43};
diff --git a/sources/core/dom/range.js b/sources/core/dom/range.js
new file mode 100644
index 0000000..6407074
--- /dev/null
+++ b/sources/core/dom/range.js
@@ -0,0 +1,2978 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Represents a delimited piece of content in a DOM Document.
8 * It is contiguous in the sense that it can be characterized as selecting all
9 * of the content between a pair of boundary-points.
10 *
11 * This class shares much of the W3C
12 * [Document Object Model Range](http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html)
13 * ideas and features, adding several range manipulation tools to it, but it's
14 * not intended to be compatible with it.
15 *
16 * // Create a range for the entire contents of the editor document body.
17 * var range = new CKEDITOR.dom.range( editor.document );
18 * range.selectNodeContents( editor.document.getBody() );
19 * // Delete the contents.
20 * range.deleteContents();
21 *
22 * Usually you will want to work on a ranges rooted in the editor's {@link CKEDITOR.editable editable}
23 * element. Such ranges can be created with a shorthand method &ndash; {@link CKEDITOR.editor#createRange editor.createRange}.
24 *
25 * var range = editor.createRange();
26 * range.root.equals( editor.editable() ); // -> true
27 *
28 * Note that the {@link #root} of a range is an important property, which limits many
29 * algorithms implemented in range's methods. Therefore it is crucial, especially
30 * when using ranges inside inline editors, to specify correct root, so using
31 * the {@link CKEDITOR.editor#createRange} method is highly recommended.
32 *
33 * ### Selection
34 *
35 * Range is only a logical representation of a piece of content in a DOM. It should not
36 * be confused with a {@link CKEDITOR.dom.selection selection} which represents "physically
37 * marked" content. It is possible to create unlimited number of various ranges, when
38 * only one real selection may exist at a time in a document. Ranges are used to read position
39 * of selection in the DOM and to move selection to new positions.
40 *
41 * The editor selection may be retrieved using the {@link CKEDITOR.editor#getSelection} method:
42 *
43 * var sel = editor.getSelection(),
44 * ranges = sel.getRanges(); // CKEDITOR.dom.rangeList instance.
45 *
46 * var range = ranges[ 0 ];
47 * range.root; // -> editor's editable element.
48 *
49 * A range can also be selected:
50 *
51 * var range = editor.createRange();
52 * range.selectNodeContents( editor.editable() );
53 * sel.selectRanges( [ range ] );
54 *
55 * @class
56 * @constructor Creates a {@link CKEDITOR.dom.range} instance that can be used inside a specific DOM Document.
57 * @param {CKEDITOR.dom.document/CKEDITOR.dom.element} root The document or element
58 * within which the range will be scoped.
59 * @todo global "TODO" - precise algorithms descriptions needed for the most complex methods like #enlarge.
60 */
61CKEDITOR.dom.range = function( root ) {
62 /**
63 * Node within which the range begins.
64 *
65 * var range = new CKEDITOR.dom.range( editor.document );
66 * range.selectNodeContents( editor.document.getBody() );
67 * alert( range.startContainer.getName() ); // 'body'
68 *
69 * @readonly
70 * @property {CKEDITOR.dom.element/CKEDITOR.dom.text}
71 */
72 this.startContainer = null;
73
74 /**
75 * Offset within the starting node of the range.
76 *
77 * var range = new CKEDITOR.dom.range( editor.document );
78 * range.selectNodeContents( editor.document.getBody() );
79 * alert( range.startOffset ); // 0
80 *
81 * @readonly
82 * @property {Number}
83 */
84 this.startOffset = null;
85
86 /**
87 * Node within which the range ends.
88 *
89 * var range = new CKEDITOR.dom.range( editor.document );
90 * range.selectNodeContents( editor.document.getBody() );
91 * alert( range.endContainer.getName() ); // 'body'
92 *
93 * @readonly
94 * @property {CKEDITOR.dom.element/CKEDITOR.dom.text}
95 */
96 this.endContainer = null;
97
98 /**
99 * Offset within the ending node of the range.
100 *
101 * var range = new CKEDITOR.dom.range( editor.document );
102 * range.selectNodeContents( editor.document.getBody() );
103 * alert( range.endOffset ); // == editor.document.getBody().getChildCount()
104 *
105 * @readonly
106 * @property {Number}
107 */
108 this.endOffset = null;
109
110 /**
111 * Indicates that this is a collapsed range. A collapsed range has its
112 * start and end boundaries at the very same point so nothing is contained
113 * in it.
114 *
115 * var range = new CKEDITOR.dom.range( editor.document );
116 * range.selectNodeContents( editor.document.getBody() );
117 * alert( range.collapsed ); // false
118 * range.collapse();
119 * alert( range.collapsed ); // true
120 *
121 * @readonly
122 */
123 this.collapsed = true;
124
125 var isDocRoot = root instanceof CKEDITOR.dom.document;
126 /**
127 * The document within which the range can be used.
128 *
129 * // Selects the body contents of the range document.
130 * range.selectNodeContents( range.document.getBody() );
131 *
132 * @readonly
133 * @property {CKEDITOR.dom.document}
134 */
135 this.document = isDocRoot ? root : root.getDocument();
136
137 /**
138 * The ancestor DOM element within which the range manipulation are limited.
139 *
140 * @readonly
141 * @property {CKEDITOR.dom.element}
142 */
143 this.root = isDocRoot ? root.getBody() : root;
144};
145
146( function() {
147 // Updates the "collapsed" property for the given range object.
148 function updateCollapsed( range ) {
149 range.collapsed = ( range.startContainer && range.endContainer && range.startContainer.equals( range.endContainer ) && range.startOffset == range.endOffset );
150 }
151
152 // This is a shared function used to delete, extract and clone the range content.
153 //
154 // The outline of the algorithm:
155 //
156 // 1. Normalization. We handle special cases, split text nodes if we can, find boundary nodes (startNode and endNode).
157 // 2. Gathering data.
158 // * We start by creating two arrays of boundary nodes parents. You can imagine these arrays as lines limiting
159 // the tree from the left and right and thus marking the part which is selected by the range. The both lines
160 // start in the same node which is the range.root and end in startNode and endNode.
161 // * Then we find min level and max levels. Level represents all nodes which are equally far from the range.root.
162 // Min level is the level at which the left and right boundaries diverged (the first diverged level). And max levels
163 // are how deep the start and end nodes are nested.
164 // 3. Cloning/extraction.
165 // * We start iterating over start node parents (left branch) from min level and clone the parent (usually shallow clone,
166 // because we know that it's not fully selected) and its right siblings (deep clone, because they are fully selected).
167 // We iterate over siblings up to meeting end node parent or end of the siblings chain.
168 // * We clone level after level down to the startNode.
169 // * Then we do the same with end node parents (right branch), because it may contains notes we omit during the previous
170 // step, for example if the right branch is deeper then left branch. Things are more complicated here because we have to
171 // watch out for nodes that were already cloned.
172 // * ***Note:** Setting `cloneId` option to `false` for **extraction** works for partially selected elements only.
173 // See range.extractContents to know more.
174 // 4. Clean up.
175 // * There are two things we need to do - updating the range position and perform the action of the "mergeThen"
176 // param (see range.deleteContents or range.extractContents).
177 // See comments in mergeAndUpdate because this is lots of fun too.
178 function execContentsAction( range, action, docFrag, mergeThen, cloneId ) {
179 'use strict';
180
181 range.optimizeBookmark();
182
183 var isDelete = action === 0;
184 var isExtract = action == 1;
185 var isClone = action == 2;
186 var doClone = isClone || isExtract;
187
188 var startNode = range.startContainer;
189 var endNode = range.endContainer;
190
191 var startOffset = range.startOffset;
192 var endOffset = range.endOffset;
193
194 var cloneStartNode;
195 var cloneEndNode;
196
197 var doNotRemoveStartNode;
198 var doNotRemoveEndNode;
199
200 var cloneStartText;
201 var cloneEndText;
202
203 // Handle here an edge case where we clone a range which is located in one text node.
204 // This allows us to not think about startNode == endNode case later on.
205 // We do that only when cloning, because in other cases we can safely split this text node
206 // and hence we can easily handle this case as many others.
207 if ( isClone && endNode.type == CKEDITOR.NODE_TEXT && startNode.equals( endNode ) ) {
208 startNode = range.document.createText( startNode.substring( startOffset, endOffset ) );
209 docFrag.append( startNode );
210 return;
211 }
212
213 // For text containers, we must simply split the node and point to the
214 // second part. The removal will be handled by the rest of the code.
215 if ( endNode.type == CKEDITOR.NODE_TEXT ) {
216 // If Extract or Delete we can split the text node,
217 // but if Clone (2), then we cannot modify the DOM (#11586) so we mark the text node for cloning.
218 if ( !isClone ) {
219 endNode = endNode.split( endOffset );
220 } else {
221 cloneEndText = true;
222 }
223 } else {
224 // If there's no node after the range boundary we set endNode to the previous node
225 // and mark it to be cloned.
226 if ( endNode.getChildCount() > 0 ) {
227 // If the offset points after the last node.
228 if ( endOffset >= endNode.getChildCount() ) {
229 endNode = endNode.getChild( endOffset - 1 );
230 cloneEndNode = true;
231 } else {
232 endNode = endNode.getChild( endOffset );
233 }
234 }
235 // The end container is empty (<h1>]</h1>), but we want to clone it, although not remove.
236 else {
237 cloneEndNode = true;
238 doNotRemoveEndNode = true;
239 }
240 }
241
242 // For text containers, we must simply split the node. The removal will
243 // be handled by the rest of the code .
244 if ( startNode.type == CKEDITOR.NODE_TEXT ) {
245 // If Extract or Delete we can split the text node,
246 // but if Clone (2), then we cannot modify the DOM (#11586) so we mark
247 // the text node for cloning.
248 if ( !isClone ) {
249 startNode.split( startOffset );
250 } else {
251 cloneStartText = true;
252 }
253 } else {
254 // If there's no node before the range boundary we set startNode to the next node
255 // and mark it to be cloned.
256 if ( startNode.getChildCount() > 0 ) {
257 if ( startOffset === 0 ) {
258 startNode = startNode.getChild( startOffset );
259 cloneStartNode = true;
260 } else {
261 startNode = startNode.getChild( startOffset - 1 );
262 }
263 }
264 // The start container is empty (<h1>[</h1>), but we want to clone it, although not remove.
265 else {
266 cloneStartNode = true;
267 doNotRemoveStartNode = true;
268 }
269 }
270
271 // Get the parent nodes tree for the start and end boundaries.
272 var startParents = startNode.getParents(),
273 endParents = endNode.getParents(),
274 // Level at which start and end boundaries diverged.
275 minLevel = findMinLevel(),
276 maxLevelLeft = startParents.length - 1,
277 maxLevelRight = endParents.length - 1,
278 // Keeps the frag/element which is parent of the level that we are currently cloning.
279 levelParent = docFrag,
280 nextLevelParent,
281 leftNode,
282 rightNode,
283 nextSibling,
284 // Keeps track of the last connected level (on which left and right branches are connected)
285 // Usually this is minLevel, but not always.
286 lastConnectedLevel = -1;
287
288 // THE LEFT BRANCH.
289 for ( var level = minLevel; level <= maxLevelLeft; level++ ) {
290 leftNode = startParents[ level ];
291 nextSibling = leftNode.getNext();
292
293 // 1.
294 // The first step is to handle partial selection of the left branch.
295
296 // Max depth of the left branch. It means that ( leftSibling == endNode ).
297 // We also check if the leftNode isn't only partially selected, because in this case
298 // we want to make a shallow clone of it (the else part).
299 if ( level == maxLevelLeft && !( leftNode.equals( endParents[ level ] ) && maxLevelLeft < maxLevelRight ) ) {
300 if ( cloneStartNode ) {
301 consume( leftNode, levelParent, false, doNotRemoveStartNode );
302 } else if ( cloneStartText ) {
303 levelParent.append( range.document.createText( leftNode.substring( startOffset ) ) );
304 }
305 } else if ( doClone ) {
306 nextLevelParent = levelParent.append( leftNode.clone( 0, cloneId ) );
307 }
308
309 // 2.
310 // The second step is to handle full selection of the content between the left branch and the right branch.
311
312 while ( nextSibling ) {
313 // We can't clone entire endParent just like we can't clone entire startParent -
314 // - they are not fully selected with the range. Partial endParent selection
315 // will be cloned in the next loop.
316 if ( nextSibling.equals( endParents[ level ] ) ) {
317 lastConnectedLevel = level;
318 break;
319 }
320
321 nextSibling = consume( nextSibling, levelParent );
322 }
323
324 levelParent = nextLevelParent;
325 }
326
327 // Reset levelParent, because we reset the level.
328 levelParent = docFrag;
329
330 // THE RIGHT BRANCH.
331 for ( level = minLevel; level <= maxLevelRight; level++ ) {
332 rightNode = endParents[ level ];
333 nextSibling = rightNode.getPrevious();
334
335 // Do not process this node if it is shared with the left branch
336 // because it was already processed.
337 //
338 // Note: Don't worry about text nodes selection - if the entire range was placed in a single text node
339 // it was handled as a special case at the beginning. In other cases when startNode == endNode
340 // or when on this level leftNode == rightNode (so rightNode.equals( startParents[ level ] ))
341 // this node was handled by the previous loop.
342 if ( !rightNode.equals( startParents[ level ] ) ) {
343 // 1.
344 // The first step is to handle partial selection of the right branch.
345
346 // Max depth of the right branch. It means that ( rightNode == endNode ).
347 // We also check if the rightNode isn't only partially selected, because in this case
348 // we want to make a shallow clone of it (the else part).
349 if ( level == maxLevelRight && !( rightNode.equals( startParents[ level ] ) && maxLevelRight < maxLevelLeft ) ) {
350 if ( cloneEndNode ) {
351 consume( rightNode, levelParent, false, doNotRemoveEndNode );
352 } else if ( cloneEndText ) {
353 levelParent.append( range.document.createText( rightNode.substring( 0, endOffset ) ) );
354 }
355 } else if ( doClone ) {
356 nextLevelParent = levelParent.append( rightNode.clone( 0, cloneId ) );
357 }
358
359 // 2.
360 // The second step is to handle all left (selected) siblings of the rightNode which
361 // have not yet been handled. If the level branches were connected, the previous loop
362 // already copied all siblings (except the current rightNode).
363 if ( level > lastConnectedLevel ) {
364 while ( nextSibling ) {
365 nextSibling = consume( nextSibling, levelParent, true );
366 }
367 }
368
369 levelParent = nextLevelParent;
370 } else if ( doClone ) {
371 // If this is "shared" node and we are in cloning mode we have to update levelParent to
372 // reflect that we visited the node (even though we didn't process it).
373 // If we don't do that, in next iterations nodes will be appended to wrong parent.
374 //
375 // We can just take first child because the algorithm guarantees
376 // that this will be the only child on this level. (#13568)
377 levelParent = levelParent.getChild( 0 );
378 }
379 }
380
381 // Delete or Extract.
382 // We need to update the range and if mergeThen was passed do it.
383 if ( !isClone ) {
384 mergeAndUpdate();
385 }
386
387 // Depending on an action:
388 // * clones node and adds to new parent,
389 // * removes node,
390 // * moves node to the new parent.
391 function consume( node, newParent, toStart, forceClone ) {
392 var nextSibling = toStart ? node.getPrevious() : node.getNext();
393
394 // We do not clone if we are only deleting, so do nothing.
395 if ( forceClone && isDelete ) {
396 return nextSibling;
397 }
398
399 // If cloning, just clone it.
400 if ( isClone || forceClone ) {
401 newParent.append( node.clone( true, cloneId ), toStart );
402 } else {
403 // Both Delete and Extract will remove the node.
404 node.remove();
405
406 // When Extracting, move the removed node to the docFrag.
407 if ( isExtract ) {
408 newParent.append( node );
409 }
410 }
411
412 return nextSibling;
413 }
414
415 // Finds a level number on which both branches starts diverging.
416 // If such level does not exist, return the last on which both branches have nodes.
417 function findMinLevel() {
418 // Compare them, to find the top most siblings.
419 var i, topStart, topEnd,
420 maxLevel = Math.min( startParents.length, endParents.length );
421
422 for ( i = 0; i < maxLevel; i++ ) {
423 topStart = startParents[ i ];
424 topEnd = endParents[ i ];
425
426 // The compared nodes will match until we find the top most siblings (different nodes that have the same parent).
427 // "i" will hold the index in the parents array for the top most element.
428 if ( !topStart.equals( topEnd ) ) {
429 return i;
430 }
431 }
432
433 // When startNode == endNode.
434 return i - 1;
435 }
436
437 // Executed only when deleting or extracting to update range position
438 // and perform the merge operation.
439 function mergeAndUpdate() {
440 var commonLevel = minLevel - 1,
441 boundariesInEmptyNode = doNotRemoveStartNode && doNotRemoveEndNode && !startNode.equals( endNode );
442
443 // If a node has been partially selected, collapse the range between
444 // startParents[ minLevel + 1 ] and endParents[ minLevel + 1 ] (the first diverged elements).
445 // Otherwise, simply collapse it to the start. (W3C specs).
446 //
447 // All clear, right?
448 //
449 // It took me few hours to truly understand a previous version of this condition.
450 // Mine seems to be more straightforward (even if it doesn't look so) and I could leave you here
451 // without additional comments, but I'm not that mean so here goes the explanation.
452 //
453 // We want to know if both ends of the range are anchored in the same element. Really. It's this simple.
454 // But why? Because we need to differentiate situations like:
455 //
456 // <p>foo[<b>x</b>bar]y</p> (commonLevel = p, maxLL = "foo", maxLR = "y")
457 // from:
458 // <p>foo<b>x[</b>bar]y</p> (commonLevel = p, maxLL = "x", maxLR = "y")
459 //
460 // In the first case we can collapse the range to the left, because simply everything between range's
461 // boundaries was removed.
462 // In the second case we must place the range after </b>, because <b> was only **partially selected**.
463 //
464 // * <b> is our startParents[ commonLevel + 1 ]
465 // * "y" is our endParents[ commonLevel + 1 ].
466 //
467 // By now "bar" is removed from the DOM so <b> is a direct sibling of "y":
468 // <p>foo<b>x</b>y</p>
469 //
470 // Therefore it's enough to place the range between <b> and "y".
471 //
472 // Now, what does the comparison mean? Why not just taking startNode and endNode and checking
473 // their parents? Because the tree is already changed and they may be gone. Plus, thanks to
474 // cloneStartNode and cloneEndNode, that would be reaaaaly tricky.
475 //
476 // So we play with levels which can give us the same information:
477 // * commonLevel - the level of common ancestor,
478 // * maxLevel - 1 - the level of range boundary parent (range boundary is here like a bookmark span).
479 // * commonLevel < maxLevel - 1 - whether the range boundary is not a child of common ancestor.
480 //
481 // There's also an edge case in which both range boundaries were placed in empty nodes like:
482 // <p>[</p><p>]</p>
483 // Those boundaries were not removed, but in this case start and end nodes are child of the common ancestor.
484 // We handle this edge case separately.
485 if ( commonLevel < ( maxLevelLeft - 1 ) || commonLevel < ( maxLevelRight - 1 ) || boundariesInEmptyNode ) {
486 if ( boundariesInEmptyNode ) {
487 range.moveToPosition( endNode, CKEDITOR.POSITION_BEFORE_START );
488 } else if ( ( maxLevelRight == commonLevel + 1 ) && cloneEndNode ) {
489 // The maxLevelRight + 1 element could be already removed so we use the fact that
490 // we know that it was the last element in its parent.
491 range.moveToPosition( endParents[ commonLevel ], CKEDITOR.POSITION_BEFORE_END );
492 } else {
493 range.moveToPosition( endParents[ commonLevel + 1 ], CKEDITOR.POSITION_BEFORE_START );
494 }
495
496 // Merge split parents.
497 if ( mergeThen ) {
498 // Find the first diverged node in the left branch.
499 var topLeft = startParents[ commonLevel + 1 ];
500
501 // TopLeft may simply not exist if commonLevel == maxLevel or may be a text node.
502 if ( topLeft && topLeft.type == CKEDITOR.NODE_ELEMENT ) {
503 var span = CKEDITOR.dom.element.createFromHtml( '<span ' +
504 'data-cke-bookmark="1" style="display:none">&nbsp;</span>', range.document );
505 span.insertAfter( topLeft );
506 topLeft.mergeSiblings( false );
507 range.moveToBookmark( { startNode: span } );
508 }
509 }
510 } else {
511 // Collapse it to the start.
512 range.collapse( true );
513 }
514 }
515 }
516
517 var inlineChildReqElements = {
518 abbr: 1, acronym: 1, b: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1,
519 dfn: 1, em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, q: 1, samp: 1, small: 1, span: 1, strike: 1,
520 strong: 1, sub: 1, sup: 1, tt: 1, u: 1, 'var': 1
521 };
522
523 // Creates the appropriate node evaluator for the dom walker used inside
524 // check(Start|End)OfBlock.
525 function getCheckStartEndBlockEvalFunction() {
526 var skipBogus = false,
527 whitespaces = CKEDITOR.dom.walker.whitespaces(),
528 bookmarkEvaluator = CKEDITOR.dom.walker.bookmark( true ),
529 isBogus = CKEDITOR.dom.walker.bogus();
530
531 return function( node ) {
532 // First skip empty nodes
533 if ( bookmarkEvaluator( node ) || whitespaces( node ) )
534 return true;
535
536 // Skip the bogus node at the end of block.
537 if ( isBogus( node ) && !skipBogus ) {
538 skipBogus = true;
539 return true;
540 }
541
542 // If there's any visible text, then we're not at the start.
543 if ( node.type == CKEDITOR.NODE_TEXT &&
544 ( node.hasAscendant( 'pre' ) ||
545 CKEDITOR.tools.trim( node.getText() ).length ) ) {
546 return false;
547 }
548
549 // If there are non-empty inline elements (e.g. <img />), then we're not
550 // at the start.
551 if ( node.type == CKEDITOR.NODE_ELEMENT && !node.is( inlineChildReqElements ) )
552 return false;
553
554 return true;
555 };
556 }
557
558 var isBogus = CKEDITOR.dom.walker.bogus(),
559 nbspRegExp = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/,
560 editableEval = CKEDITOR.dom.walker.editable(),
561 notIgnoredEval = CKEDITOR.dom.walker.ignored( true );
562
563 // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject any
564 // text node and non-empty elements unless it's being bookmark text.
565 function elementBoundaryEval( checkStart ) {
566 var whitespaces = CKEDITOR.dom.walker.whitespaces(),
567 bookmark = CKEDITOR.dom.walker.bookmark( 1 );
568
569 return function( node ) {
570 // First skip empty nodes.
571 if ( bookmark( node ) || whitespaces( node ) )
572 return true;
573
574 // Tolerant bogus br when checking at the end of block.
575 // Reject any text node unless it's being bookmark
576 // OR it's spaces.
577 // Reject any element unless it's being invisible empty. (#3883)
578 return !checkStart && isBogus( node ) ||
579 node.type == CKEDITOR.NODE_ELEMENT &&
580 node.is( CKEDITOR.dtd.$removeEmpty );
581 };
582 }
583
584 function getNextEditableNode( isPrevious ) {
585 return function() {
586 var first;
587
588 return this[ isPrevious ? 'getPreviousNode' : 'getNextNode' ]( function( node ) {
589 // Cache first not ignorable node.
590 if ( !first && notIgnoredEval( node ) )
591 first = node;
592
593 // Return true if found editable node, but not a bogus next to start of our lookup (first != bogus).
594 return editableEval( node ) && !( isBogus( node ) && node.equals( first ) );
595 } );
596 };
597 }
598
599 CKEDITOR.dom.range.prototype = {
600 /**
601 * Clones this range.
602 *
603 * @returns {CKEDITOR.dom.range}
604 */
605 clone: function() {
606 var clone = new CKEDITOR.dom.range( this.root );
607
608 clone._setStartContainer( this.startContainer );
609 clone.startOffset = this.startOffset;
610 clone._setEndContainer( this.endContainer );
611 clone.endOffset = this.endOffset;
612 clone.collapsed = this.collapsed;
613
614 return clone;
615 },
616
617 /**
618 * Makes the range collapsed by moving its start point (or end point if `toStart==true`)
619 * to the second end.
620 *
621 * @param {Boolean} toStart Collapse range "to start".
622 */
623 collapse: function( toStart ) {
624 if ( toStart ) {
625 this._setEndContainer( this.startContainer );
626 this.endOffset = this.startOffset;
627 } else {
628 this._setStartContainer( this.endContainer );
629 this.startOffset = this.endOffset;
630 }
631
632 this.collapsed = true;
633 },
634
635 /**
636 * Clones content nodes of the range and adds them to a document fragment, which is returned.
637 *
638 * @param {Boolean} [cloneId=true] Whether to preserve ID attributes in the clone.
639 * @returns {CKEDITOR.dom.documentFragment} Document fragment containing a clone of range's content.
640 */
641 cloneContents: function( cloneId ) {
642 var docFrag = new CKEDITOR.dom.documentFragment( this.document );
643
644 cloneId = typeof cloneId == 'undefined' ? true : cloneId;
645
646 if ( !this.collapsed )
647 execContentsAction( this, 2, docFrag, false, cloneId );
648
649 return docFrag;
650 },
651
652 /**
653 * Deletes the content nodes of the range permanently from the DOM tree.
654 *
655 * @param {Boolean} [mergeThen] Merge any split elements result in DOM true due to partial selection.
656 */
657 deleteContents: function( mergeThen ) {
658 if ( this.collapsed )
659 return;
660
661 execContentsAction( this, 0, null, mergeThen );
662 },
663
664 /**
665 * The content nodes of the range are cloned and added to a document fragment,
666 * meanwhile they are removed permanently from the DOM tree.
667 *
668 * **Note:** Setting the `cloneId` parameter to `false` works for **partially** selected elements only.
669 * If an element with an ID attribute is **fully enclosed** in a range, it will keep the ID attribute
670 * regardless of the `cloneId` parameter value, because it is not cloned &mdash; it is moved to the returned
671 * document fragment.
672 *
673 * @param {Boolean} [mergeThen] Merge any split elements result in DOM true due to partial selection.
674 * @param {Boolean} [cloneId=true] Whether to preserve ID attributes in the extracted content.
675 * @returns {CKEDITOR.dom.documentFragment} Document fragment containing extracted content.
676 */
677 extractContents: function( mergeThen, cloneId ) {
678 var docFrag = new CKEDITOR.dom.documentFragment( this.document );
679
680 cloneId = typeof cloneId == 'undefined' ? true : cloneId;
681
682 if ( !this.collapsed )
683 execContentsAction( this, 1, docFrag, mergeThen, cloneId );
684
685 return docFrag;
686 },
687
688 /**
689 * Creates a bookmark object, which can be later used to restore the
690 * range by using the {@link #moveToBookmark} function.
691 *
692 * This is an "intrusive" way to create a bookmark. It includes `<span>` tags
693 * in the range boundaries. The advantage of it is that it is possible to
694 * handle DOM mutations when moving back to the bookmark.
695 *
696 * **Note:** The inclusion of nodes in the DOM is a design choice and
697 * should not be changed as there are other points in the code that may be
698 * using those nodes to perform operations.
699 *
700 * @param {Boolean} [serializable] Indicates that the bookmark nodes
701 * must contain IDs, which can be used to restore the range even
702 * when these nodes suffer mutations (like cloning or `innerHTML` change).
703 * @returns {Object} And object representing a bookmark.
704 * @returns {CKEDITOR.dom.node/String} return.startNode Node or element ID.
705 * @returns {CKEDITOR.dom.node/String} return.endNode Node or element ID.
706 * @returns {Boolean} return.serializable
707 * @returns {Boolean} return.collapsed
708 */
709 createBookmark: function( serializable ) {
710 var startNode, endNode;
711 var baseId;
712 var clone;
713 var collapsed = this.collapsed;
714
715 startNode = this.document.createElement( 'span' );
716 startNode.data( 'cke-bookmark', 1 );
717 startNode.setStyle( 'display', 'none' );
718
719 // For IE, it must have something inside, otherwise it may be
720 // removed during DOM operations.
721 startNode.setHtml( '&nbsp;' );
722
723 if ( serializable ) {
724 baseId = 'cke_bm_' + CKEDITOR.tools.getNextNumber();
725 startNode.setAttribute( 'id', baseId + ( collapsed ? 'C' : 'S' ) );
726 }
727
728 // If collapsed, the endNode will not be created.
729 if ( !collapsed ) {
730 endNode = startNode.clone();
731 endNode.setHtml( '&nbsp;' );
732
733 if ( serializable )
734 endNode.setAttribute( 'id', baseId + 'E' );
735
736 clone = this.clone();
737 clone.collapse();
738 clone.insertNode( endNode );
739 }
740
741 clone = this.clone();
742 clone.collapse( true );
743 clone.insertNode( startNode );
744
745 // Update the range position.
746 if ( endNode ) {
747 this.setStartAfter( startNode );
748 this.setEndBefore( endNode );
749 } else {
750 this.moveToPosition( startNode, CKEDITOR.POSITION_AFTER_END );
751 }
752
753 return {
754 startNode: serializable ? baseId + ( collapsed ? 'C' : 'S' ) : startNode,
755 endNode: serializable ? baseId + 'E' : endNode,
756 serializable: serializable,
757 collapsed: collapsed
758 };
759 },
760
761 /**
762 * Creates a "non intrusive" and "mutation sensible" bookmark. This
763 * kind of bookmark should be used only when the DOM is supposed to
764 * remain stable after its creation.
765 *
766 * @param {Boolean} [normalized] Indicates that the bookmark must
767 * be normalized. When normalized, the successive text nodes are
768 * considered a single node. To successfully load a normalized
769 * bookmark, the DOM tree must also be normalized before calling
770 * {@link #moveToBookmark}.
771 * @returns {Object} An object representing the bookmark.
772 * @returns {Array} return.start Start container's address (see {@link CKEDITOR.dom.node#getAddress}).
773 * @returns {Array} return.end Start container's address.
774 * @returns {Number} return.startOffset
775 * @returns {Number} return.endOffset
776 * @returns {Boolean} return.collapsed
777 * @returns {Boolean} return.normalized
778 * @returns {Boolean} return.is2 This is "bookmark2".
779 */
780 createBookmark2: ( function() {
781 var isNotText = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_TEXT, true );
782
783 // Returns true for limit anchored in element and placed between text nodes.
784 //
785 // v
786 // <p>[text node] [text node]</p> -> true
787 //
788 // v
789 // <p> [text node]</p> -> false
790 //
791 // v
792 // <p>[text node][text node]</p> -> false (limit is anchored in text node)
793 function betweenTextNodes( container, offset ) {
794 // Not anchored in element or limit is on the edge.
795 if ( container.type != CKEDITOR.NODE_ELEMENT || offset === 0 || offset == container.getChildCount() )
796 return 0;
797
798 return container.getChild( offset - 1 ).type == CKEDITOR.NODE_TEXT &&
799 container.getChild( offset ).type == CKEDITOR.NODE_TEXT;
800 }
801
802 // Sums lengths of all preceding text nodes.
803 function getLengthOfPrecedingTextNodes( node ) {
804 var sum = 0;
805
806 while ( ( node = node.getPrevious() ) && node.type == CKEDITOR.NODE_TEXT )
807 sum += node.getText().replace( CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE, '' ).length;
808
809 return sum;
810 }
811
812 function normalizeTextNodes( limit ) {
813 var container = limit.container,
814 offset = limit.offset;
815
816 // If limit is between text nodes move it to the end of preceding one,
817 // because they will be merged.
818 if ( betweenTextNodes( container, offset ) ) {
819 container = container.getChild( offset - 1 );
820 offset = container.getLength();
821 }
822
823 // Now, if limit is anchored in element and has at least one node before it,
824 // it may happen that some of them will be merged. Normalize the offset
825 // by setting it to normalized index of its preceding, safe node.
826 // (safe == one for which getIndex(true) does not return -1, so one which won't disappear).
827 if ( container.type == CKEDITOR.NODE_ELEMENT && offset > 0 ) {
828 offset = getPrecedingSafeNodeIndex( container, offset ) + 1;
829 }
830
831 // The last step - fix the offset inside text node by adding
832 // lengths of preceding text nodes which will be merged with container.
833 if ( container.type == CKEDITOR.NODE_TEXT ) {
834 var precedingLength = getLengthOfPrecedingTextNodes( container );
835
836 // Normal case - text node is not empty.
837 if ( container.getText() ) {
838 offset += precedingLength;
839
840 // Awful case - the text node is empty and thus will be totally lost.
841 // In this case we are trying to normalize the limit to the left:
842 // * either to the preceding text node,
843 // * or to the "gap" after the preceding element.
844 } else {
845 // Find the closest non-text sibling.
846 var precedingContainer = container.getPrevious( isNotText );
847
848 // If there are any characters on the left, that means that we can anchor
849 // there, because this text node will not be lost.
850 if ( precedingLength ) {
851 offset = precedingLength;
852
853 if ( precedingContainer ) {
854 // The text node is the first node after the closest non-text sibling.
855 container = precedingContainer.getNext();
856 } else {
857 // But if there was no non-text sibling, then the text node is the first child.
858 container = container.getParent().getFirst();
859 }
860
861 // If there are no characters on the left, then anchor after the previous non-text node.
862 // E.g. (see tests for a legend :D):
863 // <b>x</b>(foo)({}bar) -> <b>x</b>[](foo)(bar)
864 } else {
865 container = container.getParent();
866 offset = precedingContainer ? ( precedingContainer.getIndex( true ) + 1 ) : 0;
867 }
868 }
869 }
870
871 limit.container = container;
872 limit.offset = offset;
873 }
874
875 function normalizeFCSeq( limit, root ) {
876 var fcseq = root.getCustomData( 'cke-fillingChar' );
877
878 if ( !fcseq ) {
879 return;
880 }
881
882 var container = limit.container;
883
884 if ( fcseq.equals( container ) ) {
885 limit.offset -= CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE.length;
886
887 // == 0 handles case when limit was at the end of FCS.
888 // < 0 handles all cases where limit was somewhere in the middle or at the beginning.
889 // > 0 (the "else" case) means cases where there are some more characters in the FCS node (FCSabc^def).
890 if ( limit.offset <= 0 ) {
891 limit.offset = container.getIndex();
892 limit.container = container.getParent();
893 }
894 return;
895 }
896
897 // And here goes the funny part - all other cases are handled inside node.getAddress() and getIndex() thanks to
898 // node.getIndex() being aware of FCS (handling it as an empty node).
899 }
900
901 // Finds a normalized index of a safe node preceding this one.
902 // Safe == one that will not disappear, so one for which getIndex( true ) does not return -1.
903 // Return -1 if there's no safe preceding node.
904 function getPrecedingSafeNodeIndex( container, offset ) {
905 var index;
906
907 while ( offset-- ) {
908 index = container.getChild( offset ).getIndex( true );
909
910 if ( index >= 0 )
911 return index;
912 }
913
914 return -1;
915 }
916
917 return function( normalized ) {
918 var collapsed = this.collapsed,
919 bmStart = {
920 container: this.startContainer,
921 offset: this.startOffset
922 },
923 bmEnd = {
924 container: this.endContainer,
925 offset: this.endOffset
926 };
927
928 if ( normalized ) {
929 normalizeTextNodes( bmStart );
930 normalizeFCSeq( bmStart, this.root );
931
932 if ( !collapsed ) {
933 normalizeTextNodes( bmEnd );
934 normalizeFCSeq( bmEnd, this.root );
935 }
936 }
937
938 return {
939 start: bmStart.container.getAddress( normalized ),
940 end: collapsed ? null : bmEnd.container.getAddress( normalized ),
941 startOffset: bmStart.offset,
942 endOffset: bmEnd.offset,
943 normalized: normalized,
944 collapsed: collapsed,
945 is2: true // It's a createBookmark2 bookmark.
946 };
947 };
948 } )(),
949
950 /**
951 * Moves this range to the given bookmark. See {@link #createBookmark} and {@link #createBookmark2}.
952 *
953 * If serializable bookmark passed, then its `<span>` markers will be removed.
954 *
955 * @param {Object} bookmark
956 */
957 moveToBookmark: function( bookmark ) {
958 // Created with createBookmark2().
959 if ( bookmark.is2 ) {
960 // Get the start information.
961 var startContainer = this.document.getByAddress( bookmark.start, bookmark.normalized ),
962 startOffset = bookmark.startOffset;
963
964 // Get the end information.
965 var endContainer = bookmark.end && this.document.getByAddress( bookmark.end, bookmark.normalized ),
966 endOffset = bookmark.endOffset;
967
968 // Set the start boundary.
969 this.setStart( startContainer, startOffset );
970
971 // Set the end boundary. If not available, collapse it.
972 if ( endContainer )
973 this.setEnd( endContainer, endOffset );
974 else
975 this.collapse( true );
976 }
977 // Created with createBookmark().
978 else {
979 var serializable = bookmark.serializable,
980 startNode = serializable ? this.document.getById( bookmark.startNode ) : bookmark.startNode,
981 endNode = serializable ? this.document.getById( bookmark.endNode ) : bookmark.endNode;
982
983 // Set the range start at the bookmark start node position.
984 this.setStartBefore( startNode );
985
986 // Remove it, because it may interfere in the setEndBefore call.
987 startNode.remove();
988
989 // Set the range end at the bookmark end node position, or simply
990 // collapse it if it is not available.
991 if ( endNode ) {
992 this.setEndBefore( endNode );
993 endNode.remove();
994 } else {
995 this.collapse( true );
996 }
997 }
998 },
999
1000 /**
1001 * Returns two nodes which are on the boundaries of this range.
1002 *
1003 * @returns {Object}
1004 * @returns {CKEDITOR.dom.node} return.startNode
1005 * @returns {CKEDITOR.dom.node} return.endNode
1006 * @todo precise desc/algorithm
1007 */
1008 getBoundaryNodes: function() {
1009 var startNode = this.startContainer,
1010 endNode = this.endContainer,
1011 startOffset = this.startOffset,
1012 endOffset = this.endOffset,
1013 childCount;
1014
1015 if ( startNode.type == CKEDITOR.NODE_ELEMENT ) {
1016 childCount = startNode.getChildCount();
1017 if ( childCount > startOffset ) {
1018 startNode = startNode.getChild( startOffset );
1019 } else if ( childCount < 1 ) {
1020 startNode = startNode.getPreviousSourceNode();
1021 }
1022 // startOffset > childCount but childCount is not 0
1023 else {
1024 // Try to take the node just after the current position.
1025 startNode = startNode.$;
1026 while ( startNode.lastChild )
1027 startNode = startNode.lastChild;
1028 startNode = new CKEDITOR.dom.node( startNode );
1029
1030 // Normally we should take the next node in DFS order. But it
1031 // is also possible that we've already reached the end of
1032 // document.
1033 startNode = startNode.getNextSourceNode() || startNode;
1034 }
1035 }
1036
1037 if ( endNode.type == CKEDITOR.NODE_ELEMENT ) {
1038 childCount = endNode.getChildCount();
1039 if ( childCount > endOffset ) {
1040 endNode = endNode.getChild( endOffset ).getPreviousSourceNode( true );
1041 } else if ( childCount < 1 ) {
1042 endNode = endNode.getPreviousSourceNode();
1043 }
1044 // endOffset > childCount but childCount is not 0.
1045 else {
1046 // Try to take the node just before the current position.
1047 endNode = endNode.$;
1048 while ( endNode.lastChild )
1049 endNode = endNode.lastChild;
1050 endNode = new CKEDITOR.dom.node( endNode );
1051 }
1052 }
1053
1054 // Sometimes the endNode will come right before startNode for collapsed
1055 // ranges. Fix it. (#3780)
1056 if ( startNode.getPosition( endNode ) & CKEDITOR.POSITION_FOLLOWING )
1057 startNode = endNode;
1058
1059 return { startNode: startNode, endNode: endNode };
1060 },
1061
1062 /**
1063 * Find the node which fully contains the range.
1064 *
1065 * @param {Boolean} [includeSelf=false]
1066 * @param {Boolean} [ignoreTextNode=false] Whether ignore {@link CKEDITOR#NODE_TEXT} type.
1067 * @returns {CKEDITOR.dom.element}
1068 */
1069 getCommonAncestor: function( includeSelf, ignoreTextNode ) {
1070 var start = this.startContainer,
1071 end = this.endContainer,
1072 ancestor;
1073
1074 if ( start.equals( end ) ) {
1075 if ( includeSelf && start.type == CKEDITOR.NODE_ELEMENT && this.startOffset == this.endOffset - 1 )
1076 ancestor = start.getChild( this.startOffset );
1077 else
1078 ancestor = start;
1079 } else {
1080 ancestor = start.getCommonAncestor( end );
1081 }
1082
1083 return ignoreTextNode && !ancestor.is ? ancestor.getParent() : ancestor;
1084 },
1085
1086 /**
1087 * Transforms the {@link #startContainer} and {@link #endContainer} properties from text
1088 * nodes to element nodes, whenever possible. This is actually possible
1089 * if either of the boundary containers point to a text node, and its
1090 * offset is set to zero, or after the last char in the node.
1091 */
1092 optimize: function() {
1093 var container = this.startContainer;
1094 var offset = this.startOffset;
1095
1096 if ( container.type != CKEDITOR.NODE_ELEMENT ) {
1097 if ( !offset )
1098 this.setStartBefore( container );
1099 else if ( offset >= container.getLength() )
1100 this.setStartAfter( container );
1101 }
1102
1103 container = this.endContainer;
1104 offset = this.endOffset;
1105
1106 if ( container.type != CKEDITOR.NODE_ELEMENT ) {
1107 if ( !offset )
1108 this.setEndBefore( container );
1109 else if ( offset >= container.getLength() )
1110 this.setEndAfter( container );
1111 }
1112 },
1113
1114 /**
1115 * Move the range out of bookmark nodes if they'd been the container.
1116 */
1117 optimizeBookmark: function() {
1118 var startNode = this.startContainer,
1119 endNode = this.endContainer;
1120
1121 if ( startNode.is && startNode.is( 'span' ) && startNode.data( 'cke-bookmark' ) )
1122 this.setStartAt( startNode, CKEDITOR.POSITION_BEFORE_START );
1123 if ( endNode && endNode.is && endNode.is( 'span' ) && endNode.data( 'cke-bookmark' ) )
1124 this.setEndAt( endNode, CKEDITOR.POSITION_AFTER_END );
1125 },
1126
1127 /**
1128 * @param {Boolean} [ignoreStart=false]
1129 * @param {Boolean} [ignoreEnd=false]
1130 * @todo precise desc/algorithm
1131 */
1132 trim: function( ignoreStart, ignoreEnd ) {
1133 var startContainer = this.startContainer,
1134 startOffset = this.startOffset,
1135 collapsed = this.collapsed;
1136 if ( ( !ignoreStart || collapsed ) && startContainer && startContainer.type == CKEDITOR.NODE_TEXT ) {
1137 // If the offset is zero, we just insert the new node before
1138 // the start.
1139 if ( !startOffset ) {
1140 startOffset = startContainer.getIndex();
1141 startContainer = startContainer.getParent();
1142 }
1143 // If the offset is at the end, we'll insert it after the text
1144 // node.
1145 else if ( startOffset >= startContainer.getLength() ) {
1146 startOffset = startContainer.getIndex() + 1;
1147 startContainer = startContainer.getParent();
1148 }
1149 // In other case, we split the text node and insert the new
1150 // node at the split point.
1151 else {
1152 var nextText = startContainer.split( startOffset );
1153
1154 startOffset = startContainer.getIndex() + 1;
1155 startContainer = startContainer.getParent();
1156
1157 // Check all necessity of updating the end boundary.
1158 if ( this.startContainer.equals( this.endContainer ) )
1159 this.setEnd( nextText, this.endOffset - this.startOffset );
1160 else if ( startContainer.equals( this.endContainer ) )
1161 this.endOffset += 1;
1162 }
1163
1164 this.setStart( startContainer, startOffset );
1165
1166 if ( collapsed ) {
1167 this.collapse( true );
1168 return;
1169 }
1170 }
1171
1172 var endContainer = this.endContainer;
1173 var endOffset = this.endOffset;
1174
1175 if ( !( ignoreEnd || collapsed ) && endContainer && endContainer.type == CKEDITOR.NODE_TEXT ) {
1176 // If the offset is zero, we just insert the new node before
1177 // the start.
1178 if ( !endOffset ) {
1179 endOffset = endContainer.getIndex();
1180 endContainer = endContainer.getParent();
1181 }
1182 // If the offset is at the end, we'll insert it after the text
1183 // node.
1184 else if ( endOffset >= endContainer.getLength() ) {
1185 endOffset = endContainer.getIndex() + 1;
1186 endContainer = endContainer.getParent();
1187 }
1188 // In other case, we split the text node and insert the new
1189 // node at the split point.
1190 else {
1191 endContainer.split( endOffset );
1192
1193 endOffset = endContainer.getIndex() + 1;
1194 endContainer = endContainer.getParent();
1195 }
1196
1197 this.setEnd( endContainer, endOffset );
1198 }
1199 },
1200
1201 /**
1202 * Expands the range so that partial units are completely contained.
1203 *
1204 * @param {Number} unit The unit type to expand with. Use one of following values: {@link CKEDITOR#ENLARGE_BLOCK_CONTENTS},
1205 * {@link CKEDITOR#ENLARGE_ELEMENT}, {@link CKEDITOR#ENLARGE_INLINE}, {@link CKEDITOR#ENLARGE_LIST_ITEM_CONTENTS}.
1206 * @param {Boolean} [excludeBrs=false] Whether include line-breaks when expanding.
1207 */
1208 enlarge: function( unit, excludeBrs ) {
1209 var leadingWhitespaceRegex = new RegExp( /[^\s\ufeff]/ );
1210
1211 switch ( unit ) {
1212 case CKEDITOR.ENLARGE_INLINE:
1213 var enlargeInlineOnly = 1;
1214
1215 /* falls through */
1216 case CKEDITOR.ENLARGE_ELEMENT:
1217
1218 if ( this.collapsed )
1219 return;
1220
1221 // Get the common ancestor.
1222 var commonAncestor = this.getCommonAncestor();
1223
1224 var boundary = this.root;
1225
1226 // For each boundary
1227 // a. Depending on its position, find out the first node to be checked (a sibling) or,
1228 // if not available, to be enlarge.
1229 // b. Go ahead checking siblings and enlarging the boundary as much as possible until the
1230 // common ancestor is not reached. After reaching the common ancestor, just save the
1231 // enlargeable node to be used later.
1232
1233 var startTop, endTop;
1234
1235 var enlargeable, sibling, commonReached;
1236
1237 // Indicates that the node can be added only if whitespace
1238 // is available before it.
1239 var needsWhiteSpace = false;
1240 var isWhiteSpace;
1241 var siblingText;
1242
1243 // Process the start boundary.
1244
1245 var container = this.startContainer;
1246 var offset = this.startOffset;
1247
1248 if ( container.type == CKEDITOR.NODE_TEXT ) {
1249 if ( offset ) {
1250 // Check if there is any non-space text before the
1251 // offset. Otherwise, container is null.
1252 container = !CKEDITOR.tools.trim( container.substring( 0, offset ) ).length && container;
1253
1254 // If we found only whitespace in the node, it
1255 // means that we'll need more whitespace to be able
1256 // to expand. For example, <i> can be expanded in
1257 // "A <i> [B]</i>", but not in "A<i> [B]</i>".
1258 needsWhiteSpace = !!container;
1259 }
1260
1261 if ( container ) {
1262 if ( !( sibling = container.getPrevious() ) )
1263 enlargeable = container.getParent();
1264 }
1265 } else {
1266 // If we have offset, get the node preceeding it as the
1267 // first sibling to be checked.
1268 if ( offset )
1269 sibling = container.getChild( offset - 1 ) || container.getLast();
1270
1271 // If there is no sibling, mark the container to be
1272 // enlarged.
1273 if ( !sibling )
1274 enlargeable = container;
1275 }
1276
1277 // Ensures that enlargeable can be indeed enlarged, if not it will be nulled.
1278 enlargeable = getValidEnlargeable( enlargeable );
1279
1280 while ( enlargeable || sibling ) {
1281 if ( enlargeable && !sibling ) {
1282 // If we reached the common ancestor, mark the flag
1283 // for it.
1284 if ( !commonReached && enlargeable.equals( commonAncestor ) )
1285 commonReached = true;
1286
1287 if ( enlargeInlineOnly ? enlargeable.isBlockBoundary() : !boundary.contains( enlargeable ) )
1288 break;
1289
1290 // If we don't need space or this element breaks
1291 // the line, then enlarge it.
1292 if ( !needsWhiteSpace || enlargeable.getComputedStyle( 'display' ) != 'inline' ) {
1293 needsWhiteSpace = false;
1294
1295 // If the common ancestor has been reached,
1296 // we'll not enlarge it immediately, but just
1297 // mark it to be enlarged later if the end
1298 // boundary also enlarges it.
1299 if ( commonReached )
1300 startTop = enlargeable;
1301 else
1302 this.setStartBefore( enlargeable );
1303 }
1304
1305 sibling = enlargeable.getPrevious();
1306 }
1307
1308 // Check all sibling nodes preceeding the enlargeable
1309 // node. The node wil lbe enlarged only if none of them
1310 // blocks it.
1311 while ( sibling ) {
1312 // This flag indicates that this node has
1313 // whitespaces at the end.
1314 isWhiteSpace = false;
1315
1316 if ( sibling.type == CKEDITOR.NODE_COMMENT ) {
1317 sibling = sibling.getPrevious();
1318 continue;
1319 } else if ( sibling.type == CKEDITOR.NODE_TEXT ) {
1320 siblingText = sibling.getText();
1321
1322 if ( leadingWhitespaceRegex.test( siblingText ) )
1323 sibling = null;
1324
1325 isWhiteSpace = /[\s\ufeff]$/.test( siblingText );
1326 } else {
1327 // #12221 (Chrome) plus #11111 (Safari).
1328 var offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0;
1329
1330 // If this is a visible element.
1331 // We need to check for the bookmark attribute because IE insists on
1332 // rendering the display:none nodes we use for bookmarks. (#3363)
1333 // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041)
1334 if ( ( sibling.$.offsetWidth > offsetWidth0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) {
1335 // We'll accept it only if we need
1336 // whitespace, and this is an inline
1337 // element with whitespace only.
1338 if ( needsWhiteSpace && CKEDITOR.dtd.$removeEmpty[ sibling.getName() ] ) {
1339 // It must contains spaces and inline elements only.
1340
1341 siblingText = sibling.getText();
1342
1343 if ( leadingWhitespaceRegex.test( siblingText ) ) // Spaces + Zero Width No-Break Space (U+FEFF)
1344 sibling = null;
1345 else {
1346 var allChildren = sibling.$.getElementsByTagName( '*' );
1347 for ( var i = 0, child; child = allChildren[ i++ ]; ) {
1348 if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] ) {
1349 sibling = null;
1350 break;
1351 }
1352 }
1353 }
1354
1355 if ( sibling )
1356 isWhiteSpace = !!siblingText.length;
1357 } else {
1358 sibling = null;
1359 }
1360 }
1361 }
1362
1363 // A node with whitespaces has been found.
1364 if ( isWhiteSpace ) {
1365 // Enlarge the last enlargeable node, if we
1366 // were waiting for spaces.
1367 if ( needsWhiteSpace ) {
1368 if ( commonReached )
1369 startTop = enlargeable;
1370 else if ( enlargeable )
1371 this.setStartBefore( enlargeable );
1372 } else {
1373 needsWhiteSpace = true;
1374 }
1375 }
1376
1377 if ( sibling ) {
1378 var next = sibling.getPrevious();
1379
1380 if ( !enlargeable && !next ) {
1381 // Set the sibling as enlargeable, so it's
1382 // parent will be get later outside this while.
1383 enlargeable = sibling;
1384 sibling = null;
1385 break;
1386 }
1387
1388 sibling = next;
1389 } else {
1390 // If sibling has been set to null, then we
1391 // need to stop enlarging.
1392 enlargeable = null;
1393 }
1394 }
1395
1396 if ( enlargeable )
1397 enlargeable = getValidEnlargeable( enlargeable.getParent() );
1398 }
1399
1400 // Process the end boundary. This is basically the same
1401 // code used for the start boundary, with small changes to
1402 // make it work in the oposite side (to the right). This
1403 // makes it difficult to reuse the code here. So, fixes to
1404 // the above code are likely to be replicated here.
1405
1406 container = this.endContainer;
1407 offset = this.endOffset;
1408
1409 // Reset the common variables.
1410 enlargeable = sibling = null;
1411 commonReached = needsWhiteSpace = false;
1412
1413 // Function check if there are only whitespaces from the given starting point
1414 // (startContainer and startOffset) till the end on block.
1415 // Examples ("[" is the start point):
1416 // - <p>foo[ </p> - will return true,
1417 // - <p><b>foo[ </b> </p> - will return true,
1418 // - <p>foo[ bar</p> - will return false,
1419 // - <p><b>foo[ </b>bar</p> - will return false,
1420 // - <p>foo[ <b></b></p> - will return false.
1421 function onlyWhiteSpaces( startContainer, startOffset ) {
1422 // We need to enlarge range if there is white space at the end of the block,
1423 // because it is not displayed in WYSIWYG mode and user can not select it. So
1424 // "<p>foo[bar] </p>" should be changed to "<p>foo[bar ]</p>". On the other hand
1425 // we should do nothing if we are not at the end of the block, so this should not
1426 // be changed: "<p><i>[foo] </i>bar</p>".
1427 var walkerRange = new CKEDITOR.dom.range( boundary );
1428 walkerRange.setStart( startContainer, startOffset );
1429 // The guard will find the end of range so I put boundary here.
1430 walkerRange.setEndAt( boundary, CKEDITOR.POSITION_BEFORE_END );
1431
1432 var walker = new CKEDITOR.dom.walker( walkerRange ),
1433 node;
1434
1435 walker.guard = function( node ) {
1436 // Stop if you exit block.
1437 return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary() );
1438 };
1439
1440 while ( ( node = walker.next() ) ) {
1441 if ( node.type != CKEDITOR.NODE_TEXT ) {
1442 // Stop if you enter to any node (walker.next() will return node only
1443 // it goes out, not if it is go into node).
1444 return false;
1445 } else {
1446 // Trim the first node to startOffset.
1447 if ( node != startContainer )
1448 siblingText = node.getText();
1449 else
1450 siblingText = node.substring( startOffset );
1451
1452 // Check if it is white space.
1453 if ( leadingWhitespaceRegex.test( siblingText ) )
1454 return false;
1455 }
1456 }
1457
1458 return true;
1459 }
1460
1461 if ( container.type == CKEDITOR.NODE_TEXT ) {
1462 // Check if there is only white space after the offset.
1463 if ( CKEDITOR.tools.trim( container.substring( offset ) ).length ) {
1464 // If we found only whitespace in the node, it
1465 // means that we'll need more whitespace to be able
1466 // to expand. For example, <i> can be expanded in
1467 // "A <i> [B]</i>", but not in "A<i> [B]</i>".
1468 needsWhiteSpace = true;
1469 } else {
1470 needsWhiteSpace = !container.getLength();
1471
1472 if ( offset == container.getLength() ) {
1473 // If we are at the end of container and this is the last text node,
1474 // we should enlarge end to the parent.
1475 if ( !( sibling = container.getNext() ) )
1476 enlargeable = container.getParent();
1477 } else {
1478 // If we are in the middle on text node and there are only whitespaces
1479 // till the end of block, we should enlarge element.
1480 if ( onlyWhiteSpaces( container, offset ) )
1481 enlargeable = container.getParent();
1482 }
1483 }
1484 } else {
1485 // Get the node right after the boudary to be checked
1486 // first.
1487 sibling = container.getChild( offset );
1488
1489 if ( !sibling )
1490 enlargeable = container;
1491 }
1492
1493 while ( enlargeable || sibling ) {
1494 if ( enlargeable && !sibling ) {
1495 if ( !commonReached && enlargeable.equals( commonAncestor ) )
1496 commonReached = true;
1497
1498 if ( enlargeInlineOnly ? enlargeable.isBlockBoundary() : !boundary.contains( enlargeable ) )
1499 break;
1500
1501 if ( !needsWhiteSpace || enlargeable.getComputedStyle( 'display' ) != 'inline' ) {
1502 needsWhiteSpace = false;
1503
1504 if ( commonReached )
1505 endTop = enlargeable;
1506 else if ( enlargeable )
1507 this.setEndAfter( enlargeable );
1508 }
1509
1510 sibling = enlargeable.getNext();
1511 }
1512
1513 while ( sibling ) {
1514 isWhiteSpace = false;
1515
1516 if ( sibling.type == CKEDITOR.NODE_TEXT ) {
1517 siblingText = sibling.getText();
1518
1519 // Check if there are not whitespace characters till the end of editable.
1520 // If so stop expanding.
1521 if ( !onlyWhiteSpaces( sibling, 0 ) )
1522 sibling = null;
1523
1524 isWhiteSpace = /^[\s\ufeff]/.test( siblingText );
1525 } else if ( sibling.type == CKEDITOR.NODE_ELEMENT ) {
1526 // If this is a visible element.
1527 // We need to check for the bookmark attribute because IE insists on
1528 // rendering the display:none nodes we use for bookmarks. (#3363)
1529 // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041)
1530 if ( ( sibling.$.offsetWidth > 0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) {
1531 // We'll accept it only if we need
1532 // whitespace, and this is an inline
1533 // element with whitespace only.
1534 if ( needsWhiteSpace && CKEDITOR.dtd.$removeEmpty[ sibling.getName() ] ) {
1535 // It must contains spaces and inline elements only.
1536
1537 siblingText = sibling.getText();
1538
1539 if ( leadingWhitespaceRegex.test( siblingText ) )
1540 sibling = null;
1541 else {
1542 allChildren = sibling.$.getElementsByTagName( '*' );
1543 for ( i = 0; child = allChildren[ i++ ]; ) {
1544 if ( !CKEDITOR.dtd.$removeEmpty[ child.nodeName.toLowerCase() ] ) {
1545 sibling = null;
1546 break;
1547 }
1548 }
1549 }
1550
1551 if ( sibling )
1552 isWhiteSpace = !!siblingText.length;
1553 } else {
1554 sibling = null;
1555 }
1556 }
1557 } else {
1558 isWhiteSpace = 1;
1559 }
1560
1561 if ( isWhiteSpace ) {
1562 if ( needsWhiteSpace ) {
1563 if ( commonReached )
1564 endTop = enlargeable;
1565 else
1566 this.setEndAfter( enlargeable );
1567 }
1568 }
1569
1570 if ( sibling ) {
1571 next = sibling.getNext();
1572
1573 if ( !enlargeable && !next ) {
1574 enlargeable = sibling;
1575 sibling = null;
1576 break;
1577 }
1578
1579 sibling = next;
1580 } else {
1581 // If sibling has been set to null, then we
1582 // need to stop enlarging.
1583 enlargeable = null;
1584 }
1585 }
1586
1587 if ( enlargeable )
1588 enlargeable = getValidEnlargeable( enlargeable.getParent() );
1589 }
1590
1591 // If the common ancestor can be enlarged by both boundaries, then include it also.
1592 if ( startTop && endTop ) {
1593 commonAncestor = startTop.contains( endTop ) ? endTop : startTop;
1594
1595 this.setStartBefore( commonAncestor );
1596 this.setEndAfter( commonAncestor );
1597 }
1598 break;
1599
1600 case CKEDITOR.ENLARGE_BLOCK_CONTENTS:
1601 case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:
1602
1603 // Enlarging the start boundary.
1604 var walkerRange = new CKEDITOR.dom.range( this.root );
1605
1606 boundary = this.root;
1607
1608 walkerRange.setStartAt( boundary, CKEDITOR.POSITION_AFTER_START );
1609 walkerRange.setEnd( this.startContainer, this.startOffset );
1610
1611 var walker = new CKEDITOR.dom.walker( walkerRange ),
1612 blockBoundary, // The node on which the enlarging should stop.
1613 tailBr, // In case BR as block boundary.
1614 notBlockBoundary = CKEDITOR.dom.walker.blockBoundary( ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? { br: 1 } : null ),
1615 inNonEditable = null,
1616 // Record the encountered 'blockBoundary' for later use.
1617 boundaryGuard = function( node ) {
1618 // We should not check contents of non-editable elements. It may happen
1619 // that inline widget has display:table child which should not block range#enlarge.
1620 // When encoutered non-editable element...
1621 if ( node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'false' ) {
1622 if ( inNonEditable ) {
1623 // ... in which we already were, reset it (because we're leaving it) and return.
1624 if ( inNonEditable.equals( node ) ) {
1625 inNonEditable = null;
1626 return;
1627 }
1628 // ... which we're entering, remember it but check it (no return).
1629 } else {
1630 inNonEditable = node;
1631 }
1632 // When we are in non-editable element, do not check if current node is a block boundary.
1633 } else if ( inNonEditable ) {
1634 return;
1635 }
1636
1637 var retval = notBlockBoundary( node );
1638 if ( !retval )
1639 blockBoundary = node;
1640 return retval;
1641 },
1642 // Record the encounted 'tailBr' for later use.
1643 tailBrGuard = function( node ) {
1644 var retval = boundaryGuard( node );
1645 if ( !retval && node.is && node.is( 'br' ) )
1646 tailBr = node;
1647 return retval;
1648 };
1649
1650 walker.guard = boundaryGuard;
1651
1652 enlargeable = walker.lastBackward();
1653
1654 // It's the body which stop the enlarging if no block boundary found.
1655 blockBoundary = blockBoundary || boundary;
1656
1657 // Start the range either after the end of found block (<p>...</p>[text)
1658 // or at the start of block (<p>[text...), by comparing the document position
1659 // with 'enlargeable' node.
1660 this.setStartAt( blockBoundary, !blockBoundary.is( 'br' ) && ( !enlargeable && this.checkStartOfBlock() ||
1661 enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_AFTER_END );
1662
1663 // Avoid enlarging the range further when end boundary spans right after the BR. (#7490)
1664 if ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) {
1665 var theRange = this.clone();
1666 walker = new CKEDITOR.dom.walker( theRange );
1667
1668 var whitespaces = CKEDITOR.dom.walker.whitespaces(),
1669 bookmark = CKEDITOR.dom.walker.bookmark();
1670
1671 walker.evaluator = function( node ) {
1672 return !whitespaces( node ) && !bookmark( node );
1673 };
1674 var previous = walker.previous();
1675 if ( previous && previous.type == CKEDITOR.NODE_ELEMENT && previous.is( 'br' ) )
1676 return;
1677 }
1678
1679 // Enlarging the end boundary.
1680 // Set up new range and reset all flags (blockBoundary, inNonEditable, tailBr).
1681
1682 walkerRange = this.clone();
1683 walkerRange.collapse();
1684 walkerRange.setEndAt( boundary, CKEDITOR.POSITION_BEFORE_END );
1685 walker = new CKEDITOR.dom.walker( walkerRange );
1686
1687 // tailBrGuard only used for on range end.
1688 walker.guard = ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? tailBrGuard : boundaryGuard;
1689 blockBoundary = inNonEditable = tailBr = null;
1690
1691 // End the range right before the block boundary node.
1692 enlargeable = walker.lastForward();
1693
1694 // It's the body which stop the enlarging if no block boundary found.
1695 blockBoundary = blockBoundary || boundary;
1696
1697 // Close the range either before the found block start (text]<p>...</p>) or at the block end (...text]</p>)
1698 // by comparing the document position with 'enlargeable' node.
1699 this.setEndAt( blockBoundary, ( !enlargeable && this.checkEndOfBlock() ||
1700 enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_BEFORE_END : CKEDITOR.POSITION_BEFORE_START );
1701 // We must include the <br> at the end of range if there's
1702 // one and we're expanding list item contents
1703 if ( tailBr ) {
1704 this.setEndAfter( tailBr );
1705 }
1706 }
1707
1708 // Ensures that returned element can be enlarged by selection, null otherwise.
1709 // @param {CKEDITOR.dom.element} enlargeable
1710 // @returns {CKEDITOR.dom.element/null}
1711 function getValidEnlargeable( enlargeable ) {
1712 return enlargeable && enlargeable.type == CKEDITOR.NODE_ELEMENT && enlargeable.hasAttribute( 'contenteditable' ) ?
1713 null : enlargeable;
1714 }
1715 },
1716
1717 /**
1718 * Descrease the range to make sure that boundaries
1719 * always anchor beside text nodes or innermost element.
1720 *
1721 * @param {Number} mode The shrinking mode ({@link CKEDITOR#SHRINK_ELEMENT} or {@link CKEDITOR#SHRINK_TEXT}).
1722 *
1723 * * {@link CKEDITOR#SHRINK_ELEMENT} - Shrink the range boundaries to the edge of the innermost element.
1724 * * {@link CKEDITOR#SHRINK_TEXT} - Shrink the range boudaries to anchor by the side of enclosed text
1725 * node, range remains if there's no text nodes on boundaries at all.
1726 *
1727 * @param {Boolean} selectContents Whether result range anchors at the inner OR outer boundary of the node.
1728 */
1729 shrink: function( mode, selectContents, shrinkOnBlockBoundary ) {
1730 // Unable to shrink a collapsed range.
1731 if ( !this.collapsed ) {
1732 mode = mode || CKEDITOR.SHRINK_TEXT;
1733
1734 var walkerRange = this.clone();
1735
1736 var startContainer = this.startContainer,
1737 endContainer = this.endContainer,
1738 startOffset = this.startOffset,
1739 endOffset = this.endOffset;
1740
1741 // Whether the start/end boundary is moveable.
1742 var moveStart = 1,
1743 moveEnd = 1;
1744
1745 if ( startContainer && startContainer.type == CKEDITOR.NODE_TEXT ) {
1746 if ( !startOffset )
1747 walkerRange.setStartBefore( startContainer );
1748 else if ( startOffset >= startContainer.getLength() )
1749 walkerRange.setStartAfter( startContainer );
1750 else {
1751 // Enlarge the range properly to avoid walker making
1752 // DOM changes caused by triming the text nodes later.
1753 walkerRange.setStartBefore( startContainer );
1754 moveStart = 0;
1755 }
1756 }
1757
1758 if ( endContainer && endContainer.type == CKEDITOR.NODE_TEXT ) {
1759 if ( !endOffset )
1760 walkerRange.setEndBefore( endContainer );
1761 else if ( endOffset >= endContainer.getLength() )
1762 walkerRange.setEndAfter( endContainer );
1763 else {
1764 walkerRange.setEndAfter( endContainer );
1765 moveEnd = 0;
1766 }
1767 }
1768
1769 var walker = new CKEDITOR.dom.walker( walkerRange ),
1770 isBookmark = CKEDITOR.dom.walker.bookmark();
1771
1772 walker.evaluator = function( node ) {
1773 return node.type == ( mode == CKEDITOR.SHRINK_ELEMENT ? CKEDITOR.NODE_ELEMENT : CKEDITOR.NODE_TEXT );
1774 };
1775
1776 var currentElement;
1777 walker.guard = function( node, movingOut ) {
1778 if ( isBookmark( node ) )
1779 return true;
1780
1781 // Stop when we're shrink in element mode while encountering a text node.
1782 if ( mode == CKEDITOR.SHRINK_ELEMENT && node.type == CKEDITOR.NODE_TEXT )
1783 return false;
1784
1785 // Stop when we've already walked "through" an element.
1786 if ( movingOut && node.equals( currentElement ) )
1787 return false;
1788
1789 if ( shrinkOnBlockBoundary === false && node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary() )
1790 return false;
1791
1792 // Stop shrinking when encountering an editable border.
1793 if ( node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'contenteditable' ) )
1794 return false;
1795
1796 if ( !movingOut && node.type == CKEDITOR.NODE_ELEMENT )
1797 currentElement = node;
1798
1799 return true;
1800 };
1801
1802 if ( moveStart ) {
1803 var textStart = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastForward' : 'next' ]();
1804 textStart && this.setStartAt( textStart, selectContents ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_START );
1805 }
1806
1807 if ( moveEnd ) {
1808 walker.reset();
1809 var textEnd = walker[ mode == CKEDITOR.SHRINK_ELEMENT ? 'lastBackward' : 'previous' ]();
1810 textEnd && this.setEndAt( textEnd, selectContents ? CKEDITOR.POSITION_BEFORE_END : CKEDITOR.POSITION_AFTER_END );
1811 }
1812
1813 return !!( moveStart || moveEnd );
1814 }
1815 },
1816
1817 /**
1818 * Inserts a node at the start of the range. The range will be expanded
1819 * the contain the node.
1820 *
1821 * @param {CKEDITOR.dom.node} node
1822 */
1823 insertNode: function( node ) {
1824 this.optimizeBookmark();
1825 this.trim( false, true );
1826
1827 var startContainer = this.startContainer;
1828 var startOffset = this.startOffset;
1829
1830 var nextNode = startContainer.getChild( startOffset );
1831
1832 if ( nextNode )
1833 node.insertBefore( nextNode );
1834 else
1835 startContainer.append( node );
1836
1837 // Check if we need to update the end boundary.
1838 if ( node.getParent() && node.getParent().equals( this.endContainer ) )
1839 this.endOffset++;
1840
1841 // Expand the range to embrace the new node.
1842 this.setStartBefore( node );
1843 },
1844
1845 /**
1846 * Moves the range to given position according to specified node.
1847 *
1848 * // HTML: <p>Foo <b>bar</b></p>
1849 * range.moveToPosition( elB, CKEDITOR.POSITION_BEFORE_START );
1850 * // Range will be moved to: <p>Foo ^<b>bar</b></p>
1851 *
1852 * See also {@link #setStartAt} and {@link #setEndAt}.
1853 *
1854 * @param {CKEDITOR.dom.node} node The node according to which position will be set.
1855 * @param {Number} position One of {@link CKEDITOR#POSITION_BEFORE_START},
1856 * {@link CKEDITOR#POSITION_AFTER_START}, {@link CKEDITOR#POSITION_BEFORE_END},
1857 * {@link CKEDITOR#POSITION_AFTER_END}.
1858 */
1859 moveToPosition: function( node, position ) {
1860 this.setStartAt( node, position );
1861 this.collapse( true );
1862 },
1863
1864 /**
1865 * Moves the range to the exact position of the specified range.
1866 *
1867 * @param {CKEDITOR.dom.range} range
1868 */
1869 moveToRange: function( range ) {
1870 this.setStart( range.startContainer, range.startOffset );
1871 this.setEnd( range.endContainer, range.endOffset );
1872 },
1873
1874 /**
1875 * Select nodes content. Range will start and end inside this node.
1876 *
1877 * @param {CKEDITOR.dom.node} node
1878 */
1879 selectNodeContents: function( node ) {
1880 this.setStart( node, 0 );
1881 this.setEnd( node, node.type == CKEDITOR.NODE_TEXT ? node.getLength() : node.getChildCount() );
1882 },
1883
1884 /**
1885 * Sets the start position of a range.
1886 *
1887 * @param {CKEDITOR.dom.node} startNode The node to start the range.
1888 * @param {Number} startOffset An integer greater than or equal to zero
1889 * representing the offset for the start of the range from the start
1890 * of `startNode`.
1891 */
1892 setStart: function( startNode, startOffset ) {
1893 // W3C requires a check for the new position. If it is after the end
1894 // boundary, the range should be collapsed to the new start. It seams
1895 // we will not need this check for our use of this class so we can
1896 // ignore it for now.
1897
1898 // Fixing invalid range start inside dtd empty elements.
1899 if ( startNode.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$empty[ startNode.getName() ] )
1900 startOffset = startNode.getIndex(), startNode = startNode.getParent();
1901
1902 this._setStartContainer( startNode );
1903 this.startOffset = startOffset;
1904
1905 if ( !this.endContainer ) {
1906 this._setEndContainer( startNode );
1907 this.endOffset = startOffset;
1908 }
1909
1910 updateCollapsed( this );
1911 },
1912
1913 /**
1914 * Sets the end position of a Range.
1915 *
1916 * @param {CKEDITOR.dom.node} endNode The node to end the range.
1917 * @param {Number} endOffset An integer greater than or equal to zero
1918 * representing the offset for the end of the range from the start
1919 * of `endNode`.
1920 */
1921 setEnd: function( endNode, endOffset ) {
1922 // W3C requires a check for the new position. If it is before the start
1923 // boundary, the range should be collapsed to the new end. It seams we
1924 // will not need this check for our use of this class so we can ignore
1925 // it for now.
1926
1927 // Fixing invalid range end inside dtd empty elements.
1928 if ( endNode.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$empty[ endNode.getName() ] )
1929 endOffset = endNode.getIndex() + 1, endNode = endNode.getParent();
1930
1931 this._setEndContainer( endNode );
1932 this.endOffset = endOffset;
1933
1934 if ( !this.startContainer ) {
1935 this._setStartContainer( endNode );
1936 this.startOffset = endOffset;
1937 }
1938
1939 updateCollapsed( this );
1940 },
1941
1942 /**
1943 * Sets start of this range after the specified node.
1944 *
1945 * // Range: <p>foo<b>bar</b>^</p>
1946 * range.setStartAfter( textFoo );
1947 * // The range will be changed to:
1948 * // <p>foo[<b>bar</b>]</p>
1949 *
1950 * @param {CKEDITOR.dom.node} node
1951 */
1952 setStartAfter: function( node ) {
1953 this.setStart( node.getParent(), node.getIndex() + 1 );
1954 },
1955
1956 /**
1957 * Sets start of this range after the specified node.
1958 *
1959 * // Range: <p>foo<b>bar</b>^</p>
1960 * range.setStartBefore( elB );
1961 * // The range will be changed to:
1962 * // <p>foo[<b>bar</b>]</p>
1963 *
1964 * @param {CKEDITOR.dom.node} node
1965 */
1966 setStartBefore: function( node ) {
1967 this.setStart( node.getParent(), node.getIndex() );
1968 },
1969
1970 /**
1971 * Sets end of this range after the specified node.
1972 *
1973 * // Range: <p>foo^<b>bar</b></p>
1974 * range.setEndAfter( elB );
1975 * // The range will be changed to:
1976 * // <p>foo[<b>bar</b>]</p>
1977 *
1978 * @param {CKEDITOR.dom.node} node
1979 */
1980 setEndAfter: function( node ) {
1981 this.setEnd( node.getParent(), node.getIndex() + 1 );
1982 },
1983
1984 /**
1985 * Sets end of this range before the specified node.
1986 *
1987 * // Range: <p>^foo<b>bar</b></p>
1988 * range.setStartAfter( textBar );
1989 * // The range will be changed to:
1990 * // <p>[foo<b>]bar</b></p>
1991 *
1992 * @param {CKEDITOR.dom.node} node
1993 */
1994 setEndBefore: function( node ) {
1995 this.setEnd( node.getParent(), node.getIndex() );
1996 },
1997
1998 /**
1999 * Moves the start of this range to given position according to specified node.
2000 *
2001 * // HTML: <p>Foo <b>bar</b>^</p>
2002 * range.setStartAt( elB, CKEDITOR.POSITION_AFTER_START );
2003 * // The range will be changed to:
2004 * // <p>Foo <b>[bar</b>]</p>
2005 *
2006 * See also {@link #setEndAt} and {@link #moveToPosition}.
2007 *
2008 * @param {CKEDITOR.dom.node} node The node according to which position will be set.
2009 * @param {Number} position One of {@link CKEDITOR#POSITION_BEFORE_START},
2010 * {@link CKEDITOR#POSITION_AFTER_START}, {@link CKEDITOR#POSITION_BEFORE_END},
2011 * {@link CKEDITOR#POSITION_AFTER_END}.
2012 */
2013 setStartAt: function( node, position ) {
2014 switch ( position ) {
2015 case CKEDITOR.POSITION_AFTER_START:
2016 this.setStart( node, 0 );
2017 break;
2018
2019 case CKEDITOR.POSITION_BEFORE_END:
2020 if ( node.type == CKEDITOR.NODE_TEXT )
2021 this.setStart( node, node.getLength() );
2022 else
2023 this.setStart( node, node.getChildCount() );
2024 break;
2025
2026 case CKEDITOR.POSITION_BEFORE_START:
2027 this.setStartBefore( node );
2028 break;
2029
2030 case CKEDITOR.POSITION_AFTER_END:
2031 this.setStartAfter( node );
2032 }
2033
2034 updateCollapsed( this );
2035 },
2036
2037 /**
2038 * Moves the end of this range to given position according to specified node.
2039 *
2040 * // HTML: <p>^Foo <b>bar</b></p>
2041 * range.setEndAt( textBar, CKEDITOR.POSITION_BEFORE_START );
2042 * // The range will be changed to:
2043 * // <p>[Foo <b>]bar</b></p>
2044 *
2045 * See also {@link #setStartAt} and {@link #moveToPosition}.
2046 *
2047 * @param {CKEDITOR.dom.node} node The node according to which position will be set.
2048 * @param {Number} position One of {@link CKEDITOR#POSITION_BEFORE_START},
2049 * {@link CKEDITOR#POSITION_AFTER_START}, {@link CKEDITOR#POSITION_BEFORE_END},
2050 * {@link CKEDITOR#POSITION_AFTER_END}.
2051 */
2052 setEndAt: function( node, position ) {
2053 switch ( position ) {
2054 case CKEDITOR.POSITION_AFTER_START:
2055 this.setEnd( node, 0 );
2056 break;
2057
2058 case CKEDITOR.POSITION_BEFORE_END:
2059 if ( node.type == CKEDITOR.NODE_TEXT )
2060 this.setEnd( node, node.getLength() );
2061 else
2062 this.setEnd( node, node.getChildCount() );
2063 break;
2064
2065 case CKEDITOR.POSITION_BEFORE_START:
2066 this.setEndBefore( node );
2067 break;
2068
2069 case CKEDITOR.POSITION_AFTER_END:
2070 this.setEndAfter( node );
2071 }
2072
2073 updateCollapsed( this );
2074 },
2075
2076 /**
2077 * Wraps inline content found around the range's start or end boundary
2078 * with a block element.
2079 *
2080 * // Assuming the following range:
2081 * // <h1>foo</h1>ba^r<br />bom<p>foo</p>
2082 * // The result of executing:
2083 * range.fixBlock( true, 'p' );
2084 * // will be:
2085 * // <h1>foo</h1><p>ba^r<br />bom</p><p>foo</p>
2086 *
2087 * Non-collapsed range:
2088 *
2089 * // Assuming the following range:
2090 * // ba[r<p>foo</p>bo]m
2091 * // The result of executing:
2092 * range.fixBlock( false, 'p' );
2093 * // will be:
2094 * // ba[r<p>foo</p><p>bo]m</p>
2095 *
2096 * @param {Boolean} isStart Whether the start or end boundary of a range should be checked.
2097 * @param {String} blockTag The name of a block element in which content will be wrapped.
2098 * For example: `'p'`.
2099 * @returns {CKEDITOR.dom.element} Created block wrapper.
2100 */
2101 fixBlock: function( isStart, blockTag ) {
2102 var bookmark = this.createBookmark(),
2103 fixedBlock = this.document.createElement( blockTag );
2104
2105 this.collapse( isStart );
2106
2107 this.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
2108
2109 this.extractContents().appendTo( fixedBlock );
2110 fixedBlock.trim();
2111
2112 this.insertNode( fixedBlock );
2113
2114 // Bogus <br> could already exist in the range's container before fixBlock() was called. In such case it was
2115 // extracted and appended to the fixBlock. However, we are not sure that it's at the end of
2116 // the fixedBlock, because of FF's terrible bug. When creating a bookmark in an empty editable
2117 // FF moves the bogus <br> before that bookmark (<editable><br /><bm />[]</editable>).
2118 // So even if the initial range was placed before the bogus <br>, after creating the bookmark it
2119 // is placed before the bookmark.
2120 // Fortunately, getBogus() is able to skip the bookmark so it finds the bogus <br> in this case.
2121 // We remove incorrectly placed one and add a brand new one. (#13001)
2122 var bogus = fixedBlock.getBogus();
2123 if ( bogus ) {
2124 bogus.remove();
2125 }
2126 fixedBlock.appendBogus();
2127
2128 this.moveToBookmark( bookmark );
2129
2130 return fixedBlock;
2131 },
2132
2133 /**
2134 * @todo
2135 * @param {Boolean} [cloneId=false] Whether to preserve ID attributes in the result blocks.
2136 */
2137 splitBlock: function( blockTag, cloneId ) {
2138 var startPath = new CKEDITOR.dom.elementPath( this.startContainer, this.root ),
2139 endPath = new CKEDITOR.dom.elementPath( this.endContainer, this.root );
2140
2141 var startBlockLimit = startPath.blockLimit,
2142 endBlockLimit = endPath.blockLimit;
2143
2144 var startBlock = startPath.block,
2145 endBlock = endPath.block;
2146
2147 var elementPath = null;
2148 // Do nothing if the boundaries are in different block limits.
2149 if ( !startBlockLimit.equals( endBlockLimit ) )
2150 return null;
2151
2152 // Get or fix current blocks.
2153 if ( blockTag != 'br' ) {
2154 if ( !startBlock ) {
2155 startBlock = this.fixBlock( true, blockTag );
2156 endBlock = new CKEDITOR.dom.elementPath( this.endContainer, this.root ).block;
2157 }
2158
2159 if ( !endBlock )
2160 endBlock = this.fixBlock( false, blockTag );
2161 }
2162
2163 // Get the range position.
2164 var isStartOfBlock = startBlock && this.checkStartOfBlock(),
2165 isEndOfBlock = endBlock && this.checkEndOfBlock();
2166
2167 // Delete the current contents.
2168 // TODO: Why is 2.x doing CheckIsEmpty()?
2169 this.deleteContents();
2170
2171 if ( startBlock && startBlock.equals( endBlock ) ) {
2172 if ( isEndOfBlock ) {
2173 elementPath = new CKEDITOR.dom.elementPath( this.startContainer, this.root );
2174 this.moveToPosition( endBlock, CKEDITOR.POSITION_AFTER_END );
2175 endBlock = null;
2176 } else if ( isStartOfBlock ) {
2177 elementPath = new CKEDITOR.dom.elementPath( this.startContainer, this.root );
2178 this.moveToPosition( startBlock, CKEDITOR.POSITION_BEFORE_START );
2179 startBlock = null;
2180 } else {
2181 endBlock = this.splitElement( startBlock, cloneId || false );
2182
2183 // In Gecko, the last child node must be a bogus <br>.
2184 // Note: bogus <br> added under <ul> or <ol> would cause
2185 // lists to be incorrectly rendered.
2186 if ( !startBlock.is( 'ul', 'ol' ) )
2187 startBlock.appendBogus();
2188 }
2189 }
2190
2191 return {
2192 previousBlock: startBlock,
2193 nextBlock: endBlock,
2194 wasStartOfBlock: isStartOfBlock,
2195 wasEndOfBlock: isEndOfBlock,
2196 elementPath: elementPath
2197 };
2198 },
2199
2200 /**
2201 * Branch the specified element from the collapsed range position and
2202 * place the caret between the two result branches.
2203 *
2204 * **Note:** The range must be collapsed and been enclosed by this element.
2205 *
2206 * @param {CKEDITOR.dom.element} element
2207 * @param {Boolean} [cloneId=false] Whether to preserve ID attributes in the result elements.
2208 * @returns {CKEDITOR.dom.element} Root element of the new branch after the split.
2209 */
2210 splitElement: function( toSplit, cloneId ) {
2211 if ( !this.collapsed )
2212 return null;
2213
2214 // Extract the contents of the block from the selection point to the end
2215 // of its contents.
2216 this.setEndAt( toSplit, CKEDITOR.POSITION_BEFORE_END );
2217 var documentFragment = this.extractContents( false, cloneId || false );
2218
2219 // Duplicate the element after it.
2220 var clone = toSplit.clone( false, cloneId || false );
2221
2222 // Place the extracted contents into the duplicated element.
2223 documentFragment.appendTo( clone );
2224 clone.insertAfter( toSplit );
2225 this.moveToPosition( toSplit, CKEDITOR.POSITION_AFTER_END );
2226 return clone;
2227 },
2228
2229 /**
2230 * Recursively remove any empty path blocks at the range boundary.
2231 *
2232 * @method
2233 * @param {Boolean} atEnd Removal to perform at the end boundary,
2234 * otherwise to perform at the start.
2235 */
2236 removeEmptyBlocksAtEnd: ( function() {
2237
2238 var whitespace = CKEDITOR.dom.walker.whitespaces(),
2239 bookmark = CKEDITOR.dom.walker.bookmark( false );
2240
2241 function childEval( parent ) {
2242 return function( node ) {
2243 // Whitespace, bookmarks, empty inlines.
2244 if ( whitespace( node ) || bookmark( node ) ||
2245 node.type == CKEDITOR.NODE_ELEMENT &&
2246 node.isEmptyInlineRemoveable() ) {
2247 return false;
2248 } else if ( parent.is( 'table' ) && node.is( 'caption' ) ) {
2249 return false;
2250 }
2251
2252 return true;
2253 };
2254 }
2255
2256 return function( atEnd ) {
2257
2258 var bm = this.createBookmark();
2259 var path = this[ atEnd ? 'endPath' : 'startPath' ]();
2260 var block = path.block || path.blockLimit, parent;
2261
2262 // Remove any childless block, including list and table.
2263 while ( block && !block.equals( path.root ) &&
2264 !block.getFirst( childEval( block ) ) ) {
2265 parent = block.getParent();
2266 this[ atEnd ? 'setEndAt' : 'setStartAt' ]( block, CKEDITOR.POSITION_AFTER_END );
2267 block.remove( 1 );
2268 block = parent;
2269 }
2270
2271 this.moveToBookmark( bm );
2272 };
2273
2274 } )(),
2275
2276 /**
2277 * Gets {@link CKEDITOR.dom.elementPath} for the {@link #startContainer}.
2278 *
2279 * @returns {CKEDITOR.dom.elementPath}
2280 */
2281 startPath: function() {
2282 return new CKEDITOR.dom.elementPath( this.startContainer, this.root );
2283 },
2284
2285 /**
2286 * Gets {@link CKEDITOR.dom.elementPath} for the {@link #endContainer}.
2287 *
2288 * @returns {CKEDITOR.dom.elementPath}
2289 */
2290 endPath: function() {
2291 return new CKEDITOR.dom.elementPath( this.endContainer, this.root );
2292 },
2293
2294 /**
2295 * Check whether a range boundary is at the inner boundary of a given
2296 * element.
2297 *
2298 * @param {CKEDITOR.dom.element} element The target element to check.
2299 * @param {Number} checkType The boundary to check for both the range
2300 * and the element. It can be {@link CKEDITOR#START} or {@link CKEDITOR#END}.
2301 * @returns {Boolean} `true` if the range boundary is at the inner
2302 * boundary of the element.
2303 */
2304 checkBoundaryOfElement: function( element, checkType ) {
2305 var checkStart = ( checkType == CKEDITOR.START );
2306
2307 // Create a copy of this range, so we can manipulate it for our checks.
2308 var walkerRange = this.clone();
2309
2310 // Collapse the range at the proper size.
2311 walkerRange.collapse( checkStart );
2312
2313 // Expand the range to element boundary.
2314 walkerRange[ checkStart ? 'setStartAt' : 'setEndAt' ]( element, checkStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
2315
2316 // Create the walker, which will check if we have anything useful
2317 // in the range.
2318 var walker = new CKEDITOR.dom.walker( walkerRange );
2319 walker.evaluator = elementBoundaryEval( checkStart );
2320
2321 return walker[ checkStart ? 'checkBackward' : 'checkForward' ]();
2322 },
2323
2324 /**
2325 * **Note:** Calls to this function may produce changes to the DOM. The range may
2326 * be updated to reflect such changes.
2327 *
2328 * @returns {Boolean}
2329 * @todo
2330 */
2331 checkStartOfBlock: function() {
2332 var startContainer = this.startContainer,
2333 startOffset = this.startOffset;
2334
2335 // [IE] Special handling for range start in text with a leading NBSP,
2336 // we it to be isolated, for bogus check.
2337 if ( CKEDITOR.env.ie && startOffset && startContainer.type == CKEDITOR.NODE_TEXT ) {
2338 var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );
2339 if ( nbspRegExp.test( textBefore ) )
2340 this.trim( 0, 1 );
2341 }
2342
2343 // Antecipate the trim() call here, so the walker will not make
2344 // changes to the DOM, which would not get reflected into this
2345 // range otherwise.
2346 this.trim();
2347
2348 // We need to grab the block element holding the start boundary, so
2349 // let's use an element path for it.
2350 var path = new CKEDITOR.dom.elementPath( this.startContainer, this.root );
2351
2352 // Creates a range starting at the block start until the range start.
2353 var walkerRange = this.clone();
2354 walkerRange.collapse( true );
2355 walkerRange.setStartAt( path.block || path.blockLimit, CKEDITOR.POSITION_AFTER_START );
2356
2357 var walker = new CKEDITOR.dom.walker( walkerRange );
2358 walker.evaluator = getCheckStartEndBlockEvalFunction();
2359
2360 return walker.checkBackward();
2361 },
2362
2363 /**
2364 * **Note:** Calls to this function may produce changes to the DOM. The range may
2365 * be updated to reflect such changes.
2366 *
2367 * @returns {Boolean}
2368 * @todo
2369 */
2370 checkEndOfBlock: function() {
2371 var endContainer = this.endContainer,
2372 endOffset = this.endOffset;
2373
2374 // [IE] Special handling for range end in text with a following NBSP,
2375 // we it to be isolated, for bogus check.
2376 if ( CKEDITOR.env.ie && endContainer.type == CKEDITOR.NODE_TEXT ) {
2377 var textAfter = CKEDITOR.tools.rtrim( endContainer.substring( endOffset ) );
2378 if ( nbspRegExp.test( textAfter ) )
2379 this.trim( 1, 0 );
2380 }
2381
2382 // Antecipate the trim() call here, so the walker will not make
2383 // changes to the DOM, which would not get reflected into this
2384 // range otherwise.
2385 this.trim();
2386
2387 // We need to grab the block element holding the start boundary, so
2388 // let's use an element path for it.
2389 var path = new CKEDITOR.dom.elementPath( this.endContainer, this.root );
2390
2391 // Creates a range starting at the block start until the range start.
2392 var walkerRange = this.clone();
2393 walkerRange.collapse( false );
2394 walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END );
2395
2396 var walker = new CKEDITOR.dom.walker( walkerRange );
2397 walker.evaluator = getCheckStartEndBlockEvalFunction();
2398
2399 return walker.checkForward();
2400 },
2401
2402 /**
2403 * Traverse with {@link CKEDITOR.dom.walker} to retrieve the previous element before the range start.
2404 *
2405 * @param {Function} evaluator Function used as the walker's evaluator.
2406 * @param {Function} [guard] Function used as the walker's guard.
2407 * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,
2408 * default to the root editable if not defined.
2409 * @returns {CKEDITOR.dom.element/null} The returned node from the traversal.
2410 */
2411 getPreviousNode: function( evaluator, guard, boundary ) {
2412 var walkerRange = this.clone();
2413 walkerRange.collapse( 1 );
2414 walkerRange.setStartAt( boundary || this.root, CKEDITOR.POSITION_AFTER_START );
2415
2416 var walker = new CKEDITOR.dom.walker( walkerRange );
2417 walker.evaluator = evaluator;
2418 walker.guard = guard;
2419 return walker.previous();
2420 },
2421
2422 /**
2423 * Traverse with {@link CKEDITOR.dom.walker} to retrieve the next element before the range start.
2424 *
2425 * @param {Function} evaluator Function used as the walker's evaluator.
2426 * @param {Function} [guard] Function used as the walker's guard.
2427 * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,
2428 * default to the root editable if not defined.
2429 * @returns {CKEDITOR.dom.element/null} The returned node from the traversal.
2430 */
2431 getNextNode: function( evaluator, guard, boundary ) {
2432 var walkerRange = this.clone();
2433 walkerRange.collapse();
2434 walkerRange.setEndAt( boundary || this.root, CKEDITOR.POSITION_BEFORE_END );
2435
2436 var walker = new CKEDITOR.dom.walker( walkerRange );
2437 walker.evaluator = evaluator;
2438 walker.guard = guard;
2439 return walker.next();
2440 },
2441
2442 /**
2443 * Check if elements at which the range boundaries anchor are read-only,
2444 * with respect to `contenteditable` attribute.
2445 *
2446 * @returns {Boolean}
2447 */
2448 checkReadOnly: ( function() {
2449 function checkNodesEditable( node, anotherEnd ) {
2450 while ( node ) {
2451 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
2452 if ( node.getAttribute( 'contentEditable' ) == 'false' && !node.data( 'cke-editable' ) )
2453 return 0;
2454
2455 // Range enclosed entirely in an editable element.
2456 else if ( node.is( 'html' ) || node.getAttribute( 'contentEditable' ) == 'true' && ( node.contains( anotherEnd ) || node.equals( anotherEnd ) ) )
2457 break;
2458
2459 }
2460 node = node.getParent();
2461 }
2462
2463 return 1;
2464 }
2465
2466 return function() {
2467 var startNode = this.startContainer,
2468 endNode = this.endContainer;
2469
2470 // Check if elements path at both boundaries are editable.
2471 return !( checkNodesEditable( startNode, endNode ) && checkNodesEditable( endNode, startNode ) );
2472 };
2473 } )(),
2474
2475 /**
2476 * Moves the range boundaries to the first/end editing point inside an
2477 * element.
2478 *
2479 * For example, in an element tree like
2480 * `<p><b><i></i></b> Text</p>`, the start editing point is
2481 * `<p><b><i>^</i></b> Text</p>` (inside `<i>`).
2482 *
2483 * @param {CKEDITOR.dom.element} el The element into which look for the
2484 * editing spot.
2485 * @param {Boolean} isMoveToEnd Whether move to the end editable position.
2486 * @returns {Boolean} Whether range was moved.
2487 */
2488 moveToElementEditablePosition: function( el, isMoveToEnd ) {
2489
2490 function nextDFS( node, childOnly ) {
2491 var next;
2492
2493 if ( node.type == CKEDITOR.NODE_ELEMENT && node.isEditable( false ) )
2494 next = node[ isMoveToEnd ? 'getLast' : 'getFirst' ]( notIgnoredEval );
2495
2496 if ( !childOnly && !next )
2497 next = node[ isMoveToEnd ? 'getPrevious' : 'getNext' ]( notIgnoredEval );
2498
2499 return next;
2500 }
2501
2502 // Handle non-editable element e.g. HR.
2503 if ( el.type == CKEDITOR.NODE_ELEMENT && !el.isEditable( false ) ) {
2504 this.moveToPosition( el, isMoveToEnd ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START );
2505 return true;
2506 }
2507
2508 var found = 0;
2509
2510 while ( el ) {
2511 // Stop immediately if we've found a text node.
2512 if ( el.type == CKEDITOR.NODE_TEXT ) {
2513 // Put cursor before block filler.
2514 if ( isMoveToEnd && this.endContainer && this.checkEndOfBlock() && nbspRegExp.test( el.getText() ) )
2515 this.moveToPosition( el, CKEDITOR.POSITION_BEFORE_START );
2516 else
2517 this.moveToPosition( el, isMoveToEnd ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START );
2518 found = 1;
2519 break;
2520 }
2521
2522 // If an editable element is found, move inside it, but not stop the searching.
2523 if ( el.type == CKEDITOR.NODE_ELEMENT ) {
2524 if ( el.isEditable() ) {
2525 this.moveToPosition( el, isMoveToEnd ? CKEDITOR.POSITION_BEFORE_END : CKEDITOR.POSITION_AFTER_START );
2526 found = 1;
2527 }
2528 // Put cursor before padding block br.
2529 else if ( isMoveToEnd && el.is( 'br' ) && this.endContainer && this.checkEndOfBlock() )
2530 this.moveToPosition( el, CKEDITOR.POSITION_BEFORE_START );
2531 // Special case - non-editable block. Select entire element, because it does not make sense
2532 // to place collapsed selection next to it, because browsers can't handle that.
2533 else if ( el.getAttribute( 'contenteditable' ) == 'false' && el.is( CKEDITOR.dtd.$block ) ) {
2534 this.setStartBefore( el );
2535 this.setEndAfter( el );
2536 return true;
2537 }
2538 }
2539
2540 el = nextDFS( el, found );
2541 }
2542
2543 return !!found;
2544 },
2545
2546 /**
2547 * Moves the range boundaries to the closest editing point after/before an
2548 * element or the current range position (depends on whether the element was specified).
2549 *
2550 * For example, if the start element has `id="start"`,
2551 * `<p><b>foo</b><span id="start">start</start></p>`, the closest previous editing point is
2552 * `<p><b>foo</b>^<span id="start">start</start></p>` (between `<b>` and `<span>`).
2553 *
2554 * See also: {@link #moveToElementEditablePosition}.
2555 *
2556 * @since 4.3
2557 * @param {CKEDITOR.dom.element} [element] The starting element. If not specified, the current range
2558 * position will be used.
2559 * @param {Boolean} [isMoveForward] Whether move to the end of editable. Otherwise, look back.
2560 * @returns {Boolean} Whether the range was moved.
2561 */
2562 moveToClosestEditablePosition: function( element, isMoveForward ) {
2563 // We don't want to modify original range if there's no editable position.
2564 var range,
2565 found = 0,
2566 sibling,
2567 isElement,
2568 positions = [ CKEDITOR.POSITION_AFTER_END, CKEDITOR.POSITION_BEFORE_START ];
2569
2570 if ( element ) {
2571 // Set collapsed range at one of ends of element.
2572 // Can't clone this range, because this range might not be yet positioned (no containers => errors).
2573 range = new CKEDITOR.dom.range( this.root );
2574 range.moveToPosition( element, positions[ isMoveForward ? 0 : 1 ] );
2575 } else {
2576 range = this.clone();
2577 }
2578
2579 // Start element isn't a block, so we can automatically place range
2580 // next to it.
2581 if ( element && !element.is( CKEDITOR.dtd.$block ) )
2582 found = 1;
2583 else {
2584 // Look for first node that fulfills eval function and place range next to it.
2585 sibling = range[ isMoveForward ? 'getNextEditableNode' : 'getPreviousEditableNode' ]();
2586 if ( sibling ) {
2587 found = 1;
2588 isElement = sibling.type == CKEDITOR.NODE_ELEMENT;
2589
2590 // Special case - eval accepts block element only if it's a non-editable block,
2591 // which we want to select, not place collapsed selection next to it (which browsers
2592 // can't handle).
2593 if ( isElement && sibling.is( CKEDITOR.dtd.$block ) && sibling.getAttribute( 'contenteditable' ) == 'false' ) {
2594 range.setStartAt( sibling, CKEDITOR.POSITION_BEFORE_START );
2595 range.setEndAt( sibling, CKEDITOR.POSITION_AFTER_END );
2596 }
2597 // Handle empty blocks which can be selection containers on old IEs.
2598 else if ( !CKEDITOR.env.needsBrFiller && isElement && sibling.is( CKEDITOR.dom.walker.validEmptyBlockContainers ) ) {
2599 range.setEnd( sibling, 0 );
2600 range.collapse();
2601 } else {
2602 range.moveToPosition( sibling, positions[ isMoveForward ? 1 : 0 ] );
2603 }
2604 }
2605 }
2606
2607 if ( found )
2608 this.moveToRange( range );
2609
2610 return !!found;
2611 },
2612
2613 /**
2614 * See {@link #moveToElementEditablePosition}.
2615 *
2616 * @returns {Boolean} Whether range was moved.
2617 */
2618 moveToElementEditStart: function( target ) {
2619 return this.moveToElementEditablePosition( target );
2620 },
2621
2622 /**
2623 * See {@link #moveToElementEditablePosition}.
2624 *
2625 * @returns {Boolean} Whether range was moved.
2626 */
2627 moveToElementEditEnd: function( target ) {
2628 return this.moveToElementEditablePosition( target, true );
2629 },
2630
2631 /**
2632 * Get the single node enclosed within the range if there's one.
2633 *
2634 * @returns {CKEDITOR.dom.node}
2635 */
2636 getEnclosedNode: function() {
2637 var walkerRange = this.clone();
2638
2639 // Optimize and analyze the range to avoid DOM destructive nature of walker. (#5780)
2640 walkerRange.optimize();
2641 if ( walkerRange.startContainer.type != CKEDITOR.NODE_ELEMENT || walkerRange.endContainer.type != CKEDITOR.NODE_ELEMENT )
2642 return null;
2643
2644 var walker = new CKEDITOR.dom.walker( walkerRange ),
2645 isNotBookmarks = CKEDITOR.dom.walker.bookmark( false, true ),
2646 isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true );
2647
2648 walker.evaluator = function( node ) {
2649 return isNotWhitespaces( node ) && isNotBookmarks( node );
2650 };
2651 var node = walker.next();
2652 walker.reset();
2653 return node && node.equals( walker.previous() ) ? node : null;
2654 },
2655
2656 /**
2657 * Get the node adjacent to the range start or {@link #startContainer}.
2658 *
2659 * @returns {CKEDITOR.dom.node}
2660 */
2661 getTouchedStartNode: function() {
2662 var container = this.startContainer;
2663
2664 if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
2665 return container;
2666
2667 return container.getChild( this.startOffset ) || container;
2668 },
2669
2670 /**
2671 * Get the node adjacent to the range end or {@link #endContainer}.
2672 *
2673 * @returns {CKEDITOR.dom.node}
2674 */
2675 getTouchedEndNode: function() {
2676 var container = this.endContainer;
2677
2678 if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
2679 return container;
2680
2681 return container.getChild( this.endOffset - 1 ) || container;
2682 },
2683
2684 /**
2685 * Gets next node which can be a container of a selection.
2686 * This methods mimics a behavior of right/left arrow keys in case of
2687 * collapsed selection. It does not return an exact position (with offset) though,
2688 * but just a selection's container.
2689 *
2690 * Note: use this method on a collapsed range.
2691 *
2692 * @since 4.3
2693 * @returns {CKEDITOR.dom.element/CKEDITOR.dom.text}
2694 */
2695 getNextEditableNode: getNextEditableNode(),
2696
2697 /**
2698 * See {@link #getNextEditableNode}.
2699 *
2700 * @since 4.3
2701 * @returns {CKEDITOR.dom.element/CKEDITOR.dom.text}
2702 */
2703 getPreviousEditableNode: getNextEditableNode( 1 ),
2704
2705 /**
2706 * Scrolls the start of current range into view.
2707 */
2708 scrollIntoView: function() {
2709
2710 // The reference element contains a zero-width space to avoid
2711 // a premature removal. The view is to be scrolled with respect
2712 // to this element.
2713 var reference = new CKEDITOR.dom.element.createFromHtml( '<span>&nbsp;</span>', this.document ),
2714 afterCaretNode, startContainerText, isStartText;
2715
2716 var range = this.clone();
2717
2718 // Work with the range to obtain a proper caret position.
2719 range.optimize();
2720
2721 // Currently in a text node, so we need to split it into two
2722 // halves and put the reference between.
2723 if ( isStartText = range.startContainer.type == CKEDITOR.NODE_TEXT ) {
2724 // Keep the original content. It will be restored.
2725 startContainerText = range.startContainer.getText();
2726
2727 // Split the startContainer at the this position.
2728 afterCaretNode = range.startContainer.split( range.startOffset );
2729
2730 // Insert the reference between two text nodes.
2731 reference.insertAfter( range.startContainer );
2732 }
2733
2734 // If not in a text node, simply insert the reference into the range.
2735 else {
2736 range.insertNode( reference );
2737 }
2738
2739 // Scroll with respect to the reference element.
2740 reference.scrollIntoView();
2741
2742 // Get rid of split parts if "in a text node" case.
2743 // Revert the original text of the startContainer.
2744 if ( isStartText ) {
2745 range.startContainer.setText( startContainerText );
2746 afterCaretNode.remove();
2747 }
2748
2749 // Get rid of the reference node. It is no longer necessary.
2750 reference.remove();
2751 },
2752
2753 /**
2754 * Setter for the {@link #startContainer}.
2755 *
2756 * @since 4.4.6
2757 * @private
2758 * @param {CKEDITOR.dom.element} startContainer
2759 */
2760 _setStartContainer: function( startContainer ) {
2761 // %REMOVE_START%
2762 var isRootAscendantOrSelf = this.root.equals( startContainer ) || this.root.contains( startContainer );
2763
2764 if ( !isRootAscendantOrSelf ) {
2765 CKEDITOR.warn( 'range-startcontainer', { startContainer: startContainer, root: this.root } );
2766 }
2767 // %REMOVE_END%
2768 this.startContainer = startContainer;
2769 },
2770
2771 /**
2772 * Setter for the {@link #endContainer}.
2773 *
2774 * @since 4.4.6
2775 * @private
2776 * @param {CKEDITOR.dom.element} endContainer
2777 */
2778 _setEndContainer: function( endContainer ) {
2779 // %REMOVE_START%
2780 var isRootAscendantOrSelf = this.root.equals( endContainer ) || this.root.contains( endContainer );
2781
2782 if ( !isRootAscendantOrSelf ) {
2783 CKEDITOR.warn( 'range-endcontainer', { endContainer: endContainer, root: this.root } );
2784 }
2785 // %REMOVE_END%
2786 this.endContainer = endContainer;
2787 },
2788
2789 /**
2790 * Looks for elements matching the `query` selector within a range.
2791 *
2792 * @since 4.5.11
2793 * @private
2794 * @param {String} query
2795 * @param {Boolean} [includeNonEditables=false] Whether elements with `contenteditable` set to `false` should
2796 * be included.
2797 * @returns {CKEDITOR.dom.element[]}
2798 */
2799 _find: function( query, includeNonEditables ) {
2800 var ancestor = this.getCommonAncestor(),
2801 boundaries = this.getBoundaryNodes(),
2802 // Contrary to CKEDITOR.dom.element#find we're returning array, that's because NodeList is immutable, and we need
2803 // to do some filtering in returned list.
2804 ret = [],
2805 curItem,
2806 i,
2807 initialMatches,
2808 isStartGood,
2809 isEndGood;
2810
2811 if ( ancestor && ancestor.find ) {
2812 initialMatches = ancestor.find( query );
2813
2814 for ( i = 0; i < initialMatches.count(); i++ ) {
2815 curItem = initialMatches.getItem( i );
2816
2817 // Using isReadOnly() method to filterout non editables. It checks isContentEditable including all browser quirks.
2818 if ( !includeNonEditables && curItem.isReadOnly() ) {
2819 continue;
2820 }
2821
2822 // It's not enough to get elements from common ancestor, because it migth contain too many matches.
2823 // We need to ensure that returned items are between boundary points.
2824 isStartGood = ( curItem.getPosition( boundaries.startNode ) & CKEDITOR.POSITION_FOLLOWING ) || boundaries.startNode.equals( curItem );
2825 isEndGood = ( curItem.getPosition( boundaries.endNode ) & ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IS_CONTAINED ) );
2826
2827 if ( isStartGood && isEndGood ) {
2828 ret.push( curItem );
2829 }
2830 }
2831 }
2832
2833 return ret;
2834 }
2835 };
2836
2837
2838} )();
2839
2840/**
2841 * Indicates a position after start of a node.
2842 *
2843 * // When used according to an element:
2844 * // <element>^contents</element>
2845 *
2846 * // When used according to a text node:
2847 * // "^text" (range is anchored in the text node)
2848 *
2849 * It is used as a parameter of methods like: {@link CKEDITOR.dom.range#moveToPosition},
2850 * {@link CKEDITOR.dom.range#setStartAt} and {@link CKEDITOR.dom.range#setEndAt}.
2851 *
2852 * @readonly
2853 * @member CKEDITOR
2854 * @property {Number} [=1]
2855 */
2856CKEDITOR.POSITION_AFTER_START = 1;
2857
2858/**
2859 * Indicates a position before end of a node.
2860 *
2861 * // When used according to an element:
2862 * // <element>contents^</element>
2863 *
2864 * // When used according to a text node:
2865 * // "text^" (range is anchored in the text node)
2866 *
2867 * It is used as a parameter of methods like: {@link CKEDITOR.dom.range#moveToPosition},
2868 * {@link CKEDITOR.dom.range#setStartAt} and {@link CKEDITOR.dom.range#setEndAt}.
2869 *
2870 * @readonly
2871 * @member CKEDITOR
2872 * @property {Number} [=2]
2873 */
2874CKEDITOR.POSITION_BEFORE_END = 2;
2875
2876/**
2877 * Indicates a position before start of a node.
2878 *
2879 * // When used according to an element:
2880 * // ^<element>contents</element> (range is anchored in element's parent)
2881 *
2882 * // When used according to a text node:
2883 * // ^"text" (range is anchored in text node's parent)
2884 *
2885 * It is used as a parameter of methods like: {@link CKEDITOR.dom.range#moveToPosition},
2886 * {@link CKEDITOR.dom.range#setStartAt} and {@link CKEDITOR.dom.range#setEndAt}.
2887 *
2888 * @readonly
2889 * @member CKEDITOR
2890 * @property {Number} [=3]
2891 */
2892CKEDITOR.POSITION_BEFORE_START = 3;
2893
2894/**
2895 * Indicates a position after end of a node.
2896 *
2897 * // When used according to an element:
2898 * // <element>contents</element>^ (range is anchored in element's parent)
2899 *
2900 * // When used according to a text node:
2901 * // "text"^ (range is anchored in text node's parent)
2902 *
2903 * It is used as a parameter of methods like: {@link CKEDITOR.dom.range#moveToPosition},
2904 * {@link CKEDITOR.dom.range#setStartAt} and {@link CKEDITOR.dom.range#setEndAt}.
2905 *
2906 * @readonly
2907 * @member CKEDITOR
2908 * @property {Number} [=4]
2909 */
2910CKEDITOR.POSITION_AFTER_END = 4;
2911
2912/**
2913 * @readonly
2914 * @member CKEDITOR
2915 * @property {Number} [=1]
2916 */
2917CKEDITOR.ENLARGE_ELEMENT = 1;
2918
2919/**
2920 * @readonly
2921 * @member CKEDITOR
2922 * @property {Number} [=2]
2923 */
2924CKEDITOR.ENLARGE_BLOCK_CONTENTS = 2;
2925
2926/**
2927 * @readonly
2928 * @member CKEDITOR
2929 * @property {Number} [=3]
2930 */
2931CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3;
2932
2933/**
2934 * @readonly
2935 * @member CKEDITOR
2936 * @property {Number} [=4]
2937 */
2938CKEDITOR.ENLARGE_INLINE = 4;
2939
2940// Check boundary types.
2941
2942/**
2943 * See {@link CKEDITOR.dom.range#checkBoundaryOfElement}.
2944 *
2945 * @readonly
2946 * @member CKEDITOR
2947 * @property {Number} [=1]
2948 */
2949CKEDITOR.START = 1;
2950
2951/**
2952 * See {@link CKEDITOR.dom.range#checkBoundaryOfElement}.
2953 *
2954 * @readonly
2955 * @member CKEDITOR
2956 * @property {Number} [=2]
2957 */
2958CKEDITOR.END = 2;
2959
2960// Shrink range types.
2961
2962/**
2963 * See {@link CKEDITOR.dom.range#shrink}.
2964 *
2965 * @readonly
2966 * @member CKEDITOR
2967 * @property {Number} [=1]
2968 */
2969CKEDITOR.SHRINK_ELEMENT = 1;
2970
2971/**
2972 * See {@link CKEDITOR.dom.range#shrink}.
2973 *
2974 * @readonly
2975 * @member CKEDITOR
2976 * @property {Number} [=2]
2977 */
2978CKEDITOR.SHRINK_TEXT = 2;
diff --git a/sources/core/dom/rangelist.js b/sources/core/dom/rangelist.js
new file mode 100644
index 0000000..250dfd9
--- /dev/null
+++ b/sources/core/dom/rangelist.js
@@ -0,0 +1,199 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 /**
8 * Represents a list os CKEDITOR.dom.range objects, which can be easily
9 * iterated sequentially.
10 *
11 * @class
12 * @extends Array
13 * @constructor Creates a rangeList class instance.
14 * @param {CKEDITOR.dom.range/CKEDITOR.dom.range[]} [ranges] The ranges contained on this list.
15 * Note that, if an array of ranges is specified, the range sequence
16 * should match its DOM order. This class will not help to sort them.
17 */
18 CKEDITOR.dom.rangeList = function( ranges ) {
19 if ( ranges instanceof CKEDITOR.dom.rangeList )
20 return ranges;
21
22 if ( !ranges )
23 ranges = [];
24 else if ( ranges instanceof CKEDITOR.dom.range )
25 ranges = [ ranges ];
26
27 return CKEDITOR.tools.extend( ranges, mixins );
28 };
29
30 var mixins = {
31 /**
32 * Creates an instance of the rangeList iterator, it should be used
33 * only when the ranges processing could be DOM intrusive, which
34 * means it may pollute and break other ranges in this list.
35 * Otherwise, it's enough to just iterate over this array in a for loop.
36 *
37 * @returns {CKEDITOR.dom.rangeListIterator}
38 */
39 createIterator: function() {
40 var rangeList = this,
41 bookmark = CKEDITOR.dom.walker.bookmark(),
42 bookmarks = [],
43 current;
44
45 return {
46 /**
47 * Retrieves the next range in the list.
48 *
49 * @member CKEDITOR.dom.rangeListIterator
50 * @param {Boolean} [mergeConsequent=false] Whether join two adjacent
51 * ranges into single, e.g. consequent table cells.
52 */
53 getNextRange: function( mergeConsequent ) {
54 current = current === undefined ? 0 : current + 1;
55
56 var range = rangeList[ current ];
57
58 // Multiple ranges might be mangled by each other.
59 if ( range && rangeList.length > 1 ) {
60 // Bookmarking all other ranges on the first iteration,
61 // the range correctness after it doesn't matter since we'll
62 // restore them before the next iteration.
63 if ( !current ) {
64 // Make sure bookmark correctness by reverse processing.
65 for ( var i = rangeList.length - 1; i >= 0; i-- )
66 bookmarks.unshift( rangeList[ i ].createBookmark( true ) );
67 }
68
69 if ( mergeConsequent ) {
70 // Figure out how many ranges should be merged.
71 var mergeCount = 0;
72 while ( rangeList[ current + mergeCount + 1 ] ) {
73 var doc = range.document,
74 found = 0,
75 left = doc.getById( bookmarks[ mergeCount ].endNode ),
76 right = doc.getById( bookmarks[ mergeCount + 1 ].startNode ),
77 next;
78
79 // Check subsequent range.
80 while ( 1 ) {
81 next = left.getNextSourceNode( false );
82 if ( !right.equals( next ) ) {
83 // This could be yet another bookmark or
84 // walking across block boundaries.
85 if ( bookmark( next ) || ( next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() ) ) {
86 left = next;
87 continue;
88 }
89 } else {
90 found = 1;
91 }
92
93 break;
94 }
95
96 if ( !found )
97 break;
98
99 mergeCount++;
100 }
101 }
102
103 range.moveToBookmark( bookmarks.shift() );
104
105 // Merge ranges finally after moving to bookmarks.
106 while ( mergeCount-- ) {
107 next = rangeList[ ++current ];
108 next.moveToBookmark( bookmarks.shift() );
109 range.setEnd( next.endContainer, next.endOffset );
110 }
111 }
112
113 return range;
114 }
115 };
116 },
117
118 /**
119 * Create bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark}.
120 *
121 * @param {Boolean} [serializable=false] See {@link CKEDITOR.dom.range#createBookmark}.
122 * @returns {Array} Array of bookmarks.
123 */
124 createBookmarks: function( serializable ) {
125 var retval = [],
126 bookmark;
127 for ( var i = 0; i < this.length; i++ ) {
128 retval.push( bookmark = this[ i ].createBookmark( serializable, true ) );
129
130 // Updating the container & offset values for ranges
131 // that have been touched.
132 for ( var j = i + 1; j < this.length; j++ ) {
133 this[ j ] = updateDirtyRange( bookmark, this[ j ] );
134 this[ j ] = updateDirtyRange( bookmark, this[ j ], true );
135 }
136 }
137 return retval;
138 },
139
140 /**
141 * Create "unobtrusive" bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark2}.
142 *
143 * @param {Boolean} [normalized=false] See {@link CKEDITOR.dom.range#createBookmark2}.
144 * @returns {Array} Array of bookmarks.
145 */
146 createBookmarks2: function( normalized ) {
147 var bookmarks = [];
148
149 for ( var i = 0; i < this.length; i++ )
150 bookmarks.push( this[ i ].createBookmark2( normalized ) );
151
152 return bookmarks;
153 },
154
155 /**
156 * Move each range in the list to the position specified by a list of bookmarks.
157 *
158 * @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.
159 */
160 moveToBookmarks: function( bookmarks ) {
161 for ( var i = 0; i < this.length; i++ )
162 this[ i ].moveToBookmark( bookmarks[ i ] );
163 }
164 };
165
166 // Update the specified range which has been mangled by previous insertion of
167 // range bookmark nodes.(#3256)
168 function updateDirtyRange( bookmark, dirtyRange, checkEnd ) {
169 var serializable = bookmark.serializable,
170 container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],
171 offset = checkEnd ? 'endOffset' : 'startOffset';
172
173 var bookmarkStart = serializable ? dirtyRange.document.getById( bookmark.startNode ) : bookmark.startNode;
174
175 var bookmarkEnd = serializable ? dirtyRange.document.getById( bookmark.endNode ) : bookmark.endNode;
176
177 if ( container.equals( bookmarkStart.getPrevious() ) ) {
178 dirtyRange.startOffset = dirtyRange.startOffset - container.getLength() - bookmarkEnd.getPrevious().getLength();
179 container = bookmarkEnd.getNext();
180 } else if ( container.equals( bookmarkEnd.getPrevious() ) ) {
181 dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();
182 container = bookmarkEnd.getNext();
183 }
184
185 container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;
186 container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;
187
188 // Update and return this range.
189 dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;
190 return dirtyRange;
191 }
192} )();
193
194/**
195 * (Virtual Class) Do not call this constructor. This class is not really part
196 * of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.
197 *
198 * @class CKEDITOR.dom.rangeListIterator
199 */
diff --git a/sources/core/dom/text.js b/sources/core/dom/text.js
new file mode 100644
index 0000000..ce20ffe
--- /dev/null
+++ b/sources/core/dom/text.js
@@ -0,0 +1,135 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.text} class, which represents
8 * a DOM text node.
9 */
10
11/**
12 * Represents a DOM text node.
13 *
14 * var nativeNode = document.createTextNode( 'Example' );
15 * var text = new CKEDITOR.dom.text( nativeNode );
16 *
17 * var text = new CKEDITOR.dom.text( 'Example' );
18 *
19 * @class
20 * @extends CKEDITOR.dom.node
21 * @constructor Creates a text class instance.
22 * @param {Object/String} text A native DOM text node or a string containing
23 * the text to use to create a new text node.
24 * @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
25 * the node in case of new node creation. Defaults to the current document.
26 */
27CKEDITOR.dom.text = function( text, ownerDocument ) {
28 if ( typeof text == 'string' )
29 text = ( ownerDocument ? ownerDocument.$ : document ).createTextNode( text );
30
31 // Theoretically, we should call the base constructor here
32 // (not CKEDITOR.dom.node though). But, IE doesn't support expando
33 // properties on text node, so the features provided by domObject will not
34 // work for text nodes (which is not a big issue for us).
35 //
36 // CKEDITOR.dom.domObject.call( this, element );
37
38 this.$ = text;
39};
40
41CKEDITOR.dom.text.prototype = new CKEDITOR.dom.node();
42
43CKEDITOR.tools.extend( CKEDITOR.dom.text.prototype, {
44 /**
45 * The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
46 *
47 * @readonly
48 * @property {Number} [=CKEDITOR.NODE_TEXT]
49 */
50 type: CKEDITOR.NODE_TEXT,
51
52 /**
53 * Gets length of node's value.
54 *
55 * @returns {Number}
56 */
57 getLength: function() {
58 return this.$.nodeValue.length;
59 },
60
61 /**
62 * Gets node's value.
63 *
64 * @returns {String}
65 */
66 getText: function() {
67 return this.$.nodeValue;
68 },
69
70 /**
71 * Sets node's value.
72 *
73 * @param {String} text
74 */
75 setText: function( text ) {
76 this.$.nodeValue = text;
77 },
78
79 /**
80 * Breaks this text node into two nodes at the specified offset,
81 * keeping both in the tree as siblings. This node then only contains
82 * all the content up to the offset point. A new text node, which is
83 * inserted as the next sibling of this node, contains all the content
84 * at and after the offset point. When the offset is equal to the
85 * length of this node, the new node has no data.
86 *
87 * @param {Number} The position at which to split, starting from zero.
88 * @returns {CKEDITOR.dom.text} The new text node.
89 */
90 split: function( offset ) {
91
92 // Saved the children count and text length beforehand.
93 var parent = this.$.parentNode,
94 count = parent.childNodes.length,
95 length = this.getLength();
96
97 var doc = this.getDocument();
98 var retval = new CKEDITOR.dom.text( this.$.splitText( offset ), doc );
99
100 if ( parent.childNodes.length == count ) {
101 // If the offset is after the last char, IE creates the text node
102 // on split, but don't include it into the DOM. So, we have to do
103 // that manually here.
104 if ( offset >= length ) {
105 retval = doc.createText( '' );
106 retval.insertAfter( this );
107 } else {
108 // IE BUG: IE8+ does not update the childNodes array in DOM after splitText(),
109 // we need to make some DOM changes to make it update. (#3436)
110 var workaround = doc.createText( '' );
111 workaround.insertAfter( retval );
112 workaround.remove();
113 }
114 }
115
116 return retval;
117 },
118
119 /**
120 * Extracts characters from indexA up to but not including `indexB`.
121 *
122 * @param {Number} indexA An integer between `0` and one less than the
123 * length of the text.
124 * @param {Number} [indexB] An integer between `0` and the length of the
125 * string. If omitted, extracts characters to the end of the text.
126 */
127 substring: function( indexA, indexB ) {
128 // We need the following check due to a Firefox bug
129 // https://bugzilla.mozilla.org/show_bug.cgi?id=458886
130 if ( typeof indexB != 'number' )
131 return this.$.nodeValue.substr( indexA );
132 else
133 return this.$.nodeValue.substring( indexA, indexB );
134 }
135} );
diff --git a/sources/core/dom/walker.js b/sources/core/dom/walker.js
new file mode 100644
index 0000000..cec4574
--- /dev/null
+++ b/sources/core/dom/walker.js
@@ -0,0 +1,652 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 // This function is to be called under a "walker" instance scope.
8 function iterate( rtl, breakOnFalse ) {
9 var range = this.range;
10
11 // Return null if we have reached the end.
12 if ( this._.end )
13 return null;
14
15 // This is the first call. Initialize it.
16 if ( !this._.start ) {
17 this._.start = 1;
18
19 // A collapsed range must return null at first call.
20 if ( range.collapsed ) {
21 this.end();
22 return null;
23 }
24
25 // Move outside of text node edges.
26 range.optimize();
27 }
28
29 var node,
30 startCt = range.startContainer,
31 endCt = range.endContainer,
32 startOffset = range.startOffset,
33 endOffset = range.endOffset,
34 guard,
35 userGuard = this.guard,
36 type = this.type,
37 getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
38
39 // Create the LTR guard function, if necessary.
40 if ( !rtl && !this._.guardLTR ) {
41 // The node that stops walker from moving up.
42 var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt : endCt.getParent();
43
44 // The node that stops the walker from going to next.
45 var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt.getChild( endOffset ) : endCt.getNext();
46
47 this._.guardLTR = function( node, movingOut ) {
48 return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
49 };
50 }
51
52 // Create the RTL guard function, if necessary.
53 if ( rtl && !this._.guardRTL ) {
54 // The node that stops walker from moving up.
55 var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startCt : startCt.getParent();
56
57 // The node that stops the walker from going to next.
58 var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startOffset ? startCt.getChild( startOffset - 1 ) : null : startCt.getPrevious();
59
60 this._.guardRTL = function( node, movingOut ) {
61 return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
62 };
63 }
64
65 // Define which guard function to use.
66 var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
67
68 // Make the user defined guard function participate in the process,
69 // otherwise simply use the boundary guard.
70 if ( userGuard ) {
71 guard = function( node, movingOut ) {
72 if ( stopGuard( node, movingOut ) === false )
73 return false;
74
75 return userGuard( node, movingOut );
76 };
77 } else {
78 guard = stopGuard;
79 }
80
81 if ( this.current )
82 node = this.current[ getSourceNodeFn ]( false, type, guard );
83 else {
84 // Get the first node to be returned.
85 if ( rtl ) {
86 node = endCt;
87
88 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
89 if ( endOffset > 0 )
90 node = node.getChild( endOffset - 1 );
91 else
92 node = ( guard( node, true ) === false ) ? null : node.getPreviousSourceNode( true, type, guard );
93 }
94 } else {
95 node = startCt;
96
97 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
98 if ( !( node = node.getChild( startOffset ) ) )
99 node = ( guard( startCt, true ) === false ) ? null : startCt.getNextSourceNode( true, type, guard );
100 }
101 }
102
103 if ( node && guard( node ) === false )
104 node = null;
105 }
106
107 while ( node && !this._.end ) {
108 this.current = node;
109
110 if ( !this.evaluator || this.evaluator( node ) !== false ) {
111 if ( !breakOnFalse )
112 return node;
113 } else if ( breakOnFalse && this.evaluator ) {
114 return false;
115 }
116
117 node = node[ getSourceNodeFn ]( false, type, guard );
118 }
119
120 this.end();
121 return this.current = null;
122 }
123
124 function iterateToLast( rtl ) {
125 var node,
126 last = null;
127
128 while ( ( node = iterate.call( this, rtl ) ) )
129 last = node;
130
131 return last;
132 }
133
134 /**
135 * Utility class to "walk" the DOM inside range boundaries. If the
136 * range starts or ends in the middle of the text node, this node will
137 * be included as a whole. Outside changes to the range may break the walker.
138 *
139 * The walker may return nodes that are not totally included in the
140 * range boundaries. Let us take the following range representation,
141 * where the square brackets indicate the boundaries:
142 *
143 * [<p>Some <b>sample] text</b>
144 *
145 * While walking forward into the above range, the following nodes are
146 * returned: `<p>`, `"Some "`, `<b>` and `"sample"`. Going
147 * backwards instead we have: `"sample"` and `"Some "`. So note that the
148 * walker always returns nodes when "entering" them, but not when
149 * "leaving" them. The {@link #guard} function is instead called both when
150 * entering and when leaving nodes.
151 *
152 * @class
153 */
154 CKEDITOR.dom.walker = CKEDITOR.tools.createClass( {
155 /**
156 * Creates a walker class instance.
157 *
158 * @constructor
159 * @param {CKEDITOR.dom.range} range The range within which to walk.
160 */
161 $: function( range ) {
162 this.range = range;
163
164 /**
165 * A function executed for every matched node to check whether
166 * it is to be considered in the walk or not. If not provided, all
167 * matched nodes are considered good.
168 *
169 * If the function returns `false`, the node is ignored.
170 *
171 * @property {Function} evaluator
172 */
173 // this.evaluator = null;
174
175 /**
176 * A function executed for every node the walk passes by to check
177 * whether the walk is to be finished. It is called both when
178 * entering and when exiting nodes, as well as for the matched nodes.
179 *
180 * If this function returns `false`, the walking ends and no more
181 * nodes are evaluated.
182
183 * @property {Function} guard
184 */
185 // this.guard = null;
186
187 /** @private */
188 this._ = {};
189 },
190
191 // statics :
192 // {
193 // /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
194 // * @param {CKEDITOR.dom.node} startNode The node from which the walk
195 // * will start.
196 // * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
197 // * in the walk. No more nodes are retrieved after touching or
198 // * passing it. If not provided, the walker stops at the
199 // * &lt;body&gt; closing boundary.
200 // * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
201 // * provided nodes.
202 // */
203 // createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
204 // {
205 // var range = new CKEDITOR.dom.range();
206 // if ( startNode )
207 // range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
208 // else
209 // range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;
210 //
211 // if ( endNode )
212 // range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
213 // else
214 // range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
215 //
216 // return new CKEDITOR.dom.walker( range );
217 // }
218 // },
219 //
220 proto: {
221 /**
222 * Stops walking. No more nodes are retrieved if this function is called.
223 */
224 end: function() {
225 this._.end = 1;
226 },
227
228 /**
229 * Retrieves the next node (on the right).
230 *
231 * @returns {CKEDITOR.dom.node} The next node or `null` if no more
232 * nodes are available.
233 */
234 next: function() {
235 return iterate.call( this );
236 },
237
238 /**
239 * Retrieves the previous node (on the left).
240 *
241 * @returns {CKEDITOR.dom.node} The previous node or `null` if no more
242 * nodes are available.
243 */
244 previous: function() {
245 return iterate.call( this, 1 );
246 },
247
248 /**
249 * Checks all nodes on the right, executing the evaluation function.
250 *
251 * @returns {Boolean} `false` if the evaluator function returned
252 * `false` for any of the matched nodes. Otherwise `true`.
253 */
254 checkForward: function() {
255 return iterate.call( this, 0, 1 ) !== false;
256 },
257
258 /**
259 * Check all nodes on the left, executing the evaluation function.
260 *
261 * @returns {Boolean} `false` if the evaluator function returned
262 * `false` for any of the matched nodes. Otherwise `true`.
263 */
264 checkBackward: function() {
265 return iterate.call( this, 1, 1 ) !== false;
266 },
267
268 /**
269 * Executes a full walk forward (to the right), until no more nodes
270 * are available, returning the last valid node.
271 *
272 * @returns {CKEDITOR.dom.node} The last node on the right or `null`
273 * if no valid nodes are available.
274 */
275 lastForward: function() {
276 return iterateToLast.call( this );
277 },
278
279 /**
280 * Executes a full walk backwards (to the left), until no more nodes
281 * are available, returning the last valid node.
282 *
283 * @returns {CKEDITOR.dom.node} The last node on the left or `null`
284 * if no valid nodes are available.
285 */
286 lastBackward: function() {
287 return iterateToLast.call( this, 1 );
288 },
289
290 /**
291 * Resets the walker.
292 */
293 reset: function() {
294 delete this.current;
295 this._ = {};
296 }
297
298 }
299 } );
300
301 // Anything whose display computed style is block, list-item, table,
302 // table-row-group, table-header-group, table-footer-group, table-row,
303 // table-column-group, table-column, table-cell, table-caption, or whose node
304 // name is hr, br (when enterMode is br only) is a block boundary.
305 var blockBoundaryDisplayMatch = {
306 block: 1, 'list-item': 1, table: 1, 'table-row-group': 1,
307 'table-header-group': 1, 'table-footer-group': 1, 'table-row': 1, 'table-column-group': 1,
308 'table-column': 1, 'table-cell': 1, 'table-caption': 1
309 },
310 outOfFlowPositions = { absolute: 1, fixed: 1 };
311
312 /**
313 * Checks whether an element is displayed as a block.
314 *
315 * @member CKEDITOR.dom.element
316 * @param [customNodeNames] Custom list of nodes which will extend
317 * the default {@link CKEDITOR.dtd#$block} list.
318 * @returns {Boolean}
319 */
320 CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) {
321 // Whether element is in normal page flow. Floated or positioned elements are out of page flow.
322 // Don't consider floated or positioned formatting as block boundary, fall back to dtd check in that case. (#6297)
323 var inPageFlow = this.getComputedStyle( 'float' ) == 'none' && !( this.getComputedStyle( 'position' ) in outOfFlowPositions );
324
325 if ( inPageFlow && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] )
326 return true;
327
328 // Either in $block or in customNodeNames if defined.
329 return !!( this.is( CKEDITOR.dtd.$block ) || customNodeNames && this.is( customNodeNames ) );
330 };
331
332 /**
333 * Returns a function which checks whether the node is a block boundary.
334 * See {@link CKEDITOR.dom.element#isBlockBoundary}.
335 *
336 * @static
337 * @param customNodeNames
338 * @returns {Function}
339 */
340 CKEDITOR.dom.walker.blockBoundary = function( customNodeNames ) {
341 return function( node ) {
342 return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary( customNodeNames ) );
343 };
344 };
345
346 /**
347 * @static
348 * @todo
349 */
350 CKEDITOR.dom.walker.listItemBoundary = function() {
351 return this.blockBoundary( { br: 1 } );
352 };
353
354 /**
355 * Returns a function which checks whether the node is a bookmark node or the bookmark node
356 * inner content.
357 *
358 * @static
359 * @param {Boolean} [contentOnly=false] Whether only test against the text content of
360 * a bookmark node instead of the element itself (default).
361 * @param {Boolean} [isReject=false] Whether to return `false` for the bookmark
362 * node instead of `true` (default).
363 * @returns {Function}
364 */
365 CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject ) {
366 function isBookmarkNode( node ) {
367 return ( node && node.getName && node.getName() == 'span' && node.data( 'cke-bookmark' ) );
368 }
369
370 return function( node ) {
371 var isBookmark, parent;
372 // Is bookmark inner text node?
373 isBookmark = ( node && node.type != CKEDITOR.NODE_ELEMENT && ( parent = node.getParent() ) && isBookmarkNode( parent ) );
374 // Is bookmark node?
375 isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node );
376 return !!( isReject ^ isBookmark );
377 };
378 };
379
380 /**
381 * Returns a function which checks whether the node is a text node containing only whitespace characters.
382 *
383 * @static
384 * @param {Boolean} [isReject=false]
385 * @returns {Function}
386 */
387 CKEDITOR.dom.walker.whitespaces = function( isReject ) {
388 return function( node ) {
389 var isWhitespace;
390 if ( node && node.type == CKEDITOR.NODE_TEXT ) {
391 // Whitespace, as well as the Filling Char Sequence text node used in Webkit. (#9384, #13816)
392 isWhitespace = !CKEDITOR.tools.trim( node.getText() ) ||
393 CKEDITOR.env.webkit && node.getText() == CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE;
394 }
395
396 return !!( isReject ^ isWhitespace );
397 };
398 };
399
400 /**
401 * Returns a function which checks whether the node is invisible in the WYSIWYG mode.
402 *
403 * @static
404 * @param {Boolean} [isReject=false]
405 * @returns {Function}
406 */
407 CKEDITOR.dom.walker.invisible = function( isReject ) {
408 var whitespace = CKEDITOR.dom.walker.whitespaces(),
409 // #12221 (Chrome) plus #11111 (Safari).
410 offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0;
411
412 return function( node ) {
413 var invisible;
414
415 if ( whitespace( node ) )
416 invisible = 1;
417 else {
418 // Visibility should be checked on element.
419 if ( node.type == CKEDITOR.NODE_TEXT )
420 node = node.getParent();
421
422 // Nodes that take no spaces in wysiwyg:
423 // 1. White-spaces but not including NBSP.
424 // 2. Empty inline elements, e.g. <b></b>.
425 // 3. <br> elements (bogus, surrounded by text) (#12423).
426 invisible = node.$.offsetWidth <= offsetWidth0;
427 }
428
429 return !!( isReject ^ invisible );
430 };
431 };
432
433 /**
434 * Returns a function which checks whether the node type is equal to the passed one.
435 *
436 * @static
437 * @param {Number} type
438 * @param {Boolean} [isReject=false]
439 * @returns {Function}
440 */
441 CKEDITOR.dom.walker.nodeType = function( type, isReject ) {
442 return function( node ) {
443 return !!( isReject ^ ( node.type == type ) );
444 };
445 };
446
447 /**
448 * Returns a function which checks whether the node is a bogus (filler) node from
449 * `contenteditable` element's point of view.
450 *
451 * @static
452 * @param {Boolean} [isReject=false]
453 * @returns {Function}
454 */
455 CKEDITOR.dom.walker.bogus = function( isReject ) {
456 function nonEmpty( node ) {
457 return !isWhitespaces( node ) && !isBookmark( node );
458 }
459
460 return function( node ) {
461 var isBogus = CKEDITOR.env.needsBrFiller ? node.is && node.is( 'br' ) : node.getText && tailNbspRegex.test( node.getText() );
462
463 if ( isBogus ) {
464 var parent = node.getParent(),
465 next = node.getNext( nonEmpty );
466
467 isBogus = parent.isBlockBoundary() && ( !next || next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() );
468 }
469
470 return !!( isReject ^ isBogus );
471 };
472 };
473
474 /**
475 * Returns a function which checks whether the node is a temporary element
476 * (element with the `data-cke-temp` attribute) or its child.
477 *
478 * @since 4.3
479 * @static
480 * @param {Boolean} [isReject=false] Whether to return `false` for the
481 * temporary element instead of `true` (default).
482 * @returns {Function}
483 */
484 CKEDITOR.dom.walker.temp = function( isReject ) {
485 return function( node ) {
486 if ( node.type != CKEDITOR.NODE_ELEMENT )
487 node = node.getParent();
488
489 var isTemp = node && node.hasAttribute( 'data-cke-temp' );
490
491 return !!( isReject ^ isTemp );
492 };
493 };
494
495 var tailNbspRegex = /^[\t\r\n ]*(?:&nbsp;|\xa0)$/,
496 isWhitespaces = CKEDITOR.dom.walker.whitespaces(),
497 isBookmark = CKEDITOR.dom.walker.bookmark(),
498 isTemp = CKEDITOR.dom.walker.temp(),
499 toSkip = function( node ) {
500 return isBookmark( node ) ||
501 isWhitespaces( node ) ||
502 node.type == CKEDITOR.NODE_ELEMENT && node.is( CKEDITOR.dtd.$inline ) && !node.is( CKEDITOR.dtd.$empty );
503 };
504
505 /**
506 * Returns a function which checks whether the node should be ignored in terms of "editability".
507 *
508 * This includes:
509 *
510 * * whitespaces (see {@link CKEDITOR.dom.walker#whitespaces}),
511 * * bookmarks (see {@link CKEDITOR.dom.walker#bookmark}),
512 * * temporary elements (see {@link CKEDITOR.dom.walker#temp}).
513 *
514 * @since 4.3
515 * @static
516 * @param {Boolean} [isReject=false] Whether to return `false` for the
517 * ignored element instead of `true` (default).
518 * @returns {Function}
519 */
520 CKEDITOR.dom.walker.ignored = function( isReject ) {
521 return function( node ) {
522 var isIgnored = isWhitespaces( node ) || isBookmark( node ) || isTemp( node );
523
524 return !!( isReject ^ isIgnored );
525 };
526 };
527
528 var isIgnored = CKEDITOR.dom.walker.ignored();
529
530 /**
531 * Returns a function which checks whether the node is empty.
532 *
533 * @since 4.5
534 * @static
535 * @param {Boolean} [isReject=false] Whether to return `false` for the
536 * ignored element instead of `true` (default).
537 * @returns {Function}
538 */
539 CKEDITOR.dom.walker.empty = function( isReject ) {
540 return function( node ) {
541 var i = 0,
542 l = node.getChildCount();
543
544 for ( ; i < l; ++i ) {
545 if ( !isIgnored( node.getChild( i ) ) ) {
546 return !!isReject;
547 }
548 }
549
550 return !isReject;
551 };
552 };
553
554 var isEmpty = CKEDITOR.dom.walker.empty();
555
556 function filterTextContainers( dtd ) {
557 var hash = {},
558 name;
559
560 for ( name in dtd ) {
561 if ( CKEDITOR.dtd[ name ][ '#' ] )
562 hash[ name ] = 1;
563 }
564 return hash;
565 }
566
567 /**
568 * A hash of element names which in browsers that {@link CKEDITOR.env#needsBrFiller do not need `<br>` fillers}
569 * can be selection containers despite being empty.
570 *
571 * @since 4.5
572 * @static
573 * @property {Object} validEmptyBlockContainers
574 */
575 var validEmptyBlocks = CKEDITOR.dom.walker.validEmptyBlockContainers = CKEDITOR.tools.extend(
576 filterTextContainers( CKEDITOR.dtd.$block ),
577 { caption: 1, td: 1, th: 1 }
578 );
579
580 function isEditable( node ) {
581 // Skip temporary elements, bookmarks and whitespaces.
582 if ( isIgnored( node ) )
583 return false;
584
585 if ( node.type == CKEDITOR.NODE_TEXT )
586 return true;
587
588 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
589 // All inline and non-editable elements are valid editable places.
590 // Note: the <hr> is currently the only element in CKEDITOR.dtd.$empty and CKEDITOR.dtd.$block,
591 // but generally speaking we need an intersection of these two sets.
592 // Note: non-editable block has to be treated differently (should be selected entirely).
593 if ( node.is( CKEDITOR.dtd.$inline ) || node.is( 'hr' ) || node.getAttribute( 'contenteditable' ) == 'false' )
594 return true;
595
596 // Empty blocks are editable on IE.
597 if ( !CKEDITOR.env.needsBrFiller && node.is( validEmptyBlocks ) && isEmpty( node ) )
598 return true;
599 }
600
601 // Skip all other nodes.
602 return false;
603 }
604
605 /**
606 * Returns a function which checks whether the node can be a container or a sibling
607 * of the selection end.
608 *
609 * This includes:
610 *
611 * * text nodes (but not whitespaces),
612 * * inline elements,
613 * * intersection of {@link CKEDITOR.dtd#$empty} and {@link CKEDITOR.dtd#$block} (currently
614 * it is only `<hr>`),
615 * * non-editable blocks (special case &mdash; such blocks cannot be containers nor
616 * siblings, they need to be selected entirely),
617 * * empty {@link #validEmptyBlockContainers blocks} which can contain text
618 * ({@link CKEDITOR.env#needsBrFiller old IEs only}).
619 *
620 * @since 4.3
621 * @static
622 * @param {Boolean} [isReject=false] Whether to return `false` for the
623 * ignored element instead of `true` (default).
624 * @returns {Function}
625 */
626 CKEDITOR.dom.walker.editable = function( isReject ) {
627 return function( node ) {
628 return !!( isReject ^ isEditable( node ) );
629 };
630 };
631
632 /**
633 * Checks if there is a filler node at the end of an element, and returns it.
634 *
635 * @member CKEDITOR.dom.element
636 * @returns {CKEDITOR.dom.node/Boolean} Bogus node or `false`.
637 */
638 CKEDITOR.dom.element.prototype.getBogus = function() {
639 // Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (#7070).
640 var tail = this;
641 do {
642 tail = tail.getPreviousSourceNode();
643 }
644 while ( toSkip( tail ) );
645
646 if ( tail && ( CKEDITOR.env.needsBrFiller ? tail.is && tail.is( 'br' ) : tail.getText && tailNbspRegex.test( tail.getText() ) ) )
647 return tail;
648
649 return false;
650 };
651
652} )();
diff --git a/sources/core/dom/window.js b/sources/core/dom/window.js
new file mode 100644
index 0000000..ceeaeff
--- /dev/null
+++ b/sources/core/dom/window.js
@@ -0,0 +1,95 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
8 * represents a DOM document.
9 */
10
11/**
12 * Represents a DOM window.
13 *
14 * var document = new CKEDITOR.dom.window( window );
15 *
16 * @class
17 * @extends CKEDITOR.dom.domObject
18 * @constructor Creates a window class instance.
19 * @param {Object} domWindow A native DOM window.
20 */
21CKEDITOR.dom.window = function( domWindow ) {
22 CKEDITOR.dom.domObject.call( this, domWindow );
23};
24
25CKEDITOR.dom.window.prototype = new CKEDITOR.dom.domObject();
26
27CKEDITOR.tools.extend( CKEDITOR.dom.window.prototype, {
28 /**
29 * Moves the selection focus to this window.
30 *
31 * var win = new CKEDITOR.dom.window( window );
32 * win.focus();
33 */
34 focus: function() {
35 this.$.focus();
36 },
37
38 /**
39 * Gets the width and height of this window's viewable area.
40 *
41 * var win = new CKEDITOR.dom.window( window );
42 * var size = win.getViewPaneSize();
43 * alert( size.width );
44 * alert( size.height );
45 *
46 * @returns {Object} An object with the `width` and `height`
47 * properties containing the size.
48 */
49 getViewPaneSize: function() {
50 var doc = this.$.document,
51 stdMode = doc.compatMode == 'CSS1Compat';
52 return {
53 width: ( stdMode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
54 height: ( stdMode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
55 };
56 },
57
58 /**
59 * Gets the current position of the window's scroll.
60 *
61 * var win = new CKEDITOR.dom.window( window );
62 * var pos = win.getScrollPosition();
63 * alert( pos.x );
64 * alert( pos.y );
65 *
66 * @returns {Object} An object with the `x` and `y` properties
67 * containing the scroll position.
68 */
69 getScrollPosition: function() {
70 var $ = this.$;
71
72 if ( 'pageXOffset' in $ ) {
73 return {
74 x: $.pageXOffset || 0,
75 y: $.pageYOffset || 0
76 };
77 } else {
78 var doc = $.document;
79 return {
80 x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
81 y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
82 };
83 }
84 },
85
86 /**
87 * Gets the frame element containing this window context.
88 *
89 * @returns {CKEDITOR.dom.element} The frame element or `null` if not in a frame context.
90 */
91 getFrame: function() {
92 var iframe = this.$.frameElement;
93 return iframe ? new CKEDITOR.dom.element.get( iframe ) : null;
94 }
95} );
diff --git a/sources/core/dtd.js b/sources/core/dtd.js
new file mode 100644
index 0000000..6059d48
--- /dev/null
+++ b/sources/core/dtd.js
@@ -0,0 +1,349 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.dtd} object, which holds the DTD
8 * mapping for XHTML 1.0 Transitional. This file was automatically
9 * generated from the file: xhtml1-transitional.dtd.
10 */
11
12/**
13 * Holds and object representation of the HTML DTD to be used by the
14 * editor in its internal operations.
15 *
16 * Each element in the DTD is represented by a property in this object. Each
17 * property contains the list of elements that can be contained by the element.
18 * Text is represented by the `#` property.
19 *
20 * Several special grouping properties are also available. Their names start
21 * with the `$` character.
22 *
23 * // Check if <div> can be contained in a <p> element.
24 * alert( !!CKEDITOR.dtd[ 'p' ][ 'div' ] ); // false
25 *
26 * // Check if <p> can be contained in a <div> element.
27 * alert( !!CKEDITOR.dtd[ 'div' ][ 'p' ] ); // true
28 *
29 * // Check if <p> is a block element.
30 * alert( !!CKEDITOR.dtd.$block[ 'p' ] ); // true
31 *
32 * @class CKEDITOR.dtd
33 * @singleton
34 */
35CKEDITOR.dtd = ( function() {
36 'use strict';
37
38 var X = CKEDITOR.tools.extend,
39 // Subtraction rest of sets, from the first set.
40 Y = function( source, removed ) {
41 var substracted = CKEDITOR.tools.clone( source );
42 for ( var i = 1; i < arguments.length; i++ ) {
43 removed = arguments[ i ];
44 for ( var name in removed )
45 delete substracted[ name ];
46 }
47 return substracted;
48 };
49
50 // Phrasing elements.
51 // P = { a: 1, em: 1, strong: 1, small: 1, abbr: 1, dfn: 1, i: 1, b: 1, s: 1,
52 // u: 1, code: 1, 'var': 1, samp: 1, kbd: 1, sup: 1, sub: 1, q: 1, cite: 1,
53 // span: 1, bdo: 1, bdi: 1, br: 1, wbr: 1, ins: 1, del: 1, img: 1, embed: 1,
54 // object: 1, iframe: 1, map: 1, area: 1, script: 1, noscript: 1, ruby: 1,
55 // video: 1, audio: 1, input: 1, textarea: 1, select: 1, button: 1, label: 1,
56 // output: 1, keygen: 1, progress: 1, command: 1, canvas: 1, time: 1,
57 // meter: 1, detalist: 1 },
58
59 // Flow elements.
60 // F = { a: 1, p: 1, hr: 1, pre: 1, ul: 1, ol: 1, dl: 1, div: 1, h1: 1, h2: 1,
61 // h3: 1, h4: 1, h5: 1, h6: 1, hgroup: 1, address: 1, blockquote: 1, ins: 1,
62 // del: 1, object: 1, map: 1, noscript: 1, section: 1, nav: 1, article: 1,
63 // aside: 1, header: 1, footer: 1, video: 1, audio: 1, figure: 1, table: 1,
64 // form: 1, fieldset: 1, menu: 1, canvas: 1, details:1 },
65
66 // Text can be everywhere.
67 // X( P, T );
68 // Flow elements set consists of phrasing elements set.
69 // X( F, P );
70
71 var P = {}, F = {},
72 // Intersection of flow elements set and phrasing elements set.
73 PF = {
74 a: 1, abbr: 1, area: 1, audio: 1, b: 1, bdi: 1, bdo: 1, br: 1, button: 1, canvas: 1, cite: 1,
75 code: 1, command: 1, datalist: 1, del: 1, dfn: 1, em: 1, embed: 1, i: 1, iframe: 1, img: 1,
76 input: 1, ins: 1, kbd: 1, keygen: 1, label: 1, map: 1, mark: 1, meter: 1, noscript: 1, object: 1,
77 output: 1, progress: 1, q: 1, ruby: 1, s: 1, samp: 1, script: 1, select: 1, small: 1, span: 1,
78 strong: 1, sub: 1, sup: 1, textarea: 1, time: 1, u: 1, 'var': 1, video: 1, wbr: 1
79 },
80 // F - PF (Flow Only).
81 FO = {
82 address: 1, article: 1, aside: 1, blockquote: 1, details: 1, div: 1, dl: 1, fieldset: 1,
83 figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
84 hr: 1, main: 1, menu: 1, nav: 1, ol: 1, p: 1, pre: 1, section: 1, table: 1, ul: 1
85 },
86 // Metadata elements.
87 M = { command: 1, link: 1, meta: 1, noscript: 1, script: 1, style: 1 },
88 // Empty.
89 E = {},
90 // Text.
91 T = { '#': 1 },
92
93 // Deprecated phrasing elements.
94 DP = { acronym: 1, applet: 1, basefont: 1, big: 1, font: 1, isindex: 1, strike: 1, style: 1, tt: 1 }, // TODO remove "style".
95 // Deprecated flow only elements.
96 DFO = { center: 1, dir: 1, noframes: 1 };
97
98 // Phrasing elements := PF + T + DP
99 X( P, PF, T, DP );
100 // Flow elements := FO + P + DFO
101 X( F, FO, P, DFO );
102
103 var dtd = {
104 a: Y( P, { a: 1, button: 1 } ), // Treat as normal inline element (not a transparent one).
105 abbr: P,
106 address: F,
107 area: E,
108 article: F,
109 aside: F,
110 audio: X( { source: 1, track: 1 }, F ),
111 b: P,
112 base: E,
113 bdi: P,
114 bdo: P,
115 blockquote: F,
116 body: F,
117 br: E,
118 button: Y( P, { a: 1, button: 1 } ),
119 canvas: P, // Treat as normal inline element (not a transparent one).
120 caption: F,
121 cite: P,
122 code: P,
123 col: E,
124 colgroup: { col: 1 },
125 command: E,
126 datalist: X( { option: 1 }, P ),
127 dd: F,
128 del: P, // Treat as normal inline element (not a transparent one).
129 details: X( { summary: 1 }, F ),
130 dfn: P,
131 div: F,
132 dl: { dt: 1, dd: 1 },
133 dt: F,
134 em: P,
135 embed: E,
136 fieldset: X( { legend: 1 }, F ),
137 figcaption: F,
138 figure: X( { figcaption: 1 }, F ),
139 footer: F,
140 form: F,
141 h1: P,
142 h2: P,
143 h3: P,
144 h4: P,
145 h5: P,
146 h6: P,
147 head: X( { title: 1, base: 1 }, M ),
148 header: F,
149 hgroup: { h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 },
150 hr: E,
151 html: X( { head: 1, body: 1 }, F, M ), // Head and body are optional...
152 i: P,
153 iframe: T,
154 img: E,
155 input: E,
156 ins: P, // Treat as normal inline element (not a transparent one).
157 kbd: P,
158 keygen: E,
159 label: P,
160 legend: P,
161 li: F,
162 link: E,
163 // Can't be a descendant of article, aside, footer, header, nav, but we don't need this
164 // complication. As well as checking if it's used only once.
165 main: F,
166 map: F,
167 mark: P, // Treat as normal inline element (not a transparent one).
168 menu: X( { li: 1 }, F ),
169 meta: E,
170 meter: Y( P, { meter: 1 } ),
171 nav: F,
172 noscript: X( { link: 1, meta: 1, style: 1 }, P ), // Treat as normal inline element (not a transparent one).
173 object: X( { param: 1 }, P ), // Treat as normal inline element (not a transparent one).
174 ol: { li: 1 },
175 optgroup: { option: 1 },
176 option: T,
177 output: P,
178 p: P,
179 param: E,
180 pre: P,
181 progress: Y( P, { progress: 1 } ),
182 q: P,
183 rp: P,
184 rt: P,
185 ruby: X( { rp: 1, rt: 1 }, P ),
186 s: P,
187 samp: P,
188 script: T,
189 section: F,
190 select: { optgroup: 1, option: 1 },
191 small: P,
192 source: E,
193 span: P,
194 strong: P,
195 style: T,
196 sub: P,
197 summary: X( { h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 }, P ),
198 sup: P,
199 table: { caption: 1, colgroup: 1, thead: 1, tfoot: 1, tbody: 1, tr: 1 },
200 tbody: { tr: 1 },
201 td: F,
202 textarea: T,
203 tfoot: { tr: 1 },
204 th: F,
205 thead: { tr: 1 },
206 time: Y( P, { time: 1 } ),
207 title: T,
208 tr: { th: 1, td: 1 },
209 track: E,
210 u: P,
211 ul: { li: 1 },
212 'var': P,
213 video: X( { source: 1, track: 1 }, F ),
214 wbr: E,
215
216 // Deprecated tags.
217 acronym: P,
218 applet: X( { param: 1 }, F ),
219 basefont: E,
220 big: P,
221 center: F,
222 dialog: E,
223 dir: { li: 1 },
224 font: P,
225 isindex: E,
226 noframes: F,
227 strike: P,
228 tt: P
229 };
230
231 X( dtd, {
232 /**
233 * List of block elements, like `<p>` or `<div>`.
234 */
235 $block: X( { audio: 1, dd: 1, dt: 1, figcaption: 1, li: 1, video: 1 }, FO, DFO ),
236
237 /**
238 * List of elements that contain other blocks, in which block-level operations should be limited,
239 * this property is not intended to be checked directly, use {@link CKEDITOR.dom.elementPath#blockLimit} instead.
240 *
241 * Some examples of editor behaviors that are impacted by block limits:
242 *
243 * * Enter key never split a block-limit element;
244 * * Style application is constraint by the block limit of the current selection.
245 * * Pasted html will be inserted into the block limit of the current selection.
246 *
247 * **Note:** As an exception `<li>` is not considered as a block limit, as it's generally used as a text block.
248 */
249 $blockLimit: {
250 article: 1, aside: 1, audio: 1, body: 1, caption: 1, details: 1, dir: 1, div: 1, dl: 1,
251 fieldset: 1, figcaption: 1, figure: 1, footer: 1, form: 1, header: 1, hgroup: 1, main: 1, menu: 1, nav: 1,
252 ol: 1, section: 1, table: 1, td: 1, th: 1, tr: 1, ul: 1, video: 1
253 },
254
255 /**
256 * List of elements that contain character data.
257 */
258 $cdata: { script: 1, style: 1 },
259
260 /**
261 * List of elements that are accepted as inline editing hosts.
262 */
263 $editable: {
264 address: 1, article: 1, aside: 1, blockquote: 1, body: 1, details: 1, div: 1, fieldset: 1,
265 figcaption: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
266 main: 1, nav: 1, p: 1, pre: 1, section: 1
267 },
268
269 /**
270 * List of empty (self-closing) elements, like `<br>` or `<img>`.
271 */
272 $empty: {
273 area: 1, base: 1, basefont: 1, br: 1, col: 1, command: 1, dialog: 1, embed: 1, hr: 1, img: 1,
274 input: 1, isindex: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, track: 1, wbr: 1
275 },
276
277 /**
278 * List of inline (`<span>` like) elements.
279 */
280 $inline: P,
281
282 /**
283 * List of list root elements.
284 */
285 $list: { dl: 1, ol: 1, ul: 1 },
286
287 /**
288 * List of list item elements, like `<li>` or `<dd>`.
289 */
290 $listItem: { dd: 1, dt: 1, li: 1 },
291
292 /**
293 * List of elements which may live outside body.
294 */
295 $nonBodyContent: X( { body: 1, head: 1, html: 1 }, dtd.head ),
296
297 /**
298 * Elements that accept text nodes, but are not possible to edit into the browser.
299 */
300 $nonEditable: {
301 applet: 1, audio: 1, button: 1, embed: 1, iframe: 1, map: 1, object: 1, option: 1,
302 param: 1, script: 1, textarea: 1, video: 1
303 },
304
305 /**
306 * Elements that are considered objects, therefore selected as a whole in the editor.
307 */
308 $object: {
309 applet: 1, audio: 1, button: 1, hr: 1, iframe: 1, img: 1, input: 1, object: 1, select: 1,
310 table: 1, textarea: 1, video: 1
311 },
312
313 /**
314 * List of elements that can be ignored if empty, like `<b>` or `<span>`.
315 */
316 $removeEmpty: {
317 abbr: 1, acronym: 1, b: 1, bdi: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1,
318 em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, mark: 1, meter: 1, output: 1, q: 1, ruby: 1, s: 1,
319 samp: 1, small: 1, span: 1, strike: 1, strong: 1, sub: 1, sup: 1, time: 1, tt: 1, u: 1, 'var': 1
320 },
321
322 /**
323 * List of elements that have tabindex set to zero by default.
324 */
325 $tabIndex: { a: 1, area: 1, button: 1, input: 1, object: 1, select: 1, textarea: 1 },
326
327 /**
328 * List of elements used inside the `<table>` element, like `<tbody>` or `<td>`.
329 */
330 $tableContent: { caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1 },
331
332 /**
333 * List of "transparent" elements. See [W3C's definition of "transparent" element](http://dev.w3.org/html5/markup/terminology.html#transparent).
334 */
335 $transparent: { a: 1, audio: 1, canvas: 1, del: 1, ins: 1, map: 1, noscript: 1, object: 1, video: 1 },
336
337 /**
338 * List of elements that are not to exist standalone that must live under it's parent element.
339 */
340 $intermediate: {
341 caption: 1, colgroup: 1, dd: 1, dt: 1, figcaption: 1, legend: 1, li: 1, optgroup: 1,
342 option: 1, rp: 1, rt: 1, summary: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1
343 }
344 } );
345
346 return dtd;
347} )();
348
349// PACKAGER_RENAME( CKEDITOR.dtd )
diff --git a/sources/core/editable.js b/sources/core/editable.js
new file mode 100644
index 0000000..c50ec7f
--- /dev/null
+++ b/sources/core/editable.js
@@ -0,0 +1,3266 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var isNotWhitespace, isNotBookmark, isEmpty, isBogus, emptyParagraphRegexp,
8 insert, fixTableAfterContentsDeletion, fixListAfterContentsDelete, getHtmlFromRangeHelpers, extractHtmlFromRangeHelpers;
9
10 /**
11 * Editable class which provides all editing related activities by
12 * the `contenteditable` element, dynamically get attached to editor instance.
13 *
14 * @class CKEDITOR.editable
15 * @extends CKEDITOR.dom.element
16 */
17 CKEDITOR.editable = CKEDITOR.tools.createClass( {
18 base: CKEDITOR.dom.element,
19 /**
20 * The constructor only stores generic editable creation logic that is commonly shared among
21 * all different editable elements.
22 *
23 * @constructor Creates an editable class instance.
24 * @param {CKEDITOR.editor} editor The editor instance on which the editable operates.
25 * @param {HTMLElement/CKEDITOR.dom.element} element Any DOM element that was as the editor's
26 * editing container, e.g. it could be either an HTML element with the `contenteditable` attribute
27 * set to the `true` that handles WYSIWYG editing or a `<textarea>` element that handles source editing.
28 */
29 $: function( editor, element ) {
30 // Transform the element into a CKEDITOR.dom.element instance.
31 this.base( element.$ || element );
32
33 this.editor = editor;
34
35 /**
36 * Indicates the initialization status of the editable element. The following statuses are available:
37 *
38 * * **unloaded** &ndash; the initial state. The editable's instance was created but
39 * is not fully loaded (in particular it has no data).
40 * * **ready** &ndash; the editable is fully initialized. The `ready` status is set after
41 * the first {@link CKEDITOR.editor#method-setData} is called.
42 * * **detached** &ndash; the editable was detached.
43 *
44 * @since 4.3.3
45 * @readonly
46 * @property {String}
47 */
48 this.status = 'unloaded';
49
50 /**
51 * Indicates whether the editable element gained focus.
52 *
53 * @property {Boolean} hasFocus
54 */
55 this.hasFocus = false;
56
57 // The bootstrapping logic.
58 this.setup();
59 },
60
61 proto: {
62 focus: function() {
63
64 var active;
65
66 // [Webkit] When DOM focus is inside of nested contenteditable elements,
67 // apply focus on the main editable will compromise it's text selection.
68 if ( CKEDITOR.env.webkit && !this.hasFocus ) {
69 // Restore focus on element which we cached (on selectionCheck) as previously active.
70 active = this.editor._.previousActive || this.getDocument().getActive();
71 if ( this.contains( active ) ) {
72 active.focus();
73 return;
74 }
75 }
76
77 // [Edge] Starting from EdgeHTML 14.14393, it does not support `setActive`. We need to use focus which
78 // causes unexpected scroll. Store scrollTop value so it can be restored after focusing editor.
79 // Scroll only happens if the editor is focused for the first time. (#14825)
80 if ( CKEDITOR.env.edge && CKEDITOR.env.version > 14 && !this.hasFocus && this.getDocument().equals( CKEDITOR.document ) ) {
81 this.editor._.previousScrollTop = this.$.scrollTop;
82 }
83
84 // [IE] Use instead "setActive" method to focus the editable if it belongs to the host page document,
85 // to avoid bringing an unexpected scroll.
86 try {
87 if ( CKEDITOR.env.ie && !( CKEDITOR.env.edge && CKEDITOR.env.version > 14 ) && this.getDocument().equals( CKEDITOR.document ) ) {
88 this.$.setActive();
89 } else {
90 this.$.focus();
91 }
92 } catch ( e ) {
93 // IE throws unspecified error when focusing editable after closing dialog opened on nested editable.
94 if ( !CKEDITOR.env.ie )
95 throw e;
96 }
97
98 // Remedy if Safari doens't applies focus properly. (#279)
99 if ( CKEDITOR.env.safari && !this.isInline() ) {
100 active = CKEDITOR.document.getActive();
101 if ( !active.equals( this.getWindow().getFrame() ) )
102 this.getWindow().focus();
103
104 }
105 },
106
107 /**
108 * Overrides {@link CKEDITOR.dom.element#on} to have special `focus/blur` handling.
109 * The `focusin/focusout` events are used in IE to replace regular `focus/blur` events
110 * because we want to avoid the asynchronous nature of later ones.
111 */
112 on: function( name, fn ) {
113 var args = Array.prototype.slice.call( arguments, 0 );
114
115 if ( CKEDITOR.env.ie && ( /^focus|blur$/ ).exec( name ) ) {
116 name = name == 'focus' ? 'focusin' : 'focusout';
117
118 // The "focusin/focusout" events bubbled, e.g. If there are elements with layout
119 // they fire this event when clicking in to edit them but it must be ignored
120 // to allow edit their contents. (#4682)
121 fn = isNotBubbling( fn, this );
122 args[ 0 ] = name;
123 args[ 1 ] = fn;
124 }
125
126 return CKEDITOR.dom.element.prototype.on.apply( this, args );
127 },
128
129 /**
130 * Registers an event listener that needs to be removed when detaching this editable.
131 * This means that it will be automatically removed when {@link #detach} is executed,
132 * for example on {@link CKEDITOR.editor#setMode changing editor mode} or destroying editor.
133 *
134 * Except for `obj` all other arguments have the same meaning as in {@link CKEDITOR.event#on}.
135 *
136 * This method is strongly related to the {@link CKEDITOR.editor#contentDom} and
137 * {@link CKEDITOR.editor#contentDomUnload} events, because they are fired
138 * when an editable is being attached and detached. Therefore, this method is usually used
139 * in the following way:
140 *
141 * editor.on( 'contentDom', function() {
142 * var editable = editor.editable();
143 * editable.attachListener( editable, 'mousedown', function() {
144 * // ...
145 * } );
146 * } );
147 *
148 * This code will attach the `mousedown` listener every time a new editable is attached
149 * to the editor, which in classic (`iframe`-based) editor happens every time the
150 * data or the mode is set. This listener will also be removed when that editable is detached.
151 *
152 * It is also possible to attach a listener to another object (e.g. to a document).
153 *
154 * editor.on( 'contentDom', function() {
155 * editor.editable().attachListener( editor.document, 'mousedown', function() {
156 * // ...
157 * } );
158 * } );
159 *
160 * @param {CKEDITOR.event} obj The element/object to which the listener will be attached. Every object
161 * which inherits from {@link CKEDITOR.event} may be used including {@link CKEDITOR.dom.element},
162 * {@link CKEDITOR.dom.document}, and {@link CKEDITOR.editable}.
163 * @param {String} eventName The name of the event that will be listened to.
164 * @param {Function} listenerFunction The function listening to the
165 * event. A single {@link CKEDITOR.eventInfo} object instance
166 * containing all the event data is passed to this function.
167 * @param {Object} [scopeObj] The object used to scope the listener
168 * call (the `this` object). If omitted, the current object is used.
169 * @param {Object} [listenerData] Data to be sent as the
170 * {@link CKEDITOR.eventInfo#listenerData} when calling the listener.
171 * @param {Number} [priority=10] The listener priority. Lower priority
172 * listeners are called first. Listeners with the same priority
173 * value are called in the registration order.
174 * @returns {Object} An object containing the `removeListener`
175 * function that can be used to remove the listener at any time.
176 */
177 attachListener: function( obj /*, event, fn, scope, listenerData, priority*/ ) {
178 !this._.listeners && ( this._.listeners = [] );
179 // Register the listener.
180 var args = Array.prototype.slice.call( arguments, 1 ),
181 listener = obj.on.apply( obj, args );
182
183 this._.listeners.push( listener );
184
185 return listener;
186 },
187
188 /**
189 * Remove all event listeners registered from {@link #attachListener}.
190 */
191 clearListeners: function() {
192 var listeners = this._.listeners;
193 // Don't get broken by this.
194 try {
195 while ( listeners.length )
196 listeners.pop().removeListener();
197 } catch ( e ) {}
198 },
199
200 /**
201 * Restore all attribution changes made by {@link #changeAttr }.
202 */
203 restoreAttrs: function() {
204 var changes = this._.attrChanges, orgVal;
205 for ( var attr in changes ) {
206 if ( changes.hasOwnProperty( attr ) ) {
207 orgVal = changes[ attr ];
208 // Restore original attribute.
209 orgVal !== null ? this.setAttribute( attr, orgVal ) : this.removeAttribute( attr );
210 }
211 }
212 },
213
214 /**
215 * Adds a CSS class name to this editable that needs to be removed on detaching.
216 *
217 * @param {String} className The class name to be added.
218 * @see CKEDITOR.dom.element#addClass
219 */
220 attachClass: function( cls ) {
221 var classes = this.getCustomData( 'classes' );
222 if ( !this.hasClass( cls ) ) {
223 !classes && ( classes = [] ), classes.push( cls );
224 this.setCustomData( 'classes', classes );
225 this.addClass( cls );
226 }
227 },
228
229 /**
230 * Make an attribution change that would be reverted on editable detaching.
231 * @param {String} attr The attribute name to be changed.
232 * @param {String} val The value of specified attribute.
233 */
234 changeAttr: function( attr, val ) {
235 var orgVal = this.getAttribute( attr );
236 if ( val !== orgVal ) {
237 !this._.attrChanges && ( this._.attrChanges = {} );
238
239 // Saved the original attribute val.
240 if ( !( attr in this._.attrChanges ) )
241 this._.attrChanges[ attr ] = orgVal;
242
243 this.setAttribute( attr, val );
244 }
245 },
246
247 /**
248 * Low-level method for inserting text into the editable.
249 * See the {@link CKEDITOR.editor#method-insertText} method which is the editor-level API
250 * for this purpose.
251 *
252 * @param {String} text
253 */
254 insertText: function( text ) {
255 // Focus the editor before calling transformPlainTextToHtml. (#12726)
256 this.editor.focus();
257 this.insertHtml( this.transformPlainTextToHtml( text ), 'text' );
258 },
259
260 /**
261 * Transforms plain text to HTML based on current selection and {@link CKEDITOR.editor#activeEnterMode}.
262 *
263 * @since 4.5
264 * @param {String} text Text to transform.
265 * @returns {String} HTML generated from the text.
266 */
267 transformPlainTextToHtml: function( text ) {
268 var enterMode = this.editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ?
269 CKEDITOR.ENTER_BR :
270 this.editor.activeEnterMode;
271
272 return CKEDITOR.tools.transformPlainTextToHtml( text, enterMode );
273 },
274
275 /**
276 * Low-level method for inserting HTML into the editable.
277 * See the {@link CKEDITOR.editor#method-insertHtml} method which is the editor-level API
278 * for this purpose.
279 *
280 * This method will insert HTML into the current selection or a given range. It also creates an undo snapshot,
281 * scrolls the viewport to the insertion and selects the range next to the inserted content.
282 * If you want to insert HTML without additional operations use {@link #method-insertHtmlIntoRange}.
283 *
284 * Fires the {@link CKEDITOR.editor#event-afterInsertHtml} event.
285 *
286 * @param {String} data The HTML to be inserted.
287 * @param {String} [mode='html'] See {@link CKEDITOR.editor#method-insertHtml}'s param.
288 * @param {CKEDITOR.dom.range} [range] If specified, the HTML will be inserted into the range
289 * instead of into the selection. The selection will be placed at the end of the insertion (like in the normal case).
290 * Introduced in CKEditor 4.5.
291 */
292 insertHtml: function( data, mode, range ) {
293 var editor = this.editor;
294
295 editor.focus();
296 editor.fire( 'saveSnapshot' );
297
298 if ( !range ) {
299 // HTML insertion only considers the first range.
300 // Note: getRanges will be overwritten for tests since we want to test
301 // custom ranges and bypass native selections.
302 range = editor.getSelection().getRanges()[ 0 ];
303 }
304
305 // Default mode is 'html'.
306 insert( this, mode || 'html', data, range );
307
308 // Make the final range selection.
309 range.select();
310
311 afterInsert( this );
312
313 this.editor.fire( 'afterInsertHtml', {} );
314 },
315
316 /**
317 * Inserts HTML into the position in the editor determined by the range.
318 *
319 * **Note:** This method does not {@link CKEDITOR.editor#saveSnapshot save undo snapshots} nor selects inserted
320 * HTML. If you want to do it, use {@link #method-insertHtml}.
321 *
322 * Fires the {@link CKEDITOR.editor#event-afterInsertHtml} event.
323 *
324 * @since 4.5
325 * @param {String} data HTML code to be inserted into the editor.
326 * @param {CKEDITOR.dom.range} range The range as a place of insertion.
327 * @param {String} [mode='html'] Mode in which HTML will be inserted.
328 * See {@link CKEDITOR.editor#method-insertHtml}.
329 */
330 insertHtmlIntoRange: function( data, range, mode ) {
331 // Default mode is 'html'
332 insert( this, mode || 'html', data, range );
333
334 this.editor.fire( 'afterInsertHtml', { intoRange: range } );
335 },
336
337 /**
338 * Low-level method for inserting an element into the editable.
339 * See the {@link CKEDITOR.editor#method-insertElement} method which is the editor-level API
340 * for this purpose.
341 *
342 * This method will insert the element into the current selection or a given range. It also creates an undo
343 * snapshot, scrolls the viewport to the insertion and selects the range next to the inserted content.
344 * If you want to insert an element without additional operations use {@link #method-insertElementIntoRange}.
345 *
346 * @param {CKEDITOR.dom.element} element The element to insert.
347 * @param {CKEDITOR.dom.range} [range] If specified, the element will be inserted into the range
348 * instead of into the selection.
349 */
350 insertElement: function( element, range ) {
351 var editor = this.editor;
352
353 // Prepare for the insertion. For example - focus editor (#11848).
354 editor.focus();
355 editor.fire( 'saveSnapshot' );
356
357 var enterMode = editor.activeEnterMode,
358 selection = editor.getSelection(),
359 elementName = element.getName(),
360 isBlock = CKEDITOR.dtd.$block[ elementName ];
361
362 if ( !range ) {
363 range = selection.getRanges()[ 0 ];
364 }
365
366 // Insert element into first range only and ignore the rest (#11183).
367 if ( this.insertElementIntoRange( element, range ) ) {
368 range.moveToPosition( element, CKEDITOR.POSITION_AFTER_END );
369
370 // If we're inserting a block element, the new cursor position must be
371 // optimized. (#3100,#5436,#8950)
372 if ( isBlock ) {
373 // Find next, meaningful element.
374 var next = element.getNext( function( node ) {
375 return isNotEmpty( node ) && !isBogus( node );
376 } );
377
378 if ( next && next.type == CKEDITOR.NODE_ELEMENT && next.is( CKEDITOR.dtd.$block ) ) {
379 // If the next one is a text block, move cursor to the start of it's content.
380 if ( next.getDtd()[ '#' ] )
381 range.moveToElementEditStart( next );
382 // Otherwise move cursor to the before end of the last element.
383 else
384 range.moveToElementEditEnd( element );
385 }
386 // Open a new line if the block is inserted at the end of parent.
387 else if ( !next && enterMode != CKEDITOR.ENTER_BR ) {
388 next = range.fixBlock( true, enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
389 range.moveToElementEditStart( next );
390 }
391 }
392 }
393
394 // Set up the correct selection.
395 selection.selectRanges( [ range ] );
396
397 afterInsert( this );
398 },
399
400 /**
401 * Alias for {@link #insertElement}.
402 *
403 * @deprecated
404 * @param {CKEDITOR.dom.element} element The element to be inserted.
405 */
406 insertElementIntoSelection: function( element ) {
407 this.insertElement( element );
408 },
409
410 /**
411 * Inserts an element into the position in the editor determined by the range.
412 *
413 * **Note:** This method does not {@link CKEDITOR.editor#saveSnapshot save undo snapshots} nor selects the inserted
414 * element. If you want to do it, use the {@link #method-insertElement} method.
415 *
416 * @param {CKEDITOR.dom.element} element The element to be inserted.
417 * @param {CKEDITOR.dom.range} range The range as a place of insertion.
418 * @returns {Boolean} Informs whether the insertion was successful.
419 */
420 insertElementIntoRange: function( element, range ) {
421 var editor = this.editor,
422 enterMode = editor.config.enterMode,
423 elementName = element.getName(),
424 isBlock = CKEDITOR.dtd.$block[ elementName ];
425
426 if ( range.checkReadOnly() )
427 return false;
428
429 // Remove the original contents, merge split nodes.
430 range.deleteContents( 1 );
431
432 if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT ) {
433 // If range is placed in intermediate element (not td or th), we need to do three things:
434 // * fill emptied <td/th>s with if browser needs them,
435 // * remove empty text nodes so IE8 won't crash
436 // (http://dev.ckeditor.com/ticket/11183#comment:8),
437 // * fix structure and move range into the <td/th> element.
438 if ( range.startContainer.is( { tr: 1, table: 1, tbody: 1, thead: 1, tfoot: 1 } ) ) {
439 fixTableAfterContentsDeletion( range );
440 } else if ( range.startContainer.is( CKEDITOR.dtd.$list ) ) {
441 // Similarly there's a need for lists.
442 fixListAfterContentsDelete( range );
443 }
444 }
445
446 // If we're inserting a block at dtd-violated position, split
447 // the parent blocks until we reach blockLimit.
448 var current, dtd;
449
450 if ( isBlock ) {
451 while ( ( current = range.getCommonAncestor( 0, 1 ) ) &&
452 ( dtd = CKEDITOR.dtd[ current.getName() ] ) &&
453 !( dtd && dtd[ elementName ] ) ) {
454 // Split up inline elements.
455 if ( current.getName() in CKEDITOR.dtd.span )
456 range.splitElement( current );
457
458 // If we're in an empty block which indicate a new paragraph,
459 // simply replace it with the inserting block.(#3664)
460 else if ( range.checkStartOfBlock() && range.checkEndOfBlock() ) {
461 range.setStartBefore( current );
462 range.collapse( true );
463 current.remove();
464 } else {
465 range.splitBlock( enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p', editor.editable() );
466 }
467 }
468 }
469
470 // Insert the new node.
471 range.insertNode( element );
472
473 // Return true if insertion was successful.
474 return true;
475 },
476
477 /**
478 * @see CKEDITOR.editor#setData
479 */
480 setData: function( data, isSnapshot ) {
481 if ( !isSnapshot )
482 data = this.editor.dataProcessor.toHtml( data );
483
484 this.setHtml( data );
485 this.fixInitialSelection();
486
487 // Editable is ready after first setData.
488 if ( this.status == 'unloaded' )
489 this.status = 'ready';
490
491 this.editor.fire( 'dataReady' );
492 },
493
494 /**
495 * @see CKEDITOR.editor#getData
496 */
497 getData: function( isSnapshot ) {
498 var data = this.getHtml();
499
500 if ( !isSnapshot )
501 data = this.editor.dataProcessor.toDataFormat( data );
502
503 return data;
504 },
505
506 /**
507 * Changes the read-only state of this editable.
508 *
509 * @param {Boolean} isReadOnly
510 */
511 setReadOnly: function( isReadOnly ) {
512 this.setAttribute( 'contenteditable', !isReadOnly );
513 },
514
515 /**
516 * Detaches this editable object from the DOM (removes classes, listeners, etc.)
517 */
518 detach: function() {
519 // Cleanup the element.
520 this.removeClass( 'cke_editable' );
521
522 this.status = 'detached';
523
524 // Save the editor reference which will be lost after
525 // calling detach from super class.
526 var editor = this.editor;
527
528 this._.detach();
529
530 delete editor.document;
531 delete editor.window;
532 },
533
534 /**
535 * Checks if the editable is one of the host page elements, indicates
536 * an inline editing environment.
537 *
538 * @returns {Boolean}
539 */
540 isInline: function() {
541 return this.getDocument().equals( CKEDITOR.document );
542 },
543
544 /**
545 * Fixes the selection and focus which may be in incorrect state after
546 * editable's inner HTML was overwritten.
547 *
548 * If the editable did not have focus, then the selection will be fixed when the editable
549 * is focused for the first time. If the editable already had focus, then the selection will
550 * be fixed immediately.
551 *
552 * To understand the problem see:
553 *
554 * * http://tests.ckeditor.dev:1030/tests/core/selection/manual/focusaftersettingdata
555 * * http://tests.ckeditor.dev:1030/tests/core/selection/manual/focusafterundoing
556 * * http://tests.ckeditor.dev:1030/tests/core/selection/manual/selectionafterfocusing
557 * * http://tests.ckeditor.dev:1030/tests/plugins/newpage/manual/selectionafternewpage
558 *
559 * @since 4.4.6
560 * @private
561 */
562 fixInitialSelection: function() {
563 var that = this;
564
565 // Deal with IE8- IEQM (the old MS selection) first.
566 if ( CKEDITOR.env.ie && ( CKEDITOR.env.version < 9 || CKEDITOR.env.quirks ) ) {
567 if ( this.hasFocus ) {
568 this.focus();
569 fixMSSelection();
570 }
571
572 return;
573 }
574
575 // If editable did not have focus, fix the selection when it is first focused.
576 if ( !this.hasFocus ) {
577 this.once( 'focus', function() {
578 fixSelection();
579 }, null, null, -999 );
580 // If editable had focus, fix the selection immediately.
581 } else {
582 this.focus();
583 fixSelection();
584 }
585
586 function fixSelection() {
587 var $doc = that.getDocument().$,
588 $sel = $doc.getSelection();
589
590 if ( requiresFix( $sel ) ) {
591 var range = new CKEDITOR.dom.range( that );
592 range.moveToElementEditStart( that );
593
594 var $range = $doc.createRange();
595 $range.setStart( range.startContainer.$, range.startOffset );
596 $range.collapse( true );
597
598 $sel.removeAllRanges();
599 $sel.addRange( $range );
600 }
601 }
602
603 function requiresFix( $sel ) {
604 // This condition covers most broken cases after setting data.
605 if ( $sel.anchorNode && $sel.anchorNode == that.$ ) {
606 return true;
607 }
608
609 // Fix for:
610 // http://tests.ckeditor.dev:1030/tests/core/selection/manual/focusaftersettingdata
611 // (the inline editor TC)
612 if ( CKEDITOR.env.webkit ) {
613 var active = that.getDocument().getActive();
614 if ( active && active.equals( that ) && !$sel.anchorNode ) {
615 return true;
616 }
617 }
618 }
619
620 function fixMSSelection() {
621 var $doc = that.getDocument().$,
622 $sel = $doc.selection,
623 active = that.getDocument().getActive();
624
625 if ( $sel.type == 'None' && active.equals( that ) ) {
626 var range = new CKEDITOR.dom.range( that ),
627 parentElement,
628 $range = $doc.body.createTextRange();
629
630 range.moveToElementEditStart( that );
631
632 parentElement = range.startContainer;
633 if ( parentElement.type != CKEDITOR.NODE_ELEMENT ) {
634 parentElement = parentElement.getParent();
635 }
636
637 $range.moveToElementText( parentElement.$ );
638 $range.collapse( true );
639 $range.select();
640 }
641 }
642 },
643
644 /**
645 * The base of the {@link CKEDITOR.editor#getSelectedHtml} method.
646 *
647 * @since 4.5
648 * @method getHtmlFromRange
649 * @param {CKEDITOR.dom.range} range
650 * @returns {CKEDITOR.dom.documentFragment}
651 */
652 getHtmlFromRange: function( range ) {
653 // There's nothing to return if range is collapsed.
654 if ( range.collapsed )
655 return new CKEDITOR.dom.documentFragment( range.document );
656
657 // Info object passed between methods.
658 var that = {
659 doc: this.getDocument(),
660 // Leave original range object untouched.
661 range: range.clone()
662 };
663
664 getHtmlFromRangeHelpers.eol.detect( that, this );
665 getHtmlFromRangeHelpers.bogus.exclude( that );
666 getHtmlFromRangeHelpers.cell.shrink( that );
667
668 that.fragment = that.range.cloneContents();
669
670 getHtmlFromRangeHelpers.tree.rebuild( that, this );
671 getHtmlFromRangeHelpers.eol.fix( that, this );
672
673 return new CKEDITOR.dom.documentFragment( that.fragment.$ );
674 },
675
676 /**
677 * The base of the {@link CKEDITOR.editor#extractSelectedHtml} method.
678 *
679 * **Note:** The range is modified so it matches the desired selection after extraction
680 * even though the selection is not made.
681 *
682 * @since 4.5
683 * @param {CKEDITOR.dom.range} range
684 * @param {Boolean} [removeEmptyBlock=false] See {@link CKEDITOR.editor#extractSelectedHtml}'s parameter.
685 * Note that the range will not be modified if this parameter is set to `true`.
686 * @returns {CKEDITOR.dom.documentFragment} The extracted fragment of the editable content.
687 */
688 extractHtmlFromRange: function( range, removeEmptyBlock ) {
689 var helpers = extractHtmlFromRangeHelpers,
690 that = {
691 range: range,
692 doc: range.document
693 },
694 // Since it is quite hard to build a valid documentFragment
695 // out of extracted contents because DOM changes, let's mimic
696 // extracted HTML with #getHtmlFromRange. Yep. It's a hack.
697 extractedFragment = this.getHtmlFromRange( range );
698
699 // Collapsed range means that there's nothing to extract.
700 if ( range.collapsed ) {
701 range.optimize();
702 return extractedFragment;
703 }
704
705 // Include inline element if possible.
706 range.enlarge( CKEDITOR.ENLARGE_INLINE, 1 );
707
708 // This got to be done before bookmarks are created because purging
709 // depends on the position of the range at the boundaries of the table,
710 // usually distorted by bookmark spans.
711 helpers.table.detectPurge( that );
712
713 // We'll play with DOM, let's hold the position of the range.
714 that.bookmark = range.createBookmark();
715 // While bookmarked, make unaccessible, to make sure that none of the methods
716 // will try to use it (they should use that.bookmark).
717 // This is done because ranges get desynchronized with the DOM when more bookmarks
718 // is created (as for instance that.targetBookmark).
719 delete that.range;
720
721 // The range to be restored after extraction should be kept
722 // outside of the range, so it's not removed by range.extractContents.
723 var targetRange = this.editor.createRange();
724 targetRange.moveToPosition( that.bookmark.startNode, CKEDITOR.POSITION_BEFORE_START );
725 that.targetBookmark = targetRange.createBookmark();
726
727 // Execute content-specific detections.
728 helpers.list.detectMerge( that, this );
729 helpers.table.detectRanges( that, this );
730 helpers.block.detectMerge( that, this );
731
732 // Simply, do the job.
733 if ( that.tableContentsRanges ) {
734 helpers.table.deleteRanges( that );
735
736 // Done here only to remove bookmark's spans.
737 range.moveToBookmark( that.bookmark );
738 that.range = range;
739 } else {
740 // To use the range we need to restore the bookmark and make
741 // the range accessible again.
742 range.moveToBookmark( that.bookmark );
743 that.range = range;
744 range.extractContents( helpers.detectExtractMerge( that ) );
745 }
746
747 // Move working range to desired, pre-computed position.
748 range.moveToBookmark( that.targetBookmark );
749
750 // Make sure range is always anchored in an element. For consistency.
751 range.optimize();
752
753 // It my happen that the uncollapsed range which referred to a valid selection,
754 // will be placed in an uneditable location after being collapsed:
755 // <tr>[<td>x</td>]</tr> -> <tr>[]<td>x</td></tr> -> <tr><td>[]x</td></tr>
756 helpers.fixUneditableRangePosition( range );
757
758 // Execute content-specific post-extract routines.
759 helpers.list.merge( that, this );
760 helpers.table.purge( that, this );
761 helpers.block.merge( that, this );
762
763 // Remove empty block, duh!
764 if ( removeEmptyBlock ) {
765 var path = range.startPath();
766
767 // <p><b>^</b></p> is empty block.
768 if (
769 range.checkStartOfBlock() &&
770 range.checkEndOfBlock() &&
771 path.block &&
772 !range.root.equals( path.block ) &&
773 // Do not remove a block with bookmarks. (#13465)
774 !hasBookmarks( path.block ) ) {
775 range.moveToPosition( path.block, CKEDITOR.POSITION_BEFORE_START );
776 path.block.remove();
777 }
778 } else {
779 // Auto paragraph, if needed.
780 helpers.autoParagraph( this.editor, range );
781
782 // Let's have a bogus next to the caret, if needed.
783 if ( isEmpty( range.startContainer ) )
784 range.startContainer.appendBogus();
785 }
786
787 // Merge inline siblings if any around the caret.
788 range.startContainer.mergeSiblings();
789
790 return extractedFragment;
791 },
792
793 /**
794 * Editable element bootstrapping.
795 *
796 * @private
797 */
798 setup: function() {
799 var editor = this.editor;
800
801 // Handle the load/read of editor data/snapshot.
802 this.attachListener( editor, 'beforeGetData', function() {
803 var data = this.getData();
804
805 // Post processing html output of wysiwyg editable.
806 if ( !this.is( 'textarea' ) ) {
807 // Reset empty if the document contains only one empty paragraph.
808 if ( editor.config.ignoreEmptyParagraph !== false )
809 data = data.replace( emptyParagraphRegexp, function( match, lookback ) {
810 return lookback;
811 } );
812 }
813
814 editor.setData( data, null, 1 );
815 }, this );
816
817 this.attachListener( editor, 'getSnapshot', function( evt ) {
818 evt.data = this.getData( 1 );
819 }, this );
820
821 this.attachListener( editor, 'afterSetData', function() {
822 this.setData( editor.getData( 1 ) );
823 }, this );
824 this.attachListener( editor, 'loadSnapshot', function( evt ) {
825 this.setData( evt.data, 1 );
826 }, this );
827
828 // Delegate editor focus/blur to editable.
829 this.attachListener( editor, 'beforeFocus', function() {
830 var sel = editor.getSelection(),
831 ieSel = sel && sel.getNative();
832
833 // IE considers control-type element as separate
834 // focus host when selected, avoid destroying the
835 // selection in such case. (#5812) (#8949)
836 if ( ieSel && ieSel.type == 'Control' )
837 return;
838
839 this.focus();
840 }, this );
841
842 this.attachListener( editor, 'insertHtml', function( evt ) {
843 this.insertHtml( evt.data.dataValue, evt.data.mode, evt.data.range );
844 }, this );
845 this.attachListener( editor, 'insertElement', function( evt ) {
846 this.insertElement( evt.data );
847 }, this );
848 this.attachListener( editor, 'insertText', function( evt ) {
849 this.insertText( evt.data );
850 }, this );
851
852 // Update editable state.
853 this.setReadOnly( editor.readOnly );
854
855 // The editable class.
856 this.attachClass( 'cke_editable' );
857
858 // The element mode css class.
859 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ) {
860 this.attachClass( 'cke_editable_inline' );
861 } else if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ||
862 editor.elementMode == CKEDITOR.ELEMENT_MODE_APPENDTO ) {
863 this.attachClass( 'cke_editable_themed' );
864 }
865
866 this.attachClass( 'cke_contents_' + editor.config.contentsLangDirection );
867
868 // Setup editor keystroke handlers on this element.
869 var keystrokeHandler = editor.keystrokeHandler;
870
871 // If editor is read-only, then make sure that BACKSPACE key
872 // is blocked to prevent browser history navigation.
873 keystrokeHandler.blockedKeystrokes[ 8 ] = +editor.readOnly;
874
875 editor.keystrokeHandler.attach( this );
876
877 // Update focus states.
878 this.on( 'blur', function() {
879 this.hasFocus = false;
880 }, null, null, -1 );
881
882 this.on( 'focus', function() {
883 this.hasFocus = true;
884 }, null, null, -1 );
885
886 if ( CKEDITOR.env.webkit ) {
887 // [WebKit] Save scrollTop value so it can be used when restoring locked selection. (#14659)
888 this.on( 'scroll', function() {
889 editor._.previousScrollTop = editor.editable().$.scrollTop;
890 }, null, null, -1 );
891 }
892
893 // [Edge] This is the other part of the workaround for Edge which restores saved
894 // scrollTop value and removes listener which is not needed anymore. (#14825)
895 if ( CKEDITOR.env.edge && CKEDITOR.env.version > 14 ) {
896
897 var fixScrollOnFocus = function() {
898 var editable = editor.editable();
899
900 if ( editor._.previousScrollTop != null && editable.getDocument().equals( CKEDITOR.document ) ) {
901 editable.$.scrollTop = editor._.previousScrollTop;
902 editor._.previousScrollTop = null;
903 this.removeListener( 'scroll', fixScrollOnFocus );
904 }
905 };
906
907 this.on( 'scroll', fixScrollOnFocus );
908 }
909
910 // Register to focus manager.
911 editor.focusManager.add( this );
912
913 // Inherit the initial focus on editable element.
914 if ( this.equals( CKEDITOR.document.getActive() ) ) {
915 this.hasFocus = true;
916 // Pending until this editable has attached.
917 editor.once( 'contentDom', function() {
918 editor.focusManager.focus( this );
919 }, this );
920 }
921
922 // Apply tab index on demand, with original direction saved.
923 if ( this.isInline() ) {
924
925 // tabIndex of the editable is different than editor's one.
926 // Update the attribute of the editable.
927 this.changeAttr( 'tabindex', editor.tabIndex );
928 }
929
930 // The above is all we'll be doing for a <textarea> editable.
931 if ( this.is( 'textarea' ) )
932 return;
933
934 // The DOM document which the editing acts upon.
935 editor.document = this.getDocument();
936 editor.window = this.getWindow();
937
938 var doc = editor.document;
939
940 this.changeAttr( 'spellcheck', !editor.config.disableNativeSpellChecker );
941
942 // Apply contents direction on demand, with original direction saved.
943 var dir = editor.config.contentsLangDirection;
944 if ( this.getDirection( 1 ) != dir )
945 this.changeAttr( 'dir', dir );
946
947 // Create the content stylesheet for this document.
948 var styles = CKEDITOR.getCss();
949 if ( styles ) {
950 var head = doc.getHead(),
951 stylesElement = head.getCustomData( 'stylesheet' );
952
953 if ( !stylesElement ) {
954 var sheet = doc.appendStyleText( styles );
955 sheet = new CKEDITOR.dom.element( sheet.ownerNode || sheet.owningElement );
956 head.setCustomData( 'stylesheet', sheet );
957 sheet.data( 'cke-temp', 1 );
958 } else if ( styles != stylesElement.getText() ) {
959 CKEDITOR.env.ie && CKEDITOR.env.version < 9 ? stylesElement.$.styleSheet.cssText = styles : stylesElement.setText( styles );
960 }
961 }
962
963 // Update the stylesheet sharing count.
964 var ref = doc.getCustomData( 'stylesheet_ref' ) || 0;
965 doc.setCustomData( 'stylesheet_ref', ref + 1 );
966
967 // Pass this configuration to styles system.
968 this.setCustomData( 'cke_includeReadonly', !editor.config.disableReadonlyStyling );
969
970 // Prevent the browser opening read-only links. (#6032 & #10912)
971 this.attachListener( this, 'click', function( evt ) {
972 evt = evt.data;
973
974 var link = new CKEDITOR.dom.elementPath( evt.getTarget(), this ).contains( 'a' );
975
976 if ( link && evt.$.button != 2 && link.isReadOnly() )
977 evt.preventDefault();
978 } );
979
980 var backspaceOrDelete = { 8: 1, 46: 1 };
981
982 // Override keystrokes which should have deletion behavior
983 // on fully selected element . (#4047) (#7645)
984 this.attachListener( editor, 'key', function( evt ) {
985 if ( editor.readOnly )
986 return true;
987
988 // Use getKey directly in order to ignore modifiers.
989 // Justification: http://dev.ckeditor.com/ticket/11861#comment:13
990 var keyCode = evt.data.domEvent.getKey(),
991 isHandled;
992
993 // Backspace OR Delete.
994 if ( keyCode in backspaceOrDelete ) {
995 var sel = editor.getSelection(),
996 selected,
997 range = sel.getRanges()[ 0 ],
998 path = range.startPath(),
999 block,
1000 parent,
1001 next,
1002 rtl = keyCode == 8;
1003
1004 if (
1005 // [IE<11] Remove selected image/anchor/etc here to avoid going back in history. (#10055)
1006 ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 && ( selected = sel.getSelectedElement() ) ) ||
1007 // Remove the entire list/table on fully selected content. (#7645)
1008 ( selected = getSelectedTableList( sel ) ) ) {
1009 // Make undo snapshot.
1010 editor.fire( 'saveSnapshot' );
1011
1012 // Delete any element that 'hasLayout' (e.g. hr,table) in IE8 will
1013 // break up the selection, safely manage it here. (#4795)
1014 range.moveToPosition( selected, CKEDITOR.POSITION_BEFORE_START );
1015 // Remove the control manually.
1016 selected.remove();
1017 range.select();
1018
1019 editor.fire( 'saveSnapshot' );
1020
1021 isHandled = 1;
1022 } else if ( range.collapsed ) {
1023 // Handle the following special cases: (#6217)
1024 // 1. Del/Backspace key before/after table;
1025 // 2. Backspace Key after start of table.
1026 if ( ( block = path.block ) &&
1027 ( next = block[ rtl ? 'getPrevious' : 'getNext' ]( isNotWhitespace ) ) &&
1028 ( next.type == CKEDITOR.NODE_ELEMENT ) &&
1029 next.is( 'table' ) &&
1030 range[ rtl ? 'checkStartOfBlock' : 'checkEndOfBlock' ]() ) {
1031 editor.fire( 'saveSnapshot' );
1032
1033 // Remove the current empty block.
1034 if ( range[ rtl ? 'checkEndOfBlock' : 'checkStartOfBlock' ]() )
1035 block.remove();
1036
1037 // Move cursor to the beginning/end of table cell.
1038 range[ 'moveToElementEdit' + ( rtl ? 'End' : 'Start' ) ]( next );
1039 range.select();
1040
1041 editor.fire( 'saveSnapshot' );
1042
1043 isHandled = 1;
1044 }
1045 else if ( path.blockLimit && path.blockLimit.is( 'td' ) &&
1046 ( parent = path.blockLimit.getAscendant( 'table' ) ) &&
1047 range.checkBoundaryOfElement( parent, rtl ? CKEDITOR.START : CKEDITOR.END ) &&
1048 ( next = parent[ rtl ? 'getPrevious' : 'getNext' ]( isNotWhitespace ) ) ) {
1049 editor.fire( 'saveSnapshot' );
1050
1051 // Move cursor to the end of previous block.
1052 range[ 'moveToElementEdit' + ( rtl ? 'End' : 'Start' ) ]( next );
1053
1054 // Remove any previous empty block.
1055 if ( range.checkStartOfBlock() && range.checkEndOfBlock() )
1056 next.remove();
1057 else
1058 range.select();
1059
1060 editor.fire( 'saveSnapshot' );
1061
1062 isHandled = 1;
1063 }
1064 // BACKSPACE/DEL pressed at the start/end of table cell.
1065 else if ( ( parent = path.contains( [ 'td', 'th', 'caption' ] ) ) &&
1066 range.checkBoundaryOfElement( parent, rtl ? CKEDITOR.START : CKEDITOR.END ) ) {
1067 isHandled = 1;
1068 }
1069 }
1070
1071 }
1072
1073 return !isHandled;
1074 } );
1075
1076 // On IE>=11 we need to fill blockless editable with <br> if it was deleted.
1077 if ( editor.blockless && CKEDITOR.env.ie && CKEDITOR.env.needsBrFiller ) {
1078 this.attachListener( this, 'keyup', function( evt ) {
1079 if ( evt.data.getKeystroke() in backspaceOrDelete && !this.getFirst( isNotEmpty ) ) {
1080 this.appendBogus();
1081
1082 // Set the selection before bogus, because IE tends to put it after.
1083 var range = editor.createRange();
1084 range.moveToPosition( this, CKEDITOR.POSITION_AFTER_START );
1085 range.select();
1086 }
1087 } );
1088 }
1089
1090 this.attachListener( this, 'dblclick', function( evt ) {
1091 if ( editor.readOnly )
1092 return false;
1093
1094 var data = { element: evt.data.getTarget() };
1095 editor.fire( 'doubleclick', data );
1096 } );
1097
1098 // Prevent automatic submission in IE #6336
1099 CKEDITOR.env.ie && this.attachListener( this, 'click', blockInputClick );
1100
1101 // Gecko/Webkit need some help when selecting control type elements. (#3448)
1102 // We apply same behavior for IE Edge. (#13386)
1103 if ( !CKEDITOR.env.ie || CKEDITOR.env.edge ) {
1104 this.attachListener( this, 'mousedown', function( ev ) {
1105 var control = ev.data.getTarget();
1106 // #11727. Note: htmlDP assures that input/textarea/select have contenteditable=false
1107 // attributes. However, they also have data-cke-editable attribute, so isReadOnly() returns false,
1108 // and therefore those elements are correctly selected by this code.
1109 if ( control.is( 'img', 'hr', 'input', 'textarea', 'select' ) && !control.isReadOnly() ) {
1110 editor.getSelection().selectElement( control );
1111
1112 // Prevent focus from stealing from the editable. (#9515)
1113 if ( control.is( 'input', 'textarea', 'select' ) )
1114 ev.data.preventDefault();
1115 }
1116 } );
1117 }
1118
1119 // For some reason, after click event is done, IE Edge loses focus on the selected element. (#13386)
1120 if ( CKEDITOR.env.edge ) {
1121 this.attachListener( this, 'mouseup', function( ev ) {
1122 var selectedElement = ev.data.getTarget();
1123 if ( selectedElement && selectedElement.is( 'img' ) ) {
1124 editor.getSelection().selectElement( selectedElement );
1125 }
1126 } );
1127 }
1128
1129 // Prevent right click from selecting an empty block even
1130 // when selection is anchored inside it. (#5845)
1131 if ( CKEDITOR.env.gecko ) {
1132 this.attachListener( this, 'mouseup', function( ev ) {
1133 if ( ev.data.$.button == 2 ) {
1134 var target = ev.data.getTarget();
1135
1136 if ( !target.getOuterHtml().replace( emptyParagraphRegexp, '' ) ) {
1137 var range = editor.createRange();
1138 range.moveToElementEditStart( target );
1139 range.select( true );
1140 }
1141 }
1142 } );
1143 }
1144
1145 // Webkit: avoid from editing form control elements content.
1146 if ( CKEDITOR.env.webkit ) {
1147 // Prevent from tick checkbox/radiobox/select
1148 this.attachListener( this, 'click', function( ev ) {
1149 if ( ev.data.getTarget().is( 'input', 'select' ) )
1150 ev.data.preventDefault();
1151 } );
1152
1153 // Prevent from editig textfield/textarea value.
1154 this.attachListener( this, 'mouseup', function( ev ) {
1155 if ( ev.data.getTarget().is( 'input', 'textarea' ) )
1156 ev.data.preventDefault();
1157 } );
1158 }
1159
1160 // Prevent Webkit/Blink from going rogue when joining
1161 // blocks on BACKSPACE/DEL (#11861,#9998).
1162 if ( CKEDITOR.env.webkit ) {
1163 this.attachListener( editor, 'key', function( evt ) {
1164 if ( editor.readOnly ) {
1165 return true;
1166 }
1167
1168 // Use getKey directly in order to ignore modifiers.
1169 // Justification: http://dev.ckeditor.com/ticket/11861#comment:13
1170 var key = evt.data.domEvent.getKey();
1171
1172 if ( !( key in backspaceOrDelete ) )
1173 return;
1174
1175 var backspace = key == 8,
1176 range = editor.getSelection().getRanges()[ 0 ],
1177 startPath = range.startPath();
1178
1179 if ( range.collapsed ) {
1180 if ( !mergeBlocksCollapsedSelection( editor, range, backspace, startPath ) )
1181 return;
1182 } else {
1183 if ( !mergeBlocksNonCollapsedSelection( editor, range, startPath ) )
1184 return;
1185 }
1186
1187 // Scroll to the new position of the caret (#11960).
1188 editor.getSelection().scrollIntoView();
1189 editor.fire( 'saveSnapshot' );
1190
1191 return false;
1192 }, this, null, 100 ); // Later is better – do not override existing listeners.
1193 }
1194 }
1195 },
1196
1197 _: {
1198 detach: function() {
1199 // Update the editor cached data with current data.
1200 this.editor.setData( this.editor.getData(), 0, 1 );
1201
1202 this.clearListeners();
1203 this.restoreAttrs();
1204
1205 // Cleanup our custom classes.
1206 var classes;
1207 if ( ( classes = this.removeCustomData( 'classes' ) ) ) {
1208 while ( classes.length )
1209 this.removeClass( classes.pop() );
1210 }
1211
1212 // Remove contents stylesheet from document if it's the last usage.
1213 if ( !this.is( 'textarea' ) ) {
1214 var doc = this.getDocument(),
1215 head = doc.getHead();
1216 if ( head.getCustomData( 'stylesheet' ) ) {
1217 var refs = doc.getCustomData( 'stylesheet_ref' );
1218 if ( !( --refs ) ) {
1219 doc.removeCustomData( 'stylesheet_ref' );
1220 var sheet = head.removeCustomData( 'stylesheet' );
1221 sheet.remove();
1222 } else {
1223 doc.setCustomData( 'stylesheet_ref', refs );
1224 }
1225 }
1226 }
1227
1228 this.editor.fire( 'contentDomUnload' );
1229
1230 // Free up the editor reference.
1231 delete this.editor;
1232 }
1233 }
1234 } );
1235
1236 /**
1237 * Creates, retrieves or detaches an editable element of the editor.
1238 * This method should always be used instead of calling {@link CKEDITOR.editable} directly.
1239 *
1240 * @method editable
1241 * @member CKEDITOR.editor
1242 * @param {CKEDITOR.dom.element/CKEDITOR.editable} [elementOrEditable] The
1243 * DOM element to become the editable or a {@link CKEDITOR.editable} object.
1244 */
1245 CKEDITOR.editor.prototype.editable = function( element ) {
1246 var editable = this._.editable;
1247
1248 // This editor has already associated with
1249 // an editable element, silently fails.
1250 if ( editable && element )
1251 return 0;
1252
1253 if ( arguments.length ) {
1254 editable = this._.editable = element ? ( element instanceof CKEDITOR.editable ? element : new CKEDITOR.editable( this, element ) ) :
1255 // Detach the editable from editor.
1256 ( editable && editable.detach(), null );
1257 }
1258
1259 // Just retrieve the editable.
1260 return editable;
1261 };
1262
1263 CKEDITOR.on( 'instanceLoaded', function( evt ) {
1264 var editor = evt.editor;
1265
1266 // and flag that the element was locked by our code so it'll be editable by the editor functions (#6046).
1267 editor.on( 'insertElement', function( evt ) {
1268 var element = evt.data;
1269 if ( element.type == CKEDITOR.NODE_ELEMENT && ( element.is( 'input' ) || element.is( 'textarea' ) ) ) {
1270 // // The element is still not inserted yet, force attribute-based check.
1271 if ( element.getAttribute( 'contentEditable' ) != 'false' )
1272 element.data( 'cke-editable', element.hasAttribute( 'contenteditable' ) ? 'true' : '1' );
1273 element.setAttribute( 'contentEditable', false );
1274 }
1275 } );
1276
1277 editor.on( 'selectionChange', function( evt ) {
1278 if ( editor.readOnly )
1279 return;
1280
1281 // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
1282 var sel = editor.getSelection();
1283 // Do it only when selection is not locked. (#8222)
1284 if ( sel && !sel.isLocked ) {
1285 var isDirty = editor.checkDirty();
1286
1287 // Lock undoM before touching DOM to prevent
1288 // recording these changes as separate snapshot.
1289 editor.fire( 'lockSnapshot' );
1290 fixDom( evt );
1291 editor.fire( 'unlockSnapshot' );
1292
1293 !isDirty && editor.resetDirty();
1294 }
1295 } );
1296 } );
1297
1298 CKEDITOR.on( 'instanceCreated', function( evt ) {
1299 var editor = evt.editor;
1300
1301 editor.on( 'mode', function() {
1302
1303 var editable = editor.editable();
1304
1305 // Setup proper ARIA roles and properties for inline editable, classic
1306 // (iframe-based) editable is instead handled by plugin.
1307 if ( editable && editable.isInline() ) {
1308
1309 var ariaLabel = editor.title;
1310
1311 editable.changeAttr( 'role', 'textbox' );
1312 editable.changeAttr( 'aria-label', ariaLabel );
1313
1314 if ( ariaLabel )
1315 editable.changeAttr( 'title', ariaLabel );
1316
1317 var helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label;
1318 if ( helpLabel ) {
1319 // Put the voice label in different spaces, depending on element mode, so
1320 // the DOM element get auto detached on mode reload or editor destroy.
1321 var ct = this.ui.space( this.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? 'top' : 'contents' );
1322 if ( ct ) {
1323 var ariaDescId = CKEDITOR.tools.getNextId(),
1324 desc = CKEDITOR.dom.element.createFromHtml( '<span id="' + ariaDescId + '" class="cke_voice_label">' + helpLabel + '</span>' );
1325 ct.append( desc );
1326 editable.changeAttr( 'aria-describedby', ariaDescId );
1327 }
1328 }
1329 }
1330 } );
1331 } );
1332
1333 // #9222: Show text cursor in Gecko.
1334 // Show default cursor over control elements on all non-IEs.
1335 CKEDITOR.addCss( '.cke_editable{cursor:text}.cke_editable img,.cke_editable input,.cke_editable textarea{cursor:default}' );
1336
1337 //
1338 //
1339 // Bazillion helpers for the editable class and above listeners.
1340 //
1341 //
1342
1343 isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ),
1344 isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ),
1345 isEmpty = CKEDITOR.dom.walker.empty(),
1346 isBogus = CKEDITOR.dom.walker.bogus(),
1347 // Matching an empty paragraph at the end of document.
1348 emptyParagraphRegexp = /(^|<body\b[^>]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:<br[^>]*>|&nbsp;|\u00A0|&#160;)?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi;
1349
1350 // Auto-fixing block-less content by wrapping paragraph (#3190), prevent
1351 // non-exitable-block by padding extra br.(#3189)
1352 // Returns truly value when dom was changed, falsy otherwise.
1353 function fixDom( evt ) {
1354 var editor = evt.editor,
1355 path = evt.data.path,
1356 blockLimit = path.blockLimit,
1357 selection = evt.data.selection,
1358 range = selection.getRanges()[ 0 ],
1359 selectionUpdateNeeded;
1360
1361 if ( CKEDITOR.env.gecko || ( CKEDITOR.env.ie && CKEDITOR.env.needsBrFiller ) ) {
1362 var blockNeedsFiller = needsBrFiller( selection, path );
1363 if ( blockNeedsFiller ) {
1364 blockNeedsFiller.appendBogus();
1365 // IE tends to place selection after appended bogus, so we need to
1366 // select the original range (placed before bogus).
1367 selectionUpdateNeeded = CKEDITOR.env.ie;
1368 }
1369 }
1370
1371 // When we're in block enter mode, a new paragraph will be established
1372 // to encapsulate inline contents inside editable. (#3657)
1373 // Don't autoparagraph if browser (namely - IE) incorrectly anchored selection
1374 // inside non-editable content. This happens e.g. if non-editable block is the only
1375 // content of editable.
1376 if ( shouldAutoParagraph( editor, path.block, blockLimit ) && range.collapsed && !range.getCommonAncestor().isReadOnly() ) {
1377 var testRng = range.clone();
1378 testRng.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
1379 var walker = new CKEDITOR.dom.walker( testRng );
1380 walker.guard = function( node ) {
1381 return !isNotEmpty( node ) ||
1382 node.type == CKEDITOR.NODE_COMMENT ||
1383 node.isReadOnly();
1384 };
1385
1386 // 1. Inline content discovered under cursor;
1387 // 2. Empty editable.
1388 if ( !walker.checkForward() || testRng.checkStartOfBlock() && testRng.checkEndOfBlock() ) {
1389 var fixedBlock = range.fixBlock( true, editor.activeEnterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
1390
1391 // For IE<11, we should remove any filler node which was introduced before.
1392 if ( !CKEDITOR.env.needsBrFiller ) {
1393 var first = fixedBlock.getFirst( isNotEmpty );
1394 if ( first && isNbsp( first ) )
1395 first.remove();
1396 }
1397
1398 selectionUpdateNeeded = 1;
1399
1400 // Cancel this selection change in favor of the next (correct). (#6811)
1401 evt.cancel();
1402 }
1403 }
1404
1405 if ( selectionUpdateNeeded )
1406 range.select();
1407 }
1408
1409 // Checks whether current selection requires br filler to be appended.
1410 // @returns Block which needs filler or falsy value.
1411 function needsBrFiller( selection, path ) {
1412 // Fake selection does not need filler, because it is fake.
1413 if ( selection.isFake )
1414 return 0;
1415
1416 // Ensure bogus br could help to move cursor (out of styles) to the end of block. (#7041)
1417 var pathBlock = path.block || path.blockLimit,
1418 lastNode = pathBlock && pathBlock.getLast( isNotEmpty );
1419
1420 // Check some specialities of the current path block:
1421 // 1. It is really displayed as block; (#7221)
1422 // 2. It doesn't end with one inner block; (#7467)
1423 // 3. It doesn't have bogus br yet.
1424 if (
1425 pathBlock && pathBlock.isBlockBoundary() &&
1426 !( lastNode && lastNode.type == CKEDITOR.NODE_ELEMENT && lastNode.isBlockBoundary() ) &&
1427 !pathBlock.is( 'pre' ) && !pathBlock.getBogus()
1428 )
1429 return pathBlock;
1430 }
1431
1432 function blockInputClick( evt ) {
1433 var element = evt.data.getTarget();
1434 if ( element.is( 'input' ) ) {
1435 var type = element.getAttribute( 'type' );
1436 if ( type == 'submit' || type == 'reset' )
1437 evt.data.preventDefault();
1438 }
1439 }
1440
1441 function isNotEmpty( node ) {
1442 return isNotWhitespace( node ) && isNotBookmark( node );
1443 }
1444
1445 function isNbsp( node ) {
1446 return node.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.trim( node.getText() ).match( /^(?:&nbsp;|\xa0)$/ );
1447 }
1448
1449 function isNotBubbling( fn, src ) {
1450 return function( evt ) {
1451 var other = evt.data.$.toElement || evt.data.$.fromElement || evt.data.$.relatedTarget;
1452
1453 // First of all, other may simply be null/undefined.
1454 // Second of all, at least early versions of Spartan returned empty objects from evt.relatedTarget,
1455 // so let's also check the node type.
1456 other = ( other && other.nodeType == CKEDITOR.NODE_ELEMENT ) ? new CKEDITOR.dom.element( other ) : null;
1457
1458 if ( !( other && ( src.equals( other ) || src.contains( other ) ) ) )
1459 fn.call( this, evt );
1460 };
1461 }
1462
1463 function hasBookmarks( element ) {
1464 // We use getElementsByTag() instead of find() to retain compatibility with IE quirks mode.
1465 var potentialBookmarks = element.getElementsByTag( 'span' ),
1466 i = 0,
1467 child;
1468
1469 if ( potentialBookmarks ) {
1470 while ( ( child = potentialBookmarks.getItem( i++ ) ) ) {
1471 if ( !isNotBookmark( child ) ) {
1472 return true;
1473 }
1474 }
1475 }
1476
1477 return false;
1478 }
1479
1480 // Check if the entire table/list contents is selected.
1481 function getSelectedTableList( sel ) {
1482 var selected,
1483 range = sel.getRanges()[ 0 ],
1484 editable = sel.root,
1485 path = range.startPath(),
1486 structural = { table: 1, ul: 1, ol: 1, dl: 1 };
1487
1488 if ( path.contains( structural ) ) {
1489 // Clone the original range.
1490 var walkerRng = range.clone();
1491
1492 // Enlarge the range: X<ul><li>[Y]</li></ul>X => [X<ul><li>]Y</li></ul>X
1493 walkerRng.collapse( 1 );
1494 walkerRng.setStartAt( editable, CKEDITOR.POSITION_AFTER_START );
1495
1496 // Create a new walker.
1497 var walker = new CKEDITOR.dom.walker( walkerRng );
1498
1499 // Assign a new guard to the walker.
1500 walker.guard = guard();
1501
1502 // Go backwards checking for selected structural node.
1503 walker.checkBackward();
1504
1505 // If there's a selected structured element when checking backwards,
1506 // then check the same forwards.
1507 if ( selected ) {
1508 // Clone the original range.
1509 walkerRng = range.clone();
1510
1511 // Enlarge the range (assuming <ul> is selected element from guard):
1512 //
1513 // X<ul><li>[Y]</li></ul>X => X<ul><li>Y[</li></ul>]X
1514 //
1515 // If the walker went deeper down DOM than a while ago when traversing
1516 // backwards, then it doesn't make sense: an element must be selected
1517 // symmetrically. By placing range end **after previously selected node**,
1518 // we make sure we don't go no deeper in DOM when going forwards.
1519 walkerRng.collapse();
1520 walkerRng.setEndAt( selected, CKEDITOR.POSITION_AFTER_END );
1521
1522 // Create a new walker.
1523 walker = new CKEDITOR.dom.walker( walkerRng );
1524
1525 // Assign a new guard to the walker.
1526 walker.guard = guard( true );
1527
1528 // Reset selected node.
1529 selected = false;
1530
1531 // Go forwards checking for selected structural node.
1532 walker.checkForward();
1533
1534 return selected;
1535 }
1536 }
1537
1538 return null;
1539
1540 function guard( forwardGuard ) {
1541 return function( node, isWalkOut ) {
1542 // Save the encountered node as selected if going down the DOM structure
1543 // and the node is structured element.
1544 if ( isWalkOut && node.type == CKEDITOR.NODE_ELEMENT && node.is( structural ) )
1545 selected = node;
1546
1547 // Stop the walker when either traversing another non-empty node at the same
1548 // DOM level as in previous step.
1549 // NOTE: When going forwards, stop if encountered a bogus.
1550 if ( !isWalkOut && isNotEmpty( node ) && !( forwardGuard && isBogus( node ) ) )
1551 return false;
1552 };
1553 }
1554 }
1555
1556 // Whether in given context (pathBlock, pathBlockLimit and editor settings)
1557 // editor should automatically wrap inline contents with blocks.
1558 function shouldAutoParagraph( editor, pathBlock, pathBlockLimit ) {
1559 // Check whether pathBlock equals pathBlockLimit to support nested editable (#12162).
1560 return editor.config.autoParagraph !== false &&
1561 editor.activeEnterMode != CKEDITOR.ENTER_BR &&
1562 (
1563 ( editor.editable().equals( pathBlockLimit ) && !pathBlock ) ||
1564 ( pathBlock && pathBlock.getAttribute( 'contenteditable' ) == 'true' )
1565 );
1566 }
1567
1568 function autoParagraphTag( editor ) {
1569 return ( editor.activeEnterMode != CKEDITOR.ENTER_BR && editor.config.autoParagraph !== false ) ? editor.activeEnterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' : false;
1570 }
1571
1572 //
1573 // Functions related to insertXXX methods
1574 //
1575 insert = ( function() {
1576 'use strict';
1577
1578 var DTD = CKEDITOR.dtd;
1579
1580 // Inserts the given (valid) HTML into the range position (with range content deleted),
1581 // guarantee it's result to be a valid DOM tree.
1582 function insert( editable, type, data, range ) {
1583 var editor = editable.editor,
1584 dontFilter = false;
1585
1586 if ( type == 'unfiltered_html' ) {
1587 type = 'html';
1588 dontFilter = true;
1589 }
1590
1591 // Check range spans in non-editable.
1592 if ( range.checkReadOnly() )
1593 return;
1594
1595 // RANGE PREPARATIONS
1596
1597 var path = new CKEDITOR.dom.elementPath( range.startContainer, range.root ),
1598 // Let root be the nearest block that's impossible to be split
1599 // during html processing.
1600 blockLimit = path.blockLimit || range.root,
1601 // The "state" value.
1602 that = {
1603 type: type,
1604 dontFilter: dontFilter,
1605 editable: editable,
1606 editor: editor,
1607 range: range,
1608 blockLimit: blockLimit,
1609 // During pre-processing / preparations startContainer of affectedRange should be placed
1610 // in this element in which inserted or moved (in case when we merge blocks) content
1611 // could create situation that will need merging inline elements.
1612 // Examples:
1613 // <div><b>A</b>^B</div> + <b>C</b> => <div><b>A</b><b>C</b>B</div> - affected container is <div>.
1614 // <p><b>A[B</b></p><p><b>C]D</b></p> + E => <p><b>AE</b></p><p><b>D</b></p> =>
1615 // <p><b>AE</b><b>D</b></p> - affected container is <p> (in text mode).
1616 mergeCandidates: [],
1617 zombies: []
1618 };
1619
1620 prepareRangeToDataInsertion( that );
1621
1622 // DATA PROCESSING
1623
1624 // Select range and stop execution.
1625 // If data has been totally emptied after the filtering,
1626 // any insertion is pointless (#10339).
1627 if ( data && processDataForInsertion( that, data ) ) {
1628 // DATA INSERTION
1629 insertDataIntoRange( that );
1630 }
1631
1632 // FINAL CLEANUP
1633 // Set final range position and clean up.
1634
1635 cleanupAfterInsertion( that );
1636 }
1637
1638 // Prepare range to its data deletion.
1639 // Delete its contents.
1640 // Prepare it to insertion.
1641 function prepareRangeToDataInsertion( that ) {
1642 var range = that.range,
1643 mergeCandidates = that.mergeCandidates,
1644 node, marker, path, startPath, endPath, previous, bm;
1645
1646 // If range starts in inline element then insert a marker, so empty
1647 // inline elements won't be removed while range.deleteContents
1648 // and we will be able to move range back into this element.
1649 // E.g. 'aa<b>[bb</b>]cc' -> (after deleting) 'aa<b><span/></b>cc'
1650 if ( that.type == 'text' && range.shrink( CKEDITOR.SHRINK_ELEMENT, true, false ) ) {
1651 marker = CKEDITOR.dom.element.createFromHtml( '<span>&nbsp;</span>', range.document );
1652 range.insertNode( marker );
1653 range.setStartAfter( marker );
1654 }
1655
1656 // By using path we can recover in which element was startContainer
1657 // before deleting contents.
1658 // Start and endPathElements will be used to squash selected blocks, after removing
1659 // selection contents. See rule 5.
1660 startPath = new CKEDITOR.dom.elementPath( range.startContainer );
1661 that.endPath = endPath = new CKEDITOR.dom.elementPath( range.endContainer );
1662
1663 if ( !range.collapsed ) {
1664 // Anticipate the possibly empty block at the end of range after deletion.
1665 node = endPath.block || endPath.blockLimit;
1666 var ancestor = range.getCommonAncestor();
1667 if ( node && !( node.equals( ancestor ) || node.contains( ancestor ) ) && range.checkEndOfBlock() ) {
1668 that.zombies.push( node );
1669 }
1670
1671 range.deleteContents();
1672 }
1673
1674 // Rule 4.
1675 // Move range into the previous block.
1676 while (
1677 ( previous = getRangePrevious( range ) ) && checkIfElement( previous ) && previous.isBlockBoundary() &&
1678 // Check if previousNode was parent of range's startContainer before deleteContents.
1679 startPath.contains( previous )
1680 )
1681 range.moveToPosition( previous, CKEDITOR.POSITION_BEFORE_END );
1682
1683 // Rule 5.
1684 mergeAncestorElementsOfSelectionEnds( range, that.blockLimit, startPath, endPath );
1685
1686 // Rule 1.
1687 if ( marker ) {
1688 // If marker was created then move collapsed range into its place.
1689 range.setEndBefore( marker );
1690 range.collapse();
1691 marker.remove();
1692 }
1693
1694 // Split inline elements so HTML will be inserted with its own styles.
1695 path = range.startPath();
1696 if ( ( node = path.contains( isInline, false, 1 ) ) ) {
1697 range.splitElement( node );
1698 that.inlineStylesRoot = node;
1699 that.inlineStylesPeak = path.lastElement;
1700 }
1701
1702 // Record inline merging candidates for later cleanup in place.
1703 bm = range.createBookmark();
1704
1705 // 1. Inline siblings.
1706 node = bm.startNode.getPrevious( isNotEmpty );
1707 node && checkIfElement( node ) && isInline( node ) && mergeCandidates.push( node );
1708 node = bm.startNode.getNext( isNotEmpty );
1709 node && checkIfElement( node ) && isInline( node ) && mergeCandidates.push( node );
1710
1711 // 2. Inline parents.
1712 node = bm.startNode;
1713 while ( ( node = node.getParent() ) && isInline( node ) )
1714 mergeCandidates.push( node );
1715
1716 range.moveToBookmark( bm );
1717 }
1718
1719 function processDataForInsertion( that, data ) {
1720 var range = that.range;
1721
1722 // Rule 8. - wrap entire data in inline styles.
1723 // (e.g. <p><b>x^z</b></p> + <p>a</p><p>b</p> -> <b><p>a</p><p>b</p></b>)
1724 // Incorrect tags order will be fixed by htmlDataProcessor.
1725 if ( that.type == 'text' && that.inlineStylesRoot )
1726 data = wrapDataWithInlineStyles( data, that );
1727
1728
1729 var context = that.blockLimit.getName();
1730
1731 // Wrap data to be inserted, to avoid losing leading whitespaces
1732 // when going through the below procedure.
1733 if ( /^\s+|\s+$/.test( data ) && 'span' in CKEDITOR.dtd[ context ] ) {
1734 var protect = '<span data-cke-marker="1">&nbsp;</span>';
1735 data = protect + data + protect;
1736 }
1737
1738 // Process the inserted html, in context of the insertion root.
1739 // Don't use the "fix for body" feature as auto paragraphing must
1740 // be handled during insertion.
1741 data = that.editor.dataProcessor.toHtml( data, {
1742 context: null,
1743 fixForBody: false,
1744 protectedWhitespaces: !!protect,
1745 dontFilter: that.dontFilter,
1746 // Use the current, contextual settings.
1747 filter: that.editor.activeFilter,
1748 enterMode: that.editor.activeEnterMode
1749 } );
1750
1751
1752 // Build the node list for insertion.
1753 var doc = range.document,
1754 wrapper = doc.createElement( 'body' );
1755
1756 wrapper.setHtml( data );
1757
1758 // Eventually remove the temporaries.
1759 if ( protect ) {
1760 wrapper.getFirst().remove();
1761 wrapper.getLast().remove();
1762 }
1763
1764 // Rule 7.
1765 var block = range.startPath().block;
1766 if ( block && // Apply when there exists path block after deleting selection's content...
1767 !( block.getChildCount() == 1 && block.getBogus() ) ) { // ... and the only content of this block isn't a bogus.
1768 stripBlockTagIfSingleLine( wrapper );
1769 }
1770
1771 that.dataWrapper = wrapper;
1772
1773 return data;
1774 }
1775
1776 function insertDataIntoRange( that ) {
1777 var range = that.range,
1778 doc = range.document,
1779 path,
1780 blockLimit = that.blockLimit,
1781 nodesData, nodeData, node,
1782 nodeIndex = 0,
1783 bogus,
1784 bogusNeededBlocks = [],
1785 pathBlock, fixBlock,
1786 splittingContainer = 0,
1787 dontMoveCaret = 0,
1788 insertionContainer, toSplit, newContainer,
1789 startContainer = range.startContainer,
1790 endContainer = that.endPath.elements[ 0 ],
1791 filteredNodes,
1792 // If endContainer was merged into startContainer: <p>a[b</p><p>c]d</p>
1793 // or it's equal to startContainer: <p>a^b</p>
1794 // or different situation happened :P
1795 // then there's no separate container for the end of selection.
1796 pos = endContainer.getPosition( startContainer ),
1797 separateEndContainer = !!endContainer.getCommonAncestor( startContainer ) && // endC is not detached.
1798 pos != CKEDITOR.POSITION_IDENTICAL && !( pos & CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_IS_CONTAINED ); // endC & endS are in separate branches.
1799
1800 nodesData = extractNodesData( that.dataWrapper, that );
1801
1802 removeBrsAdjacentToPastedBlocks( nodesData, range );
1803
1804 for ( ; nodeIndex < nodesData.length; nodeIndex++ ) {
1805 nodeData = nodesData[ nodeIndex ];
1806
1807 // Ignore trailing <brs>
1808 if ( nodeData.isLineBreak && splitOnLineBreak( range, blockLimit, nodeData ) ) {
1809 // Do not move caret towards the text (in cleanupAfterInsertion),
1810 // because caret was placed after a line break.
1811 dontMoveCaret = nodeIndex > 0;
1812 continue;
1813 }
1814
1815 path = range.startPath();
1816
1817 // Auto paragraphing.
1818 if ( !nodeData.isBlock && shouldAutoParagraph( that.editor, path.block, path.blockLimit ) && ( fixBlock = autoParagraphTag( that.editor ) ) ) {
1819 fixBlock = doc.createElement( fixBlock );
1820 fixBlock.appendBogus();
1821 range.insertNode( fixBlock );
1822 if ( CKEDITOR.env.needsBrFiller && ( bogus = fixBlock.getBogus() ) )
1823 bogus.remove();
1824 range.moveToPosition( fixBlock, CKEDITOR.POSITION_BEFORE_END );
1825 }
1826
1827 node = range.startPath().block;
1828
1829 // Remove any bogus element on the current path block for now, and mark
1830 // it for later compensation.
1831 if ( node && !node.equals( pathBlock ) ) {
1832 bogus = node.getBogus();
1833 if ( bogus ) {
1834 bogus.remove();
1835 bogusNeededBlocks.push( node );
1836 }
1837
1838 pathBlock = node;
1839 }
1840
1841 // First not allowed node reached - start splitting original container
1842 if ( nodeData.firstNotAllowed )
1843 splittingContainer = 1;
1844
1845 if ( splittingContainer && nodeData.isElement ) {
1846 insertionContainer = range.startContainer;
1847 toSplit = null;
1848
1849 // Find the first ancestor that can contain current node.
1850 // This one won't be split.
1851 while ( insertionContainer && !DTD[ insertionContainer.getName() ][ nodeData.name ] ) {
1852 if ( insertionContainer.equals( blockLimit ) ) {
1853 insertionContainer = null;
1854 break;
1855 }
1856
1857 toSplit = insertionContainer;
1858 insertionContainer = insertionContainer.getParent();
1859 }
1860
1861 // If split has to be done - do it and mark both ends as a possible zombies.
1862 if ( insertionContainer ) {
1863 if ( toSplit ) {
1864 newContainer = range.splitElement( toSplit );
1865 that.zombies.push( newContainer );
1866 that.zombies.push( toSplit );
1867 }
1868 }
1869 // Unable to make the insertion happen in place, resort to the content filter.
1870 else {
1871 // If everything worked fine insertionContainer == blockLimit here.
1872 filteredNodes = filterElement( nodeData.node, blockLimit.getName(), !nodeIndex, nodeIndex == nodesData.length - 1 );
1873 }
1874 }
1875
1876 if ( filteredNodes ) {
1877 while ( ( node = filteredNodes.pop() ) )
1878 range.insertNode( node );
1879 filteredNodes = 0;
1880 } else {
1881 // Insert current node at the start of range.
1882 range.insertNode( nodeData.node );
1883 }
1884
1885 // Move range to the endContainer for the final allowed elements.
1886 if ( nodeData.lastNotAllowed && nodeIndex < nodesData.length - 1 ) {
1887 // If separateEndContainer exists move range there.
1888 // Otherwise try to move range to container created during splitting.
1889 // If this doesn't work - don't move range.
1890 newContainer = separateEndContainer ? endContainer : newContainer;
1891 newContainer && range.setEndAt( newContainer, CKEDITOR.POSITION_AFTER_START );
1892 splittingContainer = 0;
1893 }
1894
1895 // Collapse range after insertion to end.
1896 range.collapse();
1897 }
1898
1899 // Rule 9. Non-editable content should be selected as a whole.
1900 if ( isSingleNonEditableElement( nodesData ) ) {
1901 dontMoveCaret = true;
1902 node = nodesData[ 0 ].node;
1903 range.setStartAt( node, CKEDITOR.POSITION_BEFORE_START );
1904 range.setEndAt( node, CKEDITOR.POSITION_AFTER_END );
1905 }
1906
1907 that.dontMoveCaret = dontMoveCaret;
1908 that.bogusNeededBlocks = bogusNeededBlocks;
1909 }
1910
1911 function cleanupAfterInsertion( that ) {
1912 var range = that.range,
1913 node, testRange, movedIntoInline,
1914 bogusNeededBlocks = that.bogusNeededBlocks,
1915 // Create a bookmark to defend against the following range deconstructing operations.
1916 bm = range.createBookmark();
1917
1918 // Remove all elements that could be created while splitting nodes
1919 // with ranges at its start|end.
1920 // E.g. remove <div><p></p></div>
1921 // But not <div><p> </p></div>
1922 // And replace <div><p><span data="cke-bookmark"/></p></div> with found bookmark.
1923 while ( ( node = that.zombies.pop() ) ) {
1924 // Detached element.
1925 if ( !node.getParent() )
1926 continue;
1927
1928 testRange = range.clone();
1929 testRange.moveToElementEditStart( node );
1930 testRange.removeEmptyBlocksAtEnd();
1931 }
1932
1933 if ( bogusNeededBlocks ) {
1934 // Bring back all block bogus nodes.
1935 while ( ( node = bogusNeededBlocks.pop() ) ) {
1936 if ( CKEDITOR.env.needsBrFiller )
1937 node.appendBogus();
1938 else
1939 node.append( range.document.createText( '\u00a0' ) );
1940 }
1941 }
1942
1943 // Eventually merge identical inline elements.
1944 while ( ( node = that.mergeCandidates.pop() ) )
1945 node.mergeSiblings();
1946
1947 range.moveToBookmark( bm );
1948
1949 // Rule 3.
1950 // Shrink range to the BEFOREEND of previous innermost editable node in source order.
1951
1952 if ( !that.dontMoveCaret ) {
1953 node = getRangePrevious( range );
1954
1955 while ( node && checkIfElement( node ) && !node.is( DTD.$empty ) ) {
1956 if ( node.isBlockBoundary() )
1957 range.moveToPosition( node, CKEDITOR.POSITION_BEFORE_END );
1958 else {
1959 // Don't move into inline element (which ends with a text node)
1960 // found which contains white-space at its end.
1961 // If not - move range's end to the end of this element.
1962 if ( isInline( node ) && node.getHtml().match( /(\s|&nbsp;)$/g ) ) {
1963 movedIntoInline = null;
1964 break;
1965 }
1966
1967 movedIntoInline = range.clone();
1968 movedIntoInline.moveToPosition( node, CKEDITOR.POSITION_BEFORE_END );
1969 }
1970
1971 node = node.getLast( isNotEmpty );
1972 }
1973
1974 movedIntoInline && range.moveToRange( movedIntoInline );
1975 }
1976
1977 }
1978
1979 //
1980 // HELPERS ------------------------------------------------------------
1981 //
1982
1983 function checkIfElement( node ) {
1984 return node.type == CKEDITOR.NODE_ELEMENT;
1985 }
1986
1987 function extractNodesData( dataWrapper, that ) {
1988 var node, sibling, nodeName, allowed,
1989 nodesData = [],
1990 startContainer = that.range.startContainer,
1991 path = that.range.startPath(),
1992 allowedNames = DTD[ startContainer.getName() ],
1993 nodeIndex = 0,
1994 nodesList = dataWrapper.getChildren(),
1995 nodesCount = nodesList.count(),
1996 firstNotAllowed = -1,
1997 lastNotAllowed = -1,
1998 lineBreak = 0,
1999 blockSibling;
2000
2001 // Selection start within a list.
2002 var insideOfList = path.contains( DTD.$list );
2003
2004 for ( ; nodeIndex < nodesCount; ++nodeIndex ) {
2005 node = nodesList.getItem( nodeIndex );
2006
2007 if ( checkIfElement( node ) ) {
2008 nodeName = node.getName();
2009
2010 // Extract only the list items, when insertion happens
2011 // inside of a list, reads as rearrange list items. (#7957)
2012 if ( insideOfList && nodeName in CKEDITOR.dtd.$list ) {
2013 nodesData = nodesData.concat( extractNodesData( node, that ) );
2014 continue;
2015 }
2016
2017 allowed = !!allowedNames[ nodeName ];
2018
2019 // Mark <brs data-cke-eol="1"> at the beginning and at the end.
2020 if ( nodeName == 'br' && node.data( 'cke-eol' ) && ( !nodeIndex || nodeIndex == nodesCount - 1 ) ) {
2021 sibling = nodeIndex ? nodesData[ nodeIndex - 1 ].node : nodesList.getItem( nodeIndex + 1 );
2022
2023 // Line break has to have sibling which is not an <br>.
2024 lineBreak = sibling && ( !checkIfElement( sibling ) || !sibling.is( 'br' ) );
2025 // Line break has block element as a sibling.
2026 blockSibling = sibling && checkIfElement( sibling ) && DTD.$block[ sibling.getName() ];
2027 }
2028
2029 if ( firstNotAllowed == -1 && !allowed )
2030 firstNotAllowed = nodeIndex;
2031 if ( !allowed )
2032 lastNotAllowed = nodeIndex;
2033
2034 nodesData.push( {
2035 isElement: 1,
2036 isLineBreak: lineBreak,
2037 isBlock: node.isBlockBoundary(),
2038 hasBlockSibling: blockSibling,
2039 node: node,
2040 name: nodeName,
2041 allowed: allowed
2042 } );
2043
2044 lineBreak = 0;
2045 blockSibling = 0;
2046 } else {
2047 nodesData.push( { isElement: 0, node: node, allowed: 1 } );
2048 }
2049 }
2050
2051 // Mark first node that cannot be inserted directly into startContainer
2052 // and last node for which startContainer has to be split.
2053 if ( firstNotAllowed > -1 )
2054 nodesData[ firstNotAllowed ].firstNotAllowed = 1;
2055 if ( lastNotAllowed > -1 )
2056 nodesData[ lastNotAllowed ].lastNotAllowed = 1;
2057
2058 return nodesData;
2059 }
2060
2061 // TODO: Review content transformation rules on filtering element.
2062 function filterElement( element, parentName, isFirst, isLast ) {
2063 var nodes = filterElementInner( element, parentName ),
2064 nodes2 = [],
2065 nodesCount = nodes.length,
2066 nodeIndex = 0,
2067 node,
2068 afterSpace = 0,
2069 lastSpaceIndex = -1;
2070
2071 // Remove duplicated spaces and spaces at the:
2072 // * beginnig if filtered element isFirst (isFirst that's going to be inserted)
2073 // * end if filtered element isLast.
2074 for ( ; nodeIndex < nodesCount; nodeIndex++ ) {
2075 node = nodes[ nodeIndex ];
2076
2077 if ( node == ' ' ) {
2078 // Don't push doubled space and if it's leading space for insertion.
2079 if ( !afterSpace && !( isFirst && !nodeIndex ) ) {
2080 nodes2.push( new CKEDITOR.dom.text( ' ' ) );
2081 lastSpaceIndex = nodes2.length;
2082 }
2083 afterSpace = 1;
2084 } else {
2085 nodes2.push( node );
2086 afterSpace = 0;
2087 }
2088 }
2089
2090 // Remove trailing space.
2091 if ( isLast && lastSpaceIndex == nodes2.length )
2092 nodes2.pop();
2093
2094 return nodes2;
2095 }
2096
2097 function filterElementInner( element, parentName ) {
2098 var nodes = [],
2099 children = element.getChildren(),
2100 childrenCount = children.count(),
2101 child,
2102 childIndex = 0,
2103 allowedNames = DTD[ parentName ],
2104 surroundBySpaces = !element.is( DTD.$inline ) || element.is( 'br' );
2105
2106 if ( surroundBySpaces )
2107 nodes.push( ' ' );
2108
2109 for ( ; childIndex < childrenCount; childIndex++ ) {
2110 child = children.getItem( childIndex );
2111
2112 if ( checkIfElement( child ) && !child.is( allowedNames ) )
2113 nodes = nodes.concat( filterElementInner( child, parentName ) );
2114 else
2115 nodes.push( child );
2116 }
2117
2118 if ( surroundBySpaces )
2119 nodes.push( ' ' );
2120
2121 return nodes;
2122 }
2123
2124 function getRangePrevious( range ) {
2125 return checkIfElement( range.startContainer ) && range.startContainer.getChild( range.startOffset - 1 );
2126 }
2127
2128 function isInline( node ) {
2129 return node && checkIfElement( node ) && ( node.is( DTD.$removeEmpty ) || node.is( 'a' ) && !node.isBlockBoundary() );
2130 }
2131
2132 // Checks if only non-editable element is being inserted.
2133 function isSingleNonEditableElement( nodesData ) {
2134 if ( nodesData.length != 1 )
2135 return false;
2136
2137 var nodeData = nodesData[ 0 ];
2138
2139 return nodeData.isElement && ( nodeData.node.getAttribute( 'contenteditable' ) == 'false' );
2140 }
2141
2142 var blockMergedTags = { p: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, ul: 1, ol: 1, li: 1, pre: 1, dl: 1, blockquote: 1 };
2143
2144 // See rule 5. in TCs.
2145 // Initial situation:
2146 // <ul><li>AA^</li></ul><ul><li>BB</li></ul>
2147 // We're looking for 2nd <ul>, comparing with 1st <ul> and merging.
2148 // We're not merging if caret is between these elements.
2149 function mergeAncestorElementsOfSelectionEnds( range, blockLimit, startPath, endPath ) {
2150 var walkerRange = range.clone(),
2151 walker, nextNode, previousNode;
2152
2153 walkerRange.setEndAt( blockLimit, CKEDITOR.POSITION_BEFORE_END );
2154 walker = new CKEDITOR.dom.walker( walkerRange );
2155
2156 if ( ( nextNode = walker.next() ) && // Find next source node
2157 checkIfElement( nextNode ) && // which is an element
2158 blockMergedTags[ nextNode.getName() ] && // that can be merged.
2159 ( previousNode = nextNode.getPrevious() ) && // Take previous one
2160 checkIfElement( previousNode ) && // which also has to be an element.
2161 !previousNode.getParent().equals( range.startContainer ) && // Fail if caret is on the same level.
2162 // This means that caret is between these nodes.
2163 startPath.contains( previousNode ) && // Elements path of start of selection has
2164 endPath.contains( nextNode ) && // to contain prevNode and vice versa.
2165 nextNode.isIdentical( previousNode ) // Check if elements are identical.
2166 ) {
2167 // Merge blocks and repeat.
2168 nextNode.moveChildren( previousNode );
2169 nextNode.remove();
2170 mergeAncestorElementsOfSelectionEnds( range, blockLimit, startPath, endPath );
2171 }
2172 }
2173
2174 // If last node that will be inserted is a block (but not a <br>)
2175 // and it will be inserted right before <br> remove this <br>.
2176 // Do the same for the first element that will be inserted and preceding <br>.
2177 function removeBrsAdjacentToPastedBlocks( nodesData, range ) {
2178 var succeedingNode = range.endContainer.getChild( range.endOffset ),
2179 precedingNode = range.endContainer.getChild( range.endOffset - 1 );
2180
2181 if ( succeedingNode )
2182 remove( succeedingNode, nodesData[ nodesData.length - 1 ] );
2183
2184 if ( precedingNode && remove( precedingNode, nodesData[ 0 ] ) ) {
2185 // If preceding <br> was removed - move range left.
2186 range.setEnd( range.endContainer, range.endOffset - 1 );
2187 range.collapse();
2188 }
2189
2190 function remove( maybeBr, maybeBlockData ) {
2191 if ( maybeBlockData.isBlock && maybeBlockData.isElement && !maybeBlockData.node.is( 'br' ) &&
2192 checkIfElement( maybeBr ) && maybeBr.is( 'br' ) ) {
2193 maybeBr.remove();
2194 return 1;
2195 }
2196 }
2197 }
2198
2199 // Return 1 if <br> should be skipped when inserting, 0 otherwise.
2200 function splitOnLineBreak( range, blockLimit, nodeData ) {
2201 var firstBlockAscendant, pos;
2202
2203 if ( nodeData.hasBlockSibling )
2204 return 1;
2205
2206 firstBlockAscendant = range.startContainer.getAscendant( DTD.$block, 1 );
2207 if ( !firstBlockAscendant || !firstBlockAscendant.is( { div: 1, p: 1 } ) )
2208 return 0;
2209
2210 pos = firstBlockAscendant.getPosition( blockLimit );
2211
2212 if ( pos == CKEDITOR.POSITION_IDENTICAL || pos == CKEDITOR.POSITION_CONTAINS )
2213 return 0;
2214
2215 var newContainer = range.splitElement( firstBlockAscendant );
2216 range.moveToPosition( newContainer, CKEDITOR.POSITION_AFTER_START );
2217
2218 return 1;
2219 }
2220
2221 var stripSingleBlockTags = { p: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 },
2222 inlineButNotBr = CKEDITOR.tools.extend( {}, DTD.$inline );
2223 delete inlineButNotBr.br;
2224
2225 // Rule 7.
2226 function stripBlockTagIfSingleLine( dataWrapper ) {
2227 var block, children;
2228
2229 if ( dataWrapper.getChildCount() == 1 && // Only one node bein inserted.
2230 checkIfElement( block = dataWrapper.getFirst() ) && // And it's an element.
2231 block.is( stripSingleBlockTags ) && // That's <p> or <div> or header.
2232 !block.hasAttribute( 'contenteditable' ) // It's not a non-editable block or nested editable.
2233 ) {
2234 // Check children not containing block.
2235 children = block.getElementsByTag( '*' );
2236 for ( var i = 0, child, count = children.count(); i < count; i++ ) {
2237 child = children.getItem( i );
2238 if ( !child.is( inlineButNotBr ) )
2239 return;
2240 }
2241
2242 block.moveChildren( block.getParent( 1 ) );
2243 block.remove();
2244 }
2245 }
2246
2247 function wrapDataWithInlineStyles( data, that ) {
2248 var element = that.inlineStylesPeak,
2249 doc = element.getDocument(),
2250 wrapper = doc.createText( '{cke-peak}' ),
2251 limit = that.inlineStylesRoot.getParent();
2252
2253 while ( !element.equals( limit ) ) {
2254 wrapper = wrapper.appendTo( element.clone() );
2255 element = element.getParent();
2256 }
2257
2258 // Don't use String.replace because it fails in IE7 if special replacement
2259 // characters ($$, $&, etc.) are in data (#10367).
2260 return wrapper.getOuterHtml().split( '{cke-peak}' ).join( data );
2261 }
2262
2263 return insert;
2264 } )();
2265
2266 function afterInsert( editable ) {
2267 var editor = editable.editor;
2268
2269 // Scroll using selection, not ranges, to affect native pastes.
2270 editor.getSelection().scrollIntoView();
2271
2272 // Save snaps after the whole execution completed.
2273 // This's a workaround for make DOM modification's happened after
2274 // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
2275 // call.
2276 setTimeout( function() {
2277 editor.fire( 'saveSnapshot' );
2278 }, 0 );
2279 }
2280
2281 // 1. Fixes a range which is a result of deleteContents() and is placed in an intermediate element (see dtd.$intermediate),
2282 // inside a table. A goal is to find a closest <td> or <th> element and when this fails, recreate the structure of the table.
2283 // 2. Fixes empty cells by appending bogus <br>s or deleting empty text nodes in IE<=8 case.
2284 fixTableAfterContentsDeletion = ( function() {
2285 // Creates an element walker which can only "go deeper". It won't
2286 // move out from any element. Therefore it can be used to find <td>x</td> in cases like:
2287 // <table><tbody><tr><td>x</td></tr></tbody>^<tfoot>...
2288 function getFixTableSelectionWalker( testRange ) {
2289 var walker = new CKEDITOR.dom.walker( testRange );
2290 walker.guard = function( node, isMovingOut ) {
2291 if ( isMovingOut )
2292 return false;
2293 if ( node.type == CKEDITOR.NODE_ELEMENT )
2294 return node.is( CKEDITOR.dtd.$tableContent );
2295 };
2296 walker.evaluator = function( node ) {
2297 return node.type == CKEDITOR.NODE_ELEMENT;
2298 };
2299
2300 return walker;
2301 }
2302
2303 function fixTableStructure( element, newElementName, appendToStart ) {
2304 var temp = element.getDocument().createElement( newElementName );
2305 element.append( temp, appendToStart );
2306 return temp;
2307 }
2308
2309 // Fix empty cells. This means:
2310 // * add bogus <br> if browser needs it
2311 // * remove empty text nodes on IE8, because it will crash (http://dev.ckeditor.com/ticket/11183#comment:8).
2312 function fixEmptyCells( cells ) {
2313 var i = cells.count(),
2314 cell;
2315
2316 for ( i; i-- > 0; ) {
2317 cell = cells.getItem( i );
2318
2319 if ( !CKEDITOR.tools.trim( cell.getHtml() ) ) {
2320 cell.appendBogus();
2321 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && cell.getChildCount() )
2322 cell.getFirst().remove();
2323 }
2324 }
2325 }
2326
2327 return function( range ) {
2328 var container = range.startContainer,
2329 table = container.getAscendant( 'table', 1 ),
2330 testRange,
2331 deeperSibling,
2332 appendToStart = false;
2333
2334 fixEmptyCells( table.getElementsByTag( 'td' ) );
2335 fixEmptyCells( table.getElementsByTag( 'th' ) );
2336
2337 // Look left.
2338 testRange = range.clone();
2339 testRange.setStart( container, 0 );
2340 deeperSibling = getFixTableSelectionWalker( testRange ).lastBackward();
2341
2342 // If left is empty, look right.
2343 if ( !deeperSibling ) {
2344 testRange = range.clone();
2345 testRange.setEndAt( container, CKEDITOR.POSITION_BEFORE_END );
2346 deeperSibling = getFixTableSelectionWalker( testRange ).lastForward();
2347 appendToStart = true;
2348 }
2349
2350 // If there's no deeper nested element in both direction - container is empty - we'll use it then.
2351 if ( !deeperSibling )
2352 deeperSibling = container;
2353
2354 // Fix structure...
2355
2356 // We found a table what means that it's empty - remove it completely.
2357 if ( deeperSibling.is( 'table' ) ) {
2358 range.setStartAt( deeperSibling, CKEDITOR.POSITION_BEFORE_START );
2359 range.collapse( true );
2360 deeperSibling.remove();
2361 return;
2362 }
2363
2364 // Found an empty txxx element - append tr.
2365 if ( deeperSibling.is( { tbody: 1, thead: 1, tfoot: 1 } ) )
2366 deeperSibling = fixTableStructure( deeperSibling, 'tr', appendToStart );
2367
2368 // Found an empty tr element - append td/th.
2369 if ( deeperSibling.is( 'tr' ) )
2370 deeperSibling = fixTableStructure( deeperSibling, deeperSibling.getParent().is( 'thead' ) ? 'th' : 'td', appendToStart );
2371
2372 // To avoid setting selection after bogus, remove it from the current cell.
2373 // We can safely do that, because we'll insert element into that cell.
2374 var bogus = deeperSibling.getBogus();
2375 if ( bogus )
2376 bogus.remove();
2377
2378 range.moveToPosition( deeperSibling, appendToStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
2379 };
2380 } )();
2381
2382 fixListAfterContentsDelete = ( function() {
2383 // Creates an element walker which operates only within lists.
2384 function getFixListSelectionWalker( testRange ) {
2385 var walker = new CKEDITOR.dom.walker( testRange );
2386 walker.guard = function( node, isMovingOut ) {
2387 if ( isMovingOut )
2388 return false;
2389 if ( node.type == CKEDITOR.NODE_ELEMENT )
2390 return node.is( CKEDITOR.dtd.$list ) || node.is( CKEDITOR.dtd.$listItem );
2391 };
2392 walker.evaluator = function( node ) {
2393 return node.type == CKEDITOR.NODE_ELEMENT && node.is( CKEDITOR.dtd.$listItem );
2394 };
2395
2396 return walker;
2397 }
2398
2399 return function( range ) {
2400 var container = range.startContainer,
2401 appendToStart = false,
2402 testRange,
2403 deeperSibling;
2404
2405 // Look left.
2406 testRange = range.clone();
2407 testRange.setStart( container, 0 );
2408 deeperSibling = getFixListSelectionWalker( testRange ).lastBackward();
2409
2410 // If left is empty, look right.
2411 if ( !deeperSibling ) {
2412 testRange = range.clone();
2413 testRange.setEndAt( container, CKEDITOR.POSITION_BEFORE_END );
2414 deeperSibling = getFixListSelectionWalker( testRange ).lastForward();
2415 appendToStart = true;
2416 }
2417
2418 // If there's no deeper nested element in both direction - container is empty - we'll use it then.
2419 if ( !deeperSibling )
2420 deeperSibling = container;
2421
2422 // We found a list what means that it's empty - remove it completely.
2423 if ( deeperSibling.is( CKEDITOR.dtd.$list ) ) {
2424 range.setStartAt( deeperSibling, CKEDITOR.POSITION_BEFORE_START );
2425 range.collapse( true );
2426 deeperSibling.remove();
2427 return;
2428 }
2429
2430 // To avoid setting selection after bogus, remove it from the target list item.
2431 // We can safely do that, because we'll insert element into that cell.
2432 var bogus = deeperSibling.getBogus();
2433 if ( bogus )
2434 bogus.remove();
2435
2436 range.moveToPosition( deeperSibling, appendToStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
2437 range.select();
2438 };
2439 } )();
2440
2441 function mergeBlocksCollapsedSelection( editor, range, backspace, startPath ) {
2442 var startBlock = startPath.block;
2443
2444 // Selection must be collapsed and to be anchored in a block.
2445 if ( !startBlock )
2446 return false;
2447
2448 // Exclude cases where, i.e. if pressed arrow key, selection
2449 // would move within the same block (merge inside a block).
2450 if ( !range[ backspace ? 'checkStartOfBlock' : 'checkEndOfBlock' ]() )
2451 return false;
2452
2453 // Make sure, there's an editable position to put selection,
2454 // which i.e. would be used if pressed arrow key, but abort
2455 // if such position exists but means a selected non-editable element.
2456 if ( !range.moveToClosestEditablePosition( startBlock, !backspace ) || !range.collapsed )
2457 return false;
2458
2459 // Handle special case, when block's sibling is a <hr>. Delete it and keep selection
2460 // in the same place (http://dev.ckeditor.com/ticket/11861#comment:9).
2461 if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT ) {
2462 var touched = range.startContainer.getChild( range.startOffset - ( backspace ? 1 : 0 ) );
2463 if ( touched && touched.type == CKEDITOR.NODE_ELEMENT && touched.is( 'hr' ) ) {
2464 editor.fire( 'saveSnapshot' );
2465 touched.remove();
2466 return true;
2467 }
2468 }
2469
2470 var siblingBlock = range.startPath().block;
2471
2472 // Abort if an editable position exists, but either it's not
2473 // in a block or that block is the parent of the start block
2474 // (merging child into parent).
2475 if ( !siblingBlock || ( siblingBlock && siblingBlock.contains( startBlock ) ) )
2476 return;
2477
2478 editor.fire( 'saveSnapshot' );
2479
2480 // Remove bogus to avoid duplicated boguses.
2481 var bogus;
2482 if ( ( bogus = ( backspace ? siblingBlock : startBlock ).getBogus() ) )
2483 bogus.remove();
2484
2485 // Save selection. It will be restored.
2486 var selection = editor.getSelection(),
2487 bookmarks = selection.createBookmarks();
2488
2489 // Merge blocks.
2490 ( backspace ? startBlock : siblingBlock ).moveChildren( backspace ? siblingBlock : startBlock, false );
2491
2492 // Also merge children along with parents.
2493 startPath.lastElement.mergeSiblings();
2494
2495 // Cut off removable branch of the DOM tree.
2496 pruneEmptyDisjointAncestors( startBlock, siblingBlock, !backspace );
2497
2498 // Restore selection.
2499 selection.selectBookmarks( bookmarks );
2500
2501 return true;
2502 }
2503
2504 function mergeBlocksNonCollapsedSelection( editor, range, startPath ) {
2505 var startBlock = startPath.block,
2506 endPath = range.endPath(),
2507 endBlock = endPath.block;
2508
2509 // Selection must be anchored in two different blocks.
2510 if ( !startBlock || !endBlock || startBlock.equals( endBlock ) )
2511 return false;
2512
2513 editor.fire( 'saveSnapshot' );
2514
2515 // Remove bogus to avoid duplicated boguses.
2516 var bogus;
2517 if ( ( bogus = startBlock.getBogus() ) )
2518 bogus.remove();
2519
2520 // Changing end container to element from text node (#12503).
2521 range.enlarge( CKEDITOR.ENLARGE_INLINE );
2522
2523 // Delete range contents. Do NOT merge. Merging is weird.
2524 range.deleteContents();
2525
2526 // If something has left of the block to be merged, clean it up.
2527 // It may happen when merging with list items.
2528 if ( endBlock.getParent() ) {
2529 // Move children to the first block.
2530 endBlock.moveChildren( startBlock, false );
2531
2532 // ...and merge them if that's possible.
2533 startPath.lastElement.mergeSiblings();
2534
2535 // If expanded selection, things are always merged like with BACKSPACE.
2536 pruneEmptyDisjointAncestors( startBlock, endBlock, true );
2537 }
2538
2539 // Make sure the result selection is collapsed.
2540 range = editor.getSelection().getRanges()[ 0 ];
2541 range.collapse( 1 );
2542
2543 // Optimizing range containers from text nodes to elements (#12503).
2544 range.optimize();
2545 if ( range.startContainer.getHtml() === '' ) {
2546 range.startContainer.appendBogus();
2547 }
2548
2549 range.select();
2550
2551 return true;
2552 }
2553
2554 // Finds the innermost child of common parent, which,
2555 // if removed, removes nothing but the contents of the element.
2556 //
2557 // before: <div><p><strong>first</strong></p><p>second</p></div>
2558 // after: <div><p>second</p></div>
2559 //
2560 // before: <div><p>x<strong>first</strong></p><p>second</p></div>
2561 // after: <div><p>x</p><p>second</p></div>
2562 //
2563 // isPruneToEnd=true
2564 // before: <div><p><strong>first</strong></p><p>second</p></div>
2565 // after: <div><p><strong>first</strong></p></div>
2566 //
2567 // @param {CKEDITOR.dom.element} first
2568 // @param {CKEDITOR.dom.element} second
2569 // @param {Boolean} isPruneToEnd
2570 function pruneEmptyDisjointAncestors( first, second, isPruneToEnd ) {
2571 var commonParent = first.getCommonAncestor( second ),
2572 node = isPruneToEnd ? second : first,
2573 removableParent = node;
2574
2575 while ( ( node = node.getParent() ) && !commonParent.equals( node ) && node.getChildCount() == 1 )
2576 removableParent = node;
2577
2578 removableParent.remove();
2579 }
2580
2581 //
2582 // Helpers for editable.getHtmlFromRange.
2583 //
2584 getHtmlFromRangeHelpers = {
2585 eol: {
2586 detect: function( that, editable ) {
2587 var range = that.range,
2588 rangeStart = range.clone(),
2589 rangeEnd = range.clone(),
2590
2591 startPath = new CKEDITOR.dom.elementPath( range.startContainer, editable ),
2592 endPath = new CKEDITOR.dom.elementPath( range.endContainer, editable );
2593
2594 // Note: checkBoundaryOfElement will not work on original range as CKEDITOR.START|END
2595 // means that range start|end must be literally anchored at block start|end, e.g.
2596 //
2597 // <p>a{</p><p>}b</p>
2598 //
2599 // will return false for both paragraphs but two similar ranges
2600 //
2601 // <p>a{}</p><p>{}b</p>
2602 //
2603 // will return true if checked separately.
2604 rangeStart.collapse( 1 );
2605 rangeEnd.collapse();
2606
2607 if ( startPath.block && rangeStart.checkBoundaryOfElement( startPath.block, CKEDITOR.END ) ) {
2608 range.setStartAfter( startPath.block );
2609 that.prependEolBr = 1;
2610 }
2611
2612 if ( endPath.block && rangeEnd.checkBoundaryOfElement( endPath.block, CKEDITOR.START ) ) {
2613 range.setEndBefore( endPath.block );
2614 that.appendEolBr = 1;
2615 }
2616 },
2617
2618 fix: function( that, editable ) {
2619 var doc = editable.getDocument(),
2620 appended;
2621
2622 // Append <br data-cke-eol="1"> to the fragment.
2623 if ( that.appendEolBr ) {
2624 appended = this.createEolBr( doc );
2625 that.fragment.append( appended );
2626 }
2627
2628 // Prepend <br data-cke-eol="1"> to the fragment but avoid duplicates. Such
2629 // elements should never follow each other in DOM.
2630 if ( that.prependEolBr && ( !appended || appended.getPrevious() ) ) {
2631 that.fragment.append( this.createEolBr( doc ), 1 );
2632 }
2633 },
2634
2635 createEolBr: function( doc ) {
2636 return doc.createElement( 'br', {
2637 attributes: {
2638 'data-cke-eol': 1
2639 }
2640 } );
2641 }
2642 },
2643
2644 bogus: {
2645 exclude: function( that ) {
2646 var boundaryNodes = that.range.getBoundaryNodes(),
2647 startNode = boundaryNodes.startNode,
2648 endNode = boundaryNodes.endNode;
2649
2650 // If bogus is the last node in range but not the only node, exclude it.
2651 if ( endNode && isBogus( endNode ) && ( !startNode || !startNode.equals( endNode ) ) )
2652 that.range.setEndBefore( endNode );
2653 }
2654 },
2655
2656 tree: {
2657 rebuild: function( that, editable ) {
2658 var range = that.range,
2659 node = range.getCommonAncestor(),
2660
2661 // A path relative to the common ancestor.
2662 commonPath = new CKEDITOR.dom.elementPath( node, editable ),
2663 startPath = new CKEDITOR.dom.elementPath( range.startContainer, editable ),
2664 endPath = new CKEDITOR.dom.elementPath( range.endContainer, editable ),
2665 limit;
2666
2667 if ( node.type == CKEDITOR.NODE_TEXT )
2668 node = node.getParent();
2669
2670 // Fix DOM of partially enclosed tables
2671 // <table><tbody><tr><td>a{b</td><td>c}d</td></tr></tbody></table>
2672 // Full table is returned
2673 // <table><tbody><tr><td>b</td><td>c</td></tr></tbody></table>
2674 // instead of
2675 // <td>b</td><td>c</td>
2676 if ( commonPath.blockLimit.is( { tr: 1, table: 1 } ) ) {
2677 var tableParent = commonPath.contains( 'table' ).getParent();
2678
2679 limit = function( node ) {
2680 return !node.equals( tableParent );
2681 };
2682 }
2683
2684 // Fix DOM in the following case
2685 // <ol><li>a{b<ul><li>c}d</li></ul></li></ol>
2686 // Full list is returned
2687 // <ol><li>b<ul><li>c</li></ul></li></ol>
2688 // instead of
2689 // b<ul><li>c</li></ul>
2690 else if ( commonPath.block && commonPath.block.is( CKEDITOR.dtd.$listItem ) ) {
2691 var startList = startPath.contains( CKEDITOR.dtd.$list ),
2692 endList = endPath.contains( CKEDITOR.dtd.$list );
2693
2694 if ( !startList.equals( endList ) ) {
2695 var listParent = commonPath.contains( CKEDITOR.dtd.$list ).getParent();
2696
2697 limit = function( node ) {
2698 return !node.equals( listParent );
2699 };
2700 }
2701 }
2702
2703 // If not defined, use generic limit function.
2704 if ( !limit ) {
2705 limit = function( node ) {
2706 return !node.equals( commonPath.block ) && !node.equals( commonPath.blockLimit );
2707 };
2708 }
2709
2710 this.rebuildFragment( that, editable, node, limit );
2711 },
2712
2713 rebuildFragment: function( that, editable, node, checkLimit ) {
2714 var clone;
2715
2716 while ( node && !node.equals( editable ) && checkLimit( node ) ) {
2717 // Don't clone children. Preserve element ids.
2718 clone = node.clone( 0, 1 );
2719 that.fragment.appendTo( clone );
2720 that.fragment = clone;
2721
2722 node = node.getParent();
2723 }
2724 }
2725 },
2726
2727 cell: {
2728 // Handle range anchored in table row with a single cell enclosed:
2729 // <table><tbody><tr>[<td>a</td>]</tr></tbody></table>
2730 // becomes
2731 // <table><tbody><tr><td>{a}</td></tr></tbody></table>
2732 shrink: function( that ) {
2733 var range = that.range,
2734 startContainer = range.startContainer,
2735 endContainer = range.endContainer,
2736 startOffset = range.startOffset,
2737 endOffset = range.endOffset;
2738
2739 if ( startContainer.type == CKEDITOR.NODE_ELEMENT && startContainer.equals( endContainer ) && startContainer.is( 'tr' ) && ++startOffset == endOffset ) {
2740 range.shrink( CKEDITOR.SHRINK_TEXT );
2741 }
2742 }
2743 }
2744 };
2745
2746 //
2747 // Helpers for editable.extractHtmlFromRange.
2748 //
2749 extractHtmlFromRangeHelpers = ( function() {
2750 function optimizeBookmarkNode( node, toStart ) {
2751 var parent = node.getParent();
2752
2753 if ( parent.is( CKEDITOR.dtd.$inline ) )
2754 node[ toStart ? 'insertBefore' : 'insertAfter' ]( parent );
2755 }
2756
2757 function mergeElements( merged, startBookmark, endBookmark ) {
2758 optimizeBookmarkNode( startBookmark );
2759 optimizeBookmarkNode( endBookmark, 1 );
2760
2761 var next;
2762 while ( ( next = endBookmark.getNext() ) ) {
2763 next.insertAfter( startBookmark );
2764
2765 // Update startBookmark after insertion to avoid the reversal of nodes (#13449).
2766 startBookmark = next;
2767 }
2768
2769 if ( isEmpty( merged ) )
2770 merged.remove();
2771 }
2772
2773 function getPath( startElement, root ) {
2774 return new CKEDITOR.dom.elementPath( startElement, root );
2775 }
2776
2777 // Creates a range from a bookmark without removing the bookmark.
2778 function createRangeFromBookmark( root, bookmark ) {
2779 var range = new CKEDITOR.dom.range( root );
2780 range.setStartAfter( bookmark.startNode );
2781 range.setEndBefore( bookmark.endNode );
2782 return range;
2783 }
2784
2785 var list = {
2786 detectMerge: function( that, editable ) {
2787 var range = createRangeFromBookmark( editable, that.bookmark ),
2788 startPath = range.startPath(),
2789 endPath = range.endPath(),
2790
2791 startList = startPath.contains( CKEDITOR.dtd.$list ),
2792 endList = endPath.contains( CKEDITOR.dtd.$list );
2793
2794 that.mergeList =
2795 // Both lists must exist
2796 startList && endList &&
2797 // ...and be of the same type
2798 // startList.getName() == endList.getName() &&
2799 // ...and share the same parent (same level in the tree)
2800 startList.getParent().equals( endList.getParent() ) &&
2801 // ...and must be different.
2802 !startList.equals( endList );
2803
2804 that.mergeListItems =
2805 startPath.block && endPath.block &&
2806 // Both containers must be list items
2807 startPath.block.is( CKEDITOR.dtd.$listItem ) && endPath.block.is( CKEDITOR.dtd.$listItem );
2808
2809 // Create merge bookmark.
2810 if ( that.mergeList || that.mergeListItems ) {
2811 var rangeClone = range.clone();
2812
2813 rangeClone.setStartBefore( that.bookmark.startNode );
2814 rangeClone.setEndAfter( that.bookmark.endNode );
2815
2816 that.mergeListBookmark = rangeClone.createBookmark();
2817 }
2818 },
2819
2820 merge: function( that, editable ) {
2821 if ( !that.mergeListBookmark )
2822 return;
2823
2824 var startNode = that.mergeListBookmark.startNode,
2825 endNode = that.mergeListBookmark.endNode,
2826
2827 startPath = getPath( startNode, editable ),
2828 endPath = getPath( endNode, editable );
2829
2830 if ( that.mergeList ) {
2831 var firstList = startPath.contains( CKEDITOR.dtd.$list ),
2832 secondList = endPath.contains( CKEDITOR.dtd.$list );
2833
2834 if ( !firstList.equals( secondList ) ) {
2835 secondList.moveChildren( firstList );
2836 secondList.remove();
2837 }
2838 }
2839
2840 if ( that.mergeListItems ) {
2841 var firstListItem = startPath.contains( CKEDITOR.dtd.$listItem ),
2842 secondListItem = endPath.contains( CKEDITOR.dtd.$listItem );
2843
2844 if ( !firstListItem.equals( secondListItem ) ) {
2845 mergeElements( secondListItem, startNode, endNode );
2846 }
2847 }
2848
2849 // Remove bookmark nodes.
2850 startNode.remove();
2851 endNode.remove();
2852 }
2853 };
2854
2855 var block = {
2856 // Detects whether blocks should be merged once contents are extracted.
2857 detectMerge: function( that, editable ) {
2858 // Don't merge blocks if lists or tables are already involved.
2859 if ( that.tableContentsRanges || that.mergeListBookmark )
2860 return;
2861
2862 var rangeClone = new CKEDITOR.dom.range( editable );
2863
2864 rangeClone.setStartBefore( that.bookmark.startNode );
2865 rangeClone.setEndAfter( that.bookmark.endNode );
2866
2867 that.mergeBlockBookmark = rangeClone.createBookmark();
2868 },
2869
2870 merge: function( that, editable ) {
2871 if ( !that.mergeBlockBookmark || that.purgeTableBookmark )
2872 return;
2873
2874 var startNode = that.mergeBlockBookmark.startNode,
2875 endNode = that.mergeBlockBookmark.endNode,
2876
2877 startPath = getPath( startNode, editable ),
2878 endPath = getPath( endNode, editable ),
2879
2880 firstBlock = startPath.block,
2881 secondBlock = endPath.block;
2882
2883 if ( firstBlock && secondBlock && !firstBlock.equals( secondBlock ) ) {
2884 mergeElements( secondBlock, startNode, endNode );
2885 }
2886
2887 // Remove bookmark nodes.
2888 startNode.remove();
2889 endNode.remove();
2890 }
2891 };
2892
2893 var table = ( function() {
2894 var tableEditable = { td: 1, th: 1, caption: 1 };
2895
2896 // Returns an array of ranges which should be entirely extracted.
2897 //
2898 // <table><tr>[<td>xx</td><td>y}y</td></tr></table>
2899 // will find:
2900 // <table><tr><td>[xx]</td><td>[y}y</td></tr></table>
2901 function findTableContentsRanges( range ) {
2902 // Leaving the below for debugging purposes.
2903 //
2904 // console.log( 'findTableContentsRanges' );
2905 // console.log( bender.tools.range.getWithHtml( range.root, range ) );
2906
2907 var contentsRanges = [],
2908 editableRange,
2909 walker = new CKEDITOR.dom.walker( range ),
2910 startCell = range.startPath().contains( tableEditable ),
2911 endCell = range.endPath().contains( tableEditable ),
2912 database = {};
2913
2914 walker.guard = function( node, leaving ) {
2915 // Guard may be executed on some node boundaries multiple times,
2916 // what results in creating more than one range for each selected cell. (#12964)
2917 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
2918 var key = 'visited_' + ( leaving ? 'out' : 'in' );
2919 if ( node.getCustomData( key ) ) {
2920 return;
2921 }
2922
2923 CKEDITOR.dom.element.setMarker( database, node, key, 1 );
2924 }
2925
2926 // Handle partial selection in a cell in which the range starts:
2927 // <td><p>x{xx</p></td>...
2928 // will store:
2929 // <td><p>x{xx</p>]</td>
2930 if ( leaving && startCell && node.equals( startCell ) ) {
2931 editableRange = range.clone();
2932 editableRange.setEndAt( startCell, CKEDITOR.POSITION_BEFORE_END );
2933 contentsRanges.push( editableRange );
2934 return;
2935 }
2936
2937 // Handle partial selection in a cell in which the range ends.
2938 if ( !leaving && endCell && node.equals( endCell ) ) {
2939 editableRange = range.clone();
2940 editableRange.setStartAt( endCell, CKEDITOR.POSITION_AFTER_START );
2941 contentsRanges.push( editableRange );
2942 return;
2943 }
2944
2945 // Handle all other cells visited by the walker.
2946 // We need to check whether the cell is disjoint with
2947 // the start and end cells to correctly handle case like:
2948 // <td>x{x</td><td><table>..<td>y}y</td>..</table></td>
2949 // without the check the second cell's content would be entirely removed.
2950 if ( !leaving && checkRemoveCellContents( node ) ) {
2951 editableRange = range.clone();
2952 editableRange.selectNodeContents( node );
2953 contentsRanges.push( editableRange );
2954 }
2955 };
2956
2957 walker.lastForward();
2958
2959 // Clear all markers so next extraction will not be affected by this one.
2960 CKEDITOR.dom.element.clearAllMarkers( database );
2961
2962 return contentsRanges;
2963
2964 function checkRemoveCellContents( node ) {
2965 return (
2966 // Must be a cell.
2967 node.type == CKEDITOR.NODE_ELEMENT && node.is( tableEditable ) &&
2968 // Must be disjoint with the range's startCell if exists.
2969 ( !startCell || checkDisjointNodes( node, startCell ) ) &&
2970 // Must be disjoint with the range's endCell if exists.
2971 ( !endCell || checkDisjointNodes( node, endCell ) )
2972 );
2973 }
2974 }
2975
2976 // Returns a normalized common ancestor of a range.
2977 // If the real common ancestor is located somewhere in between a table and a td/th/caption,
2978 // then the table will be returned.
2979 function getNormalizedAncestor( range ) {
2980 var common = range.getCommonAncestor();
2981
2982 if ( common.is( CKEDITOR.dtd.$tableContent ) && !common.is( tableEditable ) ) {
2983 common = common.getAscendant( 'table', true );
2984 }
2985
2986 return common;
2987 }
2988
2989 // Check whether node1 and node2 are disjoint, so are:
2990 // * not identical,
2991 // * not contained in each other.
2992 function checkDisjointNodes( node1, node2 ) {
2993 var disallowedPositions = CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_IS_CONTAINED,
2994 pos = node1.getPosition( node2 );
2995
2996 // Baaah... IDENTICAL is 0, so we can't simplify this ;/.
2997 return pos === CKEDITOR.POSITION_IDENTICAL ?
2998 false :
2999 ( ( pos & disallowedPositions ) === 0 );
3000 }
3001
3002 return {
3003 // Detects whether to purge entire list.
3004 detectPurge: function( that ) {
3005 var range = that.range,
3006 walkerRange = range.clone();
3007
3008 walkerRange.enlarge( CKEDITOR.ENLARGE_ELEMENT );
3009
3010 var walker = new CKEDITOR.dom.walker( walkerRange ),
3011 editablesCount = 0;
3012
3013 // Count the number of table editables in the range. If there's more than one,
3014 // table MAY be removed completely (it's a cross-cell range). Otherwise, only
3015 // the contents of the cell are usually removed.
3016 walker.evaluator = function( node ) {
3017 if ( node.type == CKEDITOR.NODE_ELEMENT && node.is( tableEditable ) ) {
3018 ++editablesCount;
3019 }
3020 };
3021
3022 walker.checkForward();
3023
3024 if ( editablesCount > 1 ) {
3025 var startTable = range.startPath().contains( 'table' ),
3026 endTable = range.endPath().contains( 'table' );
3027
3028 if ( startTable && endTable && range.checkBoundaryOfElement( startTable, CKEDITOR.START ) && range.checkBoundaryOfElement( endTable, CKEDITOR.END ) ) {
3029 var rangeClone = that.range.clone();
3030
3031 rangeClone.setStartBefore( startTable );
3032 rangeClone.setEndAfter( endTable );
3033
3034 that.purgeTableBookmark = rangeClone.createBookmark();
3035 }
3036 }
3037 },
3038
3039 // The magic.
3040 //
3041 // This method tries to discover whether the range starts or ends somewhere in a table
3042 // (it is not interested whether the range contains a table, because in such case
3043 // the extractContents() methods does the job correctly).
3044 // If the range meets these criteria, then the method tries to discover and store the following:
3045 //
3046 // * that.tableSurroundingRange - a part of the range which is located outside of any table which
3047 // will be touched (note: when range is located in a single cell it does not touch the table).
3048 // This range can be placed at:
3049 // * at the beginning: <p>he{re</p><table>..]..</table>
3050 // * in the middle: <table>..[..</table><p>here</p><table>..]..</table>
3051 // * at the end: <table>..[..</table><p>he}re</p>
3052 // * that.tableContentsRanges - an array of ranges with contents of td/th/caption that should be removed.
3053 // This assures that calling extractContents() does not change the structure of the table(s).
3054 detectRanges: function( that, editable ) {
3055 var range = createRangeFromBookmark( editable, that.bookmark ),
3056 surroundingRange = range.clone(),
3057 leftRange,
3058 rightRange,
3059
3060 // Find a common ancestor and normalize it (so the following paths contain tables).
3061 commonAncestor = getNormalizedAncestor( range ),
3062
3063 // Create paths using the normalized ancestor, so tables beyond the context
3064 // of the input range are not found.
3065 startPath = new CKEDITOR.dom.elementPath( range.startContainer, commonAncestor ),
3066 endPath = new CKEDITOR.dom.elementPath( range.endContainer, commonAncestor ),
3067
3068 startTable = startPath.contains( 'table' ),
3069 endTable = endPath.contains( 'table' ),
3070
3071 tableContentsRanges;
3072
3073 // Nothing to do here - the range doesn't touch any table or
3074 // it contains a table, but that table is fully selected so it will be simply fully removed
3075 // by the normal algorithm.
3076 if ( !startTable && !endTable ) {
3077 return;
3078 }
3079
3080 // Handle two disjoint tables case:
3081 // <table>..[..</table><p>ab</p><table>..]..</table>
3082 // is handled as (respectively: findTableContents( left ), surroundingRange, findTableContents( right )):
3083 // <table>..[..</table>][<p>ab</p>][<table>..]..</table>
3084 // Check that tables are disjoint to exclude a case when start equals end or one is contained
3085 // in the other.
3086 if ( startTable && endTable && checkDisjointNodes( startTable, endTable ) ) {
3087 that.tableSurroundingRange = surroundingRange;
3088 surroundingRange.setStartAt( startTable, CKEDITOR.POSITION_AFTER_END );
3089 surroundingRange.setEndAt( endTable, CKEDITOR.POSITION_BEFORE_START );
3090
3091 leftRange = range.clone();
3092 leftRange.setEndAt( startTable, CKEDITOR.POSITION_AFTER_END );
3093
3094 rightRange = range.clone();
3095 rightRange.setStartAt( endTable, CKEDITOR.POSITION_BEFORE_START );
3096
3097 tableContentsRanges = findTableContentsRanges( leftRange ).concat( findTableContentsRanges( rightRange ) );
3098 }
3099 // Divide the initial range into two parts:
3100 // * range which contains the part containing the table,
3101 // * surroundingRange which contains the part outside the table.
3102 //
3103 // The surroundingRange exists only if one of the range ends is
3104 // located outside the table.
3105 //
3106 // <p>a{b</p><table>..]..</table><p>cd</p>
3107 // becomes (respectively: surroundingRange, range):
3108 // <p>a{b</p>][<table>..]..</table><p>cd</p>
3109 else if ( !startTable ) {
3110 that.tableSurroundingRange = surroundingRange;
3111 surroundingRange.setEndAt( endTable, CKEDITOR.POSITION_BEFORE_START );
3112
3113 range.setStartAt( endTable, CKEDITOR.POSITION_AFTER_START );
3114 }
3115 // <p>ab</p><table>..[..</table><p>c}d</p>
3116 // becomes (respectively range, surroundingRange):
3117 // <p>ab</p><table>..[..</table>][<p>c}d</p>
3118 else if ( !endTable ) {
3119 that.tableSurroundingRange = surroundingRange;
3120 surroundingRange.setStartAt( startTable, CKEDITOR.POSITION_AFTER_END );
3121
3122 range.setEndAt( startTable, CKEDITOR.POSITION_AFTER_END );
3123 }
3124
3125 // Use already calculated or calculate for the remaining range.
3126 that.tableContentsRanges = tableContentsRanges ? tableContentsRanges : findTableContentsRanges( range );
3127
3128 // Leaving the below for debugging purposes.
3129 //
3130 // if ( that.tableSurroundingRange ) {
3131 // console.log( 'tableSurroundingRange' );
3132 // console.log( bender.tools.range.getWithHtml( that.tableSurroundingRange.root, that.tableSurroundingRange ) );
3133 // }
3134 //
3135 // console.log( 'tableContentsRanges' );
3136 // that.tableContentsRanges.forEach( function( range ) {
3137 // console.log( bender.tools.range.getWithHtml( range.root, range ) );
3138 // } );
3139 },
3140
3141 deleteRanges: function( that ) {
3142 var range;
3143
3144 // Delete table cell contents.
3145 while ( ( range = that.tableContentsRanges.pop() ) ) {
3146 range.extractContents();
3147
3148 if ( isEmpty( range.startContainer ) )
3149 range.startContainer.appendBogus();
3150 }
3151
3152 // Finally delete surroundings of the table.
3153 if ( that.tableSurroundingRange ) {
3154 that.tableSurroundingRange.extractContents();
3155 }
3156 },
3157
3158 purge: function( that ) {
3159 if ( !that.purgeTableBookmark )
3160 return;
3161
3162 var doc = that.doc,
3163 range = that.range,
3164 rangeClone = range.clone(),
3165 // How about different enter modes?
3166 block = doc.createElement( 'p' );
3167
3168 block.insertBefore( that.purgeTableBookmark.startNode );
3169
3170 rangeClone.moveToBookmark( that.purgeTableBookmark );
3171 rangeClone.deleteContents();
3172
3173 that.range.moveToPosition( block, CKEDITOR.POSITION_AFTER_START );
3174 }
3175 };
3176 } )();
3177
3178 return {
3179 list: list,
3180 block: block,
3181 table: table,
3182
3183 // Detects whether use "mergeThen" argument in range.extractContents().
3184 detectExtractMerge: function( that ) {
3185 // Don't merge if playing with lists.
3186 return !(
3187 that.range.startPath().contains( CKEDITOR.dtd.$listItem ) &&
3188 that.range.endPath().contains( CKEDITOR.dtd.$listItem )
3189 );
3190 },
3191
3192 fixUneditableRangePosition: function( range ) {
3193 if ( !range.startContainer.getDtd()[ '#' ] ) {
3194 range.moveToClosestEditablePosition( null, true );
3195 }
3196 },
3197
3198 // Perform auto paragraphing if needed.
3199 autoParagraph: function( editor, range ) {
3200 var path = range.startPath(),
3201 fixBlock;
3202
3203 if ( shouldAutoParagraph( editor, path.block, path.blockLimit ) && ( fixBlock = autoParagraphTag( editor ) ) ) {
3204 fixBlock = range.document.createElement( fixBlock );
3205 fixBlock.appendBogus();
3206 range.insertNode( fixBlock );
3207 range.moveToPosition( fixBlock, CKEDITOR.POSITION_AFTER_START );
3208 }
3209 }
3210 };
3211 } )();
3212
3213} )();
3214
3215/**
3216 * Whether the editor must output an empty value (`''`) if its content only consists
3217 * of an empty paragraph.
3218 *
3219 * config.ignoreEmptyParagraph = false;
3220 *
3221 * @cfg {Boolean} [ignoreEmptyParagraph=true]
3222 * @member CKEDITOR.config
3223 */
3224
3225/**
3226 * Event fired by the editor in order to get accessibility help label.
3227 * The event is responded to by a component which provides accessibility
3228 * help (i.e. the `a11yhelp` plugin) hence the editor is notified whether
3229 * accessibility help is available.
3230 *
3231 * Providing info:
3232 *
3233 * editor.on( 'ariaEditorHelpLabel', function( evt ) {
3234 * evt.data.label = editor.lang.common.editorHelp;
3235 * } );
3236 *
3237 * Getting label:
3238 *
3239 * var helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label;
3240 *
3241 * @since 4.4.3
3242 * @event ariaEditorHelpLabel
3243 * @param {String} label The label to be used.
3244 * @member CKEDITOR.editor
3245 */
3246
3247/**
3248 * Event fired when the user double-clicks in the editable area.
3249 * The event allows to open a dialog window for a clicked element in a convenient way:
3250 *
3251 * editor.on( 'doubleclick', function( evt ) {
3252 * var element = evt.data.element;
3253 *
3254 * if ( element.is( 'table' ) )
3255 * evt.data.dialog = 'tableProperties';
3256 * } );
3257 *
3258 * **Note:** To handle double-click on a widget use {@link CKEDITOR.plugins.widget#doubleclick}.
3259 *
3260 * @event doubleclick
3261 * @param data
3262 * @param {CKEDITOR.dom.element} data.element The double-clicked element.
3263 * @param {String} data.dialog The dialog window to be opened. If set by the listener,
3264 * the specified dialog window will be opened.
3265 * @member CKEDITOR.editor
3266 */
diff --git a/sources/core/editor.js b/sources/core/editor.js
new file mode 100644
index 0000000..8dfce7f
--- /dev/null
+++ b/sources/core/editor.js
@@ -0,0 +1,2039 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.editor} class that represents an
8 * editor instance.
9 */
10
11( function() {
12 // Override the basic constructor defined at editor_basic.js.
13 Editor.prototype = CKEDITOR.editor.prototype;
14 CKEDITOR.editor = Editor;
15
16 /**
17 * Represents an editor instance. This constructor should be rarely
18 * used in favor of the {@link CKEDITOR} editor creation functions.
19 *
20 * @class CKEDITOR.editor
21 * @mixins CKEDITOR.event
22 * @constructor Creates an editor class instance.
23 * @param {Object} [instanceConfig] Configuration values for this specific instance.
24 * @param {CKEDITOR.dom.element} [element] The DOM element upon which this editor
25 * will be created.
26 * @param {Number} [mode] The element creation mode to be used by this editor.
27 */
28 function Editor( instanceConfig, element, mode ) {
29 // Call the CKEDITOR.event constructor to initialize this instance.
30 CKEDITOR.event.call( this );
31
32 // Make a clone of the config object, to avoid having it touched by our code. (#9636)
33 instanceConfig = instanceConfig && CKEDITOR.tools.clone( instanceConfig );
34
35 // if editor is created off one page element.
36 if ( element !== undefined ) {
37 // Asserting element and mode not null.
38 if ( !( element instanceof CKEDITOR.dom.element ) )
39 throw new Error( 'Expect element of type CKEDITOR.dom.element.' );
40 else if ( !mode )
41 throw new Error( 'One of the element modes must be specified.' );
42
43 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && mode == CKEDITOR.ELEMENT_MODE_INLINE )
44 throw new Error( 'Inline element mode is not supported on IE quirks.' );
45
46 if ( !isSupportedElement( element, mode ) )
47 throw new Error( 'The specified element mode is not supported on element: "' + element.getName() + '".' );
48
49 /**
50 * The original host page element upon which the editor is created. It is only
51 * supposed to be provided by the particular editor creator and is not subject to
52 * be modified.
53 *
54 * @readonly
55 * @property {CKEDITOR.dom.element}
56 */
57 this.element = element;
58
59 /**
60 * This property indicates the way this instance is associated with the {@link #element}.
61 * See also {@link CKEDITOR#ELEMENT_MODE_INLINE} and {@link CKEDITOR#ELEMENT_MODE_REPLACE}.
62 *
63 * @readonly
64 * @property {Number}
65 */
66 this.elementMode = mode;
67
68 this.name = ( this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) && ( element.getId() || element.getNameAtt() );
69 } else {
70 this.elementMode = CKEDITOR.ELEMENT_MODE_NONE;
71 }
72
73 // Declare the private namespace.
74 this._ = {};
75
76 this.commands = {};
77
78 /**
79 * Contains all UI templates created for this editor instance.
80 *
81 * @readonly
82 * @property {Object}
83 */
84 this.templates = {};
85
86 /**
87 * A unique identifier of this editor instance.
88 *
89 * **Note:** It will be originated from the `id` or `name`
90 * attribute of the {@link #element}, otherwise a name pattern of
91 * `'editor{n}'` will be used.
92 *
93 * @readonly
94 * @property {String}
95 */
96 this.name = this.name || genEditorName();
97
98 /**
99 * A unique random string assigned to each editor instance on the page.
100 *
101 * @readonly
102 * @property {String}
103 */
104 this.id = CKEDITOR.tools.getNextId();
105
106 /**
107 * Indicates editor initialization status. The following statuses are available:
108 *
109 * * **unloaded**: The initial state &mdash; the editor instance was initialized,
110 * but its components (configuration, plugins, language files) are not loaded yet.
111 * * **loaded**: The editor components were loaded &mdash; see the {@link CKEDITOR.editor#loaded} event.
112 * * **ready**: The editor is fully initialized and ready &mdash; see the {@link CKEDITOR.editor#instanceReady} event.
113 * * **destroyed**: The editor was destroyed &mdash; see the {@link CKEDITOR.editor#method-destroy} method.
114 *
115 * @since 4.1
116 * @readonly
117 * @property {String}
118 */
119 this.status = 'unloaded';
120
121 /**
122 * The configuration for this editor instance. It inherits all
123 * settings defined in {@link CKEDITOR.config}, combined with settings
124 * loaded from custom configuration files and those defined inline in
125 * the page when creating the editor.
126 *
127 * var editor = CKEDITOR.instances.editor1;
128 * alert( editor.config.skin ); // e.g. 'moono'
129 *
130 * @readonly
131 * @property {CKEDITOR.config}
132 */
133 this.config = CKEDITOR.tools.prototypedCopy( CKEDITOR.config );
134
135 /**
136 * The namespace containing UI features related to this editor instance.
137 *
138 * @readonly
139 * @property {CKEDITOR.ui}
140 */
141 this.ui = new CKEDITOR.ui( this );
142
143 /**
144 * Controls the focus state of this editor instance. This property
145 * is rarely used for normal API operations. It is mainly
146 * targeted at developers adding UI elements to the editor interface.
147 *
148 * @readonly
149 * @property {CKEDITOR.focusManager}
150 */
151 this.focusManager = new CKEDITOR.focusManager( this );
152
153 /**
154 * Controls keystroke typing in this editor instance.
155 *
156 * @readonly
157 * @property {CKEDITOR.keystrokeHandler}
158 */
159 this.keystrokeHandler = new CKEDITOR.keystrokeHandler( this );
160
161 // Make the editor update its command states on mode change.
162 this.on( 'readOnly', updateCommands );
163 this.on( 'selectionChange', function( evt ) {
164 updateCommandsContext( this, evt.data.path );
165 } );
166 this.on( 'activeFilterChange', function() {
167 updateCommandsContext( this, this.elementPath(), true );
168 } );
169 this.on( 'mode', updateCommands );
170
171 // Handle startup focus.
172 this.on( 'instanceReady', function() {
173 this.config.startupFocus && this.focus();
174 } );
175
176 CKEDITOR.fire( 'instanceCreated', null, this );
177
178 // Add this new editor to the CKEDITOR.instances collections.
179 CKEDITOR.add( this );
180
181 // Return the editor instance immediately to enable early stage event registrations.
182 CKEDITOR.tools.setTimeout( function() {
183 if ( this.status !== 'destroyed' ) {
184 initConfig( this, instanceConfig );
185 } else {
186 CKEDITOR.warn( 'editor-incorrect-destroy' );
187 }
188 }, 0, this );
189 }
190
191 var nameCounter = 0;
192
193 function genEditorName() {
194 do {
195 var name = 'editor' + ( ++nameCounter );
196 }
197 while ( CKEDITOR.instances[ name ] );
198
199 return name;
200 }
201
202 // Asserting element DTD depending on mode.
203 function isSupportedElement( element, mode ) {
204 if ( mode == CKEDITOR.ELEMENT_MODE_INLINE )
205 return element.is( CKEDITOR.dtd.$editable ) || element.is( 'textarea' );
206 else if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE )
207 return !element.is( CKEDITOR.dtd.$nonBodyContent );
208 return 1;
209 }
210
211 function updateCommands() {
212 var commands = this.commands,
213 name;
214
215 for ( name in commands )
216 updateCommand( this, commands[ name ] );
217 }
218
219 function updateCommand( editor, cmd ) {
220 cmd[ cmd.startDisabled ? 'disable' : editor.readOnly && !cmd.readOnly ? 'disable' : cmd.modes[ editor.mode ] ? 'enable' : 'disable' ]();
221 }
222
223 function updateCommandsContext( editor, path, forceRefresh ) {
224 // Commands cannot be refreshed without a path. In edge cases
225 // it may happen that there's no selection when this function is executed.
226 // For example when active filter is changed in #10877.
227 if ( !path )
228 return;
229
230 var command,
231 name,
232 commands = editor.commands;
233
234 for ( name in commands ) {
235 command = commands[ name ];
236
237 if ( forceRefresh || command.contextSensitive )
238 command.refresh( editor, path );
239 }
240 }
241
242 // ##### START: Config Privates
243
244 // These function loads custom configuration files and cache the
245 // CKEDITOR.editorConfig functions defined on them, so there is no need to
246 // download them more than once for several instances.
247 var loadConfigLoaded = {};
248
249 function loadConfig( editor ) {
250 var customConfig = editor.config.customConfig;
251
252 // Check if there is a custom config to load.
253 if ( !customConfig )
254 return false;
255
256 customConfig = CKEDITOR.getUrl( customConfig );
257
258 var loadedConfig = loadConfigLoaded[ customConfig ] || ( loadConfigLoaded[ customConfig ] = {} );
259
260 // If the custom config has already been downloaded, reuse it.
261 if ( loadedConfig.fn ) {
262 // Call the cached CKEDITOR.editorConfig defined in the custom
263 // config file for the editor instance depending on it.
264 loadedConfig.fn.call( editor, editor.config );
265
266 // If there is no other customConfig in the chain, fire the
267 // "configLoaded" event.
268 if ( CKEDITOR.getUrl( editor.config.customConfig ) == customConfig || !loadConfig( editor ) )
269 editor.fireOnce( 'customConfigLoaded' );
270 } else {
271 // Load the custom configuration file.
272 // To resolve customConfig race conflicts, use scriptLoader#queue
273 // instead of scriptLoader#load (#6504).
274 CKEDITOR.scriptLoader.queue( customConfig, function() {
275 // If the CKEDITOR.editorConfig function has been properly
276 // defined in the custom configuration file, cache it.
277 if ( CKEDITOR.editorConfig )
278 loadedConfig.fn = CKEDITOR.editorConfig;
279 else
280 loadedConfig.fn = function() {};
281
282 // Call the load config again. This time the custom
283 // config is already cached and so it will get loaded.
284 loadConfig( editor );
285 } );
286 }
287
288 return true;
289 }
290
291 function initConfig( editor, instanceConfig ) {
292 // Setup the lister for the "customConfigLoaded" event.
293 editor.on( 'customConfigLoaded', function() {
294 if ( instanceConfig ) {
295 // Register the events that may have been set at the instance
296 // configuration object.
297 if ( instanceConfig.on ) {
298 for ( var eventName in instanceConfig.on ) {
299 editor.on( eventName, instanceConfig.on[ eventName ] );
300 }
301 }
302
303 // Overwrite the settings from the in-page config.
304 CKEDITOR.tools.extend( editor.config, instanceConfig, true );
305
306 delete editor.config.on;
307 }
308
309 onConfigLoaded( editor );
310 } );
311
312 // The instance config may override the customConfig setting to avoid
313 // loading the default ~/config.js file.
314 if ( instanceConfig && instanceConfig.customConfig != null )
315 editor.config.customConfig = instanceConfig.customConfig;
316
317 // Load configs from the custom configuration files.
318 if ( !loadConfig( editor ) )
319 editor.fireOnce( 'customConfigLoaded' );
320 }
321
322 // ##### END: Config Privates
323
324 // Set config related properties.
325 function onConfigLoaded( editor ) {
326 var config = editor.config;
327
328 /**
329 * Indicates the read-only state of this editor. This is a read-only property.
330 * See also {@link CKEDITOR.editor#setReadOnly}.
331 *
332 * @since 3.6
333 * @readonly
334 * @property {Boolean}
335 */
336 editor.readOnly = isEditorReadOnly();
337
338 function isEditorReadOnly() {
339 if ( config.readOnly ) {
340 return true;
341 }
342
343 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ) {
344 if ( editor.element.is( 'textarea' ) ) {
345 return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' );
346 } else {
347 return editor.element.isReadOnly();
348 }
349 } else if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
350 return editor.element.hasAttribute( 'disabled' ) || editor.element.hasAttribute( 'readonly' );
351 }
352
353 return false;
354 }
355
356 /**
357 * Indicates that the editor is running in an environment where
358 * no block elements are accepted inside the content.
359 *
360 * This can be for example inline editor based on an `<h1>` element.
361 *
362 * @readonly
363 * @property {Boolean}
364 */
365 editor.blockless = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ?
366 !( editor.element.is( 'textarea' ) || CKEDITOR.dtd[ editor.element.getName() ].p ) :
367 false;
368
369 /**
370 * The [tabbing navigation](http://en.wikipedia.org/wiki/Tabbing_navigation) order determined for this editor instance.
371 * This can be set by the <code>{@link CKEDITOR.config#tabIndex}</code>
372 * setting or taken from the `tabindex` attribute of the
373 * {@link #element} associated with the editor.
374 *
375 * alert( editor.tabIndex ); // e.g. 0
376 *
377 * @readonly
378 * @property {Number} [=0]
379 */
380 editor.tabIndex = config.tabIndex || editor.element && editor.element.getAttribute( 'tabindex' ) || 0;
381
382 editor.activeEnterMode = editor.enterMode = validateEnterMode( editor, config.enterMode );
383 editor.activeShiftEnterMode = editor.shiftEnterMode = validateEnterMode( editor, config.shiftEnterMode );
384
385 // Set CKEDITOR.skinName. Note that it is not possible to have
386 // different skins on the same page, so the last one to set it "wins".
387 if ( config.skin )
388 CKEDITOR.skinName = config.skin;
389
390 // Fire the "configLoaded" event.
391 editor.fireOnce( 'configLoaded' );
392
393 initComponents( editor );
394 }
395
396 // Various other core components that read editor configuration.
397 function initComponents( editor ) {
398 // Documented in dataprocessor.js.
399 editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor );
400
401 // Set activeFilter directly to avoid firing event.
402 editor.filter = editor.activeFilter = new CKEDITOR.filter( editor );
403
404 loadSkin( editor );
405 }
406
407 function loadSkin( editor ) {
408 CKEDITOR.skin.loadPart( 'editor', function() {
409 loadLang( editor );
410 } );
411 }
412
413 function loadLang( editor ) {
414 CKEDITOR.lang.load( editor.config.language, editor.config.defaultLanguage, function( languageCode, lang ) {
415 var configTitle = editor.config.title;
416
417 /**
418 * The code for the language resources that have been loaded
419 * for the user interface elements of this editor instance.
420 *
421 * alert( editor.langCode ); // e.g. 'en'
422 *
423 * @readonly
424 * @property {String}
425 */
426 editor.langCode = languageCode;
427
428 /**
429 * An object that contains all language strings used by the editor interface.
430 *
431 * alert( editor.lang.basicstyles.bold ); // e.g. 'Negrito' (if the language is set to Portuguese)
432 *
433 * @readonly
434 * @property {Object} lang
435 */
436 // As we'll be adding plugin specific entries that could come
437 // from different language code files, we need a copy of lang,
438 // not a direct reference to it.
439 editor.lang = CKEDITOR.tools.prototypedCopy( lang );
440
441 /**
442 * Indicates the human-readable title of this editor. Although this is a read-only property,
443 * it can be initialized with {@link CKEDITOR.config#title}.
444 *
445 * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name editor.name}
446 * which identifies the instance in the {@link CKEDITOR#instances} literal.
447 *
448 * @since 4.2
449 * @readonly
450 * @property {String/Boolean}
451 */
452 editor.title = typeof configTitle == 'string' || configTitle === false ? configTitle : [ editor.lang.editor, editor.name ].join( ', ' );
453
454 if ( !editor.config.contentsLangDirection ) {
455 // Fallback to either the editable element direction or editor UI direction depending on creators.
456 editor.config.contentsLangDirection = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? editor.element.getDirection( 1 ) : editor.lang.dir;
457 }
458
459 editor.fire( 'langLoaded' );
460
461 preloadStylesSet( editor );
462 } );
463 }
464
465 // Preloads styles set file (config.stylesSet).
466 // If stylesSet was defined directly (by an array)
467 // this function will call loadPlugins fully synchronously.
468 // If stylesSet is a string (path) loadPlugins will
469 // be called asynchronously.
470 // In both cases - styles will be preload before plugins initialization.
471 function preloadStylesSet( editor ) {
472 editor.getStylesSet( function( styles ) {
473 // Wait for editor#loaded, so plugins could add their listeners.
474 // But listen with high priority to fire editor#stylesSet before editor#uiReady and editor#setData.
475 editor.once( 'loaded', function() {
476 // Note: we can't use fireOnce because this event may canceled and fired again.
477 editor.fire( 'stylesSet', { styles: styles } );
478 }, null, null, 1 );
479
480 loadPlugins( editor );
481 } );
482 }
483
484 function loadPlugins( editor ) {
485 var config = editor.config,
486 plugins = config.plugins,
487 extraPlugins = config.extraPlugins,
488 removePlugins = config.removePlugins;
489
490 if ( extraPlugins ) {
491 // Remove them first to avoid duplications.
492 var extraRegex = new RegExp( '(?:^|,)(?:' + extraPlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)', 'g' );
493 plugins = plugins.replace( extraRegex, '' );
494
495 plugins += ',' + extraPlugins;
496 }
497
498 if ( removePlugins ) {
499 var removeRegex = new RegExp( '(?:^|,)(?:' + removePlugins.replace( /\s*,\s*/g, '|' ) + ')(?=,|$)', 'g' );
500 plugins = plugins.replace( removeRegex, '' );
501 }
502
503 // Load the Adobe AIR plugin conditionally.
504 CKEDITOR.env.air && ( plugins += ',adobeair' );
505
506 // Load all plugins defined in the "plugins" setting.
507 CKEDITOR.plugins.load( plugins.split( ',' ), function( plugins ) {
508 // The list of plugins.
509 var pluginsArray = [];
510
511 // The language code to get loaded for each plugin. Null
512 // entries will be appended for plugins with no language files.
513 var languageCodes = [];
514
515 // The list of URLs to language files.
516 var languageFiles = [];
517
518 /**
519 * An object that contains references to all plugins used by this
520 * editor instance.
521 *
522 * alert( editor.plugins.dialog.path ); // e.g. 'http://example.com/ckeditor/plugins/dialog/'
523 *
524 * // Check if a plugin is available.
525 * if ( editor.plugins.image ) {
526 * ...
527 * }
528 *
529 * @readonly
530 * @property {Object}
531 */
532 editor.plugins = plugins;
533
534 // Loop through all plugins, to build the list of language
535 // files to get loaded.
536 //
537 // Check also whether any of loaded plugins doesn't require plugins
538 // defined in config.removePlugins. Throw non-blocking error if this happens.
539 for ( var pluginName in plugins ) {
540 var plugin = plugins[ pluginName ],
541 pluginLangs = plugin.lang,
542 lang = null,
543 requires = plugin.requires,
544 match, name;
545
546 // Transform it into a string, if it's not one.
547 if ( CKEDITOR.tools.isArray( requires ) )
548 requires = requires.join( ',' );
549
550 if ( requires && ( match = requires.match( removeRegex ) ) ) {
551 while ( ( name = match.pop() ) ) {
552 CKEDITOR.error( 'editor-plugin-required', { plugin: name.replace( ',', '' ), requiredBy: pluginName } );
553 }
554 }
555
556 // If the plugin has "lang".
557 if ( pluginLangs && !editor.lang[ pluginName ] ) {
558 // Trasnform the plugin langs into an array, if it's not one.
559 if ( pluginLangs.split )
560 pluginLangs = pluginLangs.split( ',' );
561
562 // Resolve the plugin language. If the current language
563 // is not available, get English or the first one.
564 if ( CKEDITOR.tools.indexOf( pluginLangs, editor.langCode ) >= 0 )
565 lang = editor.langCode;
566 else {
567 // The language code may have the locale information (zh-cn).
568 // Fall back to locale-less in that case (zh).
569 var langPart = editor.langCode.replace( /-.*/, '' );
570 if ( langPart != editor.langCode && CKEDITOR.tools.indexOf( pluginLangs, langPart ) >= 0 )
571 lang = langPart;
572 // Try the only "generic" option we have: English.
573 else if ( CKEDITOR.tools.indexOf( pluginLangs, 'en' ) >= 0 )
574 lang = 'en';
575 else
576 lang = pluginLangs[ 0 ];
577 }
578
579 if ( !plugin.langEntries || !plugin.langEntries[ lang ] ) {
580 // Put the language file URL into the list of files to
581 // get downloaded.
582 languageFiles.push( CKEDITOR.getUrl( plugin.path + 'lang/' + lang + '.js' ) );
583 } else {
584 editor.lang[ pluginName ] = plugin.langEntries[ lang ];
585 lang = null;
586 }
587 }
588
589 // Save the language code, so we know later which
590 // language has been resolved to this plugin.
591 languageCodes.push( lang );
592
593 pluginsArray.push( plugin );
594 }
595
596 // Load all plugin specific language files in a row.
597 CKEDITOR.scriptLoader.load( languageFiles, function() {
598 // Initialize all plugins that have the "beforeInit" and "init" methods defined.
599 var methods = [ 'beforeInit', 'init', 'afterInit' ];
600 for ( var m = 0; m < methods.length; m++ ) {
601 for ( var i = 0; i < pluginsArray.length; i++ ) {
602 var plugin = pluginsArray[ i ];
603
604 // Uses the first loop to update the language entries also.
605 if ( m === 0 && languageCodes[ i ] && plugin.lang && plugin.langEntries )
606 editor.lang[ plugin.name ] = plugin.langEntries[ languageCodes[ i ] ];
607
608 // Call the plugin method (beforeInit and init).
609 if ( plugin[ methods[ m ] ] )
610 plugin[ methods[ m ] ]( editor );
611 }
612 }
613
614 editor.fireOnce( 'pluginsLoaded' );
615
616 // Setup the configured keystrokes.
617 config.keystrokes && editor.setKeystroke( editor.config.keystrokes );
618
619 // Setup the configured blocked keystrokes.
620 for ( i = 0; i < editor.config.blockedKeystrokes.length; i++ )
621 editor.keystrokeHandler.blockedKeystrokes[ editor.config.blockedKeystrokes[ i ] ] = 1;
622
623 editor.status = 'loaded';
624 editor.fireOnce( 'loaded' );
625 CKEDITOR.fire( 'instanceLoaded', null, editor );
626 } );
627 } );
628 }
629
630 // Send to data output back to editor's associated element.
631 function updateEditorElement() {
632 var element = this.element;
633
634 // Some editor creation mode will not have the
635 // associated element.
636 if ( element && this.elementMode != CKEDITOR.ELEMENT_MODE_APPENDTO ) {
637 var data = this.getData();
638
639 if ( this.config.htmlEncodeOutput )
640 data = CKEDITOR.tools.htmlEncode( data );
641
642 if ( element.is( 'textarea' ) )
643 element.setValue( data );
644 else
645 element.setHtml( data );
646
647 return true;
648 }
649 return false;
650 }
651
652 // Always returns ENTER_BR in case of blockless editor.
653 function validateEnterMode( editor, enterMode ) {
654 return editor.blockless ? CKEDITOR.ENTER_BR : enterMode;
655 }
656
657 // Create DocumentFragment from specified ranges. For now it handles only tables in Firefox
658 // and returns DocumentFragment from the 1. range for other cases. (#13884)
659 function createDocumentFragmentFromRanges( ranges, editable ) {
660 var docFragment = new CKEDITOR.dom.documentFragment(),
661 tableClone,
662 currentRow,
663 currentRowClone;
664
665 for ( var i = 0; i < ranges.length; i++ ) {
666 var range = ranges[ i ],
667 container = range.startContainer;
668
669 if ( container.getName && container.getName() == 'tr' ) {
670 if ( !tableClone ) {
671 tableClone = container.getAscendant( 'table' ).clone();
672 tableClone.append( container.getAscendant( 'tbody' ).clone() );
673 docFragment.append( tableClone );
674 tableClone = tableClone.findOne( 'tbody' );
675 }
676
677 if ( !( currentRow && currentRow.equals( container ) ) ) {
678 currentRow = container;
679 currentRowClone = container.clone();
680 tableClone.append( currentRowClone );
681 }
682
683 currentRowClone.append( range.cloneContents() );
684 } else {
685 // If there was something else copied with table,
686 // append it to DocumentFragment.
687 docFragment.append( range.cloneContents() );
688 }
689 }
690
691 if ( !tableClone ) {
692 return editable.getHtmlFromRange( ranges[ 0 ] );
693 }
694
695 return docFragment;
696 }
697
698 CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
699 /**
700 * Adds a command definition to the editor instance. Commands added with
701 * this function can be executed later with the <code>{@link #execCommand}</code> method.
702 *
703 * editorInstance.addCommand( 'sample', {
704 * exec: function( editor ) {
705 * alert( 'Executing a command for the editor name "' + editor.name + '"!' );
706 * }
707 * } );
708 *
709 * @param {String} commandName The indentifier name of the command.
710 * @param {CKEDITOR.commandDefinition} commandDefinition The command definition.
711 */
712 addCommand: function( commandName, commandDefinition ) {
713 commandDefinition.name = commandName.toLowerCase();
714 var cmd = new CKEDITOR.command( this, commandDefinition );
715
716 // Update command when mode is set.
717 // This guarantees that commands added before first editor#mode
718 // aren't immediately updated, but waits for editor#mode and that
719 // commands added later are immediately refreshed, even when added
720 // before instanceReady. #10103, #10249
721 if ( this.mode )
722 updateCommand( this, cmd );
723
724 return this.commands[ commandName ] = cmd;
725 },
726
727 /**
728 * Attaches the editor to a form to call {@link #updateElement} before form submission.
729 * This method is called by both creators ({@link CKEDITOR#replace replace} and
730 * {@link CKEDITOR#inline inline}), so there is no reason to call it manually.
731 *
732 * @private
733 */
734 _attachToForm: function() {
735 var editor = this,
736 element = editor.element,
737 form = new CKEDITOR.dom.element( element.$.form );
738
739 // If are replacing a textarea, we must
740 if ( element.is( 'textarea' ) ) {
741 if ( form ) {
742 form.on( 'submit', onSubmit );
743
744 // Check if there is no element/elements input with name == "submit".
745 // If they exists they will overwrite form submit function (form.$.submit).
746 // If form.$.submit is overwritten we can not do anything with it.
747 if ( isFunction( form.$.submit ) ) {
748 // Setup the submit function because it doesn't fire the
749 // "submit" event.
750 form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit ) {
751 return function() {
752 onSubmit();
753
754 // For IE, the DOM submit function is not a
755 // function, so we need third check.
756 if ( originalSubmit.apply )
757 originalSubmit.apply( this );
758 else
759 originalSubmit();
760 };
761 } );
762 }
763
764 // Remove 'submit' events registered on form element before destroying.(#3988)
765 editor.on( 'destroy', function() {
766 form.removeListener( 'submit', onSubmit );
767 } );
768 }
769 }
770
771 function onSubmit( evt ) {
772 editor.updateElement();
773
774 // #8031 If textarea had required attribute and editor is empty fire 'required' event and if
775 // it was cancelled, prevent submitting the form.
776 if ( editor._.required && !element.getValue() && editor.fire( 'required' ) === false ) {
777 // When user press save button event (evt) is undefined (see save plugin).
778 // This method works because it throws error so originalSubmit won't be called.
779 // Also this error won't be shown because it will be caught in save plugin.
780 evt.data.preventDefault();
781 }
782 }
783
784 function isFunction( f ) {
785 // For IE8 typeof fun == object so we cannot use it.
786 return !!( f && f.call && f.apply );
787 }
788 },
789
790 /**
791 * Destroys the editor instance, releasing all resources used by it.
792 * If the editor replaced an element, the element will be recovered.
793 *
794 * alert( CKEDITOR.instances.editor1 ); // e.g. object
795 * CKEDITOR.instances.editor1.destroy();
796 * alert( CKEDITOR.instances.editor1 ); // undefined
797 *
798 * @param {Boolean} [noUpdate] If the instance is replacing a DOM
799 * element, this parameter indicates whether or not to update the
800 * element with the instance content.
801 */
802 destroy: function( noUpdate ) {
803 this.fire( 'beforeDestroy' );
804
805 !noUpdate && updateEditorElement.call( this );
806
807 this.editable( null );
808
809 if ( this.filter ) {
810 this.filter.destroy();
811 delete this.filter;
812 }
813
814 delete this.activeFilter;
815
816 this.status = 'destroyed';
817
818 this.fire( 'destroy' );
819
820 // Plug off all listeners to prevent any further events firing.
821 this.removeAllListeners();
822
823 CKEDITOR.remove( this );
824 CKEDITOR.fire( 'instanceDestroyed', null, this );
825 },
826
827 /**
828 * Returns an {@link CKEDITOR.dom.elementPath element path} for the selection in the editor.
829 *
830 * @param {CKEDITOR.dom.node} [startNode] From which the path should start,
831 * if not specified defaults to editor selection's
832 * start element yielded by {@link CKEDITOR.dom.selection#getStartElement}.
833 * @returns {CKEDITOR.dom.elementPath}
834 */
835 elementPath: function( startNode ) {
836 if ( !startNode ) {
837 var sel = this.getSelection();
838 if ( !sel )
839 return null;
840
841 startNode = sel.getStartElement();
842 }
843
844 return startNode ? new CKEDITOR.dom.elementPath( startNode, this.editable() ) : null;
845 },
846
847 /**
848 * Shortcut to create a {@link CKEDITOR.dom.range} instance from the editable element.
849 *
850 * @returns {CKEDITOR.dom.range} The DOM range created if the editable has presented.
851 * @see CKEDITOR.dom.range
852 */
853 createRange: function() {
854 var editable = this.editable();
855 return editable ? new CKEDITOR.dom.range( editable ) : null;
856 },
857
858 /**
859 * Executes a command associated with the editor.
860 *
861 * editorInstance.execCommand( 'bold' );
862 *
863 * @param {String} commandName The indentifier name of the command.
864 * @param {Object} [data] The data to be passed to the command.
865 * @returns {Boolean} `true` if the command was executed
866 * successfully, otherwise `false`.
867 * @see CKEDITOR.editor#addCommand
868 */
869 execCommand: function( commandName, data ) {
870 var command = this.getCommand( commandName );
871
872 var eventData = {
873 name: commandName,
874 commandData: data,
875 command: command
876 };
877
878 if ( command && command.state != CKEDITOR.TRISTATE_DISABLED ) {
879 if ( this.fire( 'beforeCommandExec', eventData ) !== false ) {
880 eventData.returnValue = command.exec( eventData.commandData );
881
882 // Fire the 'afterCommandExec' immediately if command is synchronous.
883 if ( !command.async && this.fire( 'afterCommandExec', eventData ) !== false )
884 return eventData.returnValue;
885 }
886 }
887
888 // throw 'Unknown command name "' + commandName + '"';
889 return false;
890 },
891
892 /**
893 * Gets one of the registered commands. Note that after registering a
894 * command definition with {@link #addCommand}, it is
895 * transformed internally into an instance of
896 * {@link CKEDITOR.command}, which will then be returned by this function.
897 *
898 * @param {String} commandName The name of the command to be returned.
899 * This is the same name that is used to register the command with `addCommand`.
900 * @returns {CKEDITOR.command} The command object identified by the provided name.
901 */
902 getCommand: function( commandName ) {
903 return this.commands[ commandName ];
904 },
905
906 /**
907 * Gets the editor data. The data will be in "raw" format. It is the same
908 * data that is posted by the editor.
909 *
910 * if ( CKEDITOR.instances.editor1.getData() == '' )
911 * alert( 'There is no data available.' );
912 *
913 * @param {Boolean} internal If set to `true`, it will prevent firing the
914 * {@link CKEDITOR.editor#beforeGetData} and {@link CKEDITOR.editor#event-getData} events, so
915 * the real content of the editor will not be read and cached data will be returned. The method will work
916 * much faster, but this may result in the editor returning the data that is not up to date. This parameter
917 * should thus only be set to `true` when you are certain that the cached data is up to date.
918 *
919 * @returns {String} The editor data.
920 */
921 getData: function( internal ) {
922 !internal && this.fire( 'beforeGetData' );
923
924 var eventData = this._.data;
925
926 if ( typeof eventData != 'string' ) {
927 var element = this.element;
928 if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE )
929 eventData = element.is( 'textarea' ) ? element.getValue() : element.getHtml();
930 else
931 eventData = '';
932 }
933
934 eventData = { dataValue: eventData };
935
936 // Fire "getData" so data manipulation may happen.
937 !internal && this.fire( 'getData', eventData );
938
939 return eventData.dataValue;
940 },
941
942 /**
943 * Gets the "raw data" currently available in the editor. This is a
944 * fast method which returns the data as is, without processing, so it is
945 * not recommended to use it on resulting pages. Instead it can be used
946 * combined with the {@link #method-loadSnapshot} method in order
947 * to automatically save the editor data from time to time
948 * while the user is using the editor, to avoid data loss, without risking
949 * performance issues.
950 *
951 * alert( editor.getSnapshot() );
952 *
953 * See also:
954 *
955 * * {@link CKEDITOR.editor#method-getData}.
956 *
957 * @returns {String} Editor "raw data".
958 */
959 getSnapshot: function() {
960 var data = this.fire( 'getSnapshot' );
961
962 if ( typeof data != 'string' ) {
963 var element = this.element;
964
965 if ( element && this.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
966 data = element.is( 'textarea' ) ? element.getValue() : element.getHtml();
967 }
968 else {
969 // If we don't have a proper element, set data to an empty string,
970 // as this method is expected to return a string. (#13385)
971 data = '';
972 }
973 }
974
975 return data;
976 },
977
978 /**
979 * Loads "raw data" into the editor. The data is loaded with processing
980 * straight to the editing area. It should not be used as a way to load
981 * any kind of data, but instead in combination with
982 * {@link #method-getSnapshot}-produced data.
983 *
984 * var data = editor.getSnapshot();
985 * editor.loadSnapshot( data );
986 *
987 * @see CKEDITOR.editor#setData
988 */
989 loadSnapshot: function( snapshot ) {
990 this.fire( 'loadSnapshot', snapshot );
991 },
992
993 /**
994 * Sets the editor data. The data must be provided in the "raw" format (HTML).
995 *
996 * Note that this method is asynchronous. The `callback` parameter must
997 * be used if interaction with the editor is needed after setting the data.
998 *
999 * CKEDITOR.instances.editor1.setData( '<p>This is the editor data.</p>' );
1000 *
1001 * CKEDITOR.instances.editor1.setData( '<p>Some other editor data.</p>', {
1002 * callback: function() {
1003 * this.checkDirty(); // true
1004 * }
1005 * } );
1006 *
1007 * Note: In **CKEditor 4.4.2** the signature of this method has changed. All arguments
1008 * except `data` were wrapped into the `options` object. However, backward compatibility
1009 * was preserved and it is still possible to use the `data, callback, internal` arguments.
1010 *
1011 *
1012 * @param {String} data The HTML code to replace current editor content.
1013 * @param {Object} [options]
1014 * @param {Boolean} [options.internal=false] Whether to suppress any event firing when copying data internally inside the editor.
1015 * @param {Function} [options.callback] Function to be called after `setData` is completed (on {@link #dataReady}).
1016 * @param {Boolean} [options.noSnapshot=false] If set to `true`, it will prevent recording an undo snapshot.
1017 * Introduced in CKEditor 4.4.2.
1018 */
1019 setData: function( data, options, internal ) {
1020 var fireSnapshot = true,
1021 // Backward compatibility.
1022 callback = options,
1023 eventData;
1024
1025 if ( options && typeof options == 'object' ) {
1026 internal = options.internal;
1027 callback = options.callback;
1028 fireSnapshot = !options.noSnapshot;
1029 }
1030
1031 if ( !internal && fireSnapshot )
1032 this.fire( 'saveSnapshot' );
1033
1034 if ( callback || !internal ) {
1035 this.once( 'dataReady', function( evt ) {
1036 if ( !internal && fireSnapshot )
1037 this.fire( 'saveSnapshot' );
1038
1039 if ( callback )
1040 callback.call( evt.editor );
1041 } );
1042 }
1043
1044 // Fire "setData" so data manipulation may happen.
1045 eventData = { dataValue: data };
1046 !internal && this.fire( 'setData', eventData );
1047
1048 this._.data = eventData.dataValue;
1049
1050 !internal && this.fire( 'afterSetData', eventData );
1051 },
1052
1053 /**
1054 * Puts or restores the editor into the read-only state. When in read-only,
1055 * the user is not able to change the editor content, but can still use
1056 * some editor features. This function sets the {@link #property-readOnly}
1057 * property of the editor, firing the {@link #event-readOnly} event.
1058 *
1059 * **Note:** The current editing area will be reloaded.
1060 *
1061 * @since 3.6
1062 * @param {Boolean} [isReadOnly] Indicates that the editor must go
1063 * read-only (`true`, default) or be restored and made editable (`false`).
1064 */
1065 setReadOnly: function( isReadOnly ) {
1066 isReadOnly = ( isReadOnly == null ) || isReadOnly;
1067
1068 if ( this.readOnly != isReadOnly ) {
1069 this.readOnly = isReadOnly;
1070
1071 // Block or release BACKSPACE key according to current read-only
1072 // state to prevent browser's history navigation (#9761).
1073 this.keystrokeHandler.blockedKeystrokes[ 8 ] = +isReadOnly;
1074
1075 this.editable().setReadOnly( isReadOnly );
1076
1077 // Fire the readOnly event so the editor features can update
1078 // their state accordingly.
1079 this.fire( 'readOnly' );
1080 }
1081 },
1082
1083 /**
1084 * Inserts HTML code into the currently selected position in the editor in WYSIWYG mode.
1085 *
1086 * Example:
1087 *
1088 * CKEDITOR.instances.editor1.insertHtml( '<p>This is a new paragraph.</p>' );
1089 *
1090 * Fires the {@link #event-insertHtml} and {@link #event-afterInsertHtml} events. The HTML is inserted
1091 * in the {@link #event-insertHtml} event's listener with a default priority (10) so you can add listeners with
1092 * lower or higher priorities in order to execute some code before or after the HTML is inserted.
1093 *
1094 * @param {String} html HTML code to be inserted into the editor.
1095 * @param {String} [mode='html'] The mode in which the HTML code will be inserted. One of the following:
1096 *
1097 * * `'html'` &ndash; The inserted content will completely override the styles at the selected position.
1098 * * `'unfiltered_html'` &ndash; Like `'html'` but the content is not filtered with {@link CKEDITOR.filter}.
1099 * * `'text'` &ndash; The inserted content will inherit the styles applied in
1100 * the selected position. This mode should be used when inserting "htmlified" plain text
1101 * (HTML without inline styles and styling elements like `<b>`, `<strong>`, `<span style="...">`).
1102 *
1103 * @param {CKEDITOR.dom.range} [range] If specified, the HTML will be inserted into the range
1104 * instead of into the selection. The selection will be placed at the end of the insertion (like in the normal case).
1105 * Introduced in CKEditor 4.5.
1106 */
1107 insertHtml: function( html, mode, range ) {
1108 this.fire( 'insertHtml', { dataValue: html, mode: mode, range: range } );
1109 },
1110
1111 /**
1112 * Inserts text content into the currently selected position in the
1113 * editor in WYSIWYG mode. The styles of the selected element will be applied to the inserted text.
1114 * Spaces around the text will be left untouched.
1115 *
1116 * CKEDITOR.instances.editor1.insertText( ' line1 \n\n line2' );
1117 *
1118 * Fires the {@link #event-insertText} and {@link #event-afterInsertHtml} events. The text is inserted
1119 * in the {@link #event-insertText} event's listener with a default priority (10) so you can add listeners with
1120 * lower or higher priorities in order to execute some code before or after the text is inserted.
1121 *
1122 * @since 3.5
1123 * @param {String} text Text to be inserted into the editor.
1124 */
1125 insertText: function( text ) {
1126 this.fire( 'insertText', text );
1127 },
1128
1129 /**
1130 * Inserts an element into the currently selected position in the editor in WYSIWYG mode.
1131 *
1132 * var element = CKEDITOR.dom.element.createFromHtml( '<img src="hello.png" border="0" title="Hello" />' );
1133 * CKEDITOR.instances.editor1.insertElement( element );
1134 *
1135 * Fires the {@link #event-insertElement} event. The element is inserted in the listener with a default priority (10),
1136 * so you can add listeners with lower or higher priorities in order to execute some code before or after
1137 * the element is inserted.
1138 *
1139 * @param {CKEDITOR.dom.element} element The element to be inserted into the editor.
1140 */
1141 insertElement: function( element ) {
1142 this.fire( 'insertElement', element );
1143 },
1144
1145 /**
1146 * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment}
1147 * or a string). This method is designed to work as the user would expect the copy functionality to work.
1148 * For instance, if the following selection was made:
1149 *
1150 * <p>a<b>b{c}d</b>e</p>
1151 *
1152 * The following HTML will be returned:
1153 *
1154 * <b>c</b>
1155 *
1156 * As you can see, the information about the bold formatting was preserved, even though the selection was
1157 * anchored inside the `<b>` element.
1158 *
1159 * See also:
1160 *
1161 * * the {@link #extractSelectedHtml} method,
1162 * * the {@link CKEDITOR.editable#getHtmlFromRange} method.
1163 *
1164 * @since 4.5
1165 * @param {Boolean} [toString] If `true`, then stringified HTML will be returned.
1166 * @returns {CKEDITOR.dom.documentFragment/String}
1167 */
1168 getSelectedHtml: function( toString ) {
1169 var editable = this.editable(),
1170 selection = this.getSelection(),
1171 ranges = selection && selection.getRanges();
1172
1173 if ( !editable || !ranges || ranges.length === 0 ) {
1174 return null;
1175 }
1176
1177 var docFragment = createDocumentFragmentFromRanges( ranges, editable );
1178
1179 return toString ? docFragment.getHtml() : docFragment;
1180 },
1181
1182 /**
1183 * Gets the selected HTML (it is returned as a {@link CKEDITOR.dom.documentFragment document fragment}
1184 * or a string) and removes the selected part of the DOM. This method is designed to work as the user would
1185 * expect the cut and delete functionalities to work.
1186 *
1187 * See also:
1188 *
1189 * * the {@link #getSelectedHtml} method,
1190 * * the {@link CKEDITOR.editable#extractHtmlFromRange} method.
1191 *
1192 * @since 4.5
1193 * @param {Boolean} [toString] If `true`, then stringified HTML will be returned.
1194 * @param {Boolean} [removeEmptyBlock=false] Default `false` means that the function will keep an empty block (if the
1195 * entire content was removed) or it will create it (if a block element was removed) and set the selection in that block.
1196 * If `true`, the empty block will be removed or not created. In this case the function will not handle the selection.
1197 * @returns {CKEDITOR.dom.documentFragment/String/null}
1198 */
1199 extractSelectedHtml: function( toString, removeEmptyBlock ) {
1200 var editable = this.editable(),
1201 ranges = this.getSelection().getRanges();
1202
1203 if ( !editable || ranges.length === 0 ) {
1204 return null;
1205 }
1206
1207 var range = ranges[ 0 ],
1208 docFragment = editable.extractHtmlFromRange( range, removeEmptyBlock );
1209
1210 if ( !removeEmptyBlock ) {
1211 this.getSelection().selectRanges( [ range ] );
1212 }
1213
1214 return toString ? docFragment.getHtml() : docFragment;
1215 },
1216
1217 /**
1218 * Moves the selection focus to the editing area space in the editor.
1219 */
1220 focus: function() {
1221 this.fire( 'beforeFocus' );
1222 },
1223
1224 /**
1225 * Checks whether the current editor content contains changes when
1226 * compared to the content loaded into the editor at startup, or to
1227 * the content available in the editor when {@link #resetDirty}
1228 * was called.
1229 *
1230 * function beforeUnload( evt ) {
1231 * if ( CKEDITOR.instances.editor1.checkDirty() )
1232 * return evt.returnValue = "You will lose the changes made in the editor.";
1233 * }
1234 *
1235 * if ( window.addEventListener )
1236 * window.addEventListener( 'beforeunload', beforeUnload, false );
1237 * else
1238 * window.attachEvent( 'onbeforeunload', beforeUnload );
1239 *
1240 * @returns {Boolean} `true` if the content contains changes.
1241 */
1242 checkDirty: function() {
1243 return this.status == 'ready' && this._.previousValue !== this.getSnapshot();
1244 },
1245
1246 /**
1247 * Resets the "dirty state" of the editor so subsequent calls to
1248 * {@link #checkDirty} will return `false` if the user will not
1249 * have made further changes to the content.
1250 *
1251 * alert( editor.checkDirty() ); // e.g. true
1252 * editor.resetDirty();
1253 * alert( editor.checkDirty() ); // false
1254 */
1255 resetDirty: function() {
1256 this._.previousValue = this.getSnapshot();
1257 },
1258
1259 /**
1260 * Updates the `<textarea>` element that was replaced by the editor with
1261 * the current data available in the editor.
1262 *
1263 * **Note:** This method will only affect those editor instances created
1264 * with the {@link CKEDITOR#ELEMENT_MODE_REPLACE} element mode or inline instances
1265 * bound to `<textarea>` elements.
1266 *
1267 * CKEDITOR.instances.editor1.updateElement();
1268 * alert( document.getElementById( 'editor1' ).value ); // The current editor data.
1269 *
1270 * @see CKEDITOR.editor#element
1271 */
1272 updateElement: function() {
1273 return updateEditorElement.call( this );
1274 },
1275
1276 /**
1277 * Assigns keystrokes associated with editor commands.
1278 *
1279 * editor.setKeystroke( CKEDITOR.CTRL + 115, 'save' ); // Assigned Ctrl+S to the "save" command.
1280 * editor.setKeystroke( CKEDITOR.CTRL + 115, false ); // Disabled Ctrl+S keystroke assignment.
1281 * editor.setKeystroke( [
1282 * [ CKEDITOR.ALT + 122, false ],
1283 * [ CKEDITOR.CTRL + 121, 'link' ],
1284 * [ CKEDITOR.SHIFT + 120, 'bold' ]
1285 * ] );
1286 *
1287 * This method may be used in the following cases:
1288 *
1289 * * By plugins (like `link` or `basicstyles`) to set their keystrokes when plugins are being loaded.
1290 * * During the runtime to modify existing keystrokes.
1291 *
1292 * The editor handles keystroke configuration in the following order:
1293 *
1294 * 1. Plugins use this method to define default keystrokes.
1295 * 2. Editor extends default keystrokes with {@link CKEDITOR.config#keystrokes}.
1296 * 3. Editor blocks keystrokes defined in {@link CKEDITOR.config#blockedKeystrokes}.
1297 *
1298 * You can then set new keystrokes using this method during the runtime.
1299 *
1300 * @since 4.0
1301 * @param {Number/Array} keystroke A keystroke or an array of keystroke definitions.
1302 * @param {String/Boolean} [behavior] A command to be executed on the keystroke.
1303 */
1304 setKeystroke: function() {
1305 var keystrokes = this.keystrokeHandler.keystrokes,
1306 newKeystrokes = CKEDITOR.tools.isArray( arguments[ 0 ] ) ? arguments[ 0 ] : [ [].slice.call( arguments, 0 ) ],
1307 keystroke, behavior;
1308
1309 for ( var i = newKeystrokes.length; i--; ) {
1310 keystroke = newKeystrokes[ i ];
1311 behavior = 0;
1312
1313 // It may be a pair of: [ key, command ]
1314 if ( CKEDITOR.tools.isArray( keystroke ) ) {
1315 behavior = keystroke[ 1 ];
1316 keystroke = keystroke[ 0 ];
1317 }
1318
1319 if ( behavior )
1320 keystrokes[ keystroke ] = behavior;
1321 else
1322 delete keystrokes[ keystroke ];
1323 }
1324 },
1325
1326 /**
1327 * Returns the keystroke that is assigned to a specified {@link CKEDITOR.command}. If no keystroke is assigned,
1328 * it returns null.
1329 *
1330 * @since 4.6.0
1331 * @param {CKEDITOR.command} command
1332 * @returns {Number} The keystroke assigned to the provided command or null if there is no keystroke.
1333 */
1334 getCommandKeystroke: function( command ) {
1335 var commandName = command.name,
1336 keystrokes = this.keystrokeHandler.keystrokes,
1337 key;
1338
1339 // Some commands have a fake keystroke - for example CUT/COPY/PASTE commands are handled natively.
1340 if ( command.fakeKeystroke ) {
1341 return command.fakeKeystroke;
1342 }
1343
1344 for ( key in keystrokes ) {
1345 if ( keystrokes.hasOwnProperty( key ) && keystrokes[ key ] == commandName ) {
1346 return key;
1347 }
1348 }
1349
1350 return null;
1351 },
1352
1353 /**
1354 * Shorthand for {@link CKEDITOR.filter#addFeature}.
1355 *
1356 * @since 4.1
1357 * @param {CKEDITOR.feature} feature See {@link CKEDITOR.filter#addFeature}.
1358 * @returns {Boolean} See {@link CKEDITOR.filter#addFeature}.
1359 */
1360 addFeature: function( feature ) {
1361 return this.filter.addFeature( feature );
1362 },
1363
1364 /**
1365 * Sets the active filter ({@link #activeFilter}). Fires the {@link #activeFilterChange} event.
1366 *
1367 * // Set active filter which allows only 4 elements.
1368 * // Buttons like Bold, Italic will be disabled.
1369 * var filter = new CKEDITOR.filter( 'p strong em br' );
1370 * editor.setActiveFilter( filter );
1371 *
1372 * Setting a new filter will also change the {@link #setActiveEnterMode active Enter modes} to the first values
1373 * allowed by the new filter (see {@link CKEDITOR.filter#getAllowedEnterMode}).
1374 *
1375 * @since 4.3
1376 * @param {CKEDITOR.filter} filter Filter instance or a falsy value (e.g. `null`) to reset to the default one.
1377 */
1378 setActiveFilter: function( filter ) {
1379 if ( !filter )
1380 filter = this.filter;
1381
1382 if ( this.activeFilter !== filter ) {
1383 this.activeFilter = filter;
1384 this.fire( 'activeFilterChange' );
1385
1386 // Reset active filter to the main one - it resets enter modes, too.
1387 if ( filter === this.filter )
1388 this.setActiveEnterMode( null, null );
1389 else
1390 this.setActiveEnterMode(
1391 filter.getAllowedEnterMode( this.enterMode ),
1392 filter.getAllowedEnterMode( this.shiftEnterMode, true )
1393 );
1394 }
1395 },
1396
1397 /**
1398 * Sets the active Enter modes: ({@link #enterMode} and {@link #shiftEnterMode}).
1399 * Fires the {@link #activeEnterModeChange} event.
1400 *
1401 * Prior to CKEditor 4.3 Enter modes were static and it was enough to check {@link CKEDITOR.config#enterMode}
1402 * and {@link CKEDITOR.config#shiftEnterMode} when implementing a feature which should depend on the Enter modes.
1403 * Since CKEditor 4.3 these options are source of initial:
1404 *
1405 * * static {@link #enterMode} and {@link #shiftEnterMode} values,
1406 * * dynamic {@link #activeEnterMode} and {@link #activeShiftEnterMode} values.
1407 *
1408 * However, the dynamic Enter modes can be changed during runtime by using this method, to reflect the selection context.
1409 * For example, if selection is moved to the {@link CKEDITOR.plugins.widget widget}'s nested editable which
1410 * is a {@link #blockless blockless one}, then the active Enter modes should be changed to {@link CKEDITOR#ENTER_BR}
1411 * (in this case [Widget System](#!/guide/dev_widgets) takes care of that).
1412 *
1413 * **Note:** This method should not be used to configure the editor &ndash; use {@link CKEDITOR.config#enterMode} and
1414 * {@link CKEDITOR.config#shiftEnterMode} instead. This method should only be used to dynamically change
1415 * Enter modes during runtime based on selection changes.
1416 * Keep in mind that changed Enter mode may be overwritten by another plugin/feature when it decided that
1417 * the changed context requires this.
1418 *
1419 * **Note:** In case of blockless editor (inline editor based on an element which cannot contain block elements
1420 * &mdash; see {@link CKEDITOR.editor#blockless}) only {@link CKEDITOR#ENTER_BR} is a valid Enter mode. Therefore
1421 * this method will not allow to set other values.
1422 *
1423 * **Note:** Changing the {@link #activeFilter active filter} may cause the Enter mode to change if default Enter modes
1424 * are not allowed by the new filter.
1425 *
1426 * @since 4.3
1427 * @param {Number} enterMode One of {@link CKEDITOR#ENTER_P}, {@link CKEDITOR#ENTER_DIV}, {@link CKEDITOR#ENTER_BR}.
1428 * Pass falsy value (e.g. `null`) to reset the Enter mode to the default value ({@link #enterMode} and/or {@link #shiftEnterMode}).
1429 * @param {Number} shiftEnterMode See the `enterMode` argument.
1430 */
1431 setActiveEnterMode: function( enterMode, shiftEnterMode ) {
1432 // Validate passed modes or use default ones (validated on init).
1433 enterMode = enterMode ? validateEnterMode( this, enterMode ) : this.enterMode;
1434 shiftEnterMode = shiftEnterMode ? validateEnterMode( this, shiftEnterMode ) : this.shiftEnterMode;
1435
1436 if ( this.activeEnterMode != enterMode || this.activeShiftEnterMode != shiftEnterMode ) {
1437 this.activeEnterMode = enterMode;
1438 this.activeShiftEnterMode = shiftEnterMode;
1439 this.fire( 'activeEnterModeChange' );
1440 }
1441 },
1442
1443 /**
1444 * Shows a notification to the user.
1445 *
1446 * If the [Notification](http://ckeditor.com/addons/notification) plugin is not enabled, this function shows
1447 * a normal alert with the given `message`. The `type` and `progressOrDuration` parameters are supported
1448 * only by the Notification plugin.
1449 *
1450 * If the Notification plugin is enabled, this method creates and shows a new notification.
1451 * By default the notification is shown over the editor content, in the viewport if it is possible.
1452 *
1453 * See {@link CKEDITOR.plugins.notification}.
1454 *
1455 * @since 4.5
1456 * @member CKEDITOR.editor
1457 * @param {String} message The message displayed in the notification.
1458 * @param {String} [type='info'] The type of the notification. Can be `'info'`, `'warning'`, `'success'` or `'progress'`.
1459 * @param {Number} [progressOrDuration] If the type is `progress`, the third parameter may be a progress from `0` to `1`
1460 * (defaults to `0`). Otherwise the third parameter may be a notification duration denoting after how many milliseconds
1461 * the notification should be closed automatically. `0` means that the notification will not close automatically and the user
1462 * needs to close it manually. See {@link CKEDITOR.plugins.notification#duration}.
1463 * Note that `warning` notifications will not be closed automatically.
1464 * @returns {CKEDITOR.plugins.notification} Created and shown notification.
1465 */
1466 showNotification: function( message ) {
1467 alert( message ); // jshint ignore:line
1468 }
1469 } );
1470} )();
1471
1472/**
1473 * The editor has no associated element.
1474 *
1475 * @readonly
1476 * @property {Number} [=0]
1477 * @member CKEDITOR
1478 */
1479CKEDITOR.ELEMENT_MODE_NONE = 0;
1480
1481/**
1482 * The element is to be replaced by the editor instance.
1483 *
1484 * @readonly
1485 * @property {Number} [=1]
1486 * @member CKEDITOR
1487 */
1488CKEDITOR.ELEMENT_MODE_REPLACE = 1;
1489
1490/**
1491 * The editor is to be created inside the element.
1492 *
1493 * @readonly
1494 * @property {Number} [=2]
1495 * @member CKEDITOR
1496 */
1497CKEDITOR.ELEMENT_MODE_APPENDTO = 2;
1498
1499/**
1500 * The editor is to be attached to the element, using it as the editing block.
1501 *
1502 * @readonly
1503 * @property {Number} [=3]
1504 * @member CKEDITOR
1505 */
1506CKEDITOR.ELEMENT_MODE_INLINE = 3;
1507
1508/**
1509 * Whether to escape HTML when the editor updates the original input element.
1510 *
1511 * config.htmlEncodeOutput = true;
1512 *
1513 * @since 3.1
1514 * @cfg {Boolean} [htmlEncodeOutput=false]
1515 * @member CKEDITOR.config
1516 */
1517
1518/**
1519 * If `true`, makes the editor start in read-only state. Otherwise, it will check
1520 * if the linked `<textarea>` element has the `disabled` attribute.
1521 *
1522 * Read more in the [documentation](#!/guide/dev_readonly)
1523 * and see the [SDK sample](http://sdk.ckeditor.com/samples/readonly.html).
1524 *
1525 * config.readOnly = true;
1526 *
1527 * @since 3.6
1528 * @cfg {Boolean} [readOnly=false]
1529 * @member CKEDITOR.config
1530 * @see CKEDITOR.editor#setReadOnly
1531 */
1532
1533/**
1534 * Whether an editable element should have focus when the editor is loading for the first time.
1535 *
1536 * config.startupFocus = true;
1537 *
1538 * @cfg {Boolean} [startupFocus=false]
1539 * @member CKEDITOR.config
1540 */
1541
1542 /**
1543 * Customizes the {@link CKEDITOR.editor#title human-readable title} of this editor. This title is displayed in
1544 * tooltips and impacts various [accessibility aspects](#!/guide/dev_a11y-section-announcing-the-editor-on-the-page),
1545 * e.g. it is commonly used by screen readers for distinguishing editor instances and for navigation.
1546 * Accepted values are a string or `false`.
1547 *
1548 * **Note:** When `config.title` is set globally, the same value will be applied to all editor instances
1549 * loaded with this config. This may adversely affect accessibility as screen reader users will be unable
1550 * to distinguish particular editor instances and navigate between them.
1551 *
1552 * **Note:** Setting `config.title = false` may also impair accessibility in a similar way.
1553 *
1554 * **Note:** Please do not confuse this property with {@link CKEDITOR.editor#name}
1555 * which identifies the instance in the {@link CKEDITOR#instances} literal.
1556 *
1557 * // Sets the title to 'My WYSIWYG editor.'. The original title of the element (if it exists)
1558 * // will be restored once the editor instance is destroyed.
1559 * config.title = 'My WYSIWYG editor.';
1560 *
1561 * // Do not touch the title. If the element already has a title, it remains unchanged.
1562 * // Also if no `title` attribute exists, nothing new will be added.
1563 * config.title = false;
1564 *
1565 * See also:
1566 *
1567 * * CKEDITOR.editor#name
1568 * * CKEDITOR.editor#title
1569 *
1570 * @since 4.2
1571 * @cfg {String/Boolean} [title=based on editor.name]
1572 * @member CKEDITOR.config
1573 */
1574
1575/**
1576 * Sets listeners on editor events.
1577 *
1578 * **Note:** This property can only be set in the `config` object passed directly
1579 * to {@link CKEDITOR#replace}, {@link CKEDITOR#inline}, and other creators.
1580 *
1581 * CKEDITOR.replace( 'editor1', {
1582 * on: {
1583 * instanceReady: function() {
1584 * alert( this.name ); // 'editor1'
1585 * },
1586 *
1587 * key: function() {
1588 * // ...
1589 * }
1590 * }
1591 * } );
1592 *
1593 * @cfg {Object} on
1594 * @member CKEDITOR.config
1595 */
1596
1597/**
1598 * The outermost element in the DOM tree in which the editable element resides. It is provided
1599 * by a specific editor creator after the editor UI is created and is not intended to
1600 * be modified.
1601 *
1602 * var editor = CKEDITOR.instances.editor1;
1603 * alert( editor.container.getName() ); // 'span'
1604 *
1605 * @readonly
1606 * @property {CKEDITOR.dom.element} container
1607 */
1608
1609/**
1610 * The document that stores the editor content.
1611 *
1612 * * For the classic (`iframe`-based) editor it is equal to the document inside the
1613 * `iframe` containing the editable element.
1614 * * For the inline editor it is equal to {@link CKEDITOR#document}.
1615 *
1616 * The document object is available after the {@link #contentDom} event is fired
1617 * and may be invalidated when the {@link #contentDomUnload} event is fired
1618 * (classic editor only).
1619 *
1620 * editor.on( 'contentDom', function() {
1621 * console.log( editor.document );
1622 * } );
1623 *
1624 * @readonly
1625 * @property {CKEDITOR.dom.document} document
1626 */
1627
1628/**
1629 * The window instance related to the {@link #document} property.
1630 *
1631 * It is always equal to the `editor.document.getWindow()`.
1632 *
1633 * See the {@link #document} property documentation.
1634 *
1635 * @readonly
1636 * @property {CKEDITOR.dom.window} window
1637 */
1638
1639/**
1640 * The main filter instance used for input data filtering, data
1641 * transformations, and activation of features.
1642 *
1643 * It points to a {@link CKEDITOR.filter} instance set up based on
1644 * editor configuration.
1645 *
1646 * @since 4.1
1647 * @readonly
1648 * @property {CKEDITOR.filter} filter
1649 */
1650
1651/**
1652 * The active filter instance which should be used in the current context (location selection).
1653 * This instance will be used to make a decision which commands, buttons and other
1654 * {@link CKEDITOR.feature features} can be enabled.
1655 *
1656 * By default it equals the {@link #filter} and it can be changed by the {@link #setActiveFilter} method.
1657 *
1658 * editor.on( 'activeFilterChange', function() {
1659 * if ( editor.activeFilter.check( 'cite' ) )
1660 * // Do something when <cite> was enabled - e.g. enable a button.
1661 * else
1662 * // Otherwise do something else.
1663 * } );
1664 *
1665 * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings.
1666 *
1667 * @since 4.3
1668 * @readonly
1669 * @property {CKEDITOR.filter} activeFilter
1670 */
1671
1672/**
1673 * The main (static) Enter mode which is a validated version of the {@link CKEDITOR.config#enterMode} setting.
1674 * Currently only one rule exists &mdash; {@link #blockless blockless editors} may have
1675 * Enter modes set only to {@link CKEDITOR#ENTER_BR}.
1676 *
1677 * @since 4.3
1678 * @readonly
1679 * @property {Number} enterMode
1680 */
1681
1682/**
1683 * See the {@link #enterMode} property.
1684 *
1685 * @since 4.3
1686 * @readonly
1687 * @property {Number} shiftEnterMode
1688 */
1689
1690/**
1691 * The dynamic Enter mode which should be used in the current context (selection location).
1692 * By default it equals the {@link #enterMode} and it can be changed by the {@link #setActiveEnterMode} method.
1693 *
1694 * See also the {@link #setActiveEnterMode} method for an explanation of dynamic settings.
1695 *
1696 * @since 4.3
1697 * @readonly
1698 * @property {Number} activeEnterMode
1699 */
1700
1701/**
1702 * See the {@link #activeEnterMode} property.
1703 *
1704 * @since 4.3
1705 * @readonly
1706 * @property {Number} activeShiftEnterMode
1707 */
1708
1709/**
1710 * Event fired by the {@link #setActiveFilter} method when the {@link #activeFilter} is changed.
1711 *
1712 * @since 4.3
1713 * @event activeFilterChange
1714 */
1715
1716/**
1717 * Event fired by the {@link #setActiveEnterMode} method when any of the active Enter modes is changed.
1718 * See also the {@link #activeEnterMode} and {@link #activeShiftEnterMode} properties.
1719 *
1720 * @since 4.3
1721 * @event activeEnterModeChange
1722 */
1723
1724/**
1725 * Event fired when a CKEDITOR instance is created, but still before initializing it.
1726 * To interact with a fully initialized instance, use the
1727 * {@link CKEDITOR#instanceReady} event instead.
1728 *
1729 * @event instanceCreated
1730 * @member CKEDITOR
1731 * @param {CKEDITOR.editor} editor The editor instance that has been created.
1732 */
1733
1734/**
1735 * Event fired when CKEDITOR instance's components (configuration, languages and plugins) are fully
1736 * loaded and initialized. However, the editor will be fully ready for interaction
1737 * on {@link CKEDITOR#instanceReady}.
1738 *
1739 * @event instanceLoaded
1740 * @member CKEDITOR
1741 * @param {CKEDITOR.editor} editor This editor instance that has been loaded.
1742 */
1743
1744/**
1745 * Event fired when a CKEDITOR instance is destroyed.
1746 *
1747 * @event instanceDestroyed
1748 * @member CKEDITOR
1749 * @param {CKEDITOR.editor} editor The editor instance that has been destroyed.
1750 */
1751
1752/**
1753 * Event fired when a CKEDITOR instance is created, fully initialized and ready for interaction.
1754 *
1755 * @event instanceReady
1756 * @member CKEDITOR
1757 * @param {CKEDITOR.editor} editor The editor instance that has been created.
1758 */
1759
1760/**
1761 * Event fired when the language is loaded into the editor instance.
1762 *
1763 * @since 3.6.1
1764 * @event langLoaded
1765 * @param {CKEDITOR.editor} editor This editor instance.
1766 */
1767
1768/**
1769 * Event fired when all plugins are loaded and initialized into the editor instance.
1770 *
1771 * @event pluginsLoaded
1772 * @param {CKEDITOR.editor} editor This editor instance.
1773 */
1774
1775/**
1776 * Event fired when the styles set is loaded. During the editor initialization
1777 * phase the {@link #getStylesSet} method returns only styles that
1778 * are already loaded, which may not include e.g. styles parsed
1779 * by the `stylesheetparser` plugin. Thus, to be notified when all
1780 * styles are ready, you can listen on this event.
1781 *
1782 * @since 4.1
1783 * @event stylesSet
1784 * @param {CKEDITOR.editor} editor This editor instance.
1785 * @param {Array} styles An array of styles definitions.
1786 */
1787
1788/**
1789 * Event fired before the command execution when {@link #execCommand} is called.
1790 *
1791 * @event beforeCommandExec
1792 * @param {CKEDITOR.editor} editor This editor instance.
1793 * @param data
1794 * @param {String} data.name The command name.
1795 * @param {Object} data.commandData The data to be sent to the command. This
1796 * can be manipulated by the event listener.
1797 * @param {CKEDITOR.command} data.command The command itself.
1798 */
1799
1800/**
1801 * Event fired after the command execution when {@link #execCommand} is called.
1802 *
1803 * @event afterCommandExec
1804 * @param {CKEDITOR.editor} editor This editor instance.
1805 * @param data
1806 * @param {String} data.name The command name.
1807 * @param {Object} data.commandData The data sent to the command.
1808 * @param {CKEDITOR.command} data.command The command itself.
1809 * @param {Object} data.returnValue The value returned by the command execution.
1810 */
1811
1812/**
1813 * Event fired when a custom configuration file is loaded, before the final
1814 * configuration initialization.
1815 *
1816 * Custom configuration files can be loaded thorugh the
1817 * {@link CKEDITOR.config#customConfig} setting. Several files can be loaded
1818 * by changing this setting.
1819 *
1820 * @event customConfigLoaded
1821 * @param {CKEDITOR.editor} editor This editor instance.
1822 */
1823
1824/**
1825 * Event fired once the editor configuration is ready (loaded and processed).
1826 *
1827 * @event configLoaded
1828 * @param {CKEDITOR.editor} editor This editor instance.
1829 */
1830
1831/**
1832 * Event fired when this editor instance is destroyed. The editor at this
1833 * point is not usable and this event should be used to perform the clean-up
1834 * in any plugin.
1835 *
1836 * @event destroy
1837 * @param {CKEDITOR.editor} editor This editor instance.
1838 */
1839
1840/**
1841 * Event fired when the {@link #method-destroy} method is called,
1842 * but before destroying the editor.
1843 *
1844 * @event beforeDestroy
1845 * @param {CKEDITOR.editor} editor This editor instance.
1846 */
1847
1848/**
1849 * Internal event to get the current data.
1850 *
1851 * @event beforeGetData
1852 * @param {CKEDITOR.editor} editor This editor instance.
1853 */
1854
1855/**
1856 * Internal event to perform the {@link #method-getSnapshot} call.
1857 *
1858 * @event getSnapshot
1859 * @param {CKEDITOR.editor} editor This editor instance.
1860 */
1861
1862/**
1863 * Internal event to perform the {@link #method-loadSnapshot} call.
1864 *
1865 * @event loadSnapshot
1866 * @param {CKEDITOR.editor} editor This editor instance.
1867 * @param {String} data The data that will be used.
1868 */
1869
1870/**
1871 * Event fired before the {@link #method-getData} call returns, allowing for additional manipulation.
1872 *
1873 * @event getData
1874 * @param {CKEDITOR.editor} editor This editor instance.
1875 * @param data
1876 * @param {String} data.dataValue The data that will be returned.
1877 */
1878
1879/**
1880 * Event fired before the {@link #method-setData} call is executed, allowing for additional manipulation.
1881 *
1882 * @event setData
1883 * @param {CKEDITOR.editor} editor This editor instance.
1884 * @param data
1885 * @param {String} data.dataValue The data that will be used.
1886 */
1887
1888/**
1889 * Event fired at the end of the {@link #method-setData} call execution. Usually it is better to use the
1890 * {@link #dataReady} event.
1891 *
1892 * @event afterSetData
1893 * @param {CKEDITOR.editor} editor This editor instance.
1894 * @param data
1895 * @param {String} data.dataValue The data that has been set.
1896 */
1897
1898/**
1899 * Event fired as an indicator of the editor data loading. It may be the result of
1900 * calling {@link #method-setData} explicitly or an internal
1901 * editor function, like the editor editing mode switching (move to Source and back).
1902 *
1903 * @event dataReady
1904 * @param {CKEDITOR.editor} editor This editor instance.
1905 */
1906
1907/**
1908 * Event fired when the CKEDITOR instance is completely created, fully initialized
1909 * and ready for interaction.
1910 *
1911 * @event instanceReady
1912 * @param {CKEDITOR.editor} editor This editor instance.
1913 */
1914
1915/**
1916 * Event fired when editor components (configuration, languages and plugins) are fully
1917 * loaded and initialized. However, the editor will be fully ready to for interaction
1918 * on {@link #instanceReady}.
1919 *
1920 * @event loaded
1921 * @param {CKEDITOR.editor} editor This editor instance.
1922 */
1923
1924/**
1925 * Event fired by the {@link #method-insertHtml} method. See the method documentation for more information
1926 * about how this event can be used.
1927 *
1928 * @event insertHtml
1929 * @param {CKEDITOR.editor} editor This editor instance.
1930 * @param data
1931 * @param {String} data.mode The mode in which the data is inserted (see {@link #method-insertHtml}).
1932 * @param {String} data.dataValue The HTML code to insert.
1933 * @param {CKEDITOR.dom.range} [data.range] See {@link #method-insertHtml}'s `range` parameter.
1934 */
1935
1936/**
1937 * Event fired by the {@link #method-insertText} method. See the method documentation for more information
1938 * about how this event can be used.
1939 *
1940 * @event insertText
1941 * @param {CKEDITOR.editor} editor This editor instance.
1942 * @param {String} data The text to insert.
1943 */
1944
1945/**
1946 * Event fired by the {@link #method-insertElement} method. See the method documentation for more information
1947 * about how this event can be used.
1948 *
1949 * @event insertElement
1950 * @param {CKEDITOR.editor} editor This editor instance.
1951 * @param {CKEDITOR.dom.element} data The element to insert.
1952 */
1953
1954/**
1955 * Event fired after data insertion using the {@link #method-insertHtml}, {@link CKEDITOR.editable#insertHtml},
1956 * or {@link CKEDITOR.editable#insertHtmlIntoRange} methods.
1957 *
1958 * @since 4.5
1959 * @event afterInsertHtml
1960 * @param data
1961 * @param {CKEDITOR.dom.range} [data.intoRange] If set, the HTML was not inserted into the current selection, but into
1962 * the specified range. This property is set if the {@link CKEDITOR.editable#insertHtmlIntoRange} method was used,
1963 * but not if for the {@link CKEDITOR.editable#insertHtml} method.
1964 */
1965
1966/**
1967 * Event fired after the {@link #property-readOnly} property changes.
1968 *
1969 * @since 3.6
1970 * @event readOnly
1971 * @param {CKEDITOR.editor} editor This editor instance.
1972 */
1973
1974/**
1975 * Event fired when a UI template is added to the editor instance. It makes
1976 * it possible to bring customizations to the template source.
1977 *
1978 * @event template
1979 * @param {CKEDITOR.editor} editor This editor instance.
1980 * @param data
1981 * @param {String} data.name The template name.
1982 * @param {String} data.source The source data for this template.
1983 */
1984
1985/**
1986 * Event fired when the editor content (its DOM structure) is ready.
1987 * It is similar to the native `DOMContentLoaded` event, but it applies to
1988 * the editor content. It is also the first event fired after
1989 * the {@link CKEDITOR.editable} is initialized.
1990 *
1991 * This event is particularly important for classic (`iframe`-based)
1992 * editor, because on editor initialization and every time the data are set
1993 * (by {@link CKEDITOR.editor#method-setData}) content DOM structure
1994 * is rebuilt. Thus, e.g. you need to attach DOM event listeners
1995 * on editable one more time.
1996 *
1997 * For inline editor this event is fired only once &mdash; when the
1998 * editor is initialized for the first time. This is because setting
1999 * editor content does not cause editable destruction and creation.
2000 *
2001 * The {@link #contentDom} event goes along with {@link #contentDomUnload}
2002 * which is fired before the content DOM structure is destroyed. This is the
2003 * right moment to detach content DOM event listener. Otherwise
2004 * browsers like IE or Opera may throw exceptions when accessing
2005 * elements from the detached document.
2006 *
2007 * **Note:** {@link CKEDITOR.editable#attachListener} is a convenient
2008 * way to attach listeners that will be detached on {@link #contentDomUnload}.
2009 *
2010 * editor.on( 'contentDom', function() {
2011 * var editable = editor.editable();
2012 *
2013 * editable.attachListener( editable, 'click', function() {
2014 * console.log( 'The editable was clicked.' );
2015 * });
2016 * });
2017 *
2018 * @event contentDom
2019 * @param {CKEDITOR.editor} editor This editor instance.
2020 */
2021
2022/**
2023 * Event fired before the content DOM structure is destroyed.
2024 * See {@link #contentDom} documentation for more details.
2025 *
2026 * @event contentDomUnload
2027 * @param {CKEDITOR.editor} editor This editor instance.
2028 */
2029
2030/**
2031 * Event fired when the content DOM changes and some of the references as well as
2032 * the native DOM event listeners could be lost.
2033 * This event is useful when it is important to keep track of references
2034 * to elements in the editable content from code.
2035 *
2036 * @since 4.3
2037 * @event contentDomInvalidated
2038 * @param {CKEDITOR.editor} editor This editor instance.
2039 */
diff --git a/sources/core/editor_basic.js b/sources/core/editor_basic.js
new file mode 100644
index 0000000..b7ab577
--- /dev/null
+++ b/sources/core/editor_basic.js
@@ -0,0 +1,36 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6if ( !CKEDITOR.editor ) {
7 // Documented at editor.js.
8 CKEDITOR.editor = function() {
9 // Push this editor to the pending list. It'll be processed later once
10 // the full editor code is loaded.
11 CKEDITOR._.pending.push( [ this, arguments ] );
12
13 // Call the CKEDITOR.event constructor to initialize this instance.
14 CKEDITOR.event.call( this );
15 };
16
17 // Both fire and fireOnce will always pass this editor instance as the
18 // "editor" param in CKEDITOR.event.fire. So, we override it to do that
19 // automaticaly.
20 CKEDITOR.editor.prototype.fire = function( eventName, data ) {
21 if ( eventName in { instanceReady: 1, loaded: 1 } )
22 this[ eventName ] = true;
23
24 return CKEDITOR.event.prototype.fire.call( this, eventName, data, this );
25 };
26
27 CKEDITOR.editor.prototype.fireOnce = function( eventName, data ) {
28 if ( eventName in { instanceReady: 1, loaded: 1 } )
29 this[ eventName ] = true;
30
31 return CKEDITOR.event.prototype.fireOnce.call( this, eventName, data, this );
32 };
33
34 // "Inherit" (copy actually) from CKEDITOR.event.
35 CKEDITOR.event.implementOn( CKEDITOR.editor.prototype );
36}
diff --git a/sources/core/env.js b/sources/core/env.js
new file mode 100644
index 0000000..43b608a
--- /dev/null
+++ b/sources/core/env.js
@@ -0,0 +1,361 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.env} object which contains
8 * environment and browser information.
9 */
10
11if ( !CKEDITOR.env ) {
12 /**
13 * Environment and browser information.
14 *
15 * @class CKEDITOR.env
16 * @singleton
17 */
18 CKEDITOR.env = ( function() {
19 var agent = navigator.userAgent.toLowerCase(),
20 edge = agent.match( /edge[ \/](\d+.?\d*)/ ),
21 trident = agent.indexOf( 'trident/' ) > -1,
22 ie = !!( edge || trident );
23
24 var env = {
25 /**
26 * Indicates that CKEditor is running in Internet Explorer.
27 *
28 * if ( CKEDITOR.env.ie )
29 * alert( 'I\'m running in IE!' );
30 *
31 * **Note:** This property is also set to `true` if CKEditor is running
32 * in {@link #edge Microsoft Edge}.
33 *
34 * @property {Boolean}
35 */
36 ie: ie,
37
38 /**
39 * Indicates that CKEditor is running in Microsoft Edge.
40 *
41 * if ( CKEDITOR.env.edge )
42 * alert( 'I\'m running in Edge!' );
43 *
44 * See also {@link #ie}.
45 *
46 * @since 4.5
47 * @property {Boolean}
48 */
49 edge: !!edge,
50
51 /**
52 * Indicates that CKEditor is running in a WebKit-based browser, like Safari,
53 * or Blink-based browser, like Chrome.
54 *
55 * if ( CKEDITOR.env.webkit )
56 * alert( 'I\'m running in a WebKit browser!' );
57 *
58 * @property {Boolean}
59 */
60 webkit: !ie && ( agent.indexOf( ' applewebkit/' ) > -1 ),
61
62 /**
63 * Indicates that CKEditor is running in Adobe AIR.
64 *
65 * if ( CKEDITOR.env.air )
66 * alert( 'I\'m on AIR!' );
67 *
68 * @property {Boolean}
69 */
70 air: ( agent.indexOf( ' adobeair/' ) > -1 ),
71
72 /**
73 * Indicates that CKEditor is running on Macintosh.
74 *
75 * if ( CKEDITOR.env.mac )
76 * alert( 'I love apples!'' );
77 *
78 * @property {Boolean}
79 */
80 mac: ( agent.indexOf( 'macintosh' ) > -1 ),
81
82 /**
83 * Indicates that CKEditor is running in a Quirks Mode environment.
84 *
85 * if ( CKEDITOR.env.quirks )
86 * alert( 'Nooooo!' );
87 *
88 * Internet Explorer 10 introduced the _New Quirks Mode_, which is similar to the _Quirks Mode_
89 * implemented in other modern browsers and defined in the HTML5 specification. It can be handled
90 * as the Standards mode, so the value of this property will be set to `false`.
91 *
92 * The _Internet Explorer 5 Quirks_ mode which is still available in Internet Explorer 10+
93 * sets this value to `true` and {@link #version} to `7`.
94 *
95 * Read more: [IEBlog](http://blogs.msdn.com/b/ie/archive/2011/12/14/interoperable-html5-quirks-mode-in-ie10.aspx)
96 *
97 * @property {Boolean}
98 */
99 quirks: ( document.compatMode == 'BackCompat' && ( !document.documentMode || document.documentMode < 10 ) ),
100
101 /**
102 * Indicates that CKEditor is running in a mobile environemnt.
103 *
104 * if ( CKEDITOR.env.mobile )
105 * alert( 'I\'m running with CKEditor today!' );
106 *
107 * @deprecated
108 * @property {Boolean}
109 */
110 mobile: ( agent.indexOf( 'mobile' ) > -1 ),
111
112 /**
113 * Indicates that CKEditor is running on Apple iPhone/iPad/iPod devices.
114 *
115 * if ( CKEDITOR.env.iOS )
116 * alert( 'I like little apples!' );
117 *
118 * @property {Boolean}
119 */
120 iOS: /(ipad|iphone|ipod)/.test( agent ),
121
122 /**
123 * Indicates that the browser has a custom domain enabled. This has
124 * been set with `document.domain`.
125 *
126 * if ( CKEDITOR.env.isCustomDomain() )
127 * alert( 'I\'m in a custom domain!' );
128 *
129 * @returns {Boolean} `true` if a custom domain is enabled.
130 * @deprecated
131 */
132 isCustomDomain: function() {
133 if ( !this.ie )
134 return false;
135
136 var domain = document.domain,
137 hostname = window.location.hostname;
138
139 return domain != hostname && domain != ( '[' + hostname + ']' ); // IPv6 IP support (#5434)
140 },
141
142 /**
143 * Indicates that the page is running under an encrypted connection.
144 *
145 * if ( CKEDITOR.env.secure )
146 * alert( 'I\'m on SSL!' );
147 *
148 * @returns {Boolean} `true` if the page has an encrypted connection.
149 */
150 secure: location.protocol == 'https:'
151 };
152
153 /**
154 * Indicates that CKEditor is running in a Gecko-based browser, like
155 * Firefox.
156 *
157 * if ( CKEDITOR.env.gecko )
158 * alert( 'I\'m riding a gecko!' );
159 *
160 * @property {Boolean}
161 */
162 env.gecko = ( navigator.product == 'Gecko' && !env.webkit && !env.ie );
163
164 /**
165 * Indicates that CKEditor is running in a Blink-based browser like Chrome.
166 *
167 * if ( CKEDITOR.env.chrome )
168 * alert( 'I\'m running in Chrome!' );
169 *
170 * @property {Boolean} chrome
171 */
172
173 /**
174 * Indicates that CKEditor is running in Safari (including the mobile version).
175 *
176 * if ( CKEDITOR.env.safari )
177 * alert( 'I\'m on Safari!' );
178 *
179 * @property {Boolean} safari
180 */
181 if ( env.webkit ) {
182 if ( agent.indexOf( 'chrome' ) > -1 )
183 env.chrome = true;
184 else
185 env.safari = true;
186 }
187
188 var version = 0;
189
190 // Internet Explorer 6.0+
191 if ( env.ie ) {
192 // We use env.version for feature detection, so set it properly.
193 if ( edge ) {
194 version = parseFloat( edge[ 1 ] );
195 } else if ( env.quirks || !document.documentMode ) {
196 version = parseFloat( agent.match( /msie (\d+)/ )[ 1 ] );
197 } else {
198 version = document.documentMode;
199 }
200
201 // Deprecated features available just for backwards compatibility.
202 env.ie9Compat = version == 9;
203 env.ie8Compat = version == 8;
204 env.ie7Compat = version == 7;
205 env.ie6Compat = version < 7 || env.quirks;
206
207 /**
208 * Indicates that CKEditor is running in an IE6-like environment, which
209 * includes IE6 itself as well as IE7, IE8 and IE9 in Quirks Mode.
210 *
211 * @deprecated
212 * @property {Boolean} ie6Compat
213 */
214
215 /**
216 * Indicates that CKEditor is running in an IE7-like environment, which
217 * includes IE7 itself and IE8's IE7 Document Mode.
218 *
219 * @deprecated
220 * @property {Boolean} ie7Compat
221 */
222
223 /**
224 * Indicates that CKEditor is running in Internet Explorer 8 on
225 * Standards Mode.
226 *
227 * @deprecated
228 * @property {Boolean} ie8Compat
229 */
230
231 /**
232 * Indicates that CKEditor is running in Internet Explorer 9 on
233 * Standards Mode.
234 *
235 * @deprecated
236 * @property {Boolean} ie9Compat
237 */
238 }
239
240 // Gecko.
241 if ( env.gecko ) {
242 var geckoRelease = agent.match( /rv:([\d\.]+)/ );
243 if ( geckoRelease ) {
244 geckoRelease = geckoRelease[ 1 ].split( '.' );
245 version = geckoRelease[ 0 ] * 10000 + ( geckoRelease[ 1 ] || 0 ) * 100 + ( geckoRelease[ 2 ] || 0 ) * 1;
246 }
247 }
248
249 // Adobe AIR 1.0+
250 // Checked before Safari because AIR have the WebKit rich text editor
251 // features from Safari 3.0.4, but the version reported is 420.
252 if ( env.air )
253 version = parseFloat( agent.match( / adobeair\/(\d+)/ )[ 1 ] );
254
255 // WebKit 522+ (Safari 3+)
256 if ( env.webkit )
257 version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[ 1 ] );
258
259 /**
260 * Contains the browser version.
261 *
262 * For Gecko-based browsers (like Firefox) it contains the revision
263 * number with first three parts concatenated with a padding zero
264 * (e.g. for revision 1.9.0.2 we have 10900).
265 *
266 * For WebKit-based browsers (like Safari and Chrome) it contains the
267 * WebKit build version (e.g. 522).
268 *
269 * For IE browsers, it matches the "Document Mode".
270 *
271 * if ( CKEDITOR.env.ie && CKEDITOR.env.version <= 6 )
272 * alert( 'Ouch!' );
273 *
274 * @property {Number}
275 */
276 env.version = version;
277
278 /**
279 * Since CKEditor 4.5 this property is a blacklist of browsers incompatible with CKEditor. It means that it is
280 * set to `false` only in browsers that are known to be incompatible. Before CKEditor 4.5 this
281 * property was a whitelist of browsers that were known to be compatible with CKEditor.
282 *
283 * The reason for this change is the rising fragmentation of the browser market (especially the mobile segment).
284 * It became too complicated to check in which new environments CKEditor is going to work.
285 *
286 * In order to enable CKEditor 4.4.x and below in unsupported environments see the
287 * [Enabling CKEditor in Unsupported Environments](#!/guide/dev_unsupported_environments) article.
288 *
289 * if ( CKEDITOR.env.isCompatible )
290 * alert( 'Your browser is not known to be incompatible with CKEditor!' );
291 *
292 * @property {Boolean}
293 */
294 env.isCompatible =
295 // IE 7+ (IE 7 is not supported, but IE Compat Mode is and it is recognized as IE7).
296 !( env.ie && version < 7 ) &&
297 // Firefox 4.0+.
298 !( env.gecko && version < 40000 ) &&
299 // Chrome 6+, Safari 5.1+, iOS 5+.
300 !( env.webkit && version < 534 );
301
302 /**
303 * Indicates that CKEditor is running in the HiDPI environment.
304 *
305 * if ( CKEDITOR.env.hidpi )
306 * alert( 'You are using a screen with high pixel density.' );
307 *
308 * @property {Boolean}
309 */
310 env.hidpi = window.devicePixelRatio >= 2;
311
312 /**
313 * Indicates that CKEditor is running in a browser which uses a bogus
314 * `<br>` filler in order to correctly display caret in empty blocks.
315 *
316 * @since 4.3
317 * @property {Boolean}
318 */
319 env.needsBrFiller = env.gecko || env.webkit || ( env.ie && version > 10 );
320
321 /**
322 * Indicates that CKEditor is running in a browser which needs a
323 * non-breaking space filler in order to correctly display caret in empty blocks.
324 *
325 * @since 4.3
326 * @property {Boolean}
327 */
328 env.needsNbspFiller = env.ie && version < 11;
329
330 /**
331 * A CSS class that denotes the browser where CKEditor runs and is appended
332 * to the HTML element that contains the editor. It makes it easier to apply
333 * browser-specific styles to editor instances.
334 *
335 * myDiv.className = CKEDITOR.env.cssClass;
336 *
337 * @property {String}
338 */
339 env.cssClass = 'cke_browser_' + ( env.ie ? 'ie' : env.gecko ? 'gecko' : env.webkit ? 'webkit' : 'unknown' );
340
341 if ( env.quirks )
342 env.cssClass += ' cke_browser_quirks';
343
344 if ( env.ie )
345 env.cssClass += ' cke_browser_ie' + ( env.quirks ? '6 cke_browser_iequirks' : env.version );
346
347 if ( env.air )
348 env.cssClass += ' cke_browser_air';
349
350 if ( env.iOS )
351 env.cssClass += ' cke_browser_ios';
352
353 if ( env.hidpi )
354 env.cssClass += ' cke_hidpi';
355
356 return env;
357 } )();
358}
359
360// PACKAGER_RENAME( CKEDITOR.env )
361// PACKAGER_RENAME( CKEDITOR.env.ie )
diff --git a/sources/core/event.js b/sources/core/event.js
new file mode 100644
index 0000000..89444b5
--- /dev/null
+++ b/sources/core/event.js
@@ -0,0 +1,389 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.event} class, which serves as the
8 * base for classes and objects that require event handling features.
9 */
10
11if ( !CKEDITOR.event ) {
12 /**
13 * Creates an event class instance. This constructor is rarely used, being
14 * the {@link #implementOn} function used in class prototypes directly
15 * instead.
16 *
17 * This is a base class for classes and objects that require event
18 * handling features.
19 *
20 * Do not confuse this class with {@link CKEDITOR.dom.event} which is
21 * instead used for DOM events. The CKEDITOR.event class implements the
22 * internal event system used by the CKEditor to fire API related events.
23 *
24 * @class
25 * @constructor Creates an event class instance.
26 */
27 CKEDITOR.event = function() {};
28
29 /**
30 * Implements the {@link CKEDITOR.event} features in an object.
31 *
32 * var myObject = { message: 'Example' };
33 * CKEDITOR.event.implementOn( myObject );
34 *
35 * myObject.on( 'testEvent', function() {
36 * alert( this.message );
37 * } );
38 * myObject.fire( 'testEvent' ); // 'Example'
39 *
40 * @static
41 * @param {Object} targetObject The object into which implement the features.
42 */
43 CKEDITOR.event.implementOn = function( targetObject ) {
44 var eventProto = CKEDITOR.event.prototype;
45
46 for ( var prop in eventProto ) {
47 if ( targetObject[ prop ] == null )
48 targetObject[ prop ] = eventProto[ prop ];
49 }
50 };
51
52 CKEDITOR.event.prototype = ( function() {
53 // Returns the private events object for a given object.
54 var getPrivate = function( obj ) {
55 var _ = ( obj.getPrivate && obj.getPrivate() ) || obj._ || ( obj._ = {} );
56 return _.events || ( _.events = {} );
57 };
58
59 var eventEntry = function( eventName ) {
60 this.name = eventName;
61 this.listeners = [];
62 };
63
64 eventEntry.prototype = {
65 // Get the listener index for a specified function.
66 // Returns -1 if not found.
67 getListenerIndex: function( listenerFunction ) {
68 for ( var i = 0, listeners = this.listeners; i < listeners.length; i++ ) {
69 if ( listeners[ i ].fn == listenerFunction )
70 return i;
71 }
72 return -1;
73 }
74 };
75
76 // Retrieve the event entry on the event host (create it if needed).
77 function getEntry( name ) {
78 // Get the event entry (create it if needed).
79 var events = getPrivate( this );
80 return events[ name ] || ( events[ name ] = new eventEntry( name ) );
81 }
82
83 return {
84 /**
85 * Predefine some intrinsic properties on a specific event name.
86 *
87 * @param {String} name The event name
88 * @param meta
89 * @param [meta.errorProof=false] Whether the event firing should catch error thrown from a per listener call.
90 */
91 define: function( name, meta ) {
92 var entry = getEntry.call( this, name );
93 CKEDITOR.tools.extend( entry, meta, true );
94 },
95
96 /**
97 * Registers a listener to a specific event in the current object.
98 *
99 * someObject.on( 'someEvent', function() {
100 * alert( this == someObject ); // true
101 * } );
102 *
103 * someObject.on( 'someEvent', function() {
104 * alert( this == anotherObject ); // true
105 * }, anotherObject );
106 *
107 * someObject.on( 'someEvent', function( event ) {
108 * alert( event.listenerData ); // 'Example'
109 * }, null, 'Example' );
110 *
111 * someObject.on( 'someEvent', function() { ... } ); // 2nd called
112 * someObject.on( 'someEvent', function() { ... }, null, null, 100 ); // 3rd called
113 * someObject.on( 'someEvent', function() { ... }, null, null, 1 ); // 1st called
114 *
115 * @param {String} eventName The event name to which listen.
116 * @param {Function} listenerFunction The function listening to the
117 * event. A single {@link CKEDITOR.eventInfo} object instanced
118 * is passed to this function containing all the event data.
119 * @param {Object} [scopeObj] The object used to scope the listener
120 * call (the `this` object). If omitted, the current object is used.
121 * @param {Object} [listenerData] Data to be sent as the
122 * {@link CKEDITOR.eventInfo#listenerData} when calling the
123 * listener.
124 * @param {Number} [priority=10] The listener priority. Lower priority
125 * listeners are called first. Listeners with the same priority
126 * value are called in registration order.
127 * @returns {Object} An object containing the `removeListener`
128 * function, which can be used to remove the listener at any time.
129 */
130 on: function( eventName, listenerFunction, scopeObj, listenerData, priority ) {
131 // Create the function to be fired for this listener.
132 function listenerFirer( editor, publisherData, stopFn, cancelFn ) {
133 var ev = {
134 name: eventName,
135 sender: this,
136 editor: editor,
137 data: publisherData,
138 listenerData: listenerData,
139 stop: stopFn,
140 cancel: cancelFn,
141 removeListener: removeListener
142 };
143
144 var ret = listenerFunction.call( scopeObj, ev );
145
146 return ret === false ? false : ev.data;
147 }
148
149 function removeListener() {
150 me.removeListener( eventName, listenerFunction );
151 }
152
153 var event = getEntry.call( this, eventName );
154
155 if ( event.getListenerIndex( listenerFunction ) < 0 ) {
156 // Get the listeners.
157 var listeners = event.listeners;
158
159 // Fill the scope.
160 if ( !scopeObj )
161 scopeObj = this;
162
163 // Default the priority, if needed.
164 if ( isNaN( priority ) )
165 priority = 10;
166
167 var me = this;
168
169 listenerFirer.fn = listenerFunction;
170 listenerFirer.priority = priority;
171
172 // Search for the right position for this new listener, based on its
173 // priority.
174 for ( var i = listeners.length - 1; i >= 0; i-- ) {
175 // Find the item which should be before the new one.
176 if ( listeners[ i ].priority <= priority ) {
177 // Insert the listener in the array.
178 listeners.splice( i + 1, 0, listenerFirer );
179 return { removeListener: removeListener };
180 }
181 }
182
183 // If no position has been found (or zero length), put it in
184 // the front of list.
185 listeners.unshift( listenerFirer );
186 }
187
188 return { removeListener: removeListener };
189 },
190
191 /**
192 * Similiar with {@link #on} but the listener will be called only once upon the next event firing.
193 *
194 * @see CKEDITOR.event#on
195 */
196 once: function() {
197 var args = Array.prototype.slice.call( arguments ),
198 fn = args[ 1 ];
199
200 args[ 1 ] = function( evt ) {
201 evt.removeListener();
202 return fn.apply( this, arguments );
203 };
204
205 return this.on.apply( this, args );
206 },
207
208 /**
209 * @static
210 * @property {Boolean} useCapture
211 * @todo
212 */
213
214 /**
215 * Register event handler under the capturing stage on supported target.
216 */
217 capture: function() {
218 CKEDITOR.event.useCapture = 1;
219 var retval = this.on.apply( this, arguments );
220 CKEDITOR.event.useCapture = 0;
221 return retval;
222 },
223
224 /**
225 * Fires an specific event in the object. All registered listeners are
226 * called at this point.
227 *
228 * someObject.on( 'someEvent', function() { ... } );
229 * someObject.on( 'someEvent', function() { ... } );
230 * someObject.fire( 'someEvent' ); // Both listeners are called.
231 *
232 * someObject.on( 'someEvent', function( event ) {
233 * alert( event.data ); // 'Example'
234 * } );
235 * someObject.fire( 'someEvent', 'Example' );
236 *
237 * @method
238 * @param {String} eventName The event name to fire.
239 * @param {Object} [data] Data to be sent as the
240 * {@link CKEDITOR.eventInfo#data} when calling the listeners.
241 * @param {CKEDITOR.editor} [editor] The editor instance to send as the
242 * {@link CKEDITOR.eventInfo#editor} when calling the listener.
243 * @returns {Boolean/Object} A boolean indicating that the event is to be
244 * canceled, or data returned by one of the listeners.
245 */
246 fire: ( function() {
247 // Create the function that marks the event as stopped.
248 var stopped = 0;
249 var stopEvent = function() {
250 stopped = 1;
251 };
252
253 // Create the function that marks the event as canceled.
254 var canceled = 0;
255 var cancelEvent = function() {
256 canceled = 1;
257 };
258
259 return function( eventName, data, editor ) {
260 // Get the event entry.
261 var event = getPrivate( this )[ eventName ];
262
263 // Save the previous stopped and cancelled states. We may
264 // be nesting fire() calls.
265 var previousStopped = stopped,
266 previousCancelled = canceled;
267
268 // Reset the stopped and canceled flags.
269 stopped = canceled = 0;
270
271 if ( event ) {
272 var listeners = event.listeners;
273
274 if ( listeners.length ) {
275 // As some listeners may remove themselves from the
276 // event, the original array length is dinamic. So,
277 // let's make a copy of all listeners, so we are
278 // sure we'll call all of them.
279 listeners = listeners.slice( 0 );
280
281 var retData;
282 // Loop through all listeners.
283 for ( var i = 0; i < listeners.length; i++ ) {
284 // Call the listener, passing the event data.
285 if ( event.errorProof ) {
286 try {
287 retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
288 } catch ( er ) {}
289 } else {
290 retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
291 }
292
293 if ( retData === false )
294 canceled = 1;
295 else if ( typeof retData != 'undefined' )
296 data = retData;
297
298 // No further calls is stopped or canceled.
299 if ( stopped || canceled )
300 break;
301 }
302 }
303 }
304
305 var ret = canceled ? false : ( typeof data == 'undefined' ? true : data );
306
307 // Restore the previous stopped and canceled states.
308 stopped = previousStopped;
309 canceled = previousCancelled;
310
311 return ret;
312 };
313 } )(),
314
315 /**
316 * Fires an specific event in the object, releasing all listeners
317 * registered to that event. The same listeners are not called again on
318 * successive calls of it or of {@link #fire}.
319 *
320 * someObject.on( 'someEvent', function() { ... } );
321 * someObject.fire( 'someEvent' ); // Above listener called.
322 * someObject.fireOnce( 'someEvent' ); // Above listener called.
323 * someObject.fire( 'someEvent' ); // No listeners called.
324 *
325 * @param {String} eventName The event name to fire.
326 * @param {Object} [data] Data to be sent as the
327 * {@link CKEDITOR.eventInfo#data} when calling the listeners.
328 * @param {CKEDITOR.editor} [editor] The editor instance to send as the
329 * {@link CKEDITOR.eventInfo#editor} when calling the listener.
330 * @returns {Boolean/Object} A booloan indicating that the event is to be
331 * canceled, or data returned by one of the listeners.
332 */
333 fireOnce: function( eventName, data, editor ) {
334 var ret = this.fire( eventName, data, editor );
335 delete getPrivate( this )[ eventName ];
336 return ret;
337 },
338
339 /**
340 * Unregisters a listener function from being called at the specified
341 * event. No errors are thrown if the listener has not been registered previously.
342 *
343 * var myListener = function() { ... };
344 * someObject.on( 'someEvent', myListener );
345 * someObject.fire( 'someEvent' ); // myListener called.
346 * someObject.removeListener( 'someEvent', myListener );
347 * someObject.fire( 'someEvent' ); // myListener not called.
348 *
349 * @param {String} eventName The event name.
350 * @param {Function} listenerFunction The listener function to unregister.
351 */
352 removeListener: function( eventName, listenerFunction ) {
353 // Get the event entry.
354 var event = getPrivate( this )[ eventName ];
355
356 if ( event ) {
357 var index = event.getListenerIndex( listenerFunction );
358 if ( index >= 0 )
359 event.listeners.splice( index, 1 );
360 }
361 },
362
363 /**
364 * Remove all existing listeners on this object, for cleanup purpose.
365 */
366 removeAllListeners: function() {
367 var events = getPrivate( this );
368 for ( var i in events )
369 delete events[ i ];
370 },
371
372 /**
373 * Checks if there is any listener registered to a given event.
374 *
375 * var myListener = function() { ... };
376 * someObject.on( 'someEvent', myListener );
377 * alert( someObject.hasListeners( 'someEvent' ) ); // true
378 * alert( someObject.hasListeners( 'noEvent' ) ); // false
379 *
380 * @param {String} eventName The event name.
381 * @returns {Boolean}
382 */
383 hasListeners: function( eventName ) {
384 var event = getPrivate( this )[ eventName ];
385 return ( event && event.listeners.length > 0 );
386 }
387 };
388 } )();
389}
diff --git a/sources/core/eventInfo.js b/sources/core/eventInfo.js
new file mode 100644
index 0000000..ea62ac9
--- /dev/null
+++ b/sources/core/eventInfo.js
@@ -0,0 +1,115 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the "virtual" {@link CKEDITOR.eventInfo} class, which
8 * contains the defintions of the event object passed to event listeners.
9 * This file is for documentation purposes only.
10 */
11
12/**
13 * Virtual class that illustrates the features of the event object to be
14 * passed to event listeners by a {@link CKEDITOR.event} based object.
15 *
16 * This class is not really part of the API.
17 *
18 * @class CKEDITOR.eventInfo
19 * @abstract
20 */
21
22/**
23 * The event name.
24 *
25 * someObject.on( 'someEvent', function( event ) {
26 * alert( event.name ); // 'someEvent'
27 * } );
28 * someObject.fire( 'someEvent' );
29 *
30 * @property {String} name
31 */
32
33/**
34 * The object that publishes (sends) the event.
35 *
36 * someObject.on( 'someEvent', function( event ) {
37 * alert( event.sender == someObject ); // true
38 * } );
39 * someObject.fire( 'someEvent' );
40 *
41 * @property sender
42 */
43
44/**
45 * The editor instance that holds the sender. May be the same as sender. May be
46 * null if the sender is not part of an editor instance, like a component
47 * running in standalone mode.
48 *
49 * myButton.on( 'someEvent', function( event ) {
50 * alert( event.editor == myEditor ); // true
51 * } );
52 * myButton.fire( 'someEvent', null, myEditor );
53 *
54 * @property {CKEDITOR.editor} editor
55 */
56
57/**
58 * Any kind of additional data. Its format and usage is event dependent.
59 *
60 * someObject.on( 'someEvent', function( event ) {
61 * alert( event.data ); // 'Example'
62 * } );
63 * someObject.fire( 'someEvent', 'Example' );
64 *
65 * @property data
66 */
67
68/**
69 * Any extra data appended during the listener registration.
70 *
71 * someObject.on( 'someEvent', function( event ) {
72 * alert( event.listenerData ); // 'Example'
73 * }, null, 'Example' );
74 *
75 * @property listenerData
76 */
77
78/**
79 * Indicates that no further listeners are to be called.
80 *
81 * someObject.on( 'someEvent', function( event ) {
82 * event.stop();
83 * } );
84 * someObject.on( 'someEvent', function( event ) {
85 * // This one will not be called.
86 * } );
87 * alert( someObject.fire( 'someEvent' ) ); // true
88 *
89 * @method stop
90 */
91
92/**
93 * Indicates that the event is to be cancelled (if cancelable).
94 *
95 * someObject.on( 'someEvent', function( event ) {
96 * event.cancel();
97 * } );
98 * someObject.on( 'someEvent', function( event ) {
99 * // This one will not be called.
100 * } );
101 * alert( someObject.fire( 'someEvent' ) ); // false
102 *
103 * @method cancel
104 */
105
106/**
107 * Removes the current listener.
108 *
109 * someObject.on( 'someEvent', function( event ) {
110 * event.removeListener();
111 * // Now this function won't be called again by 'someEvent'.
112 * } );
113 *
114 * @method removeListener
115 */
diff --git a/sources/core/filter.js b/sources/core/filter.js
new file mode 100644
index 0000000..db68530
--- /dev/null
+++ b/sources/core/filter.js
@@ -0,0 +1,2540 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 'use strict';
8
9 var DTD = CKEDITOR.dtd,
10 // processElement flag - means that element has been somehow modified.
11 FILTER_ELEMENT_MODIFIED = 1,
12 // processElement flag - meaning explained in CKEDITOR.FILTER_SKIP_TREE doc.
13 FILTER_SKIP_TREE = 2,
14 copy = CKEDITOR.tools.copy,
15 trim = CKEDITOR.tools.trim,
16 TEST_VALUE = 'cke-test',
17 enterModeTags = [ '', 'p', 'br', 'div' ];
18
19 /**
20 * A flag indicating that the current element and all its ancestors
21 * should not be filtered.
22 *
23 * See {@link CKEDITOR.filter#addElementCallback} for more details.
24 *
25 * @since 4.4
26 * @readonly
27 * @property {Number} [=2]
28 * @member CKEDITOR
29 */
30 CKEDITOR.FILTER_SKIP_TREE = FILTER_SKIP_TREE;
31
32 /**
33 * Highly configurable class which implements input data filtering mechanisms
34 * and core functions used for the activation of editor features.
35 *
36 * A filter instance is always available under the {@link CKEDITOR.editor#filter}
37 * property and is used by the editor in its core features like filtering input data,
38 * applying data transformations, validating whether a feature may be enabled for
39 * the current setup. It may be configured in two ways:
40 *
41 * * By the user, with the {@link CKEDITOR.config#allowedContent} setting.
42 * * Automatically, by loaded features (toolbar items, commands, etc.).
43 *
44 * In both cases additional allowed content rules may be added by
45 * setting the {@link CKEDITOR.config#extraAllowedContent}
46 * configuration option.
47 *
48 * **Note**: Filter rules will be extended with the following elements
49 * depending on the {@link CKEDITOR.config#enterMode} and
50 * {@link CKEDITOR.config#shiftEnterMode} settings:
51 *
52 * * `'p'` &ndash; for {@link CKEDITOR#ENTER_P},
53 * * `'div'` &ndash; for {@link CKEDITOR#ENTER_DIV},
54 * * `'br'` &ndash; for {@link CKEDITOR#ENTER_BR}.
55 *
56 * **Read more** about the Advanced Content Filter in [guides](#!/guide/dev_advanced_content_filter).
57 *
58 * Filter may also be used as a standalone instance by passing
59 * {@link CKEDITOR.filter.allowedContentRules} instead of {@link CKEDITOR.editor}
60 * to the constructor:
61 *
62 * var filter = new CKEDITOR.filter( 'b' );
63 *
64 * filter.check( 'b' ); // -> true
65 * filter.check( 'i' ); // -> false
66 * filter.allow( 'i' );
67 * filter.check( 'i' ); // -> true
68 *
69 * @since 4.1
70 * @class
71 * @constructor Creates a filter class instance.
72 * @param {CKEDITOR.editor/CKEDITOR.filter.allowedContentRules} editorOrRules
73 */
74 CKEDITOR.filter = function( editorOrRules ) {
75 /**
76 * Whether custom {@link CKEDITOR.config#allowedContent} was set.
77 *
78 * This property does not apply to the standalone filter.
79 *
80 * @readonly
81 * @property {Boolean} customConfig
82 */
83
84 /**
85 * Array of rules added by the {@link #allow} method (including those
86 * loaded from {@link CKEDITOR.config#allowedContent} and
87 * {@link CKEDITOR.config#extraAllowedContent}).
88 *
89 * Rules in this array are in unified allowed content rules format.
90 *
91 * This property is useful for debugging issues with rules string parsing
92 * or for checking which rules were automatically added by editor features.
93 *
94 * @readonly
95 */
96 this.allowedContent = [];
97
98 /**
99 * Array of rules added by the {@link #disallow} method (including those
100 * loaded from {@link CKEDITOR.config#disallowedContent}).
101 *
102 * Rules in this array are in unified disallowed content rules format.
103 *
104 * This property is useful for debugging issues with rules string parsing
105 * or for checking which rules were automatically added by editor features.
106 *
107 * @since 4.4
108 * @readonly
109 */
110 this.disallowedContent = [];
111
112 /**
113 * Array of element callbacks. See {@link #addElementCallback}.
114 *
115 * @readonly
116 * @property {Function[]} [=null]
117 */
118 this.elementCallbacks = null;
119
120 /**
121 * Whether the filter is disabled.
122 *
123 * To disable the filter, set {@link CKEDITOR.config#allowedContent} to `true`
124 * or use the {@link #disable} method.
125 *
126 * @readonly
127 */
128 this.disabled = false;
129
130 /**
131 * Editor instance if not a standalone filter.
132 *
133 * @readonly
134 * @property {CKEDITOR.editor} [=null]
135 */
136 this.editor = null;
137
138 /**
139 * Filter's unique id. It can be used to find filter instance in
140 * {@link CKEDITOR.filter#instances CKEDITOR.filter.instance} object.
141 *
142 * @since 4.3
143 * @readonly
144 * @property {Number} id
145 */
146 this.id = CKEDITOR.tools.getNextNumber();
147
148 this._ = {
149 // Optimized allowed content rules.
150 allowedRules: {
151 elements: {},
152 generic: []
153 },
154 // Optimized disallowed content rules.
155 disallowedRules: {
156 elements: {},
157 generic: []
158 },
159 // Object: element name => array of transformations groups.
160 transformations: {},
161 cachedTests: {}
162 };
163
164 // Register filter instance.
165 CKEDITOR.filter.instances[ this.id ] = this;
166
167 if ( editorOrRules instanceof CKEDITOR.editor ) {
168 var editor = this.editor = editorOrRules;
169 this.customConfig = true;
170
171 var allowedContent = editor.config.allowedContent;
172
173 // Disable filter completely by setting config.allowedContent = true.
174 if ( allowedContent === true ) {
175 this.disabled = true;
176 return;
177 }
178
179 if ( !allowedContent )
180 this.customConfig = false;
181
182 this.allow( allowedContent, 'config', 1 );
183 this.allow( editor.config.extraAllowedContent, 'extra', 1 );
184
185 // Enter modes should extend filter rules (ENTER_P adds 'p' rule, etc.).
186 this.allow( enterModeTags[ editor.enterMode ] + ' ' + enterModeTags[ editor.shiftEnterMode ], 'default', 1 );
187
188 this.disallow( editor.config.disallowedContent );
189 }
190 // Rules object passed in editorOrRules argument - initialize standalone filter.
191 else {
192 this.customConfig = false;
193 this.allow( editorOrRules, 'default', 1 );
194 }
195 };
196
197 /**
198 * Object containing all filter instances stored under their
199 * {@link #id} properties.
200 *
201 * var filter = new CKEDITOR.filter( 'p' );
202 * filter === CKEDITOR.filter.instances[ filter.id ];
203 *
204 * @since 4.3
205 * @static
206 * @property instances
207 */
208 CKEDITOR.filter.instances = {};
209
210 CKEDITOR.filter.prototype = {
211 /**
212 * Adds allowed content rules to the filter.
213 *
214 * Read about rules formats in [Allowed Content Rules guide](#!/guide/dev_allowed_content_rules).
215 *
216 * // Add a basic rule for custom image feature (e.g. 'MyImage' button).
217 * editor.filter.allow( 'img[!src,alt]', 'MyImage' );
218 *
219 * // Add rules for two header styles allowed by 'HeadersCombo'.
220 * var header1Style = new CKEDITOR.style( { element: 'h1' } ),
221 * header2Style = new CKEDITOR.style( { element: 'h2' } );
222 * editor.filter.allow( [ header1Style, header2Style ], 'HeadersCombo' );
223 *
224 * @param {CKEDITOR.filter.allowedContentRules} newRules Rule(s) to be added.
225 * @param {String} [featureName] Name of a feature that allows this content (most often plugin/button/command name).
226 * @param {Boolean} [overrideCustom] By default this method will reject any rules
227 * if {@link CKEDITOR.config#allowedContent} is defined to avoid overriding it.
228 * Pass `true` to force rules addition.
229 * @returns {Boolean} Whether the rules were accepted.
230 */
231 allow: function( newRules, featureName, overrideCustom ) {
232 // Check arguments and constraints. Clear cache.
233 if ( !beforeAddingRule( this, newRules, overrideCustom ) )
234 return false;
235
236 var i, ret;
237
238 if ( typeof newRules == 'string' )
239 newRules = parseRulesString( newRules );
240 else if ( newRules instanceof CKEDITOR.style ) {
241 // If style has the cast method defined, use it and abort.
242 if ( newRules.toAllowedContentRules )
243 return this.allow( newRules.toAllowedContentRules( this.editor ), featureName, overrideCustom );
244
245 newRules = convertStyleToRules( newRules );
246 } else if ( CKEDITOR.tools.isArray( newRules ) ) {
247 for ( i = 0; i < newRules.length; ++i )
248 ret = this.allow( newRules[ i ], featureName, overrideCustom );
249 return ret; // Return last status.
250 }
251
252 addAndOptimizeRules( this, newRules, featureName, this.allowedContent, this._.allowedRules );
253
254 return true;
255 },
256
257 /**
258 * Applies this filter to passed {@link CKEDITOR.htmlParser.fragment} or {@link CKEDITOR.htmlParser.element}.
259 * The result of filtering is a DOM tree without disallowed content.
260 *
261 * // Create standalone filter passing 'p' and 'b' elements.
262 * var filter = new CKEDITOR.filter( 'p b' ),
263 * // Parse HTML string to pseudo DOM structure.
264 * fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p><b>foo</b> <i>bar</i></p>' ),
265 * writer = new CKEDITOR.htmlParser.basicWriter();
266 *
267 * filter.applyTo( fragment );
268 * fragment.writeHtml( writer );
269 * writer.getHtml(); // -> '<p><b>foo</b> bar</p>'
270 *
271 * @param {CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} fragment Node to be filtered.
272 * @param {Boolean} [toHtml] Set to `true` if the filter is used together with {@link CKEDITOR.htmlDataProcessor#toHtml}.
273 * @param {Boolean} [transformOnly] If set to `true` only transformations will be applied. Content
274 * will not be filtered with allowed content rules.
275 * @param {Number} [enterMode] Enter mode used by the filter when deciding how to strip disallowed element.
276 * Defaults to {@link CKEDITOR.editor#activeEnterMode} for a editor's filter or to {@link CKEDITOR#ENTER_P} for standalone filter.
277 * @returns {Boolean} Whether some part of the `fragment` was removed by the filter.
278 */
279 applyTo: function( fragment, toHtml, transformOnly, enterMode ) {
280 if ( this.disabled )
281 return false;
282
283 var that = this,
284 toBeRemoved = [],
285 protectedRegexs = this.editor && this.editor.config.protectedSource,
286 processRetVal,
287 isModified = false,
288 filterOpts = {
289 doFilter: !transformOnly,
290 doTransform: true,
291 doCallbacks: true,
292 toHtml: toHtml
293 };
294
295 // Filter all children, skip root (fragment or editable-like wrapper used by data processor).
296 fragment.forEach( function( el ) {
297 if ( el.type == CKEDITOR.NODE_ELEMENT ) {
298 // Do not filter element with data-cke-filter="off" and all their descendants.
299 if ( el.attributes[ 'data-cke-filter' ] == 'off' )
300 return false;
301
302 // (#10260) Don't touch elements like spans with data-cke-* attribute since they're
303 // responsible e.g. for placing markers, bookmarks, odds and stuff.
304 // We love 'em and we don't wanna lose anything during the filtering.
305 // '|' is to avoid tricky joints like data-="foo" + cke-="bar". Yes, they're possible.
306 //
307 // NOTE: data-cke-* assigned elements are preserved only when filter is used with
308 // htmlDataProcessor.toHtml because we don't want to protect them when outputting data
309 // (toDataFormat).
310 if ( toHtml && el.name == 'span' && ~CKEDITOR.tools.objectKeys( el.attributes ).join( '|' ).indexOf( 'data-cke-' ) )
311 return;
312
313 processRetVal = processElement( that, el, toBeRemoved, filterOpts );
314 if ( processRetVal & FILTER_ELEMENT_MODIFIED )
315 isModified = true;
316 else if ( processRetVal & FILTER_SKIP_TREE )
317 return false;
318 }
319 else if ( el.type == CKEDITOR.NODE_COMMENT && el.value.match( /^\{cke_protected\}(?!\{C\})/ ) ) {
320 if ( !processProtectedElement( that, el, protectedRegexs, filterOpts ) )
321 toBeRemoved.push( el );
322 }
323 }, null, true );
324
325 if ( toBeRemoved.length )
326 isModified = true;
327
328 var node, element, check,
329 toBeChecked = [],
330 enterTag = enterModeTags[ enterMode || ( this.editor ? this.editor.enterMode : CKEDITOR.ENTER_P ) ],
331 parentDtd;
332
333 // Remove elements in reverse order - from leaves to root, to avoid conflicts.
334 while ( ( node = toBeRemoved.pop() ) ) {
335 if ( node.type == CKEDITOR.NODE_ELEMENT )
336 removeElement( node, enterTag, toBeChecked );
337 // This is a comment securing rejected element - remove it completely.
338 else
339 node.remove();
340 }
341
342 // Check elements that have been marked as possibly invalid.
343 while ( ( check = toBeChecked.pop() ) ) {
344 element = check.el;
345 // Element has been already removed.
346 if ( !element.parent )
347 continue;
348
349 // Handle custom elements as inline elements (#12683).
350 parentDtd = DTD[ element.parent.name ] || DTD.span;
351
352 switch ( check.check ) {
353 // Check if element itself is correct.
354 case 'it':
355 // Check if element included in $removeEmpty has no children.
356 if ( DTD.$removeEmpty[ element.name ] && !element.children.length )
357 removeElement( element, enterTag, toBeChecked );
358 // Check if that is invalid element.
359 else if ( !validateElement( element ) )
360 removeElement( element, enterTag, toBeChecked );
361 break;
362
363 // Check if element is in correct context. If not - remove element.
364 case 'el-up':
365 // Check if e.g. li is a child of body after ul has been removed.
366 if ( element.parent.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT && !parentDtd[ element.name ] )
367 removeElement( element, enterTag, toBeChecked );
368 break;
369
370 // Check if element is in correct context. If not - remove parent.
371 case 'parent-down':
372 if ( element.parent.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT && !parentDtd[ element.name ] )
373 removeElement( element.parent, enterTag, toBeChecked );
374 break;
375 }
376 }
377
378 return isModified;
379 },
380
381 /**
382 * Checks whether a {@link CKEDITOR.feature} can be enabled. Unlike {@link #addFeature},
383 * this method always checks the feature, even when the default configuration
384 * for {@link CKEDITOR.config#allowedContent} is used.
385 *
386 * // TODO example
387 *
388 * @param {CKEDITOR.feature} feature The feature to be tested.
389 * @returns {Boolean} Whether this feature can be enabled.
390 */
391 checkFeature: function( feature ) {
392 if ( this.disabled )
393 return true;
394
395 if ( !feature )
396 return true;
397
398 // Some features may want to register other features.
399 // E.g. a button may return a command bound to it.
400 if ( feature.toFeature )
401 feature = feature.toFeature( this.editor );
402
403 return !feature.requiredContent || this.check( feature.requiredContent );
404 },
405
406 /**
407 * Disables Advanced Content Filter.
408 *
409 * This method is meant to be used by plugins which are not
410 * compatible with the filter and in other cases in which the filter
411 * has to be disabled during the initialization phase or runtime.
412 *
413 * In other cases the filter can be disabled by setting
414 * {@link CKEDITOR.config#allowedContent} to `true`.
415 */
416 disable: function() {
417 this.disabled = true;
418 },
419
420 /**
421 * Adds disallowed content rules to the filter.
422 *
423 * Read about rules formats in the [Allowed Content Rules guide](#!/guide/dev_allowed_content_rules).
424 *
425 * // Disallow all styles on the image elements.
426 * editor.filter.disallow( 'img{*}' );
427 *
428 * // Disallow all span and div elements.
429 * editor.filter.disallow( 'span div' );
430 *
431 * @since 4.4
432 * @param {CKEDITOR.filter.disallowedContentRules} newRules Rule(s) to be added.
433 */
434 disallow: function( newRules ) {
435 // Check arguments and constraints. Clear cache.
436 // Note: we pass true in the 3rd argument, because disallow() should never
437 // be blocked by custom configuration.
438 if ( !beforeAddingRule( this, newRules, true ) )
439 return false;
440
441 if ( typeof newRules == 'string' )
442 newRules = parseRulesString( newRules );
443
444 addAndOptimizeRules( this, newRules, null, this.disallowedContent, this._.disallowedRules );
445
446 return true;
447 },
448
449 /**
450 * Adds an array of {@link CKEDITOR.feature} content forms. All forms
451 * will then be transformed to the first form which is allowed by the filter.
452 *
453 * editor.filter.allow( 'i; span{!font-style}' );
454 * editor.filter.addContentForms( [
455 * 'em',
456 * 'i',
457 * [ 'span', function( el ) {
458 * return el.styles[ 'font-style' ] == 'italic';
459 * } ]
460 * ] );
461 * // Now <em> and <span style="font-style:italic"> will be replaced with <i>
462 * // because this is the first allowed form.
463 * // <span> is allowed too, but it is the last form and
464 * // additionaly, the editor cannot transform an element based on
465 * // the array+function form).
466 *
467 * This method is used by the editor to register {@link CKEDITOR.feature#contentForms}
468 * when adding a feature with {@link #addFeature} or {@link CKEDITOR.editor#addFeature}.
469 *
470 * @param {Array} forms The content forms of a feature.
471 */
472 addContentForms: function( forms ) {
473 if ( this.disabled )
474 return;
475
476 if ( !forms )
477 return;
478
479 var i, form,
480 transfGroups = [],
481 preferredForm;
482
483 // First, find preferred form - this is, first allowed.
484 for ( i = 0; i < forms.length && !preferredForm; ++i ) {
485 form = forms[ i ];
486
487 // Check only strings and styles - array format isn't supported by #check().
488 if ( ( typeof form == 'string' || form instanceof CKEDITOR.style ) && this.check( form ) )
489 preferredForm = form;
490 }
491
492 // This feature doesn't have preferredForm, so ignore it.
493 if ( !preferredForm )
494 return;
495
496 for ( i = 0; i < forms.length; ++i )
497 transfGroups.push( getContentFormTransformationGroup( forms[ i ], preferredForm ) );
498
499 this.addTransformations( transfGroups );
500 },
501
502 /**
503 * Adds a callback which will be executed on every element
504 * that the filter reaches when filtering, before the element is filtered.
505 *
506 * By returning {@link CKEDITOR#FILTER_SKIP_TREE} it is possible to
507 * skip filtering of the current element and all its ancestors.
508 *
509 * editor.filter.addElementCallback( function( el ) {
510 * if ( el.hasClass( 'protected' ) )
511 * return CKEDITOR.FILTER_SKIP_TREE;
512 * } );
513 *
514 * **Note:** At this stage the element passed to the callback does not
515 * contain `attributes`, `classes`, and `styles` properties which are available
516 * temporarily on later stages of the filtering process. Therefore you need to
517 * use the pure {@link CKEDITOR.htmlParser.element} interface.
518 *
519 * @since 4.4
520 * @param {Function} callback The callback to be executed.
521 */
522 addElementCallback: function( callback ) {
523 // We want to keep it a falsy value, to speed up finding whether there are any callbacks.
524 if ( !this.elementCallbacks )
525 this.elementCallbacks = [];
526
527 this.elementCallbacks.push( callback );
528 },
529
530 /**
531 * Checks whether a feature can be enabled for the HTML restrictions in place
532 * for the current CKEditor instance, based on the HTML code the feature might
533 * generate and the minimal HTML code the feature needs to be able to generate.
534 *
535 * // TODO example
536 *
537 * @param {CKEDITOR.feature} feature
538 * @returns {Boolean} Whether this feature can be enabled.
539 */
540 addFeature: function( feature ) {
541 if ( this.disabled )
542 return true;
543
544 if ( !feature )
545 return true;
546
547 // Some features may want to register other features.
548 // E.g. a button may return a command bound to it.
549 if ( feature.toFeature )
550 feature = feature.toFeature( this.editor );
551
552 // If default configuration (will be checked inside #allow()),
553 // then add allowed content rules.
554 this.allow( feature.allowedContent, feature.name );
555
556 this.addTransformations( feature.contentTransformations );
557 this.addContentForms( feature.contentForms );
558
559 // If custom configuration or any DACRs, then check if required content is allowed.
560 if ( feature.requiredContent && ( this.customConfig || this.disallowedContent.length ) )
561 return this.check( feature.requiredContent );
562
563 return true;
564 },
565
566 /**
567 * Adds an array of content transformation groups. One group
568 * may contain many transformation rules, but only the first
569 * matching rule in a group is executed.
570 *
571 * A single transformation rule is an object with four properties:
572 *
573 * * `check` (optional) &ndash; if set and {@link CKEDITOR.filter} does
574 * not accept this {@link CKEDITOR.filter.contentRule}, this transformation rule
575 * will not be executed (it does not *match*). This value is passed
576 * to {@link #check}.
577 * * `element` (optional) &ndash; this string property tells the filter on which
578 * element this transformation can be run. It is optional, because
579 * the element name can be obtained from `check` (if it is a String format)
580 * or `left` (if it is a {@link CKEDITOR.style} instance).
581 * * `left` (optional) &ndash; a function accepting an element or a {@link CKEDITOR.style}
582 * instance verifying whether the transformation should be
583 * executed on this specific element. If it returns `false` or if an element
584 * does not match this style, this transformation rule does not *match*.
585 * * `right` &ndash; a function accepting an element and {@link CKEDITOR.filter.transformationsTools}
586 * or a string containing the name of the {@link CKEDITOR.filter.transformationsTools} method
587 * that should be called on an element.
588 *
589 * A shorthand format is also available. A transformation rule can be defined by
590 * a single string `'check:right'`. The string before `':'` will be used as
591 * the `check` property and the second part as the `right` property.
592 *
593 * Transformation rules can be grouped. The filter will try to apply
594 * the first rule in a group. If it *matches*, the filter will ignore subsequent rules and
595 * will move to the next group. If it does not *match*, the next rule will be checked.
596 *
597 * Examples:
598 *
599 * editor.filter.addTransformations( [
600 * // First group.
601 * [
602 * // First rule. If table{width} is allowed, it
603 * // executes {@link CKEDITOR.filter.transformationsTools#sizeToStyle} on a table element.
604 * 'table{width}: sizeToStyle',
605 * // Second rule should not be executed if the first was.
606 * 'table[width]: sizeToAttribute'
607 * ],
608 * // Second group.
609 * [
610 * // This rule will add the foo="1" attribute to all images that
611 * // do not have it.
612 * {
613 * element: 'img',
614 * left: function( el ) {
615 * return !el.attributes.foo;
616 * },
617 * right: function( el, tools ) {
618 * el.attributes.foo = '1';
619 * }
620 * }
621 * ]
622 * ] );
623 *
624 * // Case 1:
625 * // config.allowedContent = 'table{height,width}; tr td'.
626 * //
627 * // '<table style="height:100px; width:200px">...</table>' -> '<table style="height:100px; width:200px">...</table>'
628 * // '<table height="100" width="200">...</table>' -> '<table style="height:100px; width:200px">...</table>'
629 *
630 * // Case 2:
631 * // config.allowedContent = 'table[height,width]; tr td'.
632 * //
633 * // '<table style="height:100px; width:200px">...</table>' -> '<table height="100" width="200">...</table>'
634 * // '<table height="100" width="200">...</table>' -> '<table height="100" width="200"">...</table>'
635 *
636 * // Case 3:
637 * // config.allowedContent = 'table{width,height}[height,width]; tr td'.
638 * //
639 * // '<table style="height:100px; width:200px">...</table>' -> '<table style="height:100px; width:200px">...</table>'
640 * // '<table height="100" width="200">...</table>' -> '<table style="height:100px; width:200px">...</table>'
641 * //
642 * // Note: Both forms are allowed (size set by style and by attributes), but only
643 * // the first transformation is applied &mdash; the size is always transformed to a style.
644 * // This is because only the first transformation matching allowed content rules is applied.
645 *
646 * This method is used by the editor to add {@link CKEDITOR.feature#contentTransformations}
647 * when adding a feature by {@link #addFeature} or {@link CKEDITOR.editor#addFeature}.
648 *
649 * @param {Array} transformations
650 */
651 addTransformations: function( transformations ) {
652 if ( this.disabled )
653 return;
654
655 if ( !transformations )
656 return;
657
658 var optimized = this._.transformations,
659 group, i;
660
661 for ( i = 0; i < transformations.length; ++i ) {
662 group = optimizeTransformationsGroup( transformations[ i ] );
663
664 if ( !optimized[ group.name ] )
665 optimized[ group.name ] = [];
666
667 optimized[ group.name ].push( group.rules );
668 }
669 },
670
671 /**
672 * Checks whether the content defined in the `test` argument is allowed
673 * by this filter.
674 *
675 * If `strictCheck` is set to `false` (default value), this method checks
676 * if all parts of the `test` (styles, attributes, and classes) are
677 * accepted by the filter. If `strictCheck` is set to `true`, the test
678 * must also contain the required attributes, styles, and classes.
679 *
680 * For example:
681 *
682 * // Rule: 'img[!src,alt]'.
683 * filter.check( 'img[alt]' ); // -> true
684 * filter.check( 'img[alt]', true, true ); // -> false
685 *
686 * Second `check()` call returned `false` because `src` is required.
687 *
688 * **Note:** The `test` argument is of {@link CKEDITOR.filter.contentRule} type, which is
689 * a limited version of {@link CKEDITOR.filter.allowedContentRules}. Read more about it
690 * in the {@link CKEDITOR.filter.contentRule}'s documentation.
691 *
692 * @param {CKEDITOR.filter.contentRule} test
693 * @param {Boolean} [applyTransformations=true] Whether to use registered transformations.
694 * @param {Boolean} [strictCheck] Whether the filter should check if an element with exactly
695 * these properties is allowed.
696 * @returns {Boolean} Returns `true` if the content is allowed.
697 */
698 check: function( test, applyTransformations, strictCheck ) {
699 if ( this.disabled )
700 return true;
701
702 // If rules are an array, expand it and return the logical OR value of
703 // the rules.
704 if ( CKEDITOR.tools.isArray( test ) ) {
705 for ( var i = test.length ; i-- ; ) {
706 if ( this.check( test[ i ], applyTransformations, strictCheck ) )
707 return true;
708 }
709 return false;
710 }
711
712 var element, result, cacheKey;
713
714 if ( typeof test == 'string' ) {
715 cacheKey = test + '<' + ( applyTransformations === false ? '0' : '1' ) + ( strictCheck ? '1' : '0' ) + '>';
716
717 // Check if result of this check hasn't been already cached.
718 if ( cacheKey in this._.cachedChecks )
719 return this._.cachedChecks[ cacheKey ];
720
721 // Create test element from string.
722 element = mockElementFromString( test );
723 } else {
724 // Create test element from CKEDITOR.style.
725 element = mockElementFromStyle( test );
726 }
727
728 // Make a deep copy.
729 var clone = CKEDITOR.tools.clone( element ),
730 toBeRemoved = [],
731 transformations;
732
733 // Apply transformations to original element.
734 // Transformations will be applied to clone by the filter function.
735 if ( applyTransformations !== false && ( transformations = this._.transformations[ element.name ] ) ) {
736 for ( i = 0; i < transformations.length; ++i )
737 applyTransformationsGroup( this, element, transformations[ i ] );
738
739 // Transformations could modify styles or classes, so they need to be copied
740 // to attributes object.
741 updateAttributes( element );
742 }
743
744 // Filter clone of mocked element.
745 processElement( this, clone, toBeRemoved, {
746 doFilter: true,
747 doTransform: applyTransformations !== false,
748 skipRequired: !strictCheck,
749 skipFinalValidation: !strictCheck
750 } );
751
752 // Element has been marked for removal.
753 if ( toBeRemoved.length > 0 ) {
754 result = false;
755 // Compare only left to right, because clone may be only trimmed version of original element.
756 } else if ( !CKEDITOR.tools.objectCompare( element.attributes, clone.attributes, true ) ) {
757 result = false;
758 } else {
759 result = true;
760 }
761
762 // Cache result of this test - we can build cache only for string tests.
763 if ( typeof test == 'string' )
764 this._.cachedChecks[ cacheKey ] = result;
765
766 return result;
767 },
768
769 /**
770 * Returns first enter mode allowed by this filter rules. Modes are checked in `p`, `div`, `br` order.
771 * If none of tags is allowed this method will return {@link CKEDITOR#ENTER_BR}.
772 *
773 * @since 4.3
774 * @param {Number} defaultMode The default mode which will be checked as the first one.
775 * @param {Boolean} [reverse] Whether to check modes in reverse order (used for shift enter mode).
776 * @returns {Number} Allowed enter mode.
777 */
778 getAllowedEnterMode: ( function() {
779 var tagsToCheck = [ 'p', 'div', 'br' ],
780 enterModes = {
781 p: CKEDITOR.ENTER_P,
782 div: CKEDITOR.ENTER_DIV,
783 br: CKEDITOR.ENTER_BR
784 };
785
786 return function( defaultMode, reverse ) {
787 // Clone the array first.
788 var tags = tagsToCheck.slice(),
789 tag;
790
791 // Check the default mode first.
792 if ( this.check( enterModeTags[ defaultMode ] ) )
793 return defaultMode;
794
795 // If not reverse order, reverse array so we can pop() from it.
796 if ( !reverse )
797 tags = tags.reverse();
798
799 while ( ( tag = tags.pop() ) ) {
800 if ( this.check( tag ) )
801 return enterModes[ tag ];
802 }
803
804 return CKEDITOR.ENTER_BR;
805 };
806 } )(),
807
808 /**
809 * Destroys the filter instance and removes it from the global {@link CKEDITOR.filter#instances} object.
810 *
811 * @since 4.4.5
812 */
813 destroy: function() {
814 delete CKEDITOR.filter.instances[ this.id ];
815 // Deleting reference to filter instance should be enough,
816 // but since these are big objects it's safe to clean them up too.
817 delete this._;
818 delete this.allowedContent;
819 delete this.disallowedContent;
820 }
821 };
822
823 function addAndOptimizeRules( that, newRules, featureName, standardizedRules, optimizedRules ) {
824 var groupName, rule,
825 rulesToOptimize = [];
826
827 for ( groupName in newRules ) {
828 rule = newRules[ groupName ];
829
830 // { 'p h1': true } => { 'p h1': {} }.
831 if ( typeof rule == 'boolean' )
832 rule = {};
833 // { 'p h1': func } => { 'p h1': { match: func } }.
834 else if ( typeof rule == 'function' )
835 rule = { match: rule };
836 // Clone (shallow) rule, because we'll modify it later.
837 else
838 rule = copy( rule );
839
840 // If this is not an unnamed rule ({ '$1' => { ... } })
841 // move elements list to property.
842 if ( groupName.charAt( 0 ) != '$' )
843 rule.elements = groupName;
844
845 if ( featureName )
846 rule.featureName = featureName.toLowerCase();
847
848 standardizeRule( rule );
849
850 // Save rule and remember to optimize it.
851 standardizedRules.push( rule );
852 rulesToOptimize.push( rule );
853 }
854
855 optimizeRules( optimizedRules, rulesToOptimize );
856 }
857
858 // Apply ACR to an element.
859 // @param rule
860 // @param element
861 // @param status Object containing status of element's filtering.
862 // @param {Boolean} skipRequired If true don't check if element has all required properties.
863 function applyAllowedRule( rule, element, status, skipRequired ) {
864 // This rule doesn't match this element - skip it.
865 if ( rule.match && !rule.match( element ) )
866 return;
867
868 // If element doesn't have all required styles/attrs/classes
869 // this rule doesn't match it.
870 if ( !skipRequired && !hasAllRequired( rule, element ) )
871 return;
872
873 // If this rule doesn't validate properties only mark element as valid.
874 if ( !rule.propertiesOnly )
875 status.valid = true;
876
877 // Apply rule only when all attrs/styles/classes haven't been marked as valid.
878 if ( !status.allAttributes )
879 status.allAttributes = applyAllowedRuleToHash( rule.attributes, element.attributes, status.validAttributes );
880
881 if ( !status.allStyles )
882 status.allStyles = applyAllowedRuleToHash( rule.styles, element.styles, status.validStyles );
883
884 if ( !status.allClasses )
885 status.allClasses = applyAllowedRuleToArray( rule.classes, element.classes, status.validClasses );
886 }
887
888 // Apply itemsRule to items (only classes are kept in array).
889 // Push accepted items to validItems array.
890 // Return true when all items are valid.
891 function applyAllowedRuleToArray( itemsRule, items, validItems ) {
892 if ( !itemsRule )
893 return false;
894
895 // True means that all elements of array are accepted (the asterix was used for classes).
896 if ( itemsRule === true )
897 return true;
898
899 for ( var i = 0, l = items.length, item; i < l; ++i ) {
900 item = items[ i ];
901 if ( !validItems[ item ] )
902 validItems[ item ] = itemsRule( item );
903 }
904
905 return false;
906 }
907
908 function applyAllowedRuleToHash( itemsRule, items, validItems ) {
909 if ( !itemsRule )
910 return false;
911
912 if ( itemsRule === true )
913 return true;
914
915 for ( var name in items ) {
916 if ( !validItems[ name ] )
917 validItems[ name ] = itemsRule( name );
918 }
919
920 return false;
921 }
922
923 // Apply DACR rule to an element.
924 function applyDisallowedRule( rule, element, status ) {
925 // This rule doesn't match this element - skip it.
926 if ( rule.match && !rule.match( element ) )
927 return;
928
929 // No properties - it's an element only rule so it disallows entire element.
930 // Early return is handled in filterElement.
931 if ( rule.noProperties )
932 return false;
933
934 // Apply rule to attributes, styles and classes. Switch hadInvalid* to true if method returned true.
935 status.hadInvalidAttribute = applyDisallowedRuleToHash( rule.attributes, element.attributes ) || status.hadInvalidAttribute;
936 status.hadInvalidStyle = applyDisallowedRuleToHash( rule.styles, element.styles ) || status.hadInvalidStyle;
937 status.hadInvalidClass = applyDisallowedRuleToArray( rule.classes, element.classes ) || status.hadInvalidClass;
938 }
939
940 // Apply DACR to items (only classes are kept in array).
941 // @returns {Boolean} True if at least one of items was invalid (disallowed).
942 function applyDisallowedRuleToArray( itemsRule, items ) {
943 if ( !itemsRule )
944 return false;
945
946 var hadInvalid = false,
947 allDisallowed = itemsRule === true;
948
949 for ( var i = items.length; i--; ) {
950 if ( allDisallowed || itemsRule( items[ i ] ) ) {
951 items.splice( i, 1 );
952 hadInvalid = true;
953 }
954 }
955
956 return hadInvalid;
957 }
958
959 // Apply DACR to items (styles and attributes).
960 // @returns {Boolean} True if at least one of items was invalid (disallowed).
961 function applyDisallowedRuleToHash( itemsRule, items ) {
962 if ( !itemsRule )
963 return false;
964
965 var hadInvalid = false,
966 allDisallowed = itemsRule === true;
967
968 for ( var name in items ) {
969 if ( allDisallowed || itemsRule( name ) ) {
970 delete items[ name ];
971 hadInvalid = true;
972 }
973 }
974
975 return hadInvalid;
976 }
977
978 function beforeAddingRule( that, newRules, overrideCustom ) {
979 if ( that.disabled )
980 return false;
981
982 // Don't override custom user's configuration if not explicitly requested.
983 if ( that.customConfig && !overrideCustom )
984 return false;
985
986 if ( !newRules )
987 return false;
988
989 // Clear cache, because new rules could change results of checks.
990 that._.cachedChecks = {};
991
992 return true;
993 }
994
995 // Convert CKEDITOR.style to filter's rule.
996 function convertStyleToRules( style ) {
997 var styleDef = style.getDefinition(),
998 rules = {},
999 rule,
1000 attrs = styleDef.attributes;
1001
1002 rules[ styleDef.element ] = rule = {
1003 styles: styleDef.styles,
1004 requiredStyles: styleDef.styles && CKEDITOR.tools.objectKeys( styleDef.styles )
1005 };
1006
1007 if ( attrs ) {
1008 attrs = copy( attrs );
1009 rule.classes = attrs[ 'class' ] ? attrs[ 'class' ].split( /\s+/ ) : null;
1010 rule.requiredClasses = rule.classes;
1011 delete attrs[ 'class' ];
1012 rule.attributes = attrs;
1013 rule.requiredAttributes = attrs && CKEDITOR.tools.objectKeys( attrs );
1014 }
1015
1016 return rules;
1017 }
1018
1019 // Convert all validator formats (string, array, object, boolean) to hash or boolean:
1020 // * true is returned for '*'/true validator,
1021 // * false is returned for empty validator (no validator at all (false/null) or e.g. empty array),
1022 // * object is returned in other cases.
1023 function convertValidatorToHash( validator, delimiter ) {
1024 if ( !validator )
1025 return false;
1026
1027 if ( validator === true )
1028 return validator;
1029
1030 if ( typeof validator == 'string' ) {
1031 validator = trim( validator );
1032 if ( validator == '*' )
1033 return true;
1034 else
1035 return CKEDITOR.tools.convertArrayToObject( validator.split( delimiter ) );
1036 }
1037 else if ( CKEDITOR.tools.isArray( validator ) ) {
1038 if ( validator.length )
1039 return CKEDITOR.tools.convertArrayToObject( validator );
1040 else
1041 return false;
1042 }
1043 // If object.
1044 else {
1045 var obj = {},
1046 len = 0;
1047
1048 for ( var i in validator ) {
1049 obj[ i ] = validator[ i ];
1050 len++;
1051 }
1052
1053 return len ? obj : false;
1054 }
1055 }
1056
1057 function executeElementCallbacks( element, callbacks ) {
1058 for ( var i = 0, l = callbacks.length, retVal; i < l; ++i ) {
1059 if ( ( retVal = callbacks[ i ]( element ) ) )
1060 return retVal;
1061 }
1062 }
1063
1064 // Extract required properties from "required" validator and "all" properties.
1065 // Remove exclamation marks from "all" properties.
1066 //
1067 // E.g.:
1068 // requiredClasses = { cl1: true }
1069 // (all) classes = { cl1: true, cl2: true, '!cl3': true }
1070 //
1071 // result:
1072 // returned = { cl1: true, cl3: true }
1073 // all = { cl1: true, cl2: true, cl3: true }
1074 //
1075 // This function returns false if nothing is required.
1076 function extractRequired( required, all ) {
1077 var unbang = [],
1078 empty = true,
1079 i;
1080
1081 if ( required )
1082 empty = false;
1083 else
1084 required = {};
1085
1086 for ( i in all ) {
1087 if ( i.charAt( 0 ) == '!' ) {
1088 i = i.slice( 1 );
1089 unbang.push( i );
1090 required[ i ] = true;
1091 empty = false;
1092 }
1093 }
1094
1095 while ( ( i = unbang.pop() ) ) {
1096 all[ i ] = all[ '!' + i ];
1097 delete all[ '!' + i ];
1098 }
1099
1100 return empty ? false : required;
1101 }
1102
1103 // Does the actual filtering by appling allowed content rules
1104 // to the element.
1105 //
1106 // @param {CKEDITOR.filter} that The context.
1107 // @param {CKEDITOR.htmlParser.element} element
1108 // @param {Object} opts The same as in processElement.
1109 function filterElement( that, element, opts ) {
1110 var name = element.name,
1111 privObj = that._,
1112 allowedRules = privObj.allowedRules.elements[ name ],
1113 genericAllowedRules = privObj.allowedRules.generic,
1114 disallowedRules = privObj.disallowedRules.elements[ name ],
1115 genericDisallowedRules = privObj.disallowedRules.generic,
1116 skipRequired = opts.skipRequired,
1117 status = {
1118 // Whether any of rules accepted element.
1119 // If not - it will be stripped.
1120 valid: false,
1121 // Objects containing accepted attributes, classes and styles.
1122 validAttributes: {},
1123 validClasses: {},
1124 validStyles: {},
1125 // Whether all are valid.
1126 // If we know that all element's attrs/classes/styles are valid
1127 // we can skip their validation, to improve performance.
1128 allAttributes: false,
1129 allClasses: false,
1130 allStyles: false,
1131 // Whether element had (before applying DACRs) at least one invalid attribute/class/style.
1132 hadInvalidAttribute: false,
1133 hadInvalidClass: false,
1134 hadInvalidStyle: false
1135 },
1136 i, l;
1137
1138 // Early return - if there are no rules for this element (specific or generic), remove it.
1139 if ( !allowedRules && !genericAllowedRules )
1140 return null;
1141
1142 // Could not be done yet if there were no transformations and if this
1143 // is real (not mocked) object.
1144 populateProperties( element );
1145
1146 // Note - this step modifies element's styles, classes and attributes.
1147 if ( disallowedRules ) {
1148 for ( i = 0, l = disallowedRules.length; i < l; ++i ) {
1149 // Apply rule and make an early return if false is returned what means
1150 // that element is completely disallowed.
1151 if ( applyDisallowedRule( disallowedRules[ i ], element, status ) === false )
1152 return null;
1153 }
1154 }
1155
1156 // Note - this step modifies element's styles, classes and attributes.
1157 if ( genericDisallowedRules ) {
1158 for ( i = 0, l = genericDisallowedRules.length; i < l; ++i )
1159 applyDisallowedRule( genericDisallowedRules[ i ], element, status );
1160 }
1161
1162 if ( allowedRules ) {
1163 for ( i = 0, l = allowedRules.length; i < l; ++i )
1164 applyAllowedRule( allowedRules[ i ], element, status, skipRequired );
1165 }
1166
1167 if ( genericAllowedRules ) {
1168 for ( i = 0, l = genericAllowedRules.length; i < l; ++i )
1169 applyAllowedRule( genericAllowedRules[ i ], element, status, skipRequired );
1170 }
1171
1172 return status;
1173 }
1174
1175 // Check whether element has all properties (styles,classes,attrs) required by a rule.
1176 function hasAllRequired( rule, element ) {
1177 if ( rule.nothingRequired )
1178 return true;
1179
1180 var i, req, reqs, existing;
1181
1182 if ( ( reqs = rule.requiredClasses ) ) {
1183 existing = element.classes;
1184 for ( i = 0; i < reqs.length; ++i ) {
1185 req = reqs[ i ];
1186 if ( typeof req == 'string' ) {
1187 if ( CKEDITOR.tools.indexOf( existing, req ) == -1 )
1188 return false;
1189 }
1190 // This means regexp.
1191 else {
1192 if ( !CKEDITOR.tools.checkIfAnyArrayItemMatches( existing, req ) )
1193 return false;
1194 }
1195 }
1196 }
1197
1198 return hasAllRequiredInHash( element.styles, rule.requiredStyles ) &&
1199 hasAllRequiredInHash( element.attributes, rule.requiredAttributes );
1200 }
1201
1202 // Check whether all items in required (array) exist in existing (object).
1203 function hasAllRequiredInHash( existing, required ) {
1204 if ( !required )
1205 return true;
1206
1207 for ( var i = 0, req; i < required.length; ++i ) {
1208 req = required[ i ];
1209 if ( typeof req == 'string' ) {
1210 if ( !( req in existing ) )
1211 return false;
1212 }
1213 // This means regexp.
1214 else {
1215 if ( !CKEDITOR.tools.checkIfAnyObjectPropertyMatches( existing, req ) )
1216 return false;
1217 }
1218 }
1219
1220 return true;
1221 }
1222
1223 // Create pseudo element that will be passed through filter
1224 // to check if tested string is allowed.
1225 function mockElementFromString( str ) {
1226 var element = parseRulesString( str ).$1,
1227 styles = element.styles,
1228 classes = element.classes;
1229
1230 element.name = element.elements;
1231 element.classes = classes = ( classes ? classes.split( /\s*,\s*/ ) : [] );
1232 element.styles = mockHash( styles );
1233 element.attributes = mockHash( element.attributes );
1234 element.children = [];
1235
1236 if ( classes.length )
1237 element.attributes[ 'class' ] = classes.join( ' ' );
1238 if ( styles )
1239 element.attributes.style = CKEDITOR.tools.writeCssText( element.styles );
1240
1241 return element;
1242 }
1243
1244 // Create pseudo element that will be passed through filter
1245 // to check if tested style is allowed.
1246 function mockElementFromStyle( style ) {
1247 var styleDef = style.getDefinition(),
1248 styles = styleDef.styles,
1249 attrs = styleDef.attributes || {};
1250
1251 if ( styles && !CKEDITOR.tools.isEmpty( styles ) ) {
1252 styles = copy( styles );
1253 attrs.style = CKEDITOR.tools.writeCssText( styles, true );
1254 } else {
1255 styles = {};
1256 }
1257
1258 return {
1259 name: styleDef.element,
1260 attributes: attrs,
1261 classes: attrs[ 'class' ] ? attrs[ 'class' ].split( /\s+/ ) : [],
1262 styles: styles,
1263 children: []
1264 };
1265 }
1266
1267 // Mock hash based on string.
1268 // 'a,b,c' => { a: 'cke-test', b: 'cke-test', c: 'cke-test' }
1269 // Used to mock styles and attributes objects.
1270 function mockHash( str ) {
1271 // It may be a null or empty string.
1272 if ( !str )
1273 return {};
1274
1275 var keys = str.split( /\s*,\s*/ ).sort(),
1276 obj = {};
1277
1278 while ( keys.length )
1279 obj[ keys.shift() ] = TEST_VALUE;
1280
1281 return obj;
1282 }
1283
1284 // Extract properties names from the object
1285 // and replace those containing wildcards with regexps.
1286 // Note: there's a room for performance improvement. Array of mixed types
1287 // breaks JIT-compiler optiomization what may invalidate compilation of pretty a lot of code.
1288 //
1289 // @returns An array of strings and regexps.
1290 function optimizeRequiredProperties( requiredProperties ) {
1291 var arr = [];
1292 for ( var propertyName in requiredProperties ) {
1293 if ( propertyName.indexOf( '*' ) > -1 )
1294 arr.push( new RegExp( '^' + propertyName.replace( /\*/g, '.*' ) + '$' ) );
1295 else
1296 arr.push( propertyName );
1297 }
1298 return arr;
1299 }
1300
1301 var validators = { styles: 1, attributes: 1, classes: 1 },
1302 validatorsRequired = {
1303 styles: 'requiredStyles',
1304 attributes: 'requiredAttributes',
1305 classes: 'requiredClasses'
1306 };
1307
1308 // Optimize a rule by replacing validators with functions
1309 // and rewriting requiredXXX validators to arrays.
1310 function optimizeRule( rule ) {
1311 var validatorName,
1312 requiredProperties,
1313 i;
1314
1315 for ( validatorName in validators )
1316 rule[ validatorName ] = validatorFunction( rule[ validatorName ] );
1317
1318 var nothingRequired = true;
1319 for ( i in validatorsRequired ) {
1320 validatorName = validatorsRequired[ i ];
1321 requiredProperties = optimizeRequiredProperties( rule[ validatorName ] );
1322 // Don't set anything if there are no required properties. This will allow to
1323 // save some memory by GCing all empty arrays (requiredProperties).
1324 if ( requiredProperties.length ) {
1325 rule[ validatorName ] = requiredProperties;
1326 nothingRequired = false;
1327 }
1328 }
1329
1330 rule.nothingRequired = nothingRequired;
1331 rule.noProperties = !( rule.attributes || rule.classes || rule.styles );
1332 }
1333
1334 // Add optimized version of rule to optimizedRules object.
1335 function optimizeRules( optimizedRules, rules ) {
1336 var elementsRules = optimizedRules.elements,
1337 genericRules = optimizedRules.generic,
1338 i, l, rule, element, priority;
1339
1340 for ( i = 0, l = rules.length; i < l; ++i ) {
1341 // Shallow copy. Do not modify original rule.
1342 rule = copy( rules[ i ] );
1343 priority = rule.classes === true || rule.styles === true || rule.attributes === true;
1344 optimizeRule( rule );
1345
1346 // E.g. "*(xxx)[xxx]" - it's a generic rule that
1347 // validates properties only.
1348 // Or '$1': { match: function() {...} }
1349 if ( rule.elements === true || rule.elements === null ) {
1350 // Add priority rules at the beginning.
1351 genericRules[ priority ? 'unshift' : 'push' ]( rule );
1352 }
1353 // If elements list was explicitly defined,
1354 // add this rule for every defined element.
1355 else {
1356 // We don't need elements validator for this kind of rule.
1357 var elements = rule.elements;
1358 delete rule.elements;
1359
1360 for ( element in elements ) {
1361 if ( !elementsRules[ element ] )
1362 elementsRules[ element ] = [ rule ];
1363 else
1364 elementsRules[ element ][ priority ? 'unshift' : 'push' ]( rule );
1365 }
1366 }
1367 }
1368 }
1369
1370 // < elements >< styles, attributes and classes >< separator >
1371 var rulePattern = /^([a-z0-9\-*\s]+)((?:\s*\{[!\w\-,\s\*]+\}\s*|\s*\[[!\w\-,\s\*]+\]\s*|\s*\([!\w\-,\s\*]+\)\s*){0,3})(?:;\s*|$)/i,
1372 groupsPatterns = {
1373 styles: /{([^}]+)}/,
1374 attrs: /\[([^\]]+)\]/,
1375 classes: /\(([^\)]+)\)/
1376 };
1377
1378 function parseRulesString( input ) {
1379 var match,
1380 props, styles, attrs, classes,
1381 rules = {},
1382 groupNum = 1;
1383
1384 input = trim( input );
1385
1386 while ( ( match = input.match( rulePattern ) ) ) {
1387 if ( ( props = match[ 2 ] ) ) {
1388 styles = parseProperties( props, 'styles' );
1389 attrs = parseProperties( props, 'attrs' );
1390 classes = parseProperties( props, 'classes' );
1391 } else {
1392 styles = attrs = classes = null;
1393 }
1394
1395 // Add as an unnamed rule, because there can be two rules
1396 // for one elements set defined in string format.
1397 rules[ '$' + groupNum++ ] = {
1398 elements: match[ 1 ],
1399 classes: classes,
1400 styles: styles,
1401 attributes: attrs
1402 };
1403
1404 // Move to the next group.
1405 input = input.slice( match[ 0 ].length );
1406 }
1407
1408 return rules;
1409 }
1410
1411 // Extract specified properties group (styles, attrs, classes) from
1412 // what stands after the elements list in string format of allowedContent.
1413 function parseProperties( properties, groupName ) {
1414 var group = properties.match( groupsPatterns[ groupName ] );
1415 return group ? trim( group[ 1 ] ) : null;
1416 }
1417
1418 function populateProperties( element ) {
1419 // Backup styles and classes, because they may be removed by DACRs.
1420 // We'll need them in updateElement().
1421 var styles = element.styleBackup = element.attributes.style,
1422 classes = element.classBackup = element.attributes[ 'class' ];
1423
1424 // Parse classes and styles if that hasn't been done before.
1425 if ( !element.styles )
1426 element.styles = CKEDITOR.tools.parseCssText( styles || '', 1 );
1427 if ( !element.classes )
1428 element.classes = classes ? classes.split( /\s+/ ) : [];
1429 }
1430
1431 // Filter element protected with a comment.
1432 // Returns true if protected content is ok, false otherwise.
1433 function processProtectedElement( that, comment, protectedRegexs, filterOpts ) {
1434 var source = decodeURIComponent( comment.value.replace( /^\{cke_protected\}/, '' ) ),
1435 protectedFrag,
1436 toBeRemoved = [],
1437 node, i, match;
1438
1439 // Protected element's and protected source's comments look exactly the same.
1440 // Check if what we have isn't a protected source instead of protected script/noscript.
1441 if ( protectedRegexs ) {
1442 for ( i = 0; i < protectedRegexs.length; ++i ) {
1443 if ( ( match = source.match( protectedRegexs[ i ] ) ) &&
1444 match[ 0 ].length == source.length // Check whether this pattern matches entire source
1445 // to avoid '<script>alert("<? 1 ?>")</script>' matching
1446 // the PHP's protectedSource regexp.
1447 )
1448 return true;
1449 }
1450 }
1451
1452 protectedFrag = CKEDITOR.htmlParser.fragment.fromHtml( source );
1453
1454 if ( protectedFrag.children.length == 1 && ( node = protectedFrag.children[ 0 ] ).type == CKEDITOR.NODE_ELEMENT )
1455 processElement( that, node, toBeRemoved, filterOpts );
1456
1457 // If protected element has been marked to be removed, return 'false' - comment was rejected.
1458 return !toBeRemoved.length;
1459 }
1460
1461 var unprotectElementsNamesRegexp = /^cke:(object|embed|param)$/,
1462 protectElementsNamesRegexp = /^(object|embed|param)$/;
1463
1464 // The actual function which filters, transforms and does other funny things with an element.
1465 //
1466 // @param {CKEDITOR.filter} that Context.
1467 // @param {CKEDITOR.htmlParser.element} element The element to be processed.
1468 // @param {Array} toBeRemoved Array into which elements rejected by the filter will be pushed.
1469 // @param {Boolean} [opts.doFilter] Whether element should be filtered.
1470 // @param {Boolean} [opts.doTransform] Whether transformations should be applied.
1471 // @param {Boolean} [opts.doCallbacks] Whether to execute element callbacks.
1472 // @param {Boolean} [opts.toHtml] Set to true if filter used together with htmlDP#toHtml
1473 // @param {Boolean} [opts.skipRequired] Whether element's required properties shouldn't be verified.
1474 // @param {Boolean} [opts.skipFinalValidation] Whether to not perform final element validation (a,img).
1475 // @returns {Number} Possible flags:
1476 // * FILTER_ELEMENT_MODIFIED,
1477 // * FILTER_SKIP_TREE.
1478 function processElement( that, element, toBeRemoved, opts ) {
1479 var status,
1480 retVal = 0,
1481 callbacksRetVal;
1482
1483 // Unprotect elements names previously protected by htmlDataProcessor
1484 // (see protectElementNames and protectSelfClosingElements functions).
1485 // Note: body, title, etc. are not protected by htmlDataP (or are protected and then unprotected).
1486 if ( opts.toHtml )
1487 element.name = element.name.replace( unprotectElementsNamesRegexp, '$1' );
1488
1489 // Execute element callbacks and return if one of them returned any value.
1490 if ( opts.doCallbacks && that.elementCallbacks ) {
1491 // For now we only support here FILTER_SKIP_TREE, so we can early return if retVal is truly value.
1492 if ( ( callbacksRetVal = executeElementCallbacks( element, that.elementCallbacks ) ) )
1493 return callbacksRetVal;
1494 }
1495
1496 // If transformations are set apply all groups.
1497 if ( opts.doTransform )
1498 transformElement( that, element );
1499
1500 if ( opts.doFilter ) {
1501 // Apply all filters.
1502 status = filterElement( that, element, opts );
1503
1504 // Handle early return from filterElement.
1505 if ( !status ) {
1506 toBeRemoved.push( element );
1507 return FILTER_ELEMENT_MODIFIED;
1508 }
1509
1510 // Finally, if after running all filter rules it still hasn't been allowed - remove it.
1511 if ( !status.valid ) {
1512 toBeRemoved.push( element );
1513 return FILTER_ELEMENT_MODIFIED;
1514 }
1515
1516 // Update element's attributes based on status of filtering.
1517 if ( updateElement( element, status ) )
1518 retVal = FILTER_ELEMENT_MODIFIED;
1519
1520 if ( !opts.skipFinalValidation && !validateElement( element ) ) {
1521 toBeRemoved.push( element );
1522 return FILTER_ELEMENT_MODIFIED;
1523 }
1524 }
1525
1526 // Protect previously unprotected elements.
1527 if ( opts.toHtml )
1528 element.name = element.name.replace( protectElementsNamesRegexp, 'cke:$1' );
1529
1530 return retVal;
1531 }
1532
1533 // Returns a regexp object which can be used to test if a property
1534 // matches one of wildcard validators.
1535 function regexifyPropertiesWithWildcards( validators ) {
1536 var patterns = [],
1537 i;
1538
1539 for ( i in validators ) {
1540 if ( i.indexOf( '*' ) > -1 )
1541 patterns.push( i.replace( /\*/g, '.*' ) );
1542 }
1543
1544 if ( patterns.length )
1545 return new RegExp( '^(?:' + patterns.join( '|' ) + ')$' );
1546 else
1547 return null;
1548 }
1549
1550 // Standardize a rule by converting all validators to hashes.
1551 function standardizeRule( rule ) {
1552 rule.elements = convertValidatorToHash( rule.elements, /\s+/ ) || null;
1553 rule.propertiesOnly = rule.propertiesOnly || ( rule.elements === true );
1554
1555 var delim = /\s*,\s*/,
1556 i;
1557
1558 for ( i in validators ) {
1559 rule[ i ] = convertValidatorToHash( rule[ i ], delim ) || null;
1560 rule[ validatorsRequired[ i ] ] = extractRequired( convertValidatorToHash(
1561 rule[ validatorsRequired[ i ] ], delim ), rule[ i ] ) || null;
1562 }
1563
1564 rule.match = rule.match || null;
1565 }
1566
1567 // Does the element transformation by applying registered
1568 // transformation rules.
1569 function transformElement( that, element ) {
1570 var transformations = that._.transformations[ element.name ],
1571 i;
1572
1573 if ( !transformations )
1574 return;
1575
1576 populateProperties( element );
1577
1578 for ( i = 0; i < transformations.length; ++i )
1579 applyTransformationsGroup( that, element, transformations[ i ] );
1580
1581 // Do not count on updateElement() which is called in processElement, because it:
1582 // * may not be called,
1583 // * may skip some properties when all are marked as valid.
1584 updateAttributes( element );
1585 }
1586
1587 // Copy element's styles and classes back to attributes array.
1588 function updateAttributes( element ) {
1589 var attrs = element.attributes,
1590 styles;
1591
1592 // Will be recreated later if any of styles/classes exists.
1593 delete attrs.style;
1594 delete attrs[ 'class' ];
1595
1596 if ( ( styles = CKEDITOR.tools.writeCssText( element.styles, true ) ) )
1597 attrs.style = styles;
1598
1599 if ( element.classes.length )
1600 attrs[ 'class' ] = element.classes.sort().join( ' ' );
1601 }
1602
1603 // Update element object based on status of filtering.
1604 // @returns Whether element was modified.
1605 function updateElement( element, status ) {
1606 var validAttrs = status.validAttributes,
1607 validStyles = status.validStyles,
1608 validClasses = status.validClasses,
1609 attrs = element.attributes,
1610 styles = element.styles,
1611 classes = element.classes,
1612 origClasses = element.classBackup,
1613 origStyles = element.styleBackup,
1614 name, origName, i,
1615 stylesArr = [],
1616 classesArr = [],
1617 internalAttr = /^data-cke-/,
1618 isModified = false;
1619
1620 // Will be recreated later if any of styles/classes were passed.
1621 delete attrs.style;
1622 delete attrs[ 'class' ];
1623 // Clean up.
1624 delete element.classBackup;
1625 delete element.styleBackup;
1626
1627 if ( !status.allAttributes ) {
1628 for ( name in attrs ) {
1629 // If not valid and not internal attribute delete it.
1630 if ( !validAttrs[ name ] ) {
1631 // Allow all internal attibutes...
1632 if ( internalAttr.test( name ) ) {
1633 // ... unless this is a saved attribute and the original one isn't allowed.
1634 if ( name != ( origName = name.replace( /^data-cke-saved-/, '' ) ) &&
1635 !validAttrs[ origName ]
1636 ) {
1637 delete attrs[ name ];
1638 isModified = true;
1639 }
1640 } else {
1641 delete attrs[ name ];
1642 isModified = true;
1643 }
1644 }
1645
1646 }
1647 }
1648
1649 if ( !status.allStyles || status.hadInvalidStyle ) {
1650 for ( name in styles ) {
1651 // We check status.allStyles because when there was a '*' ACR and some
1652 // DACR we have now both properties true - status.allStyles and status.hadInvalidStyle.
1653 // However unlike in the case when we only have '*' ACR, in which we can just copy original
1654 // styles, in this case we must copy only those styles which were not removed by DACRs.
1655 if ( status.allStyles || validStyles[ name ] )
1656 stylesArr.push( name + ':' + styles[ name ] );
1657 else
1658 isModified = true;
1659 }
1660 if ( stylesArr.length )
1661 attrs.style = stylesArr.sort().join( '; ' );
1662 }
1663 else if ( origStyles ) {
1664 attrs.style = origStyles;
1665 }
1666
1667 if ( !status.allClasses || status.hadInvalidClass ) {
1668 for ( i = 0; i < classes.length; ++i ) {
1669 // See comment for styles.
1670 if ( status.allClasses || validClasses[ classes[ i ] ] )
1671 classesArr.push( classes[ i ] );
1672 }
1673 if ( classesArr.length )
1674 attrs[ 'class' ] = classesArr.sort().join( ' ' );
1675
1676 if ( origClasses && classesArr.length < origClasses.split( /\s+/ ).length )
1677 isModified = true;
1678 }
1679 else if ( origClasses ) {
1680 attrs[ 'class' ] = origClasses;
1681 }
1682
1683 return isModified;
1684 }
1685
1686 function validateElement( element ) {
1687 switch ( element.name ) {
1688 case 'a':
1689 // Code borrowed from htmlDataProcessor, so ACF does the same clean up.
1690 if ( !( element.children.length || element.attributes.name || element.attributes.id ) )
1691 return false;
1692 break;
1693 case 'img':
1694 if ( !element.attributes.src )
1695 return false;
1696 break;
1697 }
1698
1699 return true;
1700 }
1701
1702 function validatorFunction( validator ) {
1703 if ( !validator )
1704 return false;
1705 if ( validator === true )
1706 return true;
1707
1708 // Note: We don't need to remove properties with wildcards from the validator object.
1709 // E.g. data-* is actually an edge case of /^data-.*$/, so when it's accepted
1710 // by `value in validator` it's ok.
1711 var regexp = regexifyPropertiesWithWildcards( validator );
1712
1713 return function( value ) {
1714 return value in validator || ( regexp && value.match( regexp ) );
1715 };
1716 }
1717
1718 //
1719 // REMOVE ELEMENT ---------------------------------------------------------
1720 //
1721
1722 // Check whether all children will be valid in new context.
1723 // Note: it doesn't verify if text node is valid, because
1724 // new parent should accept them.
1725 function checkChildren( children, newParentName ) {
1726 var allowed = DTD[ newParentName ];
1727
1728 for ( var i = 0, l = children.length, child; i < l; ++i ) {
1729 child = children[ i ];
1730 if ( child.type == CKEDITOR.NODE_ELEMENT && !allowed[ child.name ] )
1731 return false;
1732 }
1733
1734 return true;
1735 }
1736
1737 function createBr() {
1738 return new CKEDITOR.htmlParser.element( 'br' );
1739 }
1740
1741 // Whether this is an inline element or text.
1742 function inlineNode( node ) {
1743 return node.type == CKEDITOR.NODE_TEXT ||
1744 node.type == CKEDITOR.NODE_ELEMENT && DTD.$inline[ node.name ];
1745 }
1746
1747 function isBrOrBlock( node ) {
1748 return node.type == CKEDITOR.NODE_ELEMENT &&
1749 ( node.name == 'br' || DTD.$block[ node.name ] );
1750 }
1751
1752 // Try to remove element in the best possible way.
1753 //
1754 // @param {Array} toBeChecked After executing this function
1755 // this array will contain elements that should be checked
1756 // because they were marked as potentially:
1757 // * in wrong context (e.g. li in body),
1758 // * empty elements from $removeEmpty,
1759 // * incorrect img/a/other element validated by validateElement().
1760 function removeElement( element, enterTag, toBeChecked ) {
1761 var name = element.name;
1762
1763 if ( DTD.$empty[ name ] || !element.children.length ) {
1764 // Special case - hr in br mode should be replaced with br, not removed.
1765 if ( name == 'hr' && enterTag == 'br' )
1766 element.replaceWith( createBr() );
1767 else {
1768 // Parent might become an empty inline specified in $removeEmpty or empty a[href].
1769 if ( element.parent )
1770 toBeChecked.push( { check: 'it', el: element.parent } );
1771
1772 element.remove();
1773 }
1774 } else if ( DTD.$block[ name ] || name == 'tr' ) {
1775 if ( enterTag == 'br' )
1776 stripBlockBr( element, toBeChecked );
1777 else
1778 stripBlock( element, enterTag, toBeChecked );
1779 }
1780 // Special case - elements that may contain CDATA should be removed completely.
1781 else if ( name in { style: 1, script: 1 } )
1782 element.remove();
1783 // The rest of inline elements. May also be the last resort
1784 // for some special elements.
1785 else {
1786 // Parent might become an empty inline specified in $removeEmpty or empty a[href].
1787 if ( element.parent )
1788 toBeChecked.push( { check: 'it', el: element.parent } );
1789 element.replaceWithChildren();
1790 }
1791 }
1792
1793 // Strip element block, but leave its content.
1794 // Works in 'div' and 'p' enter modes.
1795 function stripBlock( element, enterTag, toBeChecked ) {
1796 var children = element.children;
1797
1798 // First, check if element's children may be wrapped with <p/div>.
1799 // Ignore that <p/div> may not be allowed in element.parent.
1800 // This will be fixed when removing parent or by toBeChecked rule.
1801 if ( checkChildren( children, enterTag ) ) {
1802 element.name = enterTag;
1803 element.attributes = {};
1804 // Check if this p/div was put in correct context.
1805 // If not - strip parent.
1806 toBeChecked.push( { check: 'parent-down', el: element } );
1807 return;
1808 }
1809
1810 var parent = element.parent,
1811 shouldAutoP = parent.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT || parent.name == 'body',
1812 i, child, p, parentDtd;
1813
1814 for ( i = children.length; i > 0; ) {
1815 child = children[ --i ];
1816
1817 // If parent requires auto paragraphing and child is inline node,
1818 // insert this child into newly created paragraph.
1819 if ( shouldAutoP && inlineNode( child ) ) {
1820 if ( !p ) {
1821 p = new CKEDITOR.htmlParser.element( enterTag );
1822 p.insertAfter( element );
1823
1824 // Check if this p/div was put in correct context.
1825 // If not - strip parent.
1826 toBeChecked.push( { check: 'parent-down', el: p } );
1827 }
1828 p.add( child, 0 );
1829 }
1830 // Child which doesn't need to be auto paragraphed.
1831 else {
1832 p = null;
1833 parentDtd = DTD[ parent.name ] || DTD.span;
1834
1835 child.insertAfter( element );
1836 // If inserted into invalid context, mark it and check
1837 // after removing all elements.
1838 if ( parent.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT &&
1839 child.type == CKEDITOR.NODE_ELEMENT &&
1840 !parentDtd[ child.name ]
1841 )
1842 toBeChecked.push( { check: 'el-up', el: child } );
1843 }
1844 }
1845
1846 // All children have been moved to element's parent, so remove it.
1847 element.remove();
1848 }
1849
1850 // Prepend/append block with <br> if isn't
1851 // already prepended/appended with <br> or block and
1852 // isn't first/last child of its parent.
1853 // Then replace element with its children.
1854 // <p>a</p><p>b</p> => <p>a</p><br>b => a<br>b
1855 function stripBlockBr( element ) {
1856 var br;
1857
1858 if ( element.previous && !isBrOrBlock( element.previous ) ) {
1859 br = createBr();
1860 br.insertBefore( element );
1861 }
1862
1863 if ( element.next && !isBrOrBlock( element.next ) ) {
1864 br = createBr();
1865 br.insertAfter( element );
1866 }
1867
1868 element.replaceWithChildren();
1869 }
1870
1871 //
1872 // TRANSFORMATIONS --------------------------------------------------------
1873 //
1874 var transformationsTools;
1875
1876 // Apply given transformations group to the element.
1877 function applyTransformationsGroup( filter, element, group ) {
1878 var i, rule;
1879
1880 for ( i = 0; i < group.length; ++i ) {
1881 rule = group[ i ];
1882
1883 // Test with #check or #left only if it's set.
1884 // Do not apply transformations because that creates infinite loop.
1885 if ( ( !rule.check || filter.check( rule.check, false ) ) &&
1886 ( !rule.left || rule.left( element ) ) ) {
1887 rule.right( element, transformationsTools );
1888 return; // Only first matching rule in a group is executed.
1889 }
1890 }
1891 }
1892
1893 // Check whether element matches CKEDITOR.style.
1894 // The element can be a "superset" of style,
1895 // e.g. it may have more classes, but need to have
1896 // at least those defined in style.
1897 function elementMatchesStyle( element, style ) {
1898 var def = style.getDefinition(),
1899 defAttrs = def.attributes,
1900 defStyles = def.styles,
1901 attrName, styleName,
1902 classes, classPattern, cl;
1903
1904 if ( element.name != def.element )
1905 return false;
1906
1907 for ( attrName in defAttrs ) {
1908 if ( attrName == 'class' ) {
1909 classes = defAttrs[ attrName ].split( /\s+/ );
1910 classPattern = element.classes.join( '|' );
1911 while ( ( cl = classes.pop() ) ) {
1912 if ( classPattern.indexOf( cl ) == -1 )
1913 return false;
1914 }
1915 } else {
1916 if ( element.attributes[ attrName ] != defAttrs[ attrName ] )
1917 return false;
1918 }
1919 }
1920
1921 for ( styleName in defStyles ) {
1922 if ( element.styles[ styleName ] != defStyles[ styleName ] )
1923 return false;
1924 }
1925
1926 return true;
1927 }
1928
1929 // Return transformation group for content form.
1930 // One content form makes one transformation rule in one group.
1931 function getContentFormTransformationGroup( form, preferredForm ) {
1932 var element, left;
1933
1934 if ( typeof form == 'string' )
1935 element = form;
1936 else if ( form instanceof CKEDITOR.style )
1937 left = form;
1938 else {
1939 element = form[ 0 ];
1940 left = form[ 1 ];
1941 }
1942
1943 return [ {
1944 element: element,
1945 left: left,
1946 right: function( el, tools ) {
1947 tools.transform( el, preferredForm );
1948 }
1949 } ];
1950 }
1951
1952 // Obtain element's name from transformation rule.
1953 // It will be defined by #element, or #check or #left (styleDef.element).
1954 function getElementNameForTransformation( rule, check ) {
1955 if ( rule.element )
1956 return rule.element;
1957 if ( check )
1958 return check.match( /^([a-z0-9]+)/i )[ 0 ];
1959 return rule.left.getDefinition().element;
1960 }
1961
1962 function getMatchStyleFn( style ) {
1963 return function( el ) {
1964 return elementMatchesStyle( el, style );
1965 };
1966 }
1967
1968 function getTransformationFn( toolName ) {
1969 return function( el, tools ) {
1970 tools[ toolName ]( el );
1971 };
1972 }
1973
1974 function optimizeTransformationsGroup( rules ) {
1975 var groupName, i, rule,
1976 check, left, right,
1977 optimizedRules = [];
1978
1979 for ( i = 0; i < rules.length; ++i ) {
1980 rule = rules[ i ];
1981
1982 if ( typeof rule == 'string' ) {
1983 rule = rule.split( /\s*:\s*/ );
1984 check = rule[ 0 ];
1985 left = null;
1986 right = rule[ 1 ];
1987 } else {
1988 check = rule.check;
1989 left = rule.left;
1990 right = rule.right;
1991 }
1992
1993 // Extract element name.
1994 if ( !groupName )
1995 groupName = getElementNameForTransformation( rule, check );
1996
1997 if ( left instanceof CKEDITOR.style )
1998 left = getMatchStyleFn( left );
1999
2000 optimizedRules.push( {
2001 // It doesn't make sense to test against name rule (e.g. 'table'), so don't save it.
2002 check: check == groupName ? null : check,
2003
2004 left: left,
2005
2006 // Handle shorthand format. E.g.: 'table[width]:sizeToAttribute'.
2007 right: typeof right == 'string' ? getTransformationFn( right ) : right
2008 } );
2009 }
2010
2011 return {
2012 name: groupName,
2013 rules: optimizedRules
2014 };
2015 }
2016
2017 /**
2018 * Singleton containing tools useful for transformation rules.
2019 *
2020 * @class CKEDITOR.filter.transformationsTools
2021 * @singleton
2022 */
2023 transformationsTools = CKEDITOR.filter.transformationsTools = {
2024 /**
2025 * Converts `width` and `height` attributes to styles.
2026 *
2027 * @param {CKEDITOR.htmlParser.element} element
2028 */
2029 sizeToStyle: function( element ) {
2030 this.lengthToStyle( element, 'width' );
2031 this.lengthToStyle( element, 'height' );
2032 },
2033
2034 /**
2035 * Converts `width` and `height` styles to attributes.
2036 *
2037 * @param {CKEDITOR.htmlParser.element} element
2038 */
2039 sizeToAttribute: function( element ) {
2040 this.lengthToAttribute( element, 'width' );
2041 this.lengthToAttribute( element, 'height' );
2042 },
2043
2044 /**
2045 * Converts length in the `attrName` attribute to a valid CSS length (like `width` or `height`).
2046 *
2047 * @param {CKEDITOR.htmlParser.element} element
2048 * @param {String} attrName Name of the attribute that will be converted.
2049 * @param {String} [styleName=attrName] Name of the style into which the attribute will be converted.
2050 */
2051 lengthToStyle: function( element, attrName, styleName ) {
2052 styleName = styleName || attrName;
2053
2054 if ( !( styleName in element.styles ) ) {
2055 var value = element.attributes[ attrName ];
2056
2057 if ( value ) {
2058 if ( ( /^\d+$/ ).test( value ) )
2059 value += 'px';
2060
2061 element.styles[ styleName ] = value;
2062 }
2063 }
2064
2065 delete element.attributes[ attrName ];
2066 },
2067
2068 /**
2069 * Converts length in the `styleName` style to a valid length attribute (like `width` or `height`).
2070 *
2071 * @param {CKEDITOR.htmlParser.element} element
2072 * @param {String} styleName The name of the style that will be converted.
2073 * @param {String} [attrName=styleName] The name of the attribute into which the style will be converted.
2074 */
2075 lengthToAttribute: function( element, styleName, attrName ) {
2076 attrName = attrName || styleName;
2077
2078 if ( !( attrName in element.attributes ) ) {
2079 var value = element.styles[ styleName ],
2080 match = value && value.match( /^(\d+)(?:\.\d*)?px$/ );
2081
2082 if ( match )
2083 element.attributes[ attrName ] = match[ 1 ];
2084 // Pass the TEST_VALUE used by filter#check when mocking element.
2085 else if ( value == TEST_VALUE )
2086 element.attributes[ attrName ] = TEST_VALUE;
2087 }
2088
2089 delete element.styles[ styleName ];
2090 },
2091
2092 /**
2093 * Converts the `align` attribute to the `float` style if not set. The attribute
2094 * is always removed.
2095 *
2096 * @param {CKEDITOR.htmlParser.element} element
2097 */
2098 alignmentToStyle: function( element ) {
2099 if ( !( 'float' in element.styles ) ) {
2100 var value = element.attributes.align;
2101
2102 if ( value == 'left' || value == 'right' )
2103 element.styles[ 'float' ] = value; // Uh... GCC doesn't like the 'float' prop name.
2104 }
2105
2106 delete element.attributes.align;
2107 },
2108
2109 /**
2110 * Converts the `float` style to the `align` attribute if not set.
2111 * The style is always removed.
2112 *
2113 * @param {CKEDITOR.htmlParser.element} element
2114 */
2115 alignmentToAttribute: function( element ) {
2116 if ( !( 'align' in element.attributes ) ) {
2117 var value = element.styles[ 'float' ];
2118
2119 if ( value == 'left' || value == 'right' )
2120 element.attributes.align = value;
2121 }
2122
2123 delete element.styles[ 'float' ]; // Uh... GCC doesn't like the 'float' prop name.
2124 },
2125
2126 /**
2127 * Converts the shorthand form of the `border` style to seperate styles.
2128 *
2129 * @param {CKEDITOR.htmlParser.element} element
2130 */
2131 splitBorderShorthand: function( element ) {
2132 if ( !element.styles.border ) {
2133 return;
2134 }
2135
2136 var widths = element.styles.border.match( /([\.\d]+\w+)/g ) || [ '0px' ];
2137 switch ( widths.length ) {
2138 case 1:
2139 element.styles[ 'border-width' ] = widths[0];
2140 break;
2141 case 2:
2142 mapStyles( [ 0, 1, 0, 1 ] );
2143 break;
2144 case 3:
2145 mapStyles( [ 0, 1, 2, 1 ] );
2146 break;
2147 case 4:
2148 mapStyles( [ 0, 1, 2, 3 ] );
2149 break;
2150 }
2151
2152 element.styles[ 'border-style' ] = element.styles[ 'border-style' ] ||
2153 ( element.styles.border.match( /(none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset|initial|inherit)/ ) || [] )[ 0 ];
2154 if ( !element.styles[ 'border-style' ] )
2155 delete element.styles[ 'border-style' ];
2156
2157 delete element.styles.border;
2158
2159 function mapStyles( map ) {
2160 element.styles['border-top-width'] = widths[ map[0] ];
2161 element.styles['border-right-width'] = widths[ map[1] ];
2162 element.styles['border-bottom-width'] = widths[ map[2] ];
2163 element.styles['border-left-width'] = widths[ map[3] ];
2164 }
2165 },
2166
2167 listTypeToStyle: function( element ) {
2168 if ( element.attributes.type ) {
2169 switch ( element.attributes.type ) {
2170 case 'a':
2171 element.styles[ 'list-style-type' ] = 'lower-alpha';
2172 break;
2173 case 'A':
2174 element.styles[ 'list-style-type' ] = 'upper-alpha';
2175 break;
2176 case 'i':
2177 element.styles[ 'list-style-type' ] = 'lower-roman';
2178 break;
2179 case 'I':
2180 element.styles[ 'list-style-type' ] = 'upper-roman';
2181 break;
2182 case '1':
2183 element.styles[ 'list-style-type' ] = 'decimal';
2184 break;
2185 default:
2186 element.styles[ 'list-style-type' ] = element.attributes.type;
2187 }
2188 }
2189 },
2190
2191 /**
2192 * Converts the shorthand form of the `margin` style to seperate styles.
2193 *
2194 * @param {CKEDITOR.htmlParser.element} element
2195 */
2196 splitMarginShorthand: function( element ) {
2197 if ( !element.styles.margin ) {
2198 return;
2199 }
2200
2201 var widths = element.styles.margin.match( /(\-?[\.\d]+\w+)/g ) || [ '0px' ];
2202 switch ( widths.length ) {
2203 case 1:
2204 element.styles.margin = widths[0];
2205 break;
2206 case 2:
2207 mapStyles( [ 0, 1, 0, 1 ] );
2208 break;
2209 case 3:
2210 mapStyles( [ 0, 1, 2, 1 ] );
2211 break;
2212 case 4:
2213 mapStyles( [ 0, 1, 2, 3 ] );
2214 break;
2215 }
2216
2217 delete element.styles.margin;
2218
2219 function mapStyles( map ) {
2220 element.styles['margin-top'] = widths[ map[0] ];
2221 element.styles['margin-right'] = widths[ map[1] ];
2222 element.styles['margin-bottom'] = widths[ map[2] ];
2223 element.styles['margin-left'] = widths[ map[3] ];
2224 }
2225 },
2226
2227 /**
2228 * Checks whether an element matches a given {@link CKEDITOR.style}.
2229 * The element can be a "superset" of a style, e.g. it may have
2230 * more classes, but needs to have at least those defined in the style.
2231 *
2232 * @param {CKEDITOR.htmlParser.element} element
2233 * @param {CKEDITOR.style} style
2234 */
2235 matchesStyle: elementMatchesStyle,
2236
2237 /**
2238 * Transforms an element to a given form.
2239 *
2240 * Form may be a:
2241 *
2242 * * {@link CKEDITOR.style},
2243 * * string &ndash; the new name of the element.
2244 *
2245 * @param {CKEDITOR.htmlParser.element} el
2246 * @param {CKEDITOR.style/String} form
2247 */
2248 transform: function( el, form ) {
2249 if ( typeof form == 'string' )
2250 el.name = form;
2251 // Form is an instance of CKEDITOR.style.
2252 else {
2253 var def = form.getDefinition(),
2254 defStyles = def.styles,
2255 defAttrs = def.attributes,
2256 attrName, styleName,
2257 existingClassesPattern, defClasses, cl;
2258
2259 el.name = def.element;
2260
2261 for ( attrName in defAttrs ) {
2262 if ( attrName == 'class' ) {
2263 existingClassesPattern = el.classes.join( '|' );
2264 defClasses = defAttrs[ attrName ].split( /\s+/ );
2265
2266 while ( ( cl = defClasses.pop() ) ) {
2267 if ( existingClassesPattern.indexOf( cl ) == -1 )
2268 el.classes.push( cl );
2269 }
2270 } else {
2271 el.attributes[ attrName ] = defAttrs[ attrName ];
2272 }
2273
2274 }
2275
2276 for ( styleName in defStyles ) {
2277 el.styles[ styleName ] = defStyles[ styleName ];
2278 }
2279 }
2280 }
2281 };
2282
2283} )();
2284
2285/**
2286 * Allowed content rules. This setting is used when
2287 * instantiating {@link CKEDITOR.editor#filter}.
2288 *
2289 * The following values are accepted:
2290 *
2291 * * {@link CKEDITOR.filter.allowedContentRules} &ndash; defined rules will be added
2292 * to the {@link CKEDITOR.editor#filter}.
2293 * * `true` &ndash; will disable the filter (data will not be filtered,
2294 * all features will be activated).
2295 * * default &ndash; the filter will be configured by loaded features
2296 * (toolbar items, commands, etc.).
2297 *
2298 * In all cases filter configuration may be extended by
2299 * {@link CKEDITOR.config#extraAllowedContent}. This option may be especially
2300 * useful when you want to use the default `allowedContent` value
2301 * along with some additional rules.
2302 *
2303 * CKEDITOR.replace( 'textarea_id', {
2304 * allowedContent: 'p b i; a[!href]',
2305 * on: {
2306 * instanceReady: function( evt ) {
2307 * var editor = evt.editor;
2308 *
2309 * editor.filter.check( 'h1' ); // -> false
2310 * editor.setData( '<h1><i>Foo</i></h1><p class="left"><span>Bar</span> <a href="http://foo.bar">foo</a></p>' );
2311 * // Editor contents will be:
2312 * '<p><i>Foo</i></p><p>Bar <a href="http://foo.bar">foo</a></p>'
2313 * }
2314 * }
2315 * } );
2316 *
2317 * It is also possible to disallow some already allowed content. It is especially
2318 * useful when you want to "trim down" the content allowed by default by
2319 * editor features. To do that, use the {@link #disallowedContent} option.
2320 *
2321 * Read more in the [documentation](#!/guide/dev_acf)
2322 * and see the [SDK sample](http://sdk.ckeditor.com/samples/acf.html).
2323 *
2324 * @since 4.1
2325 * @cfg {CKEDITOR.filter.allowedContentRules/Boolean} [allowedContent=null]
2326 * @member CKEDITOR.config
2327 */
2328
2329/**
2330 * This option makes it possible to set additional allowed
2331 * content rules for {@link CKEDITOR.editor#filter}.
2332 *
2333 * It is especially useful in combination with the default
2334 * {@link CKEDITOR.config#allowedContent} value:
2335 *
2336 * CKEDITOR.replace( 'textarea_id', {
2337 * plugins: 'wysiwygarea,toolbar,format',
2338 * extraAllowedContent: 'b i',
2339 * on: {
2340 * instanceReady: function( evt ) {
2341 * var editor = evt.editor;
2342 *
2343 * editor.filter.check( 'h1' ); // -> true (thanks to Format combo)
2344 * editor.filter.check( 'b' ); // -> true (thanks to extraAllowedContent)
2345 * editor.setData( '<h1><i>Foo</i></h1><p class="left"><b>Bar</b> <a href="http://foo.bar">foo</a></p>' );
2346 * // Editor contents will be:
2347 * '<h1><i>Foo</i></h1><p><b>Bar</b> foo</p>'
2348 * }
2349 * }
2350 * } );
2351 *
2352 * Read more in the [documentation](#!/guide/dev_acf-section-automatic-mode-and-allow-additional-tags%2Fproperties)
2353 * and see the [SDK sample](http://sdk.ckeditor.com/samples/acf.html).
2354 * See also {@link CKEDITOR.config#allowedContent} for more details.
2355 *
2356 * @since 4.1
2357 * @cfg {Object/String} extraAllowedContent
2358 * @member CKEDITOR.config
2359 */
2360
2361/**
2362 * Disallowed content rules. They have precedence over {@link #allowedContent allowed content rules}.
2363 * Read more in the [Disallowed Content guide](#!/guide/dev_disallowed_content).
2364 *
2365 * Read more in the [documentation](#!/guide/dev_acf-section-automatic-mode-but-disallow-certain-tags%2Fproperties)
2366 * and see the [SDK sample](http://sdk.ckeditor.com/samples/acf.html).
2367 * See also {@link CKEDITOR.config#allowedContent} and {@link CKEDITOR.config#extraAllowedContent}.
2368 *
2369 * @since 4.4
2370 * @cfg {CKEDITOR.filter.disallowedContentRules} disallowedContent
2371 * @member CKEDITOR.config
2372 */
2373
2374/**
2375 * This event is fired when {@link CKEDITOR.filter} has stripped some
2376 * content from the data that was loaded (e.g. by {@link CKEDITOR.editor#method-setData}
2377 * method or in the source mode) or inserted (e.g. when pasting or using the
2378 * {@link CKEDITOR.editor#method-insertHtml} method).
2379 *
2380 * This event is useful when testing whether the {@link CKEDITOR.config#allowedContent}
2381 * setting is sufficient and correct for a system that is migrating to CKEditor 4.1
2382 * (where the [Advanced Content Filter](#!/guide/dev_advanced_content_filter) was introduced).
2383 *
2384 * @since 4.1
2385 * @event dataFiltered
2386 * @member CKEDITOR.editor
2387 * @param {CKEDITOR.editor} editor This editor instance.
2388 */
2389
2390/**
2391 * Virtual class which is the [Allowed Content Rules](#!/guide/dev_allowed_content_rules) formats type.
2392 *
2393 * Possible formats are:
2394 *
2395 * * the [string format](#!/guide/dev_allowed_content_rules-section-2),
2396 * * the [object format](#!/guide/dev_allowed_content_rules-section-3),
2397 * * a {@link CKEDITOR.style} instance &ndash; used mainly for integrating plugins with Advanced Content Filter,
2398 * * an array of the above formats.
2399 *
2400 * @since 4.1
2401 * @class CKEDITOR.filter.allowedContentRules
2402 * @abstract
2403 */
2404
2405/**
2406 * Virtual class representing the {@link CKEDITOR.filter#disallow} argument and a type of
2407 * the {@link CKEDITOR.config#disallowedContent} option.
2408 *
2409 * This is a simplified version of the {@link CKEDITOR.filter.allowedContentRules} type.
2410 * Only the string format and object format are accepted. Required properties
2411 * are not allowed in this format.
2412 *
2413 * Read more in the [Disallowed Content guide](#!/guide/dev_disallowed_content).
2414 *
2415 * @since 4.4
2416 * @class CKEDITOR.filter.disallowedContentRules
2417 * @abstract
2418 */
2419
2420/**
2421 * Virtual class representing {@link CKEDITOR.filter#check} argument.
2422 *
2423 * This is a simplified version of the {@link CKEDITOR.filter.allowedContentRules} type.
2424 * It may contain only one element and its styles, classes, and attributes. Only the
2425 * string format and a {@link CKEDITOR.style} instances are accepted. Required properties
2426 * are not allowed in this format.
2427 *
2428 * Example:
2429 *
2430 * 'img[src,alt](foo)' // Correct rule.
2431 * 'ol, ul(!foo)' // Incorrect rule. Multiple elements and required
2432 * // properties are not supported.
2433 *
2434 * @since 4.1
2435 * @class CKEDITOR.filter.contentRule
2436 * @abstract
2437 */
2438
2439/**
2440 * Interface that may be automatically implemented by any
2441 * instance of any class which has at least the `name` property and
2442 * can be meant as an editor feature.
2443 *
2444 * For example:
2445 *
2446 * * "Bold" command, button, and keystroke &ndash; it does not mean exactly
2447 * `<strong>` or `<b>` but just the ability to create bold text.
2448 * * "Format" drop-down list &ndash; it also does not imply any HTML tag.
2449 * * "Link" command, button, and keystroke.
2450 * * "Image" command, button, and dialog window.
2451 *
2452 * Thus most often a feature is an instance of one of the following classes:
2453 *
2454 * * {@link CKEDITOR.command}
2455 * * {@link CKEDITOR.ui.button}
2456 * * {@link CKEDITOR.ui.richCombo}
2457 *
2458 * None of them have a `name` property explicitly defined, but
2459 * it is set by {@link CKEDITOR.editor#addCommand} and {@link CKEDITOR.ui#add}.
2460 *
2461 * During editor initialization all features that the editor should activate
2462 * should be passed to {@link CKEDITOR.editor#addFeature} (shorthand for {@link CKEDITOR.filter#addFeature}).
2463 *
2464 * This method checks if a feature can be activated (see {@link #requiredContent}) and if yes,
2465 * then it registers allowed content rules required by this feature (see {@link #allowedContent}) along
2466 * with two kinds of transformations: {@link #contentForms} and {@link #contentTransformations}.
2467 *
2468 * By default all buttons that are included in [toolbar layout configuration](#!/guide/dev_toolbar)
2469 * are checked and registered with {@link CKEDITOR.editor#addFeature}, all styles available in the
2470 * 'Format' and 'Styles' drop-down lists are checked and registered too and so on.
2471 *
2472 * @since 4.1
2473 * @class CKEDITOR.feature
2474 * @abstract
2475 */
2476
2477/**
2478 * HTML code that can be generated by this feature.
2479 *
2480 * For example a basic image feature (image button displaying the image dialog window)
2481 * may allow `'img[!src,alt,width,height]'`.
2482 *
2483 * During the feature activation this value is passed to {@link CKEDITOR.filter#allow}.
2484 *
2485 * @property {CKEDITOR.filter.allowedContentRules} [allowedContent=null]
2486 */
2487
2488/**
2489 * Minimal HTML code that this feature must be allowed to
2490 * generate in order to work.
2491 *
2492 * For example a basic image feature (image button displaying the image dialog window)
2493 * needs `'img[src,alt]'` in order to be activated.
2494 *
2495 * During the feature validation this value is passed to {@link CKEDITOR.filter#check}.
2496 *
2497 * If this value is not provided, a feature will be always activated.
2498 *
2499 * @property {CKEDITOR.filter.contentRule} [requiredContent=null]
2500 */
2501
2502/**
2503 * The name of the feature.
2504 *
2505 * It is used for example to identify which {@link CKEDITOR.filter#allowedContent}
2506 * rule was added for which feature.
2507 *
2508 * @property {String} name
2509 */
2510
2511/**
2512 * Feature content forms to be registered in the {@link CKEDITOR.editor#filter}
2513 * during the feature activation.
2514 *
2515 * See {@link CKEDITOR.filter#addContentForms} for more details.
2516 *
2517 * @property [contentForms=null]
2518 */
2519
2520/**
2521 * Transformations (usually for content generated by this feature, but not necessarily)
2522 * that will be registered in the {@link CKEDITOR.editor#filter} during the feature activation.
2523 *
2524 * See {@link CKEDITOR.filter#addTransformations} for more details.
2525 *
2526 * @property [contentTransformations=null]
2527 */
2528
2529/**
2530 * Returns a feature that this feature needs to register.
2531 *
2532 * In some cases, during activation, one feature may need to register
2533 * another feature. For example a {@link CKEDITOR.ui.button} often registers
2534 * a related command. See {@link CKEDITOR.ui.button#toFeature}.
2535 *
2536 * This method is executed when a feature is passed to the {@link CKEDITOR.editor#addFeature}.
2537 *
2538 * @method toFeature
2539 * @returns {CKEDITOR.feature}
2540 */
diff --git a/sources/core/focusmanager.js b/sources/core/focusmanager.js
new file mode 100644
index 0000000..6fc9969
--- /dev/null
+++ b/sources/core/focusmanager.js
@@ -0,0 +1,281 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.focusManager} class, which is used
8 * to handle the focus in editor instances.
9 */
10
11( function() {
12 /**
13 * Manages the focus activity in an editor instance. This class is to be
14 * used mainly by UI element coders when adding interface elements that need
15 * to set the focus state of the editor.
16 *
17 * var focusManager = new CKEDITOR.focusManager( editor );
18 * focusManager.focus();
19 *
20 * @class
21 * @constructor Creates a focusManager class instance.
22 * @param {CKEDITOR.editor} editor The editor instance.
23 */
24 CKEDITOR.focusManager = function( editor ) {
25 if ( editor.focusManager )
26 return editor.focusManager;
27
28 /**
29 * Indicates that the editor instance has focus.
30 *
31 * alert( CKEDITOR.instances.editor1.focusManager.hasFocus ); // e.g. true
32 */
33 this.hasFocus = false;
34
35 /**
36 * Indicates the currently focused DOM element that makes the editor activated.
37 *
38 * @property {CKEDITOR.dom.domObject}
39 */
40 this.currentActive = null;
41
42 /**
43 * Object used to store private stuff.
44 *
45 * @private
46 */
47 this._ = {
48 editor: editor
49 };
50
51 return this;
52 };
53
54 var SLOT_NAME = 'focusmanager',
55 SLOT_NAME_LISTENERS = 'focusmanager_handlers';
56
57 /**
58 * Object used to store private stuff.
59 *
60 * @private
61 * @class
62 * @singleton
63 */
64 CKEDITOR.focusManager._ = {
65 /**
66 * The delay (in milliseconds) to deactivate the editor when a UI DOM element has lost focus.
67 *
68 * @private
69 * @property {Number} [blurDelay=200]
70 * @member CKEDITOR.focusManager._
71 */
72 blurDelay: 200
73 };
74
75 CKEDITOR.focusManager.prototype = {
76
77 /**
78 * Indicates that this editor instance is activated (due to a DOM focus change).
79 * The `activated` state is a symbolic indicator of an active user
80 * interaction session.
81 *
82 * **Note:** This method will not introduce UI focus
83 * impact on DOM, it is here to record the editor UI focus state internally.
84 * If you want to make the cursor blink inside the editable, use
85 * {@link CKEDITOR.editor#method-focus} instead.
86 *
87 * var editor = CKEDITOR.instances.editor1;
88 * editor.focusManage.focus( editor.editable() );
89 *
90 * @param {CKEDITOR.dom.element} [currentActive] The new value of the {@link #currentActive} property.
91 * @member CKEDITOR.focusManager
92 */
93 focus: function( currentActive ) {
94 if ( this._.timer )
95 clearTimeout( this._.timer );
96
97 if ( currentActive )
98 this.currentActive = currentActive;
99
100 if ( !( this.hasFocus || this._.locked ) ) {
101 // If another editor has the current focus, we first "blur" it. In
102 // this way the events happen in a more logical sequence, like:
103 // "focus 1" > "blur 1" > "focus 2"
104 // ... instead of:
105 // "focus 1" > "focus 2" > "blur 1"
106 var current = CKEDITOR.currentInstance;
107 current && current.focusManager.blur( 1 );
108
109 this.hasFocus = true;
110
111 var ct = this._.editor.container;
112 ct && ct.addClass( 'cke_focus' );
113 this._.editor.fire( 'focus' );
114 }
115 },
116
117 /**
118 * Prevents from changing the focus manager state until the next {@link #unlock} is called.
119 *
120 * @member CKEDITOR.focusManager
121 */
122 lock: function() {
123 this._.locked = 1;
124 },
125
126 /**
127 * Restores the automatic focus management if {@link #lock} is called.
128 *
129 * @member CKEDITOR.focusManager
130 */
131 unlock: function() {
132 delete this._.locked;
133 },
134
135 /**
136 * Used to indicate that the editor instance has been deactivated by the specified
137 * element which has just lost focus.
138 *
139 * **Note:** This function acts asynchronously with a delay of 100ms to
140 * avoid temporary deactivation. Use the `noDelay` parameter instead
141 * to deactivate immediately.
142 *
143 * var editor = CKEDITOR.instances.editor1;
144 * editor.focusManager.blur();
145 *
146 * @param {Boolean} [noDelay=false] Immediately deactivate the editor instance synchronously.
147 * @member CKEDITOR.focusManager
148 */
149 blur: function( noDelay ) {
150 if ( this._.locked )
151 return;
152
153 function doBlur() {
154 var editor = this._.editor;
155
156 if ( this.hasFocus ) {
157 this.hasFocus = false;
158
159 // Blink browsers leave selection in `[contenteditable=true]`
160 // when it's blurred and it's neccessary to remove it manually for inline editor. (#13446)
161 if ( CKEDITOR.env.chrome && editor.editable().isInline() ) {
162 editor.window.$.getSelection().removeAllRanges();
163 }
164
165 var ct = this._.editor.container;
166 ct && ct.removeClass( 'cke_focus' );
167 this._.editor.fire( 'blur' );
168 }
169 }
170
171 if ( this._.timer )
172 clearTimeout( this._.timer );
173
174 var delay = CKEDITOR.focusManager._.blurDelay;
175 if ( noDelay || !delay )
176 doBlur.call( this );
177 else {
178 this._.timer = CKEDITOR.tools.setTimeout( function() {
179 delete this._.timer;
180 doBlur.call( this );
181 }, delay, this );
182 }
183 },
184
185 /**
186 * Registers a UI DOM element to the focus manager, which will make the focus manager "hasFocus"
187 * once the input focus is relieved on the element.
188 * This method is designed to be used by plugins to expand the jurisdiction of the editor focus.
189 *
190 * @param {CKEDITOR.dom.element} element The container (topmost) element of one UI part.
191 * @param {Boolean} isCapture If specified, {@link CKEDITOR.event#useCapture} will be used when listening to the focus event.
192 * @member CKEDITOR.focusManager
193 */
194 add: function( element, isCapture ) {
195 var fm = element.getCustomData( SLOT_NAME );
196 if ( !fm || fm != this ) {
197 // If this element is already taken by another instance, dismiss it first.
198 fm && fm.remove( element );
199
200 var focusEvent = 'focus',
201 blurEvent = 'blur';
202
203 // Bypass the element's internal DOM focus change.
204 if ( isCapture ) {
205
206 // Use "focusin/focusout" events instead of capture phase in IEs,
207 // which fires synchronously.
208 if ( CKEDITOR.env.ie ) {
209 focusEvent = 'focusin';
210 blurEvent = 'focusout';
211 } else {
212 CKEDITOR.event.useCapture = 1;
213 }
214 }
215
216 var listeners = {
217 blur: function() {
218 if ( element.equals( this.currentActive ) )
219 this.blur();
220 },
221 focus: function() {
222 this.focus( element );
223 }
224 };
225
226 element.on( focusEvent, listeners.focus, this );
227 element.on( blurEvent, listeners.blur, this );
228
229 if ( isCapture )
230 CKEDITOR.event.useCapture = 0;
231
232 element.setCustomData( SLOT_NAME, this );
233 element.setCustomData( SLOT_NAME_LISTENERS, listeners );
234 }
235 },
236
237 /**
238 * Dismisses an element from the focus manager delegations added by {@link #add}.
239 *
240 * @param {CKEDITOR.dom.element} element The element to be removed from the focus manager.
241 * @member CKEDITOR.focusManager
242 */
243 remove: function( element ) {
244 element.removeCustomData( SLOT_NAME );
245 var listeners = element.removeCustomData( SLOT_NAME_LISTENERS );
246 element.removeListener( 'blur', listeners.blur );
247 element.removeListener( 'focus', listeners.focus );
248 }
249
250 };
251
252} )();
253
254/**
255 * Fired when the editor instance receives the input focus.
256 *
257 * editor.on( 'focus', function( e ) {
258 * alert( 'The editor named ' + e.editor.name + ' is now focused' );
259 * } );
260 *
261 * @event focus
262 * @member CKEDITOR.editor
263 * @param {CKEDITOR.editor} editor The editor instance.
264 */
265
266/**
267 * Fired when the editor instance loses the input focus.
268 *
269 * **Note:** This event will **NOT** be triggered when focus is moved internally, e.g. from
270 * an editable to another part of the editor UI like a dialog window.
271 * If you are interested only in the focus state of the editable, listen to the `focus`
272 * and `blur` events of the {@link CKEDITOR.editable} instead.
273 *
274 * editor.on( 'blur', function( e ) {
275 * alert( 'The editor named ' + e.editor.name + ' lost the focus' );
276 * } );
277 *
278 * @event blur
279 * @member CKEDITOR.editor
280 * @param {CKEDITOR.editor} editor The editor instance.
281 */
diff --git a/sources/core/htmldataprocessor.js b/sources/core/htmldataprocessor.js
new file mode 100644
index 0000000..56764be
--- /dev/null
+++ b/sources/core/htmldataprocessor.js
@@ -0,0 +1,1036 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 /**
8 * Represents an HTML data processor, which is responsible for translating and
9 * transforming the editor data on input and output.
10 *
11 * @class
12 * @extends CKEDITOR.dataProcessor
13 * @constructor Creates an htmlDataProcessor class instance.
14 * @param {CKEDITOR.editor} editor
15 */
16 CKEDITOR.htmlDataProcessor = function( editor ) {
17 var dataFilter, htmlFilter,
18 that = this;
19
20 this.editor = editor;
21
22 /**
23 * Data filter used when processing input by {@link #toHtml}.
24 *
25 * @property {CKEDITOR.htmlParser.filter}
26 */
27 this.dataFilter = dataFilter = new CKEDITOR.htmlParser.filter();
28
29 /**
30 * HTML filter used when processing output by {@link #toDataFormat}.
31 *
32 * @property {CKEDITOR.htmlParser.filter}
33 */
34 this.htmlFilter = htmlFilter = new CKEDITOR.htmlParser.filter();
35
36 /**
37 * The HTML writer used by this data processor to format the output.
38 *
39 * @property {CKEDITOR.htmlParser.basicWriter}
40 */
41 this.writer = new CKEDITOR.htmlParser.basicWriter();
42
43 dataFilter.addRules( defaultDataFilterRulesEditableOnly );
44 dataFilter.addRules( defaultDataFilterRulesForAll, { applyToAll: true } );
45 dataFilter.addRules( createBogusAndFillerRules( editor, 'data' ), { applyToAll: true } );
46 htmlFilter.addRules( defaultHtmlFilterRulesEditableOnly );
47 htmlFilter.addRules( defaultHtmlFilterRulesForAll, { applyToAll: true } );
48 htmlFilter.addRules( createBogusAndFillerRules( editor, 'html' ), { applyToAll: true } );
49
50 editor.on( 'toHtml', function( evt ) {
51 var evtData = evt.data,
52 data = evtData.dataValue,
53 fixBodyTag;
54
55 // The source data is already HTML, but we need to clean
56 // it up and apply the filter.
57 data = protectSource( data, editor );
58
59 // Protect content of textareas. (#9995)
60 // Do this before protecting attributes to avoid breaking:
61 // <textarea><img src="..." /></textarea>
62 data = protectElements( data, protectTextareaRegex );
63
64 // Before anything, we must protect the URL attributes as the
65 // browser may changing them when setting the innerHTML later in
66 // the code.
67 data = protectAttributes( data );
68
69 // Protect elements than can't be set inside a DIV. E.g. IE removes
70 // style tags from innerHTML. (#3710)
71 data = protectElements( data, protectElementsRegex );
72
73 // Certain elements has problem to go through DOM operation, protect
74 // them by prefixing 'cke' namespace. (#3591)
75 data = protectElementsNames( data );
76
77 // All none-IE browsers ignore self-closed custom elements,
78 // protecting them into open-close. (#3591)
79 data = protectSelfClosingElements( data );
80
81 // Compensate one leading line break after <pre> open as browsers
82 // eat it up. (#5789)
83 data = protectPreFormatted( data );
84
85 // There are attributes which may execute JavaScript code inside fixBin.
86 // Encode them greedily. They will be unprotected right after getting HTML from fixBin. (#10)
87 data = protectInsecureAttributes( data );
88
89 var fixBin = evtData.context || editor.editable().getName(),
90 isPre;
91
92 // Old IEs loose formats when load html into <pre>.
93 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && fixBin == 'pre' ) {
94 fixBin = 'div';
95 data = '<pre>' + data + '</pre>';
96 isPre = 1;
97 }
98
99 // Call the browser to help us fixing a possibly invalid HTML
100 // structure.
101 var el = editor.document.createElement( fixBin );
102 // Add fake character to workaround IE comments bug. (#3801)
103 el.setHtml( 'a' + data );
104 data = el.getHtml().substr( 1 );
105
106 // Restore shortly protected attribute names.
107 data = data.replace( new RegExp( 'data-cke-' + CKEDITOR.rnd + '-', 'ig' ), '' );
108
109 isPre && ( data = data.replace( /^<pre>|<\/pre>$/gi, '' ) );
110
111 // Unprotect "some" of the protected elements at this point.
112 data = unprotectElementNames( data );
113
114 data = unprotectElements( data );
115
116 // Restore the comments that have been protected, in this way they
117 // can be properly filtered.
118 data = unprotectRealComments( data );
119
120 if ( evtData.fixForBody === false ) {
121 fixBodyTag = false;
122 } else {
123 fixBodyTag = getFixBodyTag( evtData.enterMode, editor.config.autoParagraph );
124 }
125
126 // Now use our parser to make further fixes to the structure, as
127 // well as apply the filter.
128 data = CKEDITOR.htmlParser.fragment.fromHtml( data, evtData.context, fixBodyTag );
129
130 // The empty root element needs to be fixed by adding 'p' or 'div' into it.
131 // This avoids the need to create that element on the first focus (#12630).
132 if ( fixBodyTag ) {
133 fixEmptyRoot( data, fixBodyTag );
134 }
135
136 evtData.dataValue = data;
137 }, null, null, 5 );
138
139 // Filter incoming "data".
140 // Add element filter before htmlDataProcessor.dataFilter when purifying input data to correct html.
141 editor.on( 'toHtml', function( evt ) {
142 if ( evt.data.filter.applyTo( evt.data.dataValue, true, evt.data.dontFilter, evt.data.enterMode ) )
143 editor.fire( 'dataFiltered' );
144 }, null, null, 6 );
145
146 editor.on( 'toHtml', function( evt ) {
147 evt.data.dataValue.filterChildren( that.dataFilter, true );
148 }, null, null, 10 );
149
150 editor.on( 'toHtml', function( evt ) {
151 var evtData = evt.data,
152 data = evtData.dataValue,
153 writer = new CKEDITOR.htmlParser.basicWriter();
154
155 data.writeChildrenHtml( writer );
156 data = writer.getHtml( true );
157
158 // Protect the real comments again.
159 evtData.dataValue = protectRealComments( data );
160 }, null, null, 15 );
161
162
163 editor.on( 'toDataFormat', function( evt ) {
164 var data = evt.data.dataValue;
165
166 // #10854 - we need to strip leading blockless <br> which FF adds
167 // automatically when editable contains only non-editable content.
168 // We do that for every browser (so it's a constant behavior) and
169 // not in BR mode, in which chance of valid leading blockless <br> is higher.
170 if ( evt.data.enterMode != CKEDITOR.ENTER_BR )
171 data = data.replace( /^<br *\/?>/i, '' );
172
173 evt.data.dataValue = CKEDITOR.htmlParser.fragment.fromHtml(
174 data, evt.data.context, getFixBodyTag( evt.data.enterMode, editor.config.autoParagraph ) );
175 }, null, null, 5 );
176
177 editor.on( 'toDataFormat', function( evt ) {
178 evt.data.dataValue.filterChildren( that.htmlFilter, true );
179 }, null, null, 10 );
180
181 // Transform outcoming "data".
182 // Add element filter after htmlDataProcessor.htmlFilter when preparing output data HTML.
183 editor.on( 'toDataFormat', function( evt ) {
184 evt.data.filter.applyTo( evt.data.dataValue, false, true );
185 }, null, null, 11 );
186
187 editor.on( 'toDataFormat', function( evt ) {
188 var data = evt.data.dataValue,
189 writer = that.writer;
190
191 writer.reset();
192 data.writeChildrenHtml( writer );
193 data = writer.getHtml( true );
194
195 // Restore those non-HTML protected source. (#4475,#4880)
196 data = unprotectRealComments( data );
197 data = unprotectSource( data, editor );
198
199 evt.data.dataValue = data;
200 }, null, null, 15 );
201 };
202
203 CKEDITOR.htmlDataProcessor.prototype = {
204 /**
205 * Processes the (potentially malformed) input HTML to a purified form which
206 * is suitable for using in the WYSIWYG editable.
207 *
208 * This method fires the {@link CKEDITOR.editor#toHtml} event which makes it possible
209 * to hook into the process at various stages.
210 *
211 * **Note:** Since CKEditor 4.3 the signature of this method changed and all options
212 * are now grouped in one `options` object. Previously `context`, `fixForBody` and `dontFilter`
213 * were passed separately.
214 *
215 * @param {String} data The raw data.
216 * @param {Object} [options] The options object.
217 * @param {String} [options.context] The tag name of a context element within which
218 * the input is to be processed, defaults to the editable element.
219 * If `null` is passed, then data will be parsed without context (as children of {@link CKEDITOR.htmlParser.fragment}).
220 * See {@link CKEDITOR.htmlParser.fragment#fromHtml} for more details.
221 * @param {Boolean} [options.fixForBody=true] Whether to trigger the auto paragraph for non-block content.
222 * @param {CKEDITOR.filter} [options.filter] When specified, instead of using the {@link CKEDITOR.editor#filter main filter},
223 * the passed instance will be used to filter the content.
224 * @param {Boolean} [options.dontFilter] Do not filter data with {@link CKEDITOR.filter} (note: transformations
225 * will still be applied).
226 * @param {Number} [options.enterMode] When specified, it will be used instead of the {@link CKEDITOR.editor#enterMode main enterMode}.
227 * @param {Boolean} [options.protectedWhitespaces] Indicates that content was wrapped with `<span>` elements to preserve
228 * leading and trailing whitespaces. Option used by the {@link CKEDITOR.editor#method-insertHtml} method.
229 * @returns {String}
230 */
231 toHtml: function( data, options, fixForBody, dontFilter ) {
232 var editor = this.editor,
233 context, filter, enterMode, protectedWhitespaces;
234
235 // Typeof null == 'object', so check truthiness of options too.
236 if ( options && typeof options == 'object' ) {
237 context = options.context;
238 fixForBody = options.fixForBody;
239 dontFilter = options.dontFilter;
240 filter = options.filter;
241 enterMode = options.enterMode;
242 protectedWhitespaces = options.protectedWhitespaces;
243 }
244 // Backward compatibility. Since CKEDITOR 4.3 every option was a separate argument.
245 else {
246 context = options;
247 }
248
249 // Fall back to the editable as context if not specified.
250 if ( !context && context !== null )
251 context = editor.editable().getName();
252
253 return editor.fire( 'toHtml', {
254 dataValue: data,
255 context: context,
256 fixForBody: fixForBody,
257 dontFilter: dontFilter,
258 filter: filter || editor.filter,
259 enterMode: enterMode || editor.enterMode,
260 protectedWhitespaces: protectedWhitespaces
261 } ).dataValue;
262 },
263
264 /**
265 * See {@link CKEDITOR.dataProcessor#toDataFormat}.
266 *
267 * This method fires the {@link CKEDITOR.editor#toDataFormat} event which makes it possible
268 * to hook into the process at various stages.
269 *
270 * @param {String} html
271 * @param {Object} [options] The options object.
272 * @param {String} [options.context] The tag name of the context element within which
273 * the input is to be processed, defaults to the editable element.
274 * @param {CKEDITOR.filter} [options.filter] When specified, instead of using the {@link CKEDITOR.editor#filter main filter},
275 * the passed instance will be used to apply content transformations to the content.
276 * @param {Number} [options.enterMode] When specified, it will be used instead of the {@link CKEDITOR.editor#enterMode main enterMode}.
277 * @returns {String}
278 */
279 toDataFormat: function( html, options ) {
280 var context, filter, enterMode;
281
282 // Do not shorten this to `options && options.xxx`, because
283 // falsy `options` will be passed instead of undefined.
284 if ( options ) {
285 context = options.context;
286 filter = options.filter;
287 enterMode = options.enterMode;
288 }
289
290 // Fall back to the editable as context if not specified.
291 if ( !context && context !== null )
292 context = this.editor.editable().getName();
293
294 return this.editor.fire( 'toDataFormat', {
295 dataValue: html,
296 filter: filter || this.editor.filter,
297 context: context,
298 enterMode: enterMode || this.editor.enterMode
299 } ).dataValue;
300 }
301 };
302
303 // Produce a set of filtering rules that handles bogus and filler node at the
304 // end of block/pseudo block, in the following consequence:
305 // 1. elements:<block> - this filter removes any bogus node, then check
306 // if it's an empty block that requires a filler.
307 // 2. elements:<br> - After cleaned with bogus, this filter checks the real
308 // line-break BR to compensate a filler after it.
309 //
310 // Terms definitions:
311 // filler: An element that's either <BR> or &NBSP; at the end of block that established line height.
312 // bogus: Whenever a filler is proceeded with inline content, it becomes a bogus which is subjected to be removed.
313 //
314 // Various forms of the filler:
315 // In output HTML: Filler should be consistently &NBSP; <BR> at the end of block is always considered as bogus.
316 // In Wysiwyg HTML: Browser dependent - see env.needsBrFiller. Either BR for when needsBrFiller is true, or &NBSP; otherwise.
317 // <BR> is NEVER considered as bogus when needsBrFiller is true.
318 function createBogusAndFillerRules( editor, type ) {
319 function createFiller( isOutput ) {
320 return isOutput || CKEDITOR.env.needsNbspFiller ?
321 new CKEDITOR.htmlParser.text( '\xa0' ) :
322 new CKEDITOR.htmlParser.element( 'br', { 'data-cke-bogus': 1 } );
323 }
324
325 // This text block filter, remove any bogus and create the filler on demand.
326 function blockFilter( isOutput, fillEmptyBlock ) {
327
328 return function( block ) {
329 // DO NOT apply the filler if it's a fragment node.
330 if ( block.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT )
331 return;
332
333 cleanBogus( block );
334
335 // Add fillers to input (always) and to output (if fillEmptyBlock is ok with that).
336 var shouldFillBlock = !isOutput ||
337 ( typeof fillEmptyBlock == 'function' ? fillEmptyBlock( block ) : fillEmptyBlock ) !== false;
338
339 if ( shouldFillBlock && isEmptyBlockNeedFiller( block ) ) {
340 block.add( createFiller( isOutput ) );
341 }
342 };
343 }
344
345 // Append a filler right after the last line-break BR, found at the end of block.
346 function brFilter( isOutput ) {
347 return function( br ) {
348 // DO NOT apply the filer if parent's a fragment node.
349 if ( br.parent.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT )
350 return;
351
352 var attrs = br.attributes;
353 // Dismiss BRs that are either bogus or eol marker.
354 if ( 'data-cke-bogus' in attrs || 'data-cke-eol' in attrs ) {
355 delete attrs [ 'data-cke-bogus' ];
356 return;
357 }
358
359 // Judge the tail line-break BR, and to insert bogus after it.
360 var next = getNext( br ), previous = getPrevious( br );
361
362 if ( !next && isBlockBoundary( br.parent ) )
363 append( br.parent, createFiller( isOutput ) );
364 else if ( isBlockBoundary( next ) && previous && !isBlockBoundary( previous ) )
365 createFiller( isOutput ).insertBefore( next );
366 };
367 }
368
369 // Determinate whether this node is potentially a bogus node.
370 function maybeBogus( node, atBlockEnd ) {
371
372 // BR that's not from IE<11 DOM, except for a EOL marker.
373 if ( !( isOutput && !CKEDITOR.env.needsBrFiller ) &&
374 node.type == CKEDITOR.NODE_ELEMENT && node.name == 'br' &&
375 !node.attributes[ 'data-cke-eol' ] ) {
376 return true;
377 }
378
379 var match;
380
381 // NBSP, possibly.
382 if ( node.type == CKEDITOR.NODE_TEXT && ( match = node.value.match( tailNbspRegex ) ) ) {
383 // We need to separate tail NBSP out of a text node, for later removal.
384 if ( match.index ) {
385 ( new CKEDITOR.htmlParser.text( node.value.substring( 0, match.index ) ) ).insertBefore( node );
386 node.value = match[ 0 ];
387 }
388
389 // From IE<11 DOM, at the end of a text block, or before block boundary.
390 if ( !CKEDITOR.env.needsBrFiller && isOutput && ( !atBlockEnd || node.parent.name in textBlockTags ) )
391 return true;
392
393 // From the output.
394 if ( !isOutput ) {
395 var previous = node.previous;
396
397 // Following a line-break at the end of block.
398 if ( previous && previous.name == 'br' )
399 return true;
400
401 // Or a single NBSP between two blocks.
402 if ( !previous || isBlockBoundary( previous ) )
403 return true;
404 }
405 }
406
407 return false;
408 }
409
410 // Removes all bogus inside of this block, and to convert fillers into the proper form.
411 function cleanBogus( block ) {
412 var bogus = [];
413 var last = getLast( block ), node, previous;
414
415 if ( last ) {
416 // Check for bogus at the end of this block.
417 // e.g. <p>foo<br /></p>
418 maybeBogus( last, 1 ) && bogus.push( last );
419
420 while ( last ) {
421 // Check for bogus at the end of any pseudo block contained.
422 if ( isBlockBoundary( last ) && ( node = getPrevious( last ) ) && maybeBogus( node ) ) {
423 // Bogus must have inline proceeding, instead single BR between two blocks,
424 // is considered as filler, e.g. <hr /><br /><hr />
425 if ( ( previous = getPrevious( node ) ) && !isBlockBoundary( previous ) )
426 bogus.push( node );
427 // Convert the filler into appropriate form.
428 else {
429 createFiller( isOutput ).insertAfter( node );
430 node.remove();
431 }
432 }
433
434 last = last.previous;
435 }
436 }
437
438 // Now remove all bogus collected from above.
439 for ( var i = 0 ; i < bogus.length ; i++ )
440 bogus[ i ].remove();
441 }
442
443 // Judge whether it's an empty block that requires a filler node.
444 function isEmptyBlockNeedFiller( block ) {
445
446 // DO NOT fill empty editable in IE<11.
447 if ( !isOutput && !CKEDITOR.env.needsBrFiller && block.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT )
448 return false;
449
450 // 1. For IE version >=8, empty blocks are displayed correctly themself in wysiwiyg;
451 // 2. For the rest, at least table cell and list item need no filler space. (#6248)
452 if ( !isOutput && !CKEDITOR.env.needsBrFiller &&
453 ( document.documentMode > 7 ||
454 block.name in CKEDITOR.dtd.tr ||
455 block.name in CKEDITOR.dtd.$listItem ) ) {
456 return false;
457 }
458
459 var last = getLast( block );
460 return !last || block.name == 'form' && last.name == 'input' ;
461 }
462
463 var rules = { elements: {} },
464 isOutput = type == 'html',
465 textBlockTags = CKEDITOR.tools.extend( {}, blockLikeTags );
466
467 // Build the list of text blocks.
468 for ( var i in textBlockTags ) {
469 if ( !( '#' in dtd[ i ] ) )
470 delete textBlockTags[ i ];
471 }
472
473 for ( i in textBlockTags )
474 rules.elements[ i ] = blockFilter( isOutput, editor.config.fillEmptyBlocks );
475
476 // Editable element has to be checked separately.
477 rules.root = blockFilter( isOutput, false );
478 rules.elements.br = brFilter( isOutput );
479 return rules;
480 }
481
482 function getFixBodyTag( enterMode, autoParagraph ) {
483 return ( enterMode != CKEDITOR.ENTER_BR && autoParagraph !== false ) ? enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' : false;
484 }
485
486 // Regex to scan for &nbsp; at the end of blocks, which are actually placeholders.
487 // Safari transforms the &nbsp; to \xa0. (#4172)
488 var tailNbspRegex = /(?:&nbsp;|\xa0)$/;
489
490 var protectedSourceMarker = '{cke_protected}';
491
492 function getLast( node ) {
493 var last = node.children[ node.children.length - 1 ];
494 while ( last && isEmpty( last ) )
495 last = last.previous;
496 return last;
497 }
498
499 function getNext( node ) {
500 var next = node.next;
501 while ( next && isEmpty( next ) )
502 next = next.next;
503 return next;
504 }
505
506 function getPrevious( node ) {
507 var previous = node.previous;
508 while ( previous && isEmpty( previous ) )
509 previous = previous.previous;
510 return previous;
511 }
512
513 // Judge whether the node is an ghost node to be ignored, when traversing.
514 function isEmpty( node ) {
515 return node.type == CKEDITOR.NODE_TEXT &&
516 !CKEDITOR.tools.trim( node.value ) ||
517 node.type == CKEDITOR.NODE_ELEMENT &&
518 node.attributes[ 'data-cke-bookmark' ];
519 }
520
521 // Judge whether the node is a block-like element.
522 function isBlockBoundary( node ) {
523 return node &&
524 ( node.type == CKEDITOR.NODE_ELEMENT && node.name in blockLikeTags ||
525 node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT );
526 }
527
528 function append( parent, node ) {
529 var last = parent.children[ parent.children.length - 1 ];
530 parent.children.push( node );
531 node.parent = parent;
532 if ( last ) {
533 last.next = node;
534 node.previous = last;
535 }
536 }
537
538 function getNodeIndex( node ) {
539 return node.parent ? node.getIndex() : -1;
540 }
541
542 var dtd = CKEDITOR.dtd,
543 // Define orders of table elements.
544 tableOrder = [ 'caption', 'colgroup', 'col', 'thead', 'tfoot', 'tbody' ],
545 // List of all block elements.
546 blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$blockLimit, dtd.$block );
547
548 //
549 // DATA filter rules ------------------------------------------------------
550 //
551
552 var defaultDataFilterRulesEditableOnly = {
553 elements: {
554 input: protectReadOnly,
555 textarea: protectReadOnly
556 }
557 };
558
559 // These rules will also be applied to non-editable content.
560 var defaultDataFilterRulesForAll = {
561 attributeNames: [
562 // Event attributes (onXYZ) must not be directly set. They can become
563 // active in the editing area (IE|WebKit).
564 [ ( /^on/ ), 'data-cke-pa-on' ],
565
566 // Don't let some old expando enter editor. Concerns only IE8,
567 // but for consistency remove on all browsers.
568 [ ( /^data-cke-expando$/ ), '' ]
569 ]
570 };
571
572 // Disable form elements editing mode provided by some browsers. (#5746)
573 function protectReadOnly( element ) {
574 var attrs = element.attributes;
575
576 // We should flag that the element was locked by our code so
577 // it'll be editable by the editor functions (#6046).
578 if ( attrs.contenteditable != 'false' )
579 attrs[ 'data-cke-editable' ] = attrs.contenteditable ? 'true' : 1;
580
581 attrs.contenteditable = 'false';
582 }
583
584 //
585 // HTML filter rules ------------------------------------------------------
586 //
587
588 var defaultHtmlFilterRulesEditableOnly = {
589 elements: {
590 embed: function( element ) {
591 var parent = element.parent;
592
593 // If the <embed> is child of a <object>, copy the width
594 // and height attributes from it.
595 if ( parent && parent.name == 'object' ) {
596 var parentWidth = parent.attributes.width,
597 parentHeight = parent.attributes.height;
598 if ( parentWidth )
599 element.attributes.width = parentWidth;
600 if ( parentHeight )
601 element.attributes.height = parentHeight;
602 }
603 },
604
605 // Remove empty link but not empty anchor. (#3829, #13516)
606 a: function( element ) {
607 var attrs = element.attributes;
608
609 if ( !( element.children.length || attrs.name || attrs.id || element.attributes[ 'data-cke-saved-name' ] ) )
610 return false;
611 }
612 }
613 };
614
615 // These rules will also be applied to non-editable content.
616 var defaultHtmlFilterRulesForAll = {
617 elementNames: [
618 // Remove the "cke:" namespace prefix.
619 [ ( /^cke:/ ), '' ],
620
621 // Ignore <?xml:namespace> tags.
622 [ ( /^\?xml:namespace$/ ), '' ]
623 ],
624
625 attributeNames: [
626 // Attributes saved for changes and protected attributes.
627 [ ( /^data-cke-(saved|pa)-/ ), '' ],
628
629 // All "data-cke-" attributes are to be ignored.
630 [ ( /^data-cke-.*/ ), '' ],
631
632 [ 'hidefocus', '' ]
633 ],
634
635 elements: {
636 $: function( element ) {
637 var attribs = element.attributes;
638
639 if ( attribs ) {
640 // Elements marked as temporary are to be ignored.
641 if ( attribs[ 'data-cke-temp' ] )
642 return false;
643
644 // Remove duplicated attributes - #3789.
645 var attributeNames = [ 'name', 'href', 'src' ],
646 savedAttributeName;
647 for ( var i = 0; i < attributeNames.length; i++ ) {
648 savedAttributeName = 'data-cke-saved-' + attributeNames[ i ];
649 savedAttributeName in attribs && ( delete attribs[ attributeNames[ i ] ] );
650 }
651 }
652
653 return element;
654 },
655
656 // The contents of table should be in correct order (#4809).
657 table: function( element ) {
658 // Clone the array as it would become empty during the sort call.
659 var children = element.children.slice( 0 );
660
661 children.sort( function( node1, node2 ) {
662 var index1, index2;
663
664 // Compare in the predefined order.
665 if ( node1.type == CKEDITOR.NODE_ELEMENT && node2.type == node1.type ) {
666 index1 = CKEDITOR.tools.indexOf( tableOrder, node1.name );
667 index2 = CKEDITOR.tools.indexOf( tableOrder, node2.name );
668 }
669
670 // Make sure the sort is stable, if no order can be established above.
671 if ( !( index1 > -1 && index2 > -1 && index1 != index2 ) ) {
672 index1 = getNodeIndex( node1 );
673 index2 = getNodeIndex( node2 );
674 }
675
676 return index1 > index2 ? 1 : -1;
677 } );
678 },
679
680 // Restore param elements into self-closing.
681 param: function( param ) {
682 param.children = [];
683 param.isEmpty = true;
684 return param;
685 },
686
687 // Remove dummy span in webkit.
688 span: function( element ) {
689 if ( element.attributes[ 'class' ] == 'Apple-style-span' )
690 delete element.name;
691 },
692
693 html: function( element ) {
694 delete element.attributes.contenteditable;
695 delete element.attributes[ 'class' ];
696 },
697
698 body: function( element ) {
699 delete element.attributes.spellcheck;
700 delete element.attributes.contenteditable;
701 },
702
703 style: function( element ) {
704 var child = element.children[ 0 ];
705 if ( child && child.value )
706 child.value = CKEDITOR.tools.trim( child.value );
707
708 if ( !element.attributes.type )
709 element.attributes.type = 'text/css';
710 },
711
712 title: function( element ) {
713 var titleText = element.children[ 0 ];
714
715 // Append text-node to title tag if not present (i.e. non-IEs) (#9882).
716 !titleText && append( element, titleText = new CKEDITOR.htmlParser.text() );
717
718 // Transfer data-saved title to title tag.
719 titleText.value = element.attributes[ 'data-cke-title' ] || '';
720 },
721
722 input: unprotectReadyOnly,
723 textarea: unprotectReadyOnly
724 },
725
726 attributes: {
727 'class': function( value ) {
728 // Remove all class names starting with "cke_".
729 return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false;
730 }
731 }
732 };
733
734 if ( CKEDITOR.env.ie ) {
735 // IE outputs style attribute in capital letters. We should convert
736 // them back to lower case, while not hurting the values (#5930)
737 defaultHtmlFilterRulesForAll.attributes.style = function( value ) {
738 return value.replace( /(^|;)([^\:]+)/g, function( match ) {
739 return match.toLowerCase();
740 } );
741 };
742 }
743
744 // Disable form elements editing mode provided by some browsers. (#5746)
745 function unprotectReadyOnly( element ) {
746 var attrs = element.attributes;
747 switch ( attrs[ 'data-cke-editable' ] ) {
748 case 'true':
749 attrs.contenteditable = 'true';
750 break;
751 case '1':
752 delete attrs.contenteditable;
753 break;
754 }
755 }
756
757 //
758 // Preprocessor filters ---------------------------------------------------
759 //
760
761 var protectElementRegex = /<(a|area|img|input|source)\b([^>]*)>/gi,
762 // Be greedy while looking for protected attributes. This will let us avoid an unfortunate
763 // situation when "nested attributes", which may appear valid, are also protected.
764 // I.e. if we consider the following HTML:
765 //
766 // <img data-x="&lt;a href=&quot;X&quot;" />
767 //
768 // then the "non-greedy match" returns:
769 //
770 // 'href' => '&quot;X&quot;' // It's wrong! Href is not an attribute of <img>.
771 //
772 // while greedy match returns:
773 //
774 // 'data-x' => '&lt;a href=&quot;X&quot;'
775 //
776 // which, can be easily filtered out (#11508).
777 protectAttributeRegex = /([\w-:]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi,
778 protectAttributeNameRegex = /^(href|src|name)$/i;
779
780 // Note: we use lazy star '*?' to prevent eating everything up to the last occurrence of </style> or </textarea>.
781 var protectElementsRegex = /(?:<style(?=[ >])[^>]*>[\s\S]*?<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi,
782 protectTextareaRegex = /(<textarea(?=[ >])[^>]*>)([\s\S]*?)(?:<\/textarea>)/gi,
783 encodedElementsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi;
784
785 var protectElementNamesRegex = /(<\/?)((?:object|embed|param|html|body|head|title)[^>]*>)/gi,
786 unprotectElementNamesRegex = /(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi;
787
788 var protectSelfClosingRegex = /<cke:(param|embed)([^>]*?)\/?>(?!\s*<\/cke:\1)/gi;
789
790 function protectAttributes( html ) {
791 return html.replace( protectElementRegex, function( element, tag, attributes ) {
792 return '<' + tag + attributes.replace( protectAttributeRegex, function( fullAttr, attrName ) {
793 // Avoid corrupting the inline event attributes (#7243).
794 // We should not rewrite the existed protected attributes, e.g. clipboard content from editor. (#5218)
795 if ( protectAttributeNameRegex.test( attrName ) && attributes.indexOf( 'data-cke-saved-' + attrName ) == -1 )
796 return ' data-cke-saved-' + fullAttr + ' data-cke-' + CKEDITOR.rnd + '-' + fullAttr;
797
798 return fullAttr;
799 } ) + '>';
800 } );
801 }
802
803 function protectElements( html, regex ) {
804 return html.replace( regex, function( match, tag, content ) {
805 // Encode < and > in textarea because this won't be done by a browser, since
806 // textarea will be protected during passing data through fix bin.
807 if ( match.indexOf( '<textarea' ) === 0 )
808 match = tag + unprotectRealComments( content ).replace( /</g, '&lt;' ).replace( />/g, '&gt;' ) + '</textarea>';
809
810 return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>';
811 } );
812 }
813
814 function unprotectElements( html ) {
815 return html.replace( encodedElementsRegex, function( match, encoded ) {
816 return decodeURIComponent( encoded );
817 } );
818 }
819
820 function protectElementsNames( html ) {
821 return html.replace( protectElementNamesRegex, '$1cke:$2' );
822 }
823
824 function unprotectElementNames( html ) {
825 return html.replace( unprotectElementNamesRegex, '$1$2' );
826 }
827
828 function protectSelfClosingElements( html ) {
829 return html.replace( protectSelfClosingRegex, '<cke:$1$2></cke:$1>' );
830 }
831
832 function protectPreFormatted( html ) {
833 return html.replace( /(<pre\b[^>]*>)(\r\n|\n)/g, '$1$2$2' );
834 }
835
836 function protectRealComments( html ) {
837 return html.replace( /<!--(?!{cke_protected})[\s\S]+?-->/g, function( match ) {
838 return '<!--' + protectedSourceMarker +
839 '{C}' +
840 encodeURIComponent( match ).replace( /--/g, '%2D%2D' ) +
841 '-->';
842 } );
843 }
844
845 // Replace all "on\w{3,}" strings which are not:
846 // * opening tags - e.g. `<onfoo`,
847 // * closing tags - e.g. </onfoo> (tested in "false positive 1"),
848 // * part of other attribute - e.g. `data-onfoo` or `fonfoo`.
849 function protectInsecureAttributes( html ) {
850 return html.replace( /([^a-z0-9<\-])(on\w{3,})(?!>)/gi, '$1data-cke-' + CKEDITOR.rnd + '-$2' );
851 }
852
853 function unprotectRealComments( html ) {
854 return html.replace( /<!--\{cke_protected\}\{C\}([\s\S]+?)-->/g, function( match, data ) {
855 return decodeURIComponent( data );
856 } );
857 }
858
859 function unprotectSource( html, editor ) {
860 var store = editor._.dataStore;
861
862 return html.replace( /<!--\{cke_protected\}([\s\S]+?)-->/g, function( match, data ) {
863 return decodeURIComponent( data );
864 } ).replace( /\{cke_protected_(\d+)\}/g, function( match, id ) {
865 return store && store[ id ] || '';
866 } );
867 }
868
869 function protectSource( data, editor ) {
870 var protectedHtml = [],
871 protectRegexes = editor.config.protectedSource,
872 store = editor._.dataStore || ( editor._.dataStore = { id: 1 } ),
873 tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g;
874
875 var regexes = [
876 // Script tags will also be forced to be protected, otherwise
877 // IE will execute them.
878 ( /<script[\s\S]*?(<\/script>|$)/gi ),
879
880 // <noscript> tags (get lost in IE and messed up in FF).
881 /<noscript[\s\S]*?<\/noscript>/gi,
882
883 // Avoid meta tags being stripped (#8117).
884 /<meta[\s\S]*?\/?>/gi
885 ].concat( protectRegexes );
886
887 // First of any other protection, we must protect all comments
888 // to avoid loosing them (of course, IE related).
889 // Note that we use a different tag for comments, as we need to
890 // transform them when applying filters.
891 data = data.replace( ( /<!--[\s\S]*?-->/g ), function( match ) {
892 return '<!--{cke_tempcomment}' + ( protectedHtml.push( match ) - 1 ) + '-->';
893 } );
894
895 for ( var i = 0; i < regexes.length; i++ ) {
896 data = data.replace( regexes[ i ], function( match ) {
897 match = match.replace( tempRegex, // There could be protected source inside another one. (#3869).
898 function( $, isComment, id ) {
899 return protectedHtml[ id ];
900 } );
901
902 // Avoid protecting over protected, e.g. /\{.*?\}/
903 return ( /cke_temp(comment)?/ ).test( match ) ? match : '<!--{cke_temp}' + ( protectedHtml.push( match ) - 1 ) + '-->';
904 } );
905 }
906 data = data.replace( tempRegex, function( $, isComment, id ) {
907 return '<!--' + protectedSourceMarker +
908 ( isComment ? '{C}' : '' ) +
909 encodeURIComponent( protectedHtml[ id ] ).replace( /--/g, '%2D%2D' ) +
910 '-->';
911 } );
912
913 // Different protection pattern is used for those that
914 // live in attributes to avoid from being HTML encoded.
915 // Why so serious? See #9205, #8216, #7805, #11754, #11846.
916 data = data.replace( /<\w+(?:\s+(?:(?:[^\s=>]+\s*=\s*(?:[^'"\s>]+|'[^']*'|"[^"]*"))|[^\s=\/>]+))+\s*\/?>/g, function( match ) {
917 return match.replace( /<!--\{cke_protected\}([^>]*)-->/g, function( match, data ) {
918 store[ store.id ] = decodeURIComponent( data );
919 return '{cke_protected_' + ( store.id++ ) + '}';
920 } );
921 } );
922
923 // This RegExp searches for innerText in all the title/iframe/textarea elements.
924 // This is because browser doesn't allow HTML in these elements, that's why we can't
925 // nest comments in there. (#11223)
926 data = data.replace( /<(title|iframe|textarea)([^>]*)>([\s\S]*?)<\/\1>/g, function( match, tagName, tagAttributes, innerText ) {
927 return '<' + tagName + tagAttributes + '>' + unprotectSource( unprotectRealComments( innerText ), editor ) + '</' + tagName + '>';
928 } );
929
930 return data;
931 }
932
933 // Creates a block if the root element is empty.
934 function fixEmptyRoot( root, fixBodyTag ) {
935 if ( !root.children.length && CKEDITOR.dtd[ root.name ][ fixBodyTag ] ) {
936 var fixBodyElement = new CKEDITOR.htmlParser.element( fixBodyTag );
937 root.add( fixBodyElement );
938 }
939 }
940} )();
941
942/**
943 * Whether a filler text (non-breaking space entity &mdash; `&nbsp;`) will be
944 * inserted into empty block elements in HTML output.
945 * This is used to render block elements properly with `line-height`.
946 * When a function is specified instead, it will be passed a {@link CKEDITOR.htmlParser.element}
947 * to decide whether adding the filler text by expecting a Boolean return value.
948 *
949 * config.fillEmptyBlocks = false; // Prevent filler nodes in all empty blocks.
950 *
951 * // Prevent filler node only in float cleaners.
952 * config.fillEmptyBlocks = function( element ) {
953 * if ( element.attributes[ 'class' ].indexOf( 'clear-both' ) != -1 )
954 * return false;
955 * };
956 *
957 * @since 3.5
958 * @cfg {Boolean/Function} [fillEmptyBlocks=true]
959 * @member CKEDITOR.config
960 */
961
962/**
963 * This event is fired by the {@link CKEDITOR.htmlDataProcessor} when input HTML
964 * is to be purified by the {@link CKEDITOR.htmlDataProcessor#toHtml} method.
965 *
966 * By adding listeners with different priorities it is possible
967 * to process input HTML on different stages:
968 *
969 * * 1-4: Data is available in the original string format.
970 * * 5: Data is initially filtered with regexp patterns and parsed to
971 * {@link CKEDITOR.htmlParser.fragment} {@link CKEDITOR.htmlParser.element}.
972 * * 5-9: Data is available in the parsed format, but {@link CKEDITOR.htmlDataProcessor#dataFilter}
973 * is not applied yet.
974 * * 6: Data is filtered with the {CKEDITOR.filter content filter}.
975 * * 10: Data is processed with {@link CKEDITOR.htmlDataProcessor#dataFilter}.
976 * * 10-14: Data is available in the parsed format and {@link CKEDITOR.htmlDataProcessor#dataFilter}
977 * has already been applied.
978 * * 15: Data is written back to an HTML string.
979 * * 15-*: Data is available in an HTML string.
980 *
981 * For example to be able to process parsed, but not yet filtered data add listener this way:
982 *
983 * editor.on( 'toHtml', function( evt) {
984 * evt.data.dataValue; // -> CKEDITOR.htmlParser.fragment instance
985 * }, null, null, 7 );
986 *
987 * @since 4.1
988 * @event toHtml
989 * @member CKEDITOR.editor
990 * @param {CKEDITOR.editor} editor This editor instance.
991 * @param data
992 * @param {String/CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} data.dataValue Input data to be purified.
993 * @param {String} data.context See {@link CKEDITOR.htmlDataProcessor#toHtml} The `context` argument.
994 * @param {Boolean} data.fixForBody See {@link CKEDITOR.htmlDataProcessor#toHtml} The `fixForBody` argument.
995 * @param {Boolean} data.dontFilter See {@link CKEDITOR.htmlDataProcessor#toHtml} The `dontFilter` argument.
996 * @param {Boolean} data.filter See {@link CKEDITOR.htmlDataProcessor#toHtml} The `filter` argument.
997 * @param {Boolean} data.enterMode See {@link CKEDITOR.htmlDataProcessor#toHtml} The `enterMode` argument.
998 * @param {Boolean} [data.protectedWhitespaces] See {@link CKEDITOR.htmlDataProcessor#toHtml} The `protectedWhitespaces` argument.
999 */
1000
1001/**
1002 * This event is fired when {@link CKEDITOR.htmlDataProcessor} is converting
1003 * internal HTML to output data HTML.
1004 *
1005 * By adding listeners with different priorities it is possible
1006 * to process input HTML on different stages:
1007 *
1008 * * 1-4: Data is available in the original string format.
1009 * * 5: Data is initially filtered with regexp patterns and parsed to
1010 * {@link CKEDITOR.htmlParser.fragment} {@link CKEDITOR.htmlParser.element}.
1011 * * 5-9: Data is available in the parsed format, but {@link CKEDITOR.htmlDataProcessor#htmlFilter}
1012 * is not applied yet.
1013 * * 10: Data is filtered with {@link CKEDITOR.htmlDataProcessor#htmlFilter}.
1014 * * 11: Data is filtered with the {CKEDITOR.filter content filter} (on output the content filter makes
1015 * only transformations, without filtering).
1016 * * 10-14: Data is available in the parsed format and {@link CKEDITOR.htmlDataProcessor#htmlFilter}
1017 * has already been applied.
1018 * * 15: Data is written back to an HTML string.
1019 * * 15-*: Data is available in an HTML string.
1020 *
1021 * For example to be able to process parsed and already processed data add listener this way:
1022 *
1023 * editor.on( 'toDataFormat', function( evt) {
1024 * evt.data.dataValue; // -> CKEDITOR.htmlParser.fragment instance
1025 * }, null, null, 12 );
1026 *
1027 * @since 4.1
1028 * @event toDataFormat
1029 * @member CKEDITOR.editor
1030 * @param {CKEDITOR.editor} editor This editor instance.
1031 * @param data
1032 * @param {String/CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} data.dataValue Output data to be prepared.
1033 * @param {String} data.context See {@link CKEDITOR.htmlDataProcessor#toDataFormat} The `context` argument.
1034 * @param {Boolean} data.filter See {@link CKEDITOR.htmlDataProcessor#toDataFormat} The `filter` argument.
1035 * @param {Boolean} data.enterMode See {@link CKEDITOR.htmlDataProcessor#toDataFormat} The `enterMode` argument.
1036 */
diff --git a/sources/core/htmlparser.js b/sources/core/htmlparser.js
new file mode 100644
index 0000000..8c30992
--- /dev/null
+++ b/sources/core/htmlparser.js
@@ -0,0 +1,205 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Provides an "event like" system to parse strings of HTML data.
8 *
9 * var parser = new CKEDITOR.htmlParser();
10 * parser.onTagOpen = function( tagName, attributes, selfClosing ) {
11 * alert( tagName );
12 * };
13 * parser.parse( '<p>Some <b>text</b>.</p>' ); // Alerts 'p', 'b'.
14 *
15 * @class
16 * @constructor Creates a htmlParser class instance.
17 */
18CKEDITOR.htmlParser = function() {
19 this._ = {
20 htmlPartsRegex: /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g
21 };
22};
23
24( function() {
25 var attribsRegex = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,
26 emptyAttribs = { checked: 1, compact: 1, declare: 1, defer: 1, disabled: 1, ismap: 1, multiple: 1, nohref: 1, noresize: 1, noshade: 1, nowrap: 1, readonly: 1, selected: 1 };
27
28 CKEDITOR.htmlParser.prototype = {
29 /**
30 * Function to be fired when a tag opener is found. This function
31 * should be overriden when using this class.
32 *
33 * var parser = new CKEDITOR.htmlParser();
34 * parser.onTagOpen = function( tagName, attributes, selfClosing ) {
35 * alert( tagName ); // e.g. 'b'
36 * } );
37 * parser.parse( '<!-- Example --><b>Hello</b>' );
38 *
39 * @param {String} tagName The tag name. The name is guarantted to be lowercased.
40 * @param {Object} attributes An object containing all tag attributes. Each
41 * property in this object represent and attribute name and its value is the attribute value.
42 * @param {Boolean} selfClosing `true` if the tag closes itself, false if the tag doesn't.
43 */
44 onTagOpen: function() {},
45
46 /**
47 * Function to be fired when a tag closer is found. This function
48 * should be overriden when using this class.
49 *
50 * var parser = new CKEDITOR.htmlParser();
51 * parser.onTagClose = function( tagName ) {
52 * alert( tagName ); // 'b'
53 * } );
54 * parser.parse( '<!-- Example --><b>Hello</b>' );
55 *
56 * @param {String} tagName The tag name. The name is guarantted to be lowercased.
57 */
58 onTagClose: function() {},
59
60 /**
61 * Function to be fired when text is found. This function
62 * should be overriden when using this class.
63 *
64 * var parser = new CKEDITOR.htmlParser();
65 * parser.onText = function( text ) {
66 * alert( text ); // 'Hello'
67 * } );
68 * parser.parse( '<!-- Example --><b>Hello</b>' );
69 *
70 * @param {String} text The text found.
71 */
72 onText: function() {},
73
74 /**
75 * Function to be fired when CDATA section is found. This function
76 * should be overriden when using this class.
77 *
78 * var parser = new CKEDITOR.htmlParser();
79 * parser.onCDATA = function( cdata ) {
80 * alert( cdata ); // 'var hello;'
81 * } );
82 * parser.parse( '<script>var hello;</script>' );
83 *
84 * @param {String} cdata The CDATA been found.
85 */
86 onCDATA: function() {},
87
88 /**
89 * Function to be fired when a commend is found. This function
90 * should be overriden when using this class.
91 *
92 * var parser = new CKEDITOR.htmlParser();
93 * parser.onComment = function( comment ) {
94 * alert( comment ); // ' Example '
95 * } );
96 * parser.parse( '<!-- Example --><b>Hello</b>' );
97 *
98 * @param {String} comment The comment text.
99 */
100 onComment: function() {},
101
102 /**
103 * Parses text, looking for HTML tokens, like tag openers or closers,
104 * or comments. This function fires the onTagOpen, onTagClose, onText
105 * and onComment function during its execution.
106 *
107 * var parser = new CKEDITOR.htmlParser();
108 * // The onTagOpen, onTagClose, onText and onComment should be overriden
109 * // at this point.
110 * parser.parse( '<!-- Example --><b>Hello</b>' );
111 *
112 * @param {String} html The HTML to be parsed.
113 */
114 parse: function( html ) {
115 var parts, tagName,
116 nextIndex = 0,
117 cdata; // The collected data inside a CDATA section.
118
119 while ( ( parts = this._.htmlPartsRegex.exec( html ) ) ) {
120 var tagIndex = parts.index;
121 if ( tagIndex > nextIndex ) {
122 var text = html.substring( nextIndex, tagIndex );
123
124 if ( cdata )
125 cdata.push( text );
126 else
127 this.onText( text );
128 }
129
130 nextIndex = this._.htmlPartsRegex.lastIndex;
131
132 // "parts" is an array with the following items:
133 // 0 : The entire match for opening/closing tags and comments.
134 // : Group filled with the tag name for closing tags.
135 // 2 : Group filled with the comment text.
136 // 3 : Group filled with the tag name for opening tags.
137 // 4 : Group filled with the attributes part of opening tags.
138
139 // Closing tag
140 if ( ( tagName = parts[ 1 ] ) ) {
141 tagName = tagName.toLowerCase();
142
143 if ( cdata && CKEDITOR.dtd.$cdata[ tagName ] ) {
144 // Send the CDATA data.
145 this.onCDATA( cdata.join( '' ) );
146 cdata = null;
147 }
148
149 if ( !cdata ) {
150 this.onTagClose( tagName );
151 continue;
152 }
153 }
154
155 // If CDATA is enabled, just save the raw match.
156 if ( cdata ) {
157 cdata.push( parts[ 0 ] );
158 continue;
159 }
160
161 // Opening tag
162 if ( ( tagName = parts[ 3 ] ) ) {
163 tagName = tagName.toLowerCase();
164
165 // There are some tag names that can break things, so let's
166 // simply ignore them when parsing. (#5224)
167 if ( /="/.test( tagName ) )
168 continue;
169
170 var attribs = {},
171 attribMatch,
172 attribsPart = parts[ 4 ],
173 selfClosing = !!parts[ 5 ];
174
175 if ( attribsPart ) {
176 while ( ( attribMatch = attribsRegex.exec( attribsPart ) ) ) {
177 var attName = attribMatch[ 1 ].toLowerCase(),
178 attValue = attribMatch[ 2 ] || attribMatch[ 3 ] || attribMatch[ 4 ] || '';
179
180 if ( !attValue && emptyAttribs[ attName ] )
181 attribs[ attName ] = attName;
182 else
183 attribs[ attName ] = CKEDITOR.tools.htmlDecodeAttr( attValue );
184 }
185 }
186
187 this.onTagOpen( tagName, attribs, selfClosing );
188
189 // Open CDATA mode when finding the appropriate tags.
190 if ( !cdata && CKEDITOR.dtd.$cdata[ tagName ] )
191 cdata = [];
192
193 continue;
194 }
195
196 // Comment
197 if ( ( tagName = parts[ 2 ] ) )
198 this.onComment( tagName );
199 }
200
201 if ( html.length > nextIndex )
202 this.onText( html.substring( nextIndex, html.length ) );
203 }
204 };
205} )();
diff --git a/sources/core/htmlparser/basicwriter.js b/sources/core/htmlparser/basicwriter.js
new file mode 100644
index 0000000..529fbf1
--- /dev/null
+++ b/sources/core/htmlparser/basicwriter.js
@@ -0,0 +1,152 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * TODO
8 *
9 * @class
10 * @todo
11 */
12CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass( {
13 /**
14 * Creates a basicWriter class instance.
15 *
16 * @constructor
17 */
18 $: function() {
19 this._ = {
20 output: []
21 };
22 },
23
24 proto: {
25 /**
26 * Writes the tag opening part for a opener tag.
27 *
28 * // Writes '<p'.
29 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
30 *
31 * @param {String} tagName The element name for this tag.
32 * @param {Object} attributes The attributes defined for this tag. The
33 * attributes could be used to inspect the tag.
34 */
35 openTag: function( tagName ) {
36 this._.output.push( '<', tagName );
37 },
38
39 /**
40 * Writes the tag closing part for a opener tag.
41 *
42 * // Writes '>'.
43 * writer.openTagClose( 'p', false );
44 *
45 * // Writes ' />'.
46 * writer.openTagClose( 'br', true );
47 *
48 * @param {String} tagName The element name for this tag.
49 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
50 * like `<br>` or `<img>`.
51 */
52 openTagClose: function( tagName, isSelfClose ) {
53 if ( isSelfClose )
54 this._.output.push( ' />' );
55 else
56 this._.output.push( '>' );
57 },
58
59 /**
60 * Writes an attribute. This function should be called after opening the
61 * tag with {@link #openTagClose}.
62 *
63 * // Writes ' class="MyClass"'.
64 * writer.attribute( 'class', 'MyClass' );
65 *
66 * @param {String} attName The attribute name.
67 * @param {String} attValue The attribute value.
68 */
69 attribute: function( attName, attValue ) {
70 // Browsers don't always escape special character in attribute values. (#4683, #4719).
71 if ( typeof attValue == 'string' )
72 attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );
73
74 this._.output.push( ' ', attName, '="', attValue, '"' );
75 },
76
77 /**
78 * Writes a closer tag.
79 *
80 * // Writes '</p>'.
81 * writer.closeTag( 'p' );
82 *
83 * @param {String} tagName The element name for this tag.
84 */
85 closeTag: function( tagName ) {
86 this._.output.push( '</', tagName, '>' );
87 },
88
89 /**
90 * Writes text.
91 *
92 * // Writes 'Hello Word'.
93 * writer.text( 'Hello Word' );
94 *
95 * @param {String} text The text value.
96 */
97 text: function( text ) {
98 this._.output.push( text );
99 },
100
101 /**
102 * Writes a comment.
103 *
104 * // Writes '<!-- My comment -->'.
105 * writer.comment( ' My comment ' );
106 *
107 * @param {String} comment The comment text.
108 */
109 comment: function( comment ) {
110 this._.output.push( '<!--', comment, '-->' );
111 },
112
113 /**
114 * Writes any kind of data to the ouput.
115 *
116 * writer.write( 'This is an <b>example</b>.' );
117 *
118 * @param {String} data
119 */
120 write: function( data ) {
121 this._.output.push( data );
122 },
123
124 /**
125 * Empties the current output buffer.
126 *
127 * writer.reset();
128 */
129 reset: function() {
130 this._.output = [];
131 this._.indent = false;
132 },
133
134 /**
135 * Empties the current output buffer.
136 *
137 * var html = writer.getHtml();
138 *
139 * @param {Boolean} reset Indicates that the {@link #reset} method is to
140 * be automatically called after retrieving the HTML.
141 * @returns {String} The HTML written to the writer so far.
142 */
143 getHtml: function( reset ) {
144 var html = this._.output.join( '' );
145
146 if ( reset )
147 this.reset();
148
149 return html;
150 }
151 }
152} );
diff --git a/sources/core/htmlparser/cdata.js b/sources/core/htmlparser/cdata.js
new file mode 100644
index 0000000..be8c5cf
--- /dev/null
+++ b/sources/core/htmlparser/cdata.js
@@ -0,0 +1,48 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 'use strict';
7
8( function() {
9
10 /**
11 * A lightweight representation of HTML CDATA.
12 *
13 * @class
14 * @extends CKEDITOR.htmlParser.node
15 * @constructor Creates a cdata class instance.
16 * @param {String} value The CDATA section value.
17 */
18 CKEDITOR.htmlParser.cdata = function( value ) {
19 /**
20 * The CDATA value.
21 *
22 * @property {String}
23 */
24 this.value = value;
25 };
26
27 CKEDITOR.htmlParser.cdata.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
28 /**
29 * CDATA has the same type as {@link CKEDITOR.htmlParser.text} This is
30 * a constant value set to {@link CKEDITOR#NODE_TEXT}.
31 *
32 * @readonly
33 * @property {Number} [=CKEDITOR.NODE_TEXT]
34 */
35 type: CKEDITOR.NODE_TEXT,
36
37 filter: function() {},
38
39 /**
40 * Writes the CDATA with no special manipulations.
41 *
42 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
43 */
44 writeHtml: function( writer ) {
45 writer.write( this.value );
46 }
47 } );
48} )();
diff --git a/sources/core/htmlparser/comment.js b/sources/core/htmlparser/comment.js
new file mode 100644
index 0000000..14a38f3
--- /dev/null
+++ b/sources/core/htmlparser/comment.js
@@ -0,0 +1,80 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 'use strict';
7
8/**
9 * A lightweight representation of an HTML comment.
10 *
11 * @class
12 * @extends CKEDITOR.htmlParser.node
13 * @constructor Creates a comment class instance.
14 * @param {String} value The comment text value.
15 */
16CKEDITOR.htmlParser.comment = function( value ) {
17 /**
18 * The comment text.
19 *
20 * @property {String}
21 */
22 this.value = value;
23
24 /** @private */
25 this._ = {
26 isBlockLike: false
27 };
28};
29
30CKEDITOR.htmlParser.comment.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
31 /**
32 * The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
33 *
34 * @readonly
35 * @property {Number} [=CKEDITOR.NODE_COMMENT]
36 */
37 type: CKEDITOR.NODE_COMMENT,
38
39 /**
40 * Filter this comment with given filter.
41 *
42 * @since 4.1
43 * @param {CKEDITOR.htmlParser.filter} filter
44 * @returns {Boolean} Method returns `false` when this comment has
45 * been removed or replaced with other node. This is an information for
46 * {@link CKEDITOR.htmlParser.element#filterChildren} that it has
47 * to repeat filter on current position in parent's children array.
48 */
49 filter: function( filter, context ) {
50 var comment = this.value;
51
52 if ( !( comment = filter.onComment( context, comment, this ) ) ) {
53 this.remove();
54 return false;
55 }
56
57 if ( typeof comment != 'string' ) {
58 this.replaceWith( comment );
59 return false;
60 }
61
62 this.value = comment;
63
64 return true;
65 },
66
67 /**
68 * Writes the HTML representation of this comment to a CKEDITOR.htmlWriter.
69 *
70 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
71 * @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
72 * **Note:** it's unsafe to filter offline (not appended) node.
73 */
74 writeHtml: function( writer, filter ) {
75 if ( filter )
76 this.filter( filter );
77
78 writer.comment( this.value );
79 }
80} );
diff --git a/sources/core/htmlparser/element.js b/sources/core/htmlparser/element.js
new file mode 100644
index 0000000..0ed750e
--- /dev/null
+++ b/sources/core/htmlparser/element.js
@@ -0,0 +1,568 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8/**
9 * A lightweight representation of an HTML element.
10 *
11 * @class
12 * @extends CKEDITOR.htmlParser.node
13 * @constructor Creates an element class instance.
14 * @param {String} name The element name.
15 * @param {Object} attributes An object storing all attributes defined for
16 * this element.
17 */
18CKEDITOR.htmlParser.element = function( name, attributes ) {
19 /**
20 * The element name.
21 *
22 * @property {String}
23 */
24 this.name = name;
25
26 /**
27 * Stores the attributes defined for this element.
28 *
29 * @property {Object}
30 */
31 this.attributes = attributes || {};
32
33 /**
34 * The nodes that are direct children of this element.
35 */
36 this.children = [];
37
38 // Reveal the real semantic of our internal custom tag name (#6639),
39 // when resolving whether it's block like.
40 var realName = name || '',
41 prefixed = realName.match( /^cke:(.*)/ );
42 prefixed && ( realName = prefixed[ 1 ] );
43
44 var isBlockLike = !!( CKEDITOR.dtd.$nonBodyContent[ realName ] || CKEDITOR.dtd.$block[ realName ] ||
45 CKEDITOR.dtd.$listItem[ realName ] || CKEDITOR.dtd.$tableContent[ realName ] ||
46 CKEDITOR.dtd.$nonEditable[ realName ] || realName == 'br' );
47
48 this.isEmpty = !!CKEDITOR.dtd.$empty[ name ];
49 this.isUnknown = !CKEDITOR.dtd[ name ];
50
51 /** @private */
52 this._ = {
53 isBlockLike: isBlockLike,
54 hasInlineStarted: this.isEmpty || !isBlockLike
55 };
56};
57
58/**
59 * Object presentation of the CSS style declaration text.
60 *
61 * @class
62 * @constructor Creates a `cssStyle` class instance.
63 * @param {CKEDITOR.htmlParser.element/String} elementOrStyleText
64 * An HTML parser element or the inline style text.
65 */
66CKEDITOR.htmlParser.cssStyle = function() {
67 var styleText,
68 arg = arguments[ 0 ],
69 rules = {};
70
71 styleText = arg instanceof CKEDITOR.htmlParser.element ? arg.attributes.style : arg;
72
73 // html-encoded quote might be introduced by 'font-family'
74 // from MS-Word which confused the following regexp. e.g.
75 //'font-family: &quot;Lucida, Console&quot;'
76 // TODO reuse CSS methods from tools.
77 ( styleText || '' ).replace( /&quot;/g, '"' ).replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) {
78 name == 'font-family' && ( value = value.replace( /["']/g, '' ) );
79 rules[ name.toLowerCase() ] = value;
80 } );
81
82 return {
83
84 rules: rules,
85
86 /**
87 * Applies the styles to the specified element or object.
88 *
89 * @param {CKEDITOR.htmlParser.element/CKEDITOR.dom.element/Object} obj
90 */
91 populate: function( obj ) {
92 var style = this.toString();
93 if ( style )
94 obj instanceof CKEDITOR.dom.element ? obj.setAttribute( 'style', style ) : obj instanceof CKEDITOR.htmlParser.element ? obj.attributes.style = style : obj.style = style;
95
96 },
97
98 /**
99 * Serializes CSS style declaration to a string.
100 *
101 * @returns {String}
102 */
103 toString: function() {
104 var output = [];
105 for ( var i in rules )
106 rules[ i ] && output.push( i, ':', rules[ i ], ';' );
107 return output.join( '' );
108 }
109 };
110};
111
112/** @class CKEDITOR.htmlParser.element */
113( function() {
114 // Used to sort attribute entries in an array, where the first element of
115 // each object is the attribute name.
116 var sortAttribs = function( a, b ) {
117 a = a[ 0 ];
118 b = b[ 0 ];
119 return a < b ? -1 : a > b ? 1 : 0;
120 },
121 fragProto = CKEDITOR.htmlParser.fragment.prototype;
122
123 CKEDITOR.htmlParser.element.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
124 /**
125 * The node type. This is a constant value set to {@link CKEDITOR#NODE_ELEMENT}.
126 *
127 * @readonly
128 * @property {Number} [=CKEDITOR.NODE_ELEMENT]
129 */
130 type: CKEDITOR.NODE_ELEMENT,
131
132 /**
133 * Adds a node to the element children list.
134 *
135 * @method
136 * @param {CKEDITOR.htmlParser.node} node The node to be added.
137 * @param {Number} [index] From where the insertion happens.
138 */
139 add: fragProto.add,
140
141 /**
142 * Clones this element.
143 *
144 * @returns {CKEDITOR.htmlParser.element} The element clone.
145 */
146 clone: function() {
147 return new CKEDITOR.htmlParser.element( this.name, this.attributes );
148 },
149
150 /**
151 * Filters this element and its children with the given filter.
152 *
153 * @since 4.1
154 * @param {CKEDITOR.htmlParser.filter} filter
155 * @returns {Boolean} The method returns `false` when this element has
156 * been removed or replaced with another. This information means that
157 * {@link #filterChildren} has to repeat the filter on the current
158 * position in parent's children array.
159 */
160 filter: function( filter, context ) {
161 var element = this,
162 originalName, name;
163
164 context = element.getFilterContext( context );
165
166 // Do not process elements with data-cke-processor attribute set to off.
167 if ( context.off )
168 return true;
169
170 // Filtering if it's the root node.
171 if ( !element.parent )
172 filter.onRoot( context, element );
173
174 while ( true ) {
175 originalName = element.name;
176
177 if ( !( name = filter.onElementName( context, originalName ) ) ) {
178 this.remove();
179 return false;
180 }
181
182 element.name = name;
183
184 if ( !( element = filter.onElement( context, element ) ) ) {
185 this.remove();
186 return false;
187 }
188
189 // New element has been returned - replace current one
190 // and process it (stop processing this and return false, what
191 // means that element has been removed).
192 if ( element !== this ) {
193 this.replaceWith( element );
194 return false;
195 }
196
197 // If name has been changed - continue loop, so in next iteration
198 // filters for new name will be applied to this element.
199 // If name hasn't been changed - stop.
200 if ( element.name == originalName )
201 break;
202
203 // If element has been replaced with something of a
204 // different type, then make the replacement filter itself.
205 if ( element.type != CKEDITOR.NODE_ELEMENT ) {
206 this.replaceWith( element );
207 return false;
208 }
209
210 // This indicate that the element has been dropped by
211 // filter but not the children.
212 if ( !element.name ) {
213 this.replaceWithChildren();
214 return false;
215 }
216 }
217
218 var attributes = element.attributes,
219 a, value, newAttrName;
220
221 for ( a in attributes ) {
222 newAttrName = a;
223 value = attributes[ a ];
224
225 // Loop until name isn't modified.
226 // A little bit senseless, but IE would do that anyway
227 // because it iterates with for-in loop even over properties
228 // created during its run.
229 while ( true ) {
230 if ( !( newAttrName = filter.onAttributeName( context, a ) ) ) {
231 delete attributes[ a ];
232 break;
233 } else if ( newAttrName != a ) {
234 delete attributes[ a ];
235 a = newAttrName;
236 continue;
237 } else {
238 break;
239 }
240 }
241
242 if ( newAttrName ) {
243 if ( ( value = filter.onAttribute( context, element, newAttrName, value ) ) === false )
244 delete attributes[ newAttrName ];
245 else
246 attributes[ newAttrName ] = value;
247 }
248 }
249
250 if ( !element.isEmpty )
251 this.filterChildren( filter, false, context );
252
253 return true;
254 },
255
256 /**
257 * Filters this element's children with the given filter.
258 *
259 * Element's children may only be filtered once by one
260 * instance of the filter.
261 *
262 * @method filterChildren
263 * @param {CKEDITOR.htmlParser.filter} filter
264 */
265 filterChildren: fragProto.filterChildren,
266
267 /**
268 * Writes the element HTML to the CKEDITOR.htmlWriter.
269 *
270 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
271 * @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
272 * **Note:** It is unsafe to filter an offline (not appended) node.
273 */
274 writeHtml: function( writer, filter ) {
275 if ( filter )
276 this.filter( filter );
277
278 var name = this.name,
279 attribsArray = [],
280 attributes = this.attributes,
281 attrName,
282 attr, i, l;
283
284 // Open element tag.
285 writer.openTag( name, attributes );
286
287 // Copy all attributes to an array.
288 for ( attrName in attributes )
289 attribsArray.push( [ attrName, attributes[ attrName ] ] );
290
291 // Sort the attributes by name.
292 if ( writer.sortAttributes )
293 attribsArray.sort( sortAttribs );
294
295 // Send the attributes.
296 for ( i = 0, l = attribsArray.length; i < l; i++ ) {
297 attr = attribsArray[ i ];
298 writer.attribute( attr[ 0 ], attr[ 1 ] );
299 }
300
301 // Close the tag.
302 writer.openTagClose( name, this.isEmpty );
303
304 this.writeChildrenHtml( writer );
305
306 // Close the element.
307 if ( !this.isEmpty )
308 writer.closeTag( name );
309 },
310
311 /**
312 * Sends children of this element to the writer.
313 *
314 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
315 * @param {CKEDITOR.htmlParser.filter} [filter]
316 */
317 writeChildrenHtml: fragProto.writeChildrenHtml,
318
319 /**
320 * Replaces this element with its children.
321 *
322 * @since 4.1
323 */
324 replaceWithChildren: function() {
325 var children = this.children;
326
327 for ( var i = children.length; i; )
328 children[ --i ].insertAfter( this );
329
330 this.remove();
331 },
332
333 /**
334 * Executes a callback on each node (of the given type) in this element.
335 *
336 * // Create a <p> element with foo<b>bar</b>bom as its content.
337 * var elP = CKEDITOR.htmlParser.fragment.fromHtml( 'foo<b>bar</b>bom', 'p' );
338 * elP.forEach( function( node ) {
339 * console.log( node );
340 * } );
341 * // Will log:
342 * // 1. document fragment,
343 * // 2. <p> element,
344 * // 3. "foo" text node,
345 * // 4. <b> element,
346 * // 5. "bar" text node,
347 * // 6. "bom" text node.
348 *
349 * @since 4.1
350 * @param {Function} callback Function to be executed on every node.
351 * **Since 4.3**: If `callback` returned `false`, the descendants of the current node will be ignored.
352 * @param {CKEDITOR.htmlParser.node} callback.node Node passed as an argument.
353 * @param {Number} [type] Whether the specified `callback` will be executed only on nodes of this type.
354 * @param {Boolean} [skipRoot] Do not execute `callback` on this element.
355 */
356 forEach: fragProto.forEach,
357
358 /**
359 * Gets this element's first child. If `condition` is given, this method returns
360 * the first child which satisfies that condition.
361 *
362 * @since 4.3
363 * @param {String/Object/Function} condition Name of a child, a hash of names, or a validator function.
364 * @returns {CKEDITOR.htmlParser.node}
365 */
366 getFirst: function( condition ) {
367 if ( !condition )
368 return this.children.length ? this.children[ 0 ] : null;
369
370 if ( typeof condition != 'function' )
371 condition = nameCondition( condition );
372
373 for ( var i = 0, l = this.children.length; i < l; ++i ) {
374 if ( condition( this.children[ i ] ) )
375 return this.children[ i ];
376 }
377 return null;
378 },
379
380 /**
381 * Gets this element's inner HTML.
382 *
383 * @since 4.3
384 * @returns {String}
385 */
386 getHtml: function() {
387 var writer = new CKEDITOR.htmlParser.basicWriter();
388 this.writeChildrenHtml( writer );
389 return writer.getHtml();
390 },
391
392 /**
393 * Sets this element's inner HTML.
394 *
395 * @since 4.3
396 * @param {String} html
397 */
398 setHtml: function( html ) {
399 var children = this.children = CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
400
401 for ( var i = 0, l = children.length; i < l; ++i )
402 children[ i ].parent = this;
403 },
404
405 /**
406 * Gets this element's outer HTML.
407 *
408 * @since 4.3
409 * @returns {String}
410 */
411 getOuterHtml: function() {
412 var writer = new CKEDITOR.htmlParser.basicWriter();
413 this.writeHtml( writer );
414 return writer.getHtml();
415 },
416
417 /**
418 * Splits this element at the given index.
419 *
420 * @since 4.3
421 * @param {Number} index Index at which the element will be split &mdash; `0` means the beginning,
422 * `1` after the first child node, etc.
423 * @returns {CKEDITOR.htmlParser.element} The new element following this one.
424 */
425 split: function( index ) {
426 var cloneChildren = this.children.splice( index, this.children.length - index ),
427 clone = this.clone();
428
429 for ( var i = 0; i < cloneChildren.length; ++i )
430 cloneChildren[ i ].parent = clone;
431
432 clone.children = cloneChildren;
433
434 if ( cloneChildren[ 0 ] )
435 cloneChildren[ 0 ].previous = null;
436
437 if ( index > 0 )
438 this.children[ index - 1 ].next = null;
439
440 this.parent.add( clone, this.getIndex() + 1 );
441
442 return clone;
443 },
444
445 /**
446 * Searches through the current node children to find nodes matching the `criteria`.
447 *
448 * @param {String/Function} criteria Tag name or evaluator function.
449 * @param {Boolean} [recursive=false]
450 * @returns {CKEDITOR.htmlParser.node[]}
451 */
452 find: function( criteria, recursive ) {
453 if ( recursive === undefined ) {
454 recursive = false;
455 }
456
457 var ret = [],
458 i;
459
460 for ( i = 0; i < this.children.length; i++ ) {
461 var curChild = this.children[ i ];
462
463 if ( typeof criteria == 'function' && criteria( curChild ) ) {
464 ret.push( curChild );
465 } else if ( typeof criteria == 'string' && curChild.name === criteria ) {
466 ret.push( curChild );
467 }
468
469 if ( recursive && curChild.find ) {
470 ret = ret.concat( curChild.find( criteria, recursive ) );
471 }
472 }
473
474 return ret;
475 },
476
477 /**
478 * Adds a class name to the list of classes.
479 *
480 * @since 4.4
481 * @param {String} className The class name to be added.
482 */
483 addClass: function( className ) {
484 if ( this.hasClass( className ) )
485 return;
486
487 var c = this.attributes[ 'class' ] || '';
488
489 this.attributes[ 'class' ] = c + ( c ? ' ' : '' ) + className;
490 },
491
492 /**
493 * Removes a class name from the list of classes.
494 *
495 * @since 4.3
496 * @param {String} className The class name to be removed.
497 */
498 removeClass: function( className ) {
499 var classes = this.attributes[ 'class' ];
500
501 if ( !classes )
502 return;
503
504 // We can safely assume that className won't break regexp.
505 // http://stackoverflow.com/questions/448981/what-characters-are-valid-in-css-class-names
506 classes = CKEDITOR.tools.trim( classes.replace( new RegExp( '(?:\\s+|^)' + className + '(?:\\s+|$)' ), ' ' ) );
507
508 if ( classes )
509 this.attributes[ 'class' ] = classes;
510 else
511 delete this.attributes[ 'class' ];
512 },
513
514 /**
515 * Checkes whether this element has a class name.
516 *
517 * @since 4.3
518 * @param {String} className The class name to be checked.
519 * @returns {Boolean} Whether this element has a `className`.
520 */
521 hasClass: function( className ) {
522 var classes = this.attributes[ 'class' ];
523
524 if ( !classes )
525 return false;
526
527 return ( new RegExp( '(?:^|\\s)' + className + '(?=\\s|$)' ) ).test( classes );
528 },
529
530 getFilterContext: function( ctx ) {
531 var changes = [];
532
533 if ( !ctx ) {
534 ctx = {
535 off: false,
536 nonEditable: false,
537 nestedEditable: false
538 };
539 }
540
541 if ( !ctx.off && this.attributes[ 'data-cke-processor' ] == 'off' )
542 changes.push( 'off', true );
543
544 if ( !ctx.nonEditable && this.attributes.contenteditable == 'false' )
545 changes.push( 'nonEditable', true );
546 // A context to be given nestedEditable must be nonEditable first (by inheritance) (#11372, #11698).
547 // Special case: #11504 - filter starts on <body contenteditable=true>,
548 // so ctx.nonEditable has not been yet set to true.
549 else if ( ctx.nonEditable && !ctx.nestedEditable && this.attributes.contenteditable == 'true' )
550 changes.push( 'nestedEditable', true );
551
552 if ( changes.length ) {
553 ctx = CKEDITOR.tools.copy( ctx );
554 for ( var i = 0; i < changes.length; i += 2 )
555 ctx[ changes[ i ] ] = changes[ i + 1 ];
556 }
557
558 return ctx;
559 }
560 }, true );
561
562 function nameCondition( condition ) {
563 return function( el ) {
564 return el.type == CKEDITOR.NODE_ELEMENT &&
565 ( typeof condition == 'string' ? el.name == condition : el.name in condition );
566 };
567 }
568} )();
diff --git a/sources/core/htmlparser/filter.js b/sources/core/htmlparser/filter.js
new file mode 100644
index 0000000..db6b91c
--- /dev/null
+++ b/sources/core/htmlparser/filter.js
@@ -0,0 +1,407 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8( function() {
9 /**
10 * Filter is a configurable tool for transforming and filtering {@link CKEDITOR.htmlParser.node nodes}.
11 * It is mainly used during data processing phase which is done not on real DOM nodes,
12 * but on their simplified form represented by {@link CKEDITOR.htmlParser.node} class and its subclasses.
13 *
14 * var filter = new CKEDITOR.htmlParser.filter( {
15 * text: function( value ) {
16 * return '@' + value + '@';
17 * },
18 * elements: {
19 * p: function( element ) {
20 * element.attributes.foo = '1';
21 * }
22 * }
23 * } );
24 *
25 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>Foo<b>bar!</b></p>' ),
26 * writer = new CKEDITOR.htmlParser.basicWriter();
27 * filter.applyTo( fragment );
28 * fragment.writeHtml( writer );
29 * writer.getHtml(); // '<p foo="1">@Foo@<b>@bar!@</b></p>'
30 *
31 * @class
32 */
33 CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass( {
34 /**
35 * @constructor Creates a filter class instance.
36 * @param {CKEDITOR.htmlParser.filterRulesDefinition} [rules]
37 */
38 $: function( rules ) {
39 /**
40 * ID of filter instance, which is used to mark elements
41 * to which this filter has been already applied.
42 *
43 * @property {Number} id
44 * @readonly
45 */
46 this.id = CKEDITOR.tools.getNextNumber();
47
48 /**
49 * Rules for element names.
50 *
51 * @property {CKEDITOR.htmlParser.filterRulesGroup}
52 * @readonly
53 */
54 this.elementNameRules = new filterRulesGroup();
55
56 /**
57 * Rules for attribute names.
58 *
59 * @property {CKEDITOR.htmlParser.filterRulesGroup}
60 * @readonly
61 */
62 this.attributeNameRules = new filterRulesGroup();
63
64 /**
65 * Hash of elementName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for elements}.
66 *
67 * @readonly
68 */
69 this.elementsRules = {};
70
71 /**
72 * Hash of attributeName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for attributes}.
73 *
74 * @readonly
75 */
76 this.attributesRules = {};
77
78 /**
79 * Rules for text nodes.
80 *
81 * @property {CKEDITOR.htmlParser.filterRulesGroup}
82 * @readonly
83 */
84 this.textRules = new filterRulesGroup();
85
86 /**
87 * Rules for comment nodes.
88 *
89 * @property {CKEDITOR.htmlParser.filterRulesGroup}
90 * @readonly
91 */
92 this.commentRules = new filterRulesGroup();
93
94 /**
95 * Rules for a root node.
96 *
97 * @property {CKEDITOR.htmlParser.filterRulesGroup}
98 * @readonly
99 */
100 this.rootRules = new filterRulesGroup();
101
102 if ( rules )
103 this.addRules( rules, 10 );
104 },
105
106 proto: {
107 /**
108 * Add rules to this filter.
109 *
110 * @param {CKEDITOR.htmlParser.filterRulesDefinition} rules Object containing filter rules.
111 * @param {Object/Number} [options] Object containing rules' options or a priority
112 * (for a backward compatibility with CKEditor versions up to 4.2.x).
113 * @param {Number} [options.priority=10] The priority of a rule.
114 * @param {Boolean} [options.applyToAll=false] Whether to apply rule to non-editable
115 * elements and their descendants too.
116 */
117 addRules: function( rules, options ) {
118 var priority;
119
120 // Backward compatibility.
121 if ( typeof options == 'number' )
122 priority = options;
123 // New version - try reading from options.
124 else if ( options && ( 'priority' in options ) )
125 priority = options.priority;
126
127 // Defaults.
128 if ( typeof priority != 'number' )
129 priority = 10;
130 if ( typeof options != 'object' )
131 options = {};
132
133 // Add the elementNames.
134 if ( rules.elementNames )
135 this.elementNameRules.addMany( rules.elementNames, priority, options );
136
137 // Add the attributeNames.
138 if ( rules.attributeNames )
139 this.attributeNameRules.addMany( rules.attributeNames, priority, options );
140
141 // Add the elements.
142 if ( rules.elements )
143 addNamedRules( this.elementsRules, rules.elements, priority, options );
144
145 // Add the attributes.
146 if ( rules.attributes )
147 addNamedRules( this.attributesRules, rules.attributes, priority, options );
148
149 // Add the text.
150 if ( rules.text )
151 this.textRules.add( rules.text, priority, options );
152
153 // Add the comment.
154 if ( rules.comment )
155 this.commentRules.add( rules.comment, priority, options );
156
157 // Add root node rules.
158 if ( rules.root )
159 this.rootRules.add( rules.root, priority, options );
160 },
161
162 /**
163 * Apply this filter to given node.
164 *
165 * @param {CKEDITOR.htmlParser.node} node The node to be filtered.
166 */
167 applyTo: function( node ) {
168 node.filter( this );
169 },
170
171 onElementName: function( context, name ) {
172 return this.elementNameRules.execOnName( context, name );
173 },
174
175 onAttributeName: function( context, name ) {
176 return this.attributeNameRules.execOnName( context, name );
177 },
178
179 onText: function( context, text, node ) {
180 return this.textRules.exec( context, text, node );
181 },
182
183 onComment: function( context, commentText, comment ) {
184 return this.commentRules.exec( context, commentText, comment );
185 },
186
187 onRoot: function( context, element ) {
188 return this.rootRules.exec( context, element );
189 },
190
191 onElement: function( context, element ) {
192 // We must apply filters set to the specific element name as
193 // well as those set to the generic ^/$ name. So, add both to an
194 // array and process them in a small loop.
195 var rulesGroups = [ this.elementsRules[ '^' ], this.elementsRules[ element.name ], this.elementsRules.$ ],
196 rulesGroup, ret;
197
198 for ( var i = 0; i < 3; i++ ) {
199 rulesGroup = rulesGroups[ i ];
200 if ( rulesGroup ) {
201 ret = rulesGroup.exec( context, element, this );
202
203 if ( ret === false )
204 return null;
205
206 if ( ret && ret != element )
207 return this.onNode( context, ret );
208
209 // The non-root element has been dismissed by one of the filters.
210 if ( element.parent && !element.name )
211 break;
212 }
213 }
214
215 return element;
216 },
217
218 onNode: function( context, node ) {
219 var type = node.type;
220
221 return type == CKEDITOR.NODE_ELEMENT ? this.onElement( context, node ) :
222 type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( context, node.value ) ) :
223 type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( context, node.value ) ) : null;
224 },
225
226 onAttribute: function( context, element, name, value ) {
227 var rulesGroup = this.attributesRules[ name ];
228
229 if ( rulesGroup )
230 return rulesGroup.exec( context, value, element, this );
231 return value;
232 }
233 }
234 } );
235
236 /**
237 * Class grouping filter rules for one subject (like element or attribute names).
238 *
239 * @class CKEDITOR.htmlParser.filterRulesGroup
240 */
241 function filterRulesGroup() {
242 /**
243 * Array of objects containing rule, priority and options.
244 *
245 * @property {Object[]}
246 * @readonly
247 */
248 this.rules = [];
249 }
250
251 CKEDITOR.htmlParser.filterRulesGroup = filterRulesGroup;
252
253 filterRulesGroup.prototype = {
254 /**
255 * Adds specified rule to this group.
256 *
257 * @param {Function/Array} rule Function for function based rule or [ pattern, replacement ] array for
258 * rule applicable to names.
259 * @param {Number} priority
260 * @param options
261 */
262 add: function( rule, priority, options ) {
263 this.rules.splice( this.findIndex( priority ), 0, {
264 value: rule,
265 priority: priority,
266 options: options
267 } );
268 },
269
270 /**
271 * Adds specified rules to this group.
272 *
273 * @param {Array} rules Array of rules - see {@link #add}.
274 * @param {Number} priority
275 * @param options
276 */
277 addMany: function( rules, priority, options ) {
278 var args = [ this.findIndex( priority ), 0 ];
279
280 for ( var i = 0, len = rules.length; i < len; i++ ) {
281 args.push( {
282 value: rules[ i ],
283 priority: priority,
284 options: options
285 } );
286 }
287
288 this.rules.splice.apply( this.rules, args );
289 },
290
291 /**
292 * Finds an index at which rule with given priority should be inserted.
293 *
294 * @param {Number} priority
295 * @returns {Number} Index.
296 */
297 findIndex: function( priority ) {
298 var rules = this.rules,
299 len = rules.length,
300 i = len - 1;
301
302 // Search from the end, because usually rules will be added with default priority, so
303 // we will be able to stop loop quickly.
304 while ( i >= 0 && priority < rules[ i ].priority )
305 i--;
306
307 return i + 1;
308 },
309
310 /**
311 * Executes this rules group on given value. Applicable only if function based rules were added.
312 *
313 * All arguments passed to this function will be forwarded to rules' functions.
314 *
315 * @param {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} currentValue The value to be filtered.
316 * @returns {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} Filtered value.
317 */
318 exec: function( context, currentValue ) {
319 var isNode = currentValue instanceof CKEDITOR.htmlParser.node || currentValue instanceof CKEDITOR.htmlParser.fragment,
320 // Splice '1' to remove context, which we don't want to pass to filter rules.
321 args = Array.prototype.slice.call( arguments, 1 ),
322 rules = this.rules,
323 len = rules.length,
324 orgType, orgName, ret, i, rule;
325
326 for ( i = 0; i < len; i++ ) {
327 // Backup the node info before filtering.
328 if ( isNode ) {
329 orgType = currentValue.type;
330 orgName = currentValue.name;
331 }
332
333 rule = rules[ i ];
334 if ( isRuleApplicable( context, rule ) ) {
335 ret = rule.value.apply( null, args );
336
337 if ( ret === false )
338 return ret;
339
340 // We're filtering node (element/fragment).
341 // No further filtering if it's not anymore fitable for the subsequent filters.
342 if ( isNode && ret && ( ret.name != orgName || ret.type != orgType ) )
343 return ret;
344
345 // Update currentValue and corresponding argument in args array.
346 // Updated values will be used in next for-loop step.
347 if ( ret != null )
348 args[ 0 ] = currentValue = ret;
349
350 // ret == undefined will continue loop as nothing has happened.
351 }
352 }
353
354 return currentValue;
355 },
356
357 /**
358 * Executes this rules group on name. Applicable only if filter rules for names were added.
359 *
360 * @param {String} currentName The name to be filtered.
361 * @returns {String} Filtered name.
362 */
363 execOnName: function( context, currentName ) {
364 var i = 0,
365 rules = this.rules,
366 len = rules.length,
367 rule;
368
369 for ( ; currentName && i < len; i++ ) {
370 rule = rules[ i ];
371 if ( isRuleApplicable( context, rule ) )
372 currentName = currentName.replace( rule.value[ 0 ], rule.value[ 1 ] );
373 }
374
375 return currentName;
376 }
377 };
378
379 function addNamedRules( rulesGroups, newRules, priority, options ) {
380 var ruleName, rulesGroup;
381
382 for ( ruleName in newRules ) {
383 rulesGroup = rulesGroups[ ruleName ];
384
385 if ( !rulesGroup )
386 rulesGroup = rulesGroups[ ruleName ] = new filterRulesGroup();
387
388 rulesGroup.add( newRules[ ruleName ], priority, options );
389 }
390 }
391
392 function isRuleApplicable( context, rule ) {
393 if ( context.nonEditable && !rule.options.applyToAll )
394 return false;
395
396 if ( context.nestedEditable && rule.options.excludeNestedEditable )
397 return false;
398
399 return true;
400 }
401
402} )();
403
404/**
405 * @class CKEDITOR.htmlParser.filterRulesDefinition
406 * @abstract
407 */
diff --git a/sources/core/htmlparser/fragment.js b/sources/core/htmlparser/fragment.js
new file mode 100644
index 0000000..f696a12
--- /dev/null
+++ b/sources/core/htmlparser/fragment.js
@@ -0,0 +1,646 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8/**
9 * A lightweight representation of an HTML DOM structure.
10 *
11 * @class
12 * @constructor Creates a fragment class instance.
13 */
14CKEDITOR.htmlParser.fragment = function() {
15 /**
16 * The nodes contained in the root of this fragment.
17 *
18 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
19 * alert( fragment.children.length ); // 2
20 */
21 this.children = [];
22
23 /**
24 * Get the fragment parent. Should always be null.
25 *
26 * @property {Object} [=null]
27 */
28 this.parent = null;
29
30 /** @private */
31 this._ = {
32 isBlockLike: true,
33 hasInlineStarted: false
34 };
35};
36
37( function() {
38 // Block-level elements whose internal structure should be respected during
39 // parser fixing.
40 var nonBreakingBlocks = CKEDITOR.tools.extend( { table: 1, ul: 1, ol: 1, dl: 1 }, CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl );
41
42 var listBlocks = { ol: 1, ul: 1 };
43
44 // Dtd of the fragment element, basically it accept anything except for intermediate structure, e.g. orphan <li>.
45 var rootDtd = CKEDITOR.tools.extend( {}, { html: 1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style: 1, script: 1 } );
46
47 // Which element to create when encountered not allowed content.
48 var structureFixes = {
49 ul: 'li',
50 ol: 'li',
51 dl: 'dd',
52 table: 'tbody',
53 tbody: 'tr',
54 thead: 'tr',
55 tfoot: 'tr',
56 tr: 'td'
57 };
58
59 function isRemoveEmpty( node ) {
60 // Keep marked element event if it is empty.
61 if ( node.attributes[ 'data-cke-survive' ] )
62 return false;
63
64 // Empty link is to be removed when empty but not anchor. (#7894)
65 return node.name == 'a' && node.attributes.href || CKEDITOR.dtd.$removeEmpty[ node.name ];
66 }
67
68 /**
69 * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
70 *
71 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
72 * alert( fragment.children[ 0 ].name ); // 'b'
73 * alert( fragment.children[ 1 ].value ); // ' Text'
74 *
75 * @static
76 * @param {String} fragmentHtml The HTML to be parsed, filling the fragment.
77 * @param {CKEDITOR.htmlParser.element/String} [parent] Optional contextual
78 * element which makes the content been parsed as the content of this element and fix
79 * to match it.
80 * If not provided, then {@link CKEDITOR.htmlParser.fragment} will be used
81 * as the parent and it will be returned.
82 * @param {String/Boolean} [fixingBlock] When `parent` is a block limit element,
83 * and the param is a string value other than `false`, it is to
84 * avoid having block-less content as the direct children of parent by wrapping
85 * the content with a block element of the specified tag, e.g.
86 * when `fixingBlock` specified as `p`, the content `<body><i>foo</i></body>`
87 * will be fixed into `<body><p><i>foo</i></p></body>`.
88 * @returns {CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} The created fragment or passed `parent`.
89 */
90 CKEDITOR.htmlParser.fragment.fromHtml = function( fragmentHtml, parent, fixingBlock ) {
91 var parser = new CKEDITOR.htmlParser();
92
93 var root = parent instanceof CKEDITOR.htmlParser.element ? parent : typeof parent == 'string' ? new CKEDITOR.htmlParser.element( parent ) : new CKEDITOR.htmlParser.fragment();
94
95 var pendingInline = [],
96 pendingBRs = [],
97 currentNode = root,
98 // Indicate we're inside a <textarea> element, spaces should be touched differently.
99 inTextarea = root.name == 'textarea',
100 // Indicate we're inside a <pre> element, spaces should be touched differently.
101 inPre = root.name == 'pre';
102
103 function checkPending( newTagName ) {
104 var pendingBRsSent;
105
106 if ( pendingInline.length > 0 ) {
107 for ( var i = 0; i < pendingInline.length; i++ ) {
108 var pendingElement = pendingInline[ i ],
109 pendingName = pendingElement.name,
110 pendingDtd = CKEDITOR.dtd[ pendingName ],
111 currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ];
112
113 if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) ) {
114 if ( !pendingBRsSent ) {
115 sendPendingBRs();
116 pendingBRsSent = 1;
117 }
118
119 // Get a clone for the pending element.
120 pendingElement = pendingElement.clone();
121
122 // Add it to the current node and make it the current,
123 // so the new element will be added inside of it.
124 pendingElement.parent = currentNode;
125 currentNode = pendingElement;
126
127 // Remove the pending element (back the index by one
128 // to properly process the next entry).
129 pendingInline.splice( i, 1 );
130 i--;
131 } else {
132 // Some element of the same type cannot be nested, flat them,
133 // e.g. <a href="#">foo<a href="#">bar</a></a>. (#7894)
134 if ( pendingName == currentNode.name )
135 addElement( currentNode, currentNode.parent, 1 ), i--;
136 }
137 }
138 }
139 }
140
141 function sendPendingBRs() {
142 while ( pendingBRs.length )
143 addElement( pendingBRs.shift(), currentNode );
144 }
145
146 // Rtrim empty spaces on block end boundary. (#3585)
147 function removeTailWhitespace( element ) {
148 if ( element._.isBlockLike && element.name != 'pre' && element.name != 'textarea' ) {
149
150 var length = element.children.length,
151 lastChild = element.children[ length - 1 ],
152 text;
153 if ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT ) {
154 if ( !( text = CKEDITOR.tools.rtrim( lastChild.value ) ) )
155 element.children.length = length - 1;
156 else
157 lastChild.value = text;
158 }
159 }
160 }
161
162 // Beside of simply append specified element to target, this function also takes
163 // care of other dirty lifts like forcing block in body, trimming spaces at
164 // the block boundaries etc.
165 //
166 // @param {Element} element The element to be added as the last child of {@link target}.
167 // @param {Element} target The parent element to relieve the new node.
168 // @param {Boolean} [moveCurrent=false] Don't change the "currentNode" global unless
169 // there's a return point node specified on the element, otherwise move current onto {@link target} node.
170 //
171 function addElement( element, target, moveCurrent ) {
172 target = target || currentNode || root;
173
174 // Current element might be mangled by fix body below,
175 // save it for restore later.
176 var savedCurrent = currentNode;
177
178 // Ignore any element that has already been added.
179 if ( element.previous === undefined ) {
180 if ( checkAutoParagraphing( target, element ) ) {
181 // Create a <p> in the fragment.
182 currentNode = target;
183 parser.onTagOpen( fixingBlock, {} );
184
185 // The new target now is the <p>.
186 element.returnPoint = target = currentNode;
187 }
188
189 removeTailWhitespace( element );
190
191 // Avoid adding empty inline.
192 if ( !( isRemoveEmpty( element ) && !element.children.length ) )
193 target.add( element );
194
195 if ( element.name == 'pre' )
196 inPre = false;
197
198 if ( element.name == 'textarea' )
199 inTextarea = false;
200 }
201
202 if ( element.returnPoint ) {
203 currentNode = element.returnPoint;
204 delete element.returnPoint;
205 } else {
206 currentNode = moveCurrent ? target : savedCurrent;
207 }
208 }
209
210 // Auto paragraphing should happen when inline content enters the root element.
211 function checkAutoParagraphing( parent, node ) {
212
213 // Check for parent that can contain block.
214 if ( ( parent == root || parent.name == 'body' ) && fixingBlock &&
215 ( !parent.name || CKEDITOR.dtd[ parent.name ][ fixingBlock ] ) ) {
216 var name, realName;
217
218 if ( node.attributes && ( realName = node.attributes[ 'data-cke-real-element-type' ] ) )
219 name = realName;
220 else
221 name = node.name;
222
223 // Text node, inline elements are subjected, except for <script>/<style>.
224 return name && name in CKEDITOR.dtd.$inline &&
225 !( name in CKEDITOR.dtd.head ) &&
226 !node.isOrphan ||
227 node.type == CKEDITOR.NODE_TEXT;
228 }
229 }
230
231 // Judge whether two element tag names are likely the siblings from the same
232 // structural element.
233 function possiblySibling( tag1, tag2 ) {
234
235 if ( tag1 in CKEDITOR.dtd.$listItem || tag1 in CKEDITOR.dtd.$tableContent )
236 return tag1 == tag2 || tag1 == 'dt' && tag2 == 'dd' || tag1 == 'dd' && tag2 == 'dt';
237
238 return false;
239 }
240
241 parser.onTagOpen = function( tagName, attributes, selfClosing, optionalClose ) {
242 var element = new CKEDITOR.htmlParser.element( tagName, attributes );
243
244 // "isEmpty" will be always "false" for unknown elements, so we
245 // must force it if the parser has identified it as a selfClosing tag.
246 if ( element.isUnknown && selfClosing )
247 element.isEmpty = true;
248
249 // Check for optional closed elements, including browser quirks and manually opened blocks.
250 element.isOptionalClose = optionalClose;
251
252 // This is a tag to be removed if empty, so do not add it immediately.
253 if ( isRemoveEmpty( element ) ) {
254 pendingInline.push( element );
255 return;
256 } else if ( tagName == 'pre' )
257 inPre = true;
258 else if ( tagName == 'br' && inPre ) {
259 currentNode.add( new CKEDITOR.htmlParser.text( '\n' ) );
260 return;
261 } else if ( tagName == 'textarea' ) {
262 inTextarea = true;
263 }
264
265 if ( tagName == 'br' ) {
266 pendingBRs.push( element );
267 return;
268 }
269
270 while ( 1 ) {
271 var currentName = currentNode.name;
272
273 var currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
274
275 // If the element cannot be child of the current element.
276 if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) {
277 // Current node doesn't have a close tag, time for a close
278 // as this element isn't fit in. (#7497)
279 if ( currentNode.isOptionalClose )
280 parser.onTagClose( currentName );
281 // Fixing malformed nested lists by moving it into a previous list item. (#3828)
282 else if ( tagName in listBlocks && currentName in listBlocks ) {
283 var children = currentNode.children,
284 lastChild = children[ children.length - 1 ];
285
286 // Establish the list item if it's not existed.
287 if ( !( lastChild && lastChild.name == 'li' ) )
288 addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
289
290 !element.returnPoint && ( element.returnPoint = currentNode );
291 currentNode = lastChild;
292 }
293 // Establish new list root for orphan list items, but NOT to create
294 // new list for the following ones, fix them instead. (#6975)
295 // <dl><dt>foo<dd>bar</dl>
296 // <ul><li>foo<li>bar</ul>
297 else if ( tagName in CKEDITOR.dtd.$listItem &&
298 !possiblySibling( tagName, currentName ) ) {
299 parser.onTagOpen( tagName == 'li' ? 'ul' : 'dl', {}, 0, 1 );
300 }
301 // We're inside a structural block like table and list, AND the incoming element
302 // is not of the same type (e.g. <td>td1<td>td2</td>), we simply add this new one before it,
303 // and most importantly, return back to here once this element is added,
304 // e.g. <table><tr><td>td1</td><p>p1</p><td>td2</td></tr></table>
305 else if ( currentName in nonBreakingBlocks &&
306 !possiblySibling( tagName, currentName ) ) {
307 !element.returnPoint && ( element.returnPoint = currentNode );
308 currentNode = currentNode.parent;
309 } else {
310 // The current element is an inline element, which
311 // need to be continued even after the close, so put
312 // it in the pending list.
313 if ( currentName in CKEDITOR.dtd.$inline )
314 pendingInline.unshift( currentNode );
315
316 // The most common case where we just need to close the
317 // current one and append the new one to the parent.
318 if ( currentNode.parent )
319 addElement( currentNode, currentNode.parent, 1 );
320 // We've tried our best to fix the embarrassment here, while
321 // this element still doesn't find it's parent, mark it as
322 // orphan and show our tolerance to it.
323 else {
324 element.isOrphan = 1;
325 break;
326 }
327 }
328 } else {
329 break;
330 }
331 }
332
333 checkPending( tagName );
334 sendPendingBRs();
335
336 element.parent = currentNode;
337
338 if ( element.isEmpty )
339 addElement( element );
340 else
341 currentNode = element;
342 };
343
344 parser.onTagClose = function( tagName ) {
345 // Check if there is any pending tag to be closed.
346 for ( var i = pendingInline.length - 1; i >= 0; i-- ) {
347 // If found, just remove it from the list.
348 if ( tagName == pendingInline[ i ].name ) {
349 pendingInline.splice( i, 1 );
350 return;
351 }
352 }
353
354 var pendingAdd = [],
355 newPendingInline = [],
356 candidate = currentNode;
357
358 while ( candidate != root && candidate.name != tagName ) {
359 // If this is an inline element, add it to the pending list, if we're
360 // really closing one of the parents element later, they will continue
361 // after it.
362 if ( !candidate._.isBlockLike )
363 newPendingInline.unshift( candidate );
364
365 // This node should be added to it's parent at this point. But,
366 // it should happen only if the closing tag is really closing
367 // one of the nodes. So, for now, we just cache it.
368 pendingAdd.push( candidate );
369
370 // Make sure return point is properly restored.
371 candidate = candidate.returnPoint || candidate.parent;
372 }
373
374 if ( candidate != root ) {
375 // Add all elements that have been found in the above loop.
376 for ( i = 0; i < pendingAdd.length; i++ ) {
377 var node = pendingAdd[ i ];
378 addElement( node, node.parent );
379 }
380
381 currentNode = candidate;
382
383 if ( candidate._.isBlockLike )
384 sendPendingBRs();
385
386 addElement( candidate, candidate.parent );
387
388 // The parent should start receiving new nodes now, except if
389 // addElement changed the currentNode.
390 if ( candidate == currentNode )
391 currentNode = currentNode.parent;
392
393 pendingInline = pendingInline.concat( newPendingInline );
394 }
395
396 if ( tagName == 'body' )
397 fixingBlock = false;
398 };
399
400 parser.onText = function( text ) {
401 // Trim empty spaces at beginning of text contents except <pre> and <textarea>.
402 if ( ( !currentNode._.hasInlineStarted || pendingBRs.length ) && !inPre && !inTextarea ) {
403 text = CKEDITOR.tools.ltrim( text );
404
405 if ( text.length === 0 )
406 return;
407 }
408
409 var currentName = currentNode.name,
410 currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
411
412 // Fix orphan text in list/table. (#8540) (#8870)
413 if ( !inTextarea && !currentDtd[ '#' ] && currentName in nonBreakingBlocks ) {
414 parser.onTagOpen( structureFixes[ currentName ] || '' );
415 parser.onText( text );
416 return;
417 }
418
419 sendPendingBRs();
420 checkPending();
421
422 // Shrinking consequential spaces into one single for all elements
423 // text contents.
424 if ( !inPre && !inTextarea )
425 text = text.replace( /[\t\r\n ]{2,}|[\t\r\n]/g, ' ' );
426
427 text = new CKEDITOR.htmlParser.text( text );
428
429
430 if ( checkAutoParagraphing( currentNode, text ) )
431 this.onTagOpen( fixingBlock, {}, 0, 1 );
432
433 currentNode.add( text );
434 };
435
436 parser.onCDATA = function( cdata ) {
437 currentNode.add( new CKEDITOR.htmlParser.cdata( cdata ) );
438 };
439
440 parser.onComment = function( comment ) {
441 sendPendingBRs();
442 checkPending();
443 currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
444 };
445
446 // Parse it.
447 parser.parse( fragmentHtml );
448
449 sendPendingBRs();
450
451 // Close all pending nodes, make sure return point is properly restored.
452 while ( currentNode != root )
453 addElement( currentNode, currentNode.parent, 1 );
454
455 removeTailWhitespace( root );
456
457 return root;
458 };
459
460 CKEDITOR.htmlParser.fragment.prototype = {
461
462 /**
463 * The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
464 *
465 * @readonly
466 * @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
467 */
468 type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
469
470 /**
471 * Adds a node to this fragment.
472 *
473 * @param {CKEDITOR.htmlParser.node} node The node to be added.
474 * @param {Number} [index] From where the insertion happens.
475 */
476 add: function( node, index ) {
477 isNaN( index ) && ( index = this.children.length );
478
479 var previous = index > 0 ? this.children[ index - 1 ] : null;
480 if ( previous ) {
481 // If the block to be appended is following text, trim spaces at
482 // the right of it.
483 if ( node._.isBlockLike && previous.type == CKEDITOR.NODE_TEXT ) {
484 previous.value = CKEDITOR.tools.rtrim( previous.value );
485
486 // If we have completely cleared the previous node.
487 if ( previous.value.length === 0 ) {
488 // Remove it from the list and add the node again.
489 this.children.pop();
490 this.add( node );
491 return;
492 }
493 }
494
495 previous.next = node;
496 }
497
498 node.previous = previous;
499 node.parent = this;
500
501 this.children.splice( index, 0, node );
502
503 if ( !this._.hasInlineStarted )
504 this._.hasInlineStarted = node.type == CKEDITOR.NODE_TEXT || ( node.type == CKEDITOR.NODE_ELEMENT && !node._.isBlockLike );
505 },
506
507 /**
508 * Filter this fragment's content with given filter.
509 *
510 * @since 4.1
511 * @param {CKEDITOR.htmlParser.filter} filter
512 */
513 filter: function( filter, context ) {
514 context = this.getFilterContext( context );
515
516 // Apply the root filter.
517 filter.onRoot( context, this );
518
519 this.filterChildren( filter, false, context );
520 },
521
522 /**
523 * Filter this fragment's children with given filter.
524 *
525 * Element's children may only be filtered once by one
526 * instance of filter.
527 *
528 * @since 4.1
529 * @param {CKEDITOR.htmlParser.filter} filter
530 * @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
531 */
532 filterChildren: function( filter, filterRoot, context ) {
533 // If this element's children were already filtered
534 // by current filter, don't filter them 2nd time.
535 // This situation may occur when filtering bottom-up
536 // (filterChildren() called manually in element's filter),
537 // or in unpredictable edge cases when filter
538 // is manipulating DOM structure.
539 if ( this.childrenFilteredBy == filter.id )
540 return;
541
542 context = this.getFilterContext( context );
543
544 // Filtering root if enforced.
545 if ( filterRoot && !this.parent )
546 filter.onRoot( context, this );
547
548 this.childrenFilteredBy = filter.id;
549
550 // Don't cache anything, children array may be modified by filter rule.
551 for ( var i = 0; i < this.children.length; i++ ) {
552 // Stay in place if filter returned false, what means
553 // that node has been removed.
554 if ( this.children[ i ].filter( filter, context ) === false )
555 i--;
556 }
557 },
558
559 /**
560 * Writes the fragment HTML to a {@link CKEDITOR.htmlParser.basicWriter}.
561 *
562 * var writer = new CKEDITOR.htmlWriter();
563 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<P><B>Example' );
564 * fragment.writeHtml( writer );
565 * alert( writer.getHtml() ); // '<p><b>Example</b></p>'
566 *
567 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
568 * @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
569 */
570 writeHtml: function( writer, filter ) {
571 if ( filter )
572 this.filter( filter );
573
574 this.writeChildrenHtml( writer );
575 },
576
577 /**
578 * Write and filtering the child nodes of this fragment.
579 *
580 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
581 * @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
582 * @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
583 */
584 writeChildrenHtml: function( writer, filter, filterRoot ) {
585 var context = this.getFilterContext();
586
587 // Filtering root if enforced.
588 if ( filterRoot && !this.parent && filter )
589 filter.onRoot( context, this );
590
591 if ( filter )
592 this.filterChildren( filter, false, context );
593
594 for ( var i = 0, children = this.children, l = children.length; i < l; i++ )
595 children[ i ].writeHtml( writer );
596 },
597
598 /**
599 * Execute callback on each node (of given type) in this document fragment.
600 *
601 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>foo<b>bar</b>bom</p>' );
602 * fragment.forEach( function( node ) {
603 * console.log( node );
604 * } );
605 * // Will log:
606 * // 1. document fragment,
607 * // 2. <p> element,
608 * // 3. "foo" text node,
609 * // 4. <b> element,
610 * // 5. "bar" text node,
611 * // 6. "bom" text node.
612 *
613 * @since 4.1
614 * @param {Function} callback Function to be executed on every node.
615 * **Since 4.3** if `callback` returned `false` descendants of current node will be ignored.
616 * @param {CKEDITOR.htmlParser.node} callback.node Node passed as argument.
617 * @param {Number} [type] If specified `callback` will be executed only on nodes of this type.
618 * @param {Boolean} [skipRoot] Don't execute `callback` on this fragment.
619 */
620 forEach: function( callback, type, skipRoot ) {
621 if ( !skipRoot && ( !type || this.type == type ) )
622 var ret = callback( this );
623
624 // Do not filter children if callback returned false.
625 if ( ret === false )
626 return;
627
628 var children = this.children,
629 node,
630 i = 0;
631
632 // We do not cache the size, because the list of nodes may be changed by the callback.
633 for ( ; i < children.length; i++ ) {
634 node = children[ i ];
635 if ( node.type == CKEDITOR.NODE_ELEMENT )
636 node.forEach( callback, type );
637 else if ( !type || node.type == type )
638 callback( node );
639 }
640 },
641
642 getFilterContext: function( context ) {
643 return context || {};
644 }
645 };
646} )();
diff --git a/sources/core/htmlparser/node.js b/sources/core/htmlparser/node.js
new file mode 100644
index 0000000..b38c8a8
--- /dev/null
+++ b/sources/core/htmlparser/node.js
@@ -0,0 +1,156 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8( function() {
9 /**
10 * A lightweight representation of HTML node.
11 *
12 * @since 4.1
13 * @class
14 * @constructor Creates a node class instance.
15 */
16 CKEDITOR.htmlParser.node = function() {};
17
18 CKEDITOR.htmlParser.node.prototype = {
19 /**
20 * Remove this node from a tree.
21 *
22 * @since 4.1
23 */
24 remove: function() {
25 var children = this.parent.children,
26 index = CKEDITOR.tools.indexOf( children, this ),
27 previous = this.previous,
28 next = this.next;
29
30 previous && ( previous.next = next );
31 next && ( next.previous = previous );
32 children.splice( index, 1 );
33 this.parent = null;
34 },
35
36 /**
37 * Replace this node with given one.
38 *
39 * @since 4.1
40 * @param {CKEDITOR.htmlParser.node} node The node that will replace this one.
41 */
42 replaceWith: function( node ) {
43 var children = this.parent.children,
44 index = CKEDITOR.tools.indexOf( children, this ),
45 previous = node.previous = this.previous,
46 next = node.next = this.next;
47
48 previous && ( previous.next = node );
49 next && ( next.previous = node );
50
51 children[ index ] = node;
52
53 node.parent = this.parent;
54 this.parent = null;
55 },
56
57 /**
58 * Insert this node after given one.
59 *
60 * @since 4.1
61 * @param {CKEDITOR.htmlParser.node} node The node that will precede this element.
62 */
63 insertAfter: function( node ) {
64 var children = node.parent.children,
65 index = CKEDITOR.tools.indexOf( children, node ),
66 next = node.next;
67
68 children.splice( index + 1, 0, this );
69
70 this.next = node.next;
71 this.previous = node;
72 node.next = this;
73 next && ( next.previous = this );
74
75 this.parent = node.parent;
76 },
77
78 /**
79 * Insert this node before given one.
80 *
81 * @since 4.1
82 * @param {CKEDITOR.htmlParser.node} node The node that will follow this element.
83 */
84 insertBefore: function( node ) {
85 var children = node.parent.children,
86 index = CKEDITOR.tools.indexOf( children, node );
87
88 children.splice( index, 0, this );
89
90 this.next = node;
91 this.previous = node.previous;
92 node.previous && ( node.previous.next = this );
93 node.previous = this;
94
95 this.parent = node.parent;
96 },
97
98 /**
99 * Gets the closest ancestor element of this element which satisfies given condition
100 *
101 * @since 4.3
102 * @param {String/Object/Function} condition Name of an ancestor, hash of names or validator function.
103 * @returns {CKEDITOR.htmlParser.element} The closest ancestor which satisfies given condition or `null`.
104 */
105 getAscendant: function( condition ) {
106 var checkFn =
107 typeof condition == 'function' ?
108 condition :
109 typeof condition == 'string' ?
110 function( el ) {
111 return el.name == condition;
112 } :
113 function( el ) {
114 return el.name in condition;
115 };
116
117 var parent = this.parent;
118
119 // Parent has to be an element - don't check doc fragment.
120 while ( parent && parent.type == CKEDITOR.NODE_ELEMENT ) {
121 if ( checkFn( parent ) )
122 return parent;
123 parent = parent.parent;
124 }
125
126 return null;
127 },
128
129 /**
130 * Wraps this element with given `wrapper`.
131 *
132 * @since 4.3
133 * @param {CKEDITOR.htmlParser.element} wrapper The element which will be this element's new parent.
134 * @returns {CKEDITOR.htmlParser.element} Wrapper.
135 */
136 wrapWith: function( wrapper ) {
137 this.replaceWith( wrapper );
138 wrapper.add( this );
139 return wrapper;
140 },
141
142 /**
143 * Gets this node's index in its parent's children array.
144 *
145 * @since 4.3
146 * @returns {Number}
147 */
148 getIndex: function() {
149 return CKEDITOR.tools.indexOf( this.parent.children, this );
150 },
151
152 getFilterContext: function( context ) {
153 return context || {};
154 }
155 };
156} )();
diff --git a/sources/core/htmlparser/text.js b/sources/core/htmlparser/text.js
new file mode 100644
index 0000000..190e85a
--- /dev/null
+++ b/sources/core/htmlparser/text.js
@@ -0,0 +1,70 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 'use strict';
7
8( function() {
9 /**
10 * A lightweight representation of HTML text.
11 *
12 * @class
13 * @extends CKEDITOR.htmlParser.node
14 * @constructor Creates a text class instance.
15 * @param {String} value The text node value.
16 */
17 CKEDITOR.htmlParser.text = function( value ) {
18 /**
19 * The text value.
20 *
21 * @property {String}
22 */
23 this.value = value;
24
25 /** @private */
26 this._ = {
27 isBlockLike: false
28 };
29 };
30
31 CKEDITOR.htmlParser.text.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
32 /**
33 * The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
34 *
35 * @readonly
36 * @property {Number} [=CKEDITOR.NODE_TEXT]
37 */
38 type: CKEDITOR.NODE_TEXT,
39
40 /**
41 * Filter this text node with given filter.
42 *
43 * @since 4.1
44 * @param {CKEDITOR.htmlParser.filter} filter
45 * @returns {Boolean} Method returns `false` when this text node has
46 * been removed. This is an information for {@link CKEDITOR.htmlParser.element#filterChildren}
47 * that it has to repeat filter on current position in parent's children array.
48 */
49 filter: function( filter, context ) {
50 if ( !( this.value = filter.onText( context, this.value, this ) ) ) {
51 this.remove();
52 return false;
53 }
54 },
55
56 /**
57 * Writes the HTML representation of this text to a {CKEDITOR.htmlParser.basicWriter}.
58 *
59 * @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
60 * @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
61 * **Note:** it's unsafe to filter offline (not appended) node.
62 */
63 writeHtml: function( writer, filter ) {
64 if ( filter )
65 this.filter( filter );
66
67 writer.text( this.value );
68 }
69 } );
70} )();
diff --git a/sources/core/keystrokehandler.js b/sources/core/keystrokehandler.js
new file mode 100644
index 0000000..c84089b
--- /dev/null
+++ b/sources/core/keystrokehandler.js
@@ -0,0 +1,169 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Controls keystrokes typing in an editor instance.
8 *
9 * @class
10 * @constructor Creates a keystrokeHandler class instance.
11 * @param {CKEDITOR.editor} editor The editor instance.
12 */
13CKEDITOR.keystrokeHandler = function( editor ) {
14 if ( editor.keystrokeHandler )
15 return editor.keystrokeHandler;
16
17 /**
18 * A list of keystrokes associated with commands. Each entry points to the
19 * command to be executed.
20 *
21 * Since CKEditor 4 there is no need to modify this property directly during the runtime.
22 * Use {@link CKEDITOR.editor#setKeystroke} instead.
23 */
24 this.keystrokes = {};
25
26 /**
27 * A list of keystrokes that should be blocked if not defined in
28 * {@link #keystrokes}. In this way it is possible to block the default
29 * browser behavior for those keystrokes.
30 */
31 this.blockedKeystrokes = {};
32
33 this._ = {
34 editor: editor
35 };
36
37 return this;
38};
39
40( function() {
41 var cancel;
42
43 var onKeyDown = function( event ) {
44 // The DOM event object is passed by the "data" property.
45 event = event.data;
46
47 var keyCombination = event.getKeystroke();
48 var command = this.keystrokes[ keyCombination ];
49 var editor = this._.editor;
50
51 cancel = ( editor.fire( 'key', { keyCode: keyCombination, domEvent: event } ) === false );
52
53 if ( !cancel ) {
54 if ( command ) {
55 var data = { from: 'keystrokeHandler' };
56 cancel = ( editor.execCommand( command, data ) !== false );
57 }
58
59 if ( !cancel )
60 cancel = !!this.blockedKeystrokes[ keyCombination ];
61 }
62
63 if ( cancel )
64 event.preventDefault( true );
65
66 return !cancel;
67 };
68
69 var onKeyPress = function( event ) {
70 if ( cancel ) {
71 cancel = false;
72 event.data.preventDefault( true );
73 }
74 };
75
76 CKEDITOR.keystrokeHandler.prototype = {
77 /**
78 * Attaches this keystroke handle to a DOM object. Keystrokes typed
79 * over this object will be handled by this keystrokeHandler.
80 *
81 * @param {CKEDITOR.dom.domObject} domObject The DOM object to attach to.
82 */
83 attach: function( domObject ) {
84 // For most browsers, it is enough to listen to the keydown event
85 // only.
86 domObject.on( 'keydown', onKeyDown, this );
87
88 // Some browsers instead, don't cancel key events in the keydown, but in the
89 // keypress. So we must do a longer trip in those cases.
90 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
91 domObject.on( 'keypress', onKeyPress, this );
92 }
93 };
94} )();
95
96/**
97 * A list associating keystrokes with editor commands. Each element in the list
98 * is an array where the first item is the keystroke, and the second is the
99 * name of the command to be executed.
100 *
101 * This setting should be used to define (as well as to overwrite or remove) keystrokes
102 * set by plugins (like `link` and `basicstyles`). If you want to set a keystroke
103 * for your plugin or during the runtime, use {@link CKEDITOR.editor#setKeystroke} instead.
104 *
105 * Since default keystrokes are set by the {@link CKEDITOR.editor#setKeystroke}
106 * method, by default `config.keystrokes` is an empty array.
107 *
108 * See {@link CKEDITOR.editor#setKeystroke} documentation for more details
109 * regarding the start up order.
110 *
111 * // Change default Ctrl+L keystroke for 'link' command to Ctrl+Shift+L.
112 * config.keystrokes = [
113 * ...
114 * [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 76, 'link' ], // Ctrl+Shift+L
115 * ...
116 * ];
117 *
118 * To reset a particular keystroke, the following approach can be used:
119 *
120 * // Disable default Ctrl+L keystroke which executes the 'link' command by default.
121 * config.keystrokes = [
122 * ...
123 * [ CKEDITOR.CTRL + 76, null ], // Ctrl+L
124 * ...
125 * ];
126 *
127 * In order to reset all default keystrokes, a {@link CKEDITOR#instanceReady} callback should be
128 * used. This is since editor defaults are merged rather than overwritten by
129 * user keystrokes.
130 *
131 * **Note**: This can be potentially harmful for the editor. Avoid this unless you are
132 * aware of the consequences.
133 *
134 * // Reset all default keystrokes.
135 * config.on.instanceReady = function() {
136 * this.keystrokeHandler.keystrokes = [];
137 * };
138 *
139 * @cfg {Array} [keystrokes=[]]
140 * @member CKEDITOR.config
141 */
142
143/**
144 * Fired when any keyboard key (or a combination thereof) is pressed in the editing area.
145 *
146 * editor.on( 'key', function( evt ) {
147 * if ( evt.data.keyCode == CKEDITOR.CTRL + 90 ) {
148 * // Do something...
149 *
150 * // Cancel the event, so other listeners will not be executed and
151 * // the keydown's default behavior will be prevented.
152 * evt.cancel();
153 * }
154 * } );
155 *
156 * Usually you will want to use the {@link CKEDITOR.editor#setKeystroke} method or
157 * the {@link CKEDITOR.config#keystrokes} option to attach a keystroke to some {@link CKEDITOR.command command}.
158 * Key event listeners are usuful when some action should be executed conditionally, based
159 * for example on precise selection location.
160 *
161 * @event key
162 * @member CKEDITOR.editor
163 * @param data
164 * @param {Number} data.keyCode A number representing the key code (or a combination thereof).
165 * It is the sum of the current key code and the {@link CKEDITOR#CTRL}, {@link CKEDITOR#SHIFT}
166 * and {@link CKEDITOR#ALT} constants, if those are pressed.
167 * @param {CKEDITOR.dom.event} data.domEvent A `keydown` DOM event instance. Available since CKEditor 4.4.1.
168 * @param {CKEDITOR.editor} editor This editor instance.
169 */
diff --git a/sources/core/lang.js b/sources/core/lang.js
new file mode 100644
index 0000000..8766055
--- /dev/null
+++ b/sources/core/lang.js
@@ -0,0 +1,103 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 /**
8 * Stores language-related functions.
9 *
10 * @class
11 * @singleton
12 */
13 CKEDITOR.lang = {
14 /**
15 * The list of languages available in the editor core.
16 *
17 * alert( CKEDITOR.lang.languages.en ); // 1
18 */
19 languages: {
20 af: 1, ar: 1, az: 1, bg: 1, bn: 1, bs: 1, ca: 1, cs: 1, cy: 1, da: 1, de: 1, 'de-ch': 1, el: 1,
21 'en-au': 1, 'en-ca': 1, 'en-gb': 1, en: 1, eo: 1, es: 1, et: 1, eu: 1, fa: 1, fi: 1, fo: 1,
22 'fr-ca': 1, fr: 1, gl: 1, gu: 1, he: 1, hi: 1, hr: 1, hu: 1, id: 1, is: 1, it: 1, ja: 1, ka: 1,
23 km: 1, ko: 1, ku: 1, lt: 1, lv: 1, mk: 1, mn: 1, ms: 1, nb: 1, nl: 1, no: 1, oc: 1, pl: 1, 'pt-br': 1,
24 pt: 1, ro: 1, ru: 1, si: 1, sk: 1, sl: 1, sq: 1, 'sr-latn': 1, sr: 1, sv: 1, th: 1, tr: 1, tt: 1, ug: 1,
25 uk: 1, vi: 1, 'zh-cn': 1, zh: 1
26 },
27
28 /**
29 * The list of languages that are written Right-To-Left (RTL) and are supported by the editor.
30 */
31 rtl: { ar: 1, fa: 1, he: 1, ku: 1, ug: 1 },
32
33 /**
34 * Loads a specific language file, or auto detects it. A callback is
35 * then called when the file gets loaded.
36 *
37 * @param {String} languageCode The code of the language file to be
38 * loaded. If null or empty, autodetection will be performed. The
39 * same happens if the language is not supported.
40 * @param {String} defaultLanguage The language to be used if
41 * `languageCode` is not supported or if the autodetection fails.
42 * @param {Function} callback A function to be called once the
43 * language file is loaded. Two parameters are passed to this
44 * function: the language code and the loaded language entries.
45 */
46 load: function( languageCode, defaultLanguage, callback ) {
47 // If no languageCode - fallback to browser or default.
48 // If languageCode - fallback to no-localized version or default.
49 if ( !languageCode || !CKEDITOR.lang.languages[ languageCode ] )
50 languageCode = this.detect( defaultLanguage, languageCode );
51
52 var that = this,
53 loadedCallback = function() {
54 that[ languageCode ].dir = that.rtl[ languageCode ] ? 'rtl' : 'ltr';
55 callback( languageCode, that[ languageCode ] );
56 };
57
58 if ( !this[ languageCode ] )
59 CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( 'lang/' + languageCode + '.js' ), loadedCallback, this );
60 else
61 loadedCallback();
62 },
63
64 /**
65 * Returns the language that best fits the user language. For example,
66 * suppose that the user language is "pt-br". If this language is
67 * supported by the editor, it is returned. Otherwise, if only "pt" is
68 * supported, it is returned instead. If none of the previous are
69 * supported, a default language is then returned.
70 *
71 * alert( CKEDITOR.lang.detect( 'en' ) ); // e.g., in a German browser: 'de'
72 *
73 * @param {String} defaultLanguage The default language to be returned
74 * if the user language is not supported.
75 * @param {String} [probeLanguage] A language code to try to use,
76 * instead of the browser-based autodetection.
77 * @returns {String} The detected language code.
78 */
79 detect: function( defaultLanguage, probeLanguage ) {
80 var languages = this.languages;
81 probeLanguage = probeLanguage || navigator.userLanguage || navigator.language || defaultLanguage;
82
83 var parts = probeLanguage.toLowerCase().match( /([a-z]+)(?:-([a-z]+))?/ ),
84 lang = parts[ 1 ],
85 locale = parts[ 2 ];
86
87 if ( languages[ lang + '-' + locale ] )
88 lang = lang + '-' + locale;
89 else if ( !languages[ lang ] )
90 lang = null;
91
92 CKEDITOR.lang.detect = lang ?
93 function() {
94 return lang;
95 } : function( defaultLanguage ) {
96 return defaultLanguage;
97 };
98
99 return lang || defaultLanguage;
100 }
101 };
102
103} )();
diff --git a/sources/core/loader.js b/sources/core/loader.js
new file mode 100644
index 0000000..249a8cf
--- /dev/null
+++ b/sources/core/loader.js
@@ -0,0 +1,225 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.loader} objects, which is used to
8 * load core scripts and their dependencies from _source.
9 */
10
11if ( typeof CKEDITOR == 'undefined' )
12 CKEDITOR = {}; // jshint ignore:line
13
14if ( !CKEDITOR.loader ) {
15 /**
16 * Load core scripts and their dependencies from _source.
17 *
18 * @class
19 * @singleton
20 */
21 CKEDITOR.loader = ( function() {
22 // Table of script names and their dependencies.
23 var scripts = {
24 '_bootstrap': [
25 'config', 'creators/inline', 'creators/themedui', 'editable', 'ckeditor', 'plugins',
26 'scriptloader', 'style', 'tools',
27 // The following are entries that we want to force loading at the end to avoid dependence recursion.
28 'dom/comment', 'dom/elementpath', 'dom/text', 'dom/rangelist', 'skin'
29 ],
30 'ckeditor': [
31 'ckeditor_basic', 'log', 'dom', 'dtd', 'dom/document', 'dom/element', 'dom/iterator', 'editor', 'event',
32 'htmldataprocessor', 'htmlparser', 'htmlparser/element', 'htmlparser/fragment', 'htmlparser/filter',
33 'htmlparser/basicwriter', 'template', 'tools'
34 ],
35 'ckeditor_base': [],
36 'ckeditor_basic': [ 'editor_basic', 'env', 'event' ],
37 'command': [],
38 'config': [ 'ckeditor_base' ],
39 'dom': [],
40 'dom/comment': [ 'dom/node' ],
41 'dom/document': [ 'dom/node', 'dom/window' ],
42 'dom/documentfragment': [ 'dom/element' ],
43 'dom/element': [ 'dom', 'dom/document', 'dom/domobject', 'dom/node', 'dom/nodelist', 'tools' ],
44 'dom/elementpath': [ 'dom/element' ],
45 'dom/event': [],
46 'dom/iterator': [ 'dom/range' ],
47 'dom/node': [ 'dom/domobject', 'tools' ],
48 'dom/nodelist': [ 'dom/node' ],
49 'dom/domobject': [ 'dom/event' ],
50 'dom/range': [ 'dom/document', 'dom/documentfragment', 'dom/element', 'dom/walker' ],
51 'dom/rangelist': [ 'dom/range' ],
52 'dom/text': [ 'dom/node', 'dom/domobject' ],
53 'dom/walker': [ 'dom/node' ],
54 'dom/window': [ 'dom/domobject' ],
55 'dtd': [ 'tools' ],
56 'editable': [ 'editor', 'tools' ],
57 'editor': [
58 'command', 'config', 'editor_basic', 'filter', 'focusmanager', 'keystrokehandler', 'lang',
59 'plugins', 'tools', 'ui'
60 ],
61 'editor_basic': [ 'event' ],
62 'env': [],
63 'event': [],
64 'filter': [ 'dtd', 'tools' ],
65 'focusmanager': [],
66 'htmldataprocessor': [ 'htmlparser', 'htmlparser/basicwriter', 'htmlparser/fragment', 'htmlparser/filter' ],
67 'htmlparser': [],
68 'htmlparser/comment': [ 'htmlparser', 'htmlparser/node' ],
69 'htmlparser/element': [ 'htmlparser', 'htmlparser/fragment', 'htmlparser/node' ],
70 'htmlparser/fragment': [ 'htmlparser', 'htmlparser/comment', 'htmlparser/text', 'htmlparser/cdata' ],
71 'htmlparser/text': [ 'htmlparser', 'htmlparser/node' ],
72 'htmlparser/cdata': [ 'htmlparser', 'htmlparser/node' ],
73 'htmlparser/filter': [ 'htmlparser' ],
74 'htmlparser/basicwriter': [ 'htmlparser' ],
75 'htmlparser/node': [ 'htmlparser' ],
76 'keystrokehandler': [ 'event' ],
77 'lang': [],
78 'log': [ 'ckeditor_basic' ],
79 'plugins': [ 'resourcemanager' ],
80 'resourcemanager': [ 'scriptloader', 'tools' ],
81 'scriptloader': [ 'dom/element', 'env' ],
82 'selection': [ 'dom/range', 'dom/walker' ],
83 'skin': [],
84 'style': [ 'selection' ],
85 'template': [],
86 'tools': [ 'env' ],
87 'ui': [],
88 'creators/themedui': [],
89 'creators/inline': []
90 };
91
92 // The production implementation contains a fixed timestamp generated by the releaser.
93 var timestamp = '%TIMESTAMP%';
94 // The development implementation contains a current timestamp. // %REMOVE_LINE%
95 timestamp = ( CKEDITOR && CKEDITOR.timestamp ) || ( new Date() ).valueOf(); // %REMOVE_LINE%
96
97 var getUrl = function( resource ) {
98 if ( CKEDITOR && CKEDITOR.getUrl )
99 return CKEDITOR.getUrl( resource );
100
101 return CKEDITOR.basePath + resource + ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + timestamp;
102 };
103
104 var pendingLoad = [];
105
106 return {
107 /**
108 * The list of loaded scripts in their loading order.
109 *
110 * // Alert the loaded script names.
111 * alert( CKEDITOR.loader.loadedScripts );
112 */
113 loadedScripts: [],
114 /**
115 * Table of script names and their dependencies.
116 *
117 * @property {Array}
118 */
119 scripts: scripts,
120
121 /**
122 * @todo
123 */
124 loadPending: function() {
125 var scriptName = pendingLoad.shift();
126
127 if ( !scriptName )
128 return;
129
130 var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
131
132 var script = document.createElement( 'script' );
133 script.type = 'text/javascript';
134 script.src = scriptSrc;
135
136 function onScriptLoaded() {
137 // Append this script to the list of loaded scripts.
138 CKEDITOR.loader.loadedScripts.push( scriptName );
139
140 // Load the next.
141 CKEDITOR.loader.loadPending();
142 }
143
144 // We must guarantee the execution order of the scripts, so we
145 // need to load them one by one. (#4145)
146 // The following if/else block has been taken from the scriptloader core code.
147 if ( typeof script.onreadystatechange !== 'undefined' ) {
148 /** @ignore */
149 script.onreadystatechange = function() {
150 if ( script.readyState == 'loaded' || script.readyState == 'complete' ) {
151 script.onreadystatechange = null;
152 onScriptLoaded();
153 }
154 };
155 } else {
156 /** @ignore */
157 script.onload = function() {
158 // Some browsers, such as Safari, may call the onLoad function
159 // immediately. Which will break the loading sequence. (#3661)
160 setTimeout( function() {
161 onScriptLoaded( scriptName );
162 }, 0 );
163 };
164 }
165
166 document.body.appendChild( script );
167 },
168
169 /**
170 * Loads a specific script, including its dependencies. This is not a
171 * synchronous loading, which means that the code to be loaded will
172 * not necessarily be available after this call.
173 *
174 * CKEDITOR.loader.load( 'dom/element' );
175 *
176 * @param {String} scriptName
177 * @param {Boolean} [defer=false]
178 * @todo params
179 */
180 load: function( scriptName, defer ) {
181 // Check if the script has already been loaded.
182 if ( ( 's:' + scriptName ) in this.loadedScripts )
183 return;
184
185 // Get the script dependencies list.
186 var dependencies = scripts[ scriptName ];
187 if ( !dependencies )
188 throw 'The script name"' + scriptName + '" is not defined.';
189
190 // Mark the script as loaded, even before really loading it, to
191 // avoid cross references recursion.
192 // Prepend script name with 's:' to avoid conflict with Array's methods.
193 this.loadedScripts[ 's:' + scriptName ] = true;
194
195 // Load all dependencies first.
196 for ( var i = 0; i < dependencies.length; i++ )
197 this.load( dependencies[ i ], true );
198
199 var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
200
201 // Append the <script> element to the DOM.
202 // If the page is fully loaded, we can't use document.write
203 // but if the script is run while the body is loading then it's safe to use it
204 // Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement
205 if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) {
206 pendingLoad.push( scriptName );
207
208 if ( !defer )
209 this.loadPending();
210 } else {
211 // Append this script to the list of loaded scripts.
212 this.loadedScripts.push( scriptName );
213
214 document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' );
215 }
216 }
217 };
218 } )();
219}
220
221// Check if any script has been defined for autoload.
222if ( CKEDITOR._autoLoad ) {
223 CKEDITOR.loader.load( CKEDITOR._autoLoad );
224 delete CKEDITOR._autoLoad;
225}
diff --git a/sources/core/log.js b/sources/core/log.js
new file mode 100644
index 0000000..228789e
--- /dev/null
+++ b/sources/core/log.js
@@ -0,0 +1,127 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines {@link CKEDITOR#verbosity} and binary flags {@link CKEDITOR#VERBOSITY_WARN} and
8 * {@link CKEDITOR#VERBOSITY_ERROR}. Defines also the {@link CKEDITOR#error} and {@link CKEDITOR#warn} functions
9 * and the default handler for the {@link CKEDITOR#log} event.
10 */
11
12/* global console */
13
14'use strict';
15
16/**
17 * Warning reporting verbosity level. When {@link CKEDITOR#verbosity} is set to this value, only {@link CKEDITOR#warn}
18 * messages will be output to the console. It is a binary flag so it might be combined with
19 * the {@link CKEDITOR#VERBOSITY_ERROR} flag.
20 *
21 * @since 4.5.4
22 * @readonly
23 * @property {Number} [=1]
24 * @member CKEDITOR
25 */
26CKEDITOR.VERBOSITY_WARN = 1;
27
28/**
29 * Error reporting verbosity level. When {@link CKEDITOR#verbosity} is set to this value, only {@link CKEDITOR#error}
30 * messages will be output to the console. It is a binary flag so it might be combined with
31 * the {@link CKEDITOR#VERBOSITY_WARN} flag.
32 *
33 * @since 4.5.4
34 * @readonly
35 * @property {Number} [=2]
36 * @member CKEDITOR
37 */
38CKEDITOR.VERBOSITY_ERROR = 2;
39
40/**
41 * Verbosity of {@link CKEDITOR#error} and {@link CKEDITOR#warn} methods. Accepts binary flags
42 * {@link CKEDITOR#VERBOSITY_WARN} and {@link CKEDITOR#VERBOSITY_ERROR}.
43 *
44 * CKEDITOR.verbosity = 0; // No console output after CKEDITOR.warn and CKEDITOR.error methods.
45 * CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN; // Console output after CKEDITOR.warn only.
46 * CKEDITOR.verbosity = CKEDITOR.VERBOSITY_ERROR; // Console output after CKEDITOR.error only.
47 * CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN | CKEDITOR.VERBOSITY_ERROR; // Console output after both methods.
48 *
49 * Default value enables both {@link CKEDITOR#VERBOSITY_WARN} and {@link CKEDITOR#VERBOSITY_ERROR}.
50 *
51 * @since 4.5.4
52 * @member CKEDITOR
53 * @type {Number}
54 */
55CKEDITOR.verbosity = CKEDITOR.VERBOSITY_WARN | CKEDITOR.VERBOSITY_ERROR;
56
57/**
58 * Warning reporting function. When {@link CKEDITOR#verbosity} has the {@link CKEDITOR#VERBOSITY_WARN} flag set, it fires
59 * the {@link CKEDITOR#log} event with type set to `warn`. Fired event contains also provided `errorCode` and `additionalData`.
60 *
61 * @since 4.5.4
62 * @member CKEDITOR
63 * @param {String} errorCode Error code describing reported problem.
64 * @param {Object} [additionalData] Additional data associated with reported problem.
65 */
66CKEDITOR.warn = function( errorCode, additionalData ) {
67 if ( CKEDITOR.verbosity & CKEDITOR.VERBOSITY_WARN ) {
68 CKEDITOR.fire( 'log', { type: 'warn', errorCode: errorCode, additionalData: additionalData } );
69 }
70};
71
72/**
73 * Error reporting function. When {@link CKEDITOR#verbosity} has {@link CKEDITOR#VERBOSITY_ERROR} flag set, it fires
74 * {@link CKEDITOR#log} event with the type set to `error`. The fired event also contains the provided `errorCode` and
75 * `additionalData`.
76 *
77 * @since 4.5.4
78 * @member CKEDITOR
79 * @param {String} errorCode Error code describing the reported problem.
80 * @param {Object} [additionalData] Additional data associated with the reported problem.
81 */
82CKEDITOR.error = function( errorCode, additionalData ) {
83 if ( CKEDITOR.verbosity & CKEDITOR.VERBOSITY_ERROR ) {
84 CKEDITOR.fire( 'log', { type: 'error', errorCode: errorCode, additionalData: additionalData } );
85 }
86};
87
88/**
89 * Fired by {@link CKEDITOR#warn} and {@link CKEDITOR#error} methods.
90 * Default listener logs provided information to the console.
91 *
92 * This event can be used to provide a custom error/warning handler:
93 *
94 * CKEDTIOR.on( 'log', function( evt ) {
95 * // Cancel default listener.
96 * evt.cancel();
97 * // Log event data.
98 * console.log( evt.data.type, evt.data.errorCode, evt.data.additionalData );
99 * } );
100 *
101 * @since 4.5.4
102 * @event log
103 * @member CKEDITOR
104 * @param data
105 * @param {String} data.type Log type. Can be `error` or `warn`.
106 * @param {String} data.errorCode Error code describing the reported problem.
107 * @param {Object} [data.additionalData] Additional data associated with this log event.
108 */
109CKEDITOR.on( 'log', function( evt ) {
110 if ( !window.console || !window.console.log ) {
111 return;
112 }
113
114 var type = console[ evt.data.type ] ? evt.data.type : 'log',
115 errorCode = evt.data.errorCode,
116 additionalData = evt.data.additionalData,
117 prefix = '[CKEDITOR] ',
118 errorCodeLabel = 'Error code: ';
119
120 if ( additionalData ) {
121 console[ type ]( prefix + errorCodeLabel + errorCode + '.', additionalData );
122 } else {
123 console[ type ]( prefix + errorCodeLabel + errorCode + '.' );
124 }
125
126 console[ type ]( prefix + 'For more information about this error go to http://docs.ckeditor.com/#!/guide/dev_errors-section-' + errorCode );
127}, null, null, 999 );
diff --git a/sources/core/plugindefinition.js b/sources/core/plugindefinition.js
new file mode 100644
index 0000000..9ff7683
--- /dev/null
+++ b/sources/core/plugindefinition.js
@@ -0,0 +1,177 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the "virtual" {@link CKEDITOR.pluginDefinition} class which
8 * contains the defintion of a plugin. This file serves documentation
9 * purposes only.
10 */
11
12/**
13 * A virtual class that just illustrates the features of plugin objects which are
14 * passed to the {@link CKEDITOR.plugins#add} method.
15 *
16 * This class is not really a part of the API, so its constructor should not be called.
17 *
18 * See also:
19 *
20 * * [The Plugin SDK](#!/guide/plugin_sdk_intro)
21 * * [Creating a CKEditor plugin in 20 Lines of Code](#!/guide/plugin_sdk_sample)
22 * * [Creating a Simple Plugin Tutorial](#!/guide/plugin_sdk_sample_1)
23 *
24 * @class CKEDITOR.pluginDefinition
25 * @abstract
26 */
27
28/**
29 * A list of plugins that are required by this plugin. Note that this property
30 * does not determine the loading order of the plugins.
31 *
32 * CKEDITOR.plugins.add( 'sample', {
33 * requires: 'button,selection'
34 * } );
35 *
36 * Or:
37 *
38 * CKEDITOR.plugins.add( 'sample', {
39 * requires: [ 'button', 'selection' ]
40 * } );
41 *
42 * @property {String/String[]} requires
43 */
44
45/**
46 * The list of language files available for this plugin. These files are stored inside
47 * the `lang` directory in the plugin directory, follow the name
48 * pattern of `langCode.js`, and contain the language definition created with
49 * {@link CKEDITOR.plugins#setLang}.
50 *
51 * When the plugin is being loaded, the editor checks this list to see if
52 * a language file in the current editor language ({@link CKEDITOR.editor#langCode})
53 * is available, and if so, loads it. Otherwise, the file represented by the first item
54 * in the list is loaded.
55 *
56 * CKEDITOR.plugins.add( 'sample', {
57 * lang: 'en,fr'
58 * } );
59 *
60 * Or:
61 *
62 * CKEDITOR.plugins.add( 'sample', {
63 * lang: [ 'en', 'fr' ]
64 * } );
65 *
66 * @property {String/String[]} lang
67 */
68
69/**
70 * A function called when the plugin definition is loaded for the first time.
71 * It is usually used to execute some code once for the entire page,
72 * for instance code that uses the {@link CKEDITOR}'s methods such as the {@link CKEDITOR#addCss} method.
73 *
74 * CKEDITOR.plugins.add( 'sample', {
75 * onLoad: function() {
76 * CKEDITOR.addCss( '.cke_some_class { ... }' );
77 * }
78 * } );
79 *
80 * Read more about the initialization order in the {@link #init} method documentation.
81 *
82 * @method onLoad
83 */
84
85/**
86 * A function called on initialization of every editor instance created on the
87 * page before the {@link #init} call task. This feature makes it possible to
88 * initialize things that could be used in the `init` function of other plugins.
89 *
90 * CKEDITOR.plugins.add( 'sample1', {
91 * beforeInit: function( editor ) {
92 * editor.foo = 'bar';
93 * }
94 * } );
95 *
96 * CKEDITOR.plugins.add( 'sample2', {
97 * init: function( editor ) {
98 * // This will work regardless of order in which
99 * // plugins sample1 and sample2 where initialized.
100 * console.log( editor.foo ); // 'bar'
101 * }
102 * } );
103 *
104 * Read more about the initialization order in the {@link #init} method documentation.
105 *
106 * @method beforeInit
107 * @param {CKEDITOR.editor} editor The editor instance being initialized.
108 */
109
110/**
111 * A function called on initialization of every editor instance created on the page.
112 *
113 * CKEDITOR.plugins.add( 'sample', {
114 * init: function( editor ) {
115 * console.log( 'Editor "' + editor.name + '" is being initialized!' );
116 * }
117 * } );
118 *
119 * Initialization order:
120 *
121 * 1. The {@link #beforeInit} methods of all enabled plugins are executed.
122 * 2. The {@link #init} methods of all enabled plugins are executed.
123 * 3. The {@link #afterInit} methods of all enabled plugins are executed.
124 * 4. The {@link CKEDITOR.editor#pluginsLoaded} event is fired.
125 *
126 * **Note:** The order in which the `init` methods are called does not depend on the plugins' {@link #requires requirements}
127 * or the order set in the {@link CKEDITOR.config#plugins} option. It may be random and therefore it is
128 * recommended to use the {@link #beforeInit} and {@link #afterInit} methods in order to ensure
129 * the right execution sequence.
130 *
131 * See also the {@link #onLoad} method.
132 *
133 * @method init
134 * @param {CKEDITOR.editor} editor The editor instance being initialized.
135 */
136
137/**
138 * A function called on initialization of every editor instance created on the
139 * page after the {@link #init} call task. This feature makes it possible to use things
140 * that were initialized in the `init` function of other plugins.
141 *
142 * CKEDITOR.plugins.add( 'sample1', {
143 * afterInit: function( editor ) {
144 * // This will work regardless of order in which
145 * // plugins sample1 and sample2 where initialized.
146 * console.log( editor.foo ); // 'bar'
147 * }
148 * } );
149 *
150 * CKEDITOR.plugins.add( 'sample2', {
151 * init: function( editor ) {
152 * editor.foo = 'bar';
153 * }
154 * } );
155 *
156 * Read more about the initialization order in the {@link #init} method documentation.
157 *
158 * @method afterInit
159 * @param {CKEDITOR.editor} editor The editor instance being initialized.
160 */
161
162/**
163 * Announces the plugin as HiDPI-ready (optimized for high pixel density screens, e.g. *Retina*)
164 * by providing high-resolution icons and images. HiDPI icons must be twice as big
165 * (defaults are `16px x 16px`) and stored under `plugin_name/icons/hidpi/` directory.
166 *
167 * The common place for additional HiDPI images used by the plugin (**but not icons**)
168 * is the `plugin_name/images/hidpi/` directory.
169 *
170 * This property is optional and only makes sense if `32px x 32px` icons
171 * and high-resolution images actually exist. If this flag is set to `true`, the editor
172 * will automatically detect the HiDPI environment and attempt to load the
173 * high-resolution resources.
174 *
175 * @since 4.2
176 * @property {Boolean} hidpi
177 */
diff --git a/sources/core/plugins.js b/sources/core/plugins.js
new file mode 100644
index 0000000..75cc41e
--- /dev/null
+++ b/sources/core/plugins.js
@@ -0,0 +1,119 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.plugins} object, which is used to
8 * manage plugins registration and loading.
9 */
10
11/**
12 * Manages plugins registration and loading.
13 *
14 * @class
15 * @extends CKEDITOR.resourceManager
16 * @singleton
17 */
18CKEDITOR.plugins = new CKEDITOR.resourceManager( 'plugins/', 'plugin' );
19
20// PACKAGER_RENAME( CKEDITOR.plugins )
21
22CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function( originalLoad ) {
23 var initialized = {};
24
25 return function( name, callback, scope ) {
26 var allPlugins = {};
27
28 var loadPlugins = function( names ) {
29 originalLoad.call( this, names, function( plugins ) {
30 CKEDITOR.tools.extend( allPlugins, plugins );
31
32 var requiredPlugins = [];
33 for ( var pluginName in plugins ) {
34 var plugin = plugins[ pluginName ],
35 requires = plugin && plugin.requires;
36
37 if ( !initialized[ pluginName ] ) {
38 // Register all icons eventually defined by this plugin.
39 if ( plugin.icons ) {
40 var icons = plugin.icons.split( ',' );
41 for ( var ic = icons.length; ic--; ) {
42 CKEDITOR.skin.addIcon( icons[ ic ],
43 plugin.path +
44 'icons/' +
45 ( CKEDITOR.env.hidpi && plugin.hidpi ? 'hidpi/' : '' ) +
46 icons[ ic ] +
47 '.png' );
48 }
49 }
50 initialized[ pluginName ] = 1;
51 }
52
53 if ( requires ) {
54 // Trasnform it into an array, if it's not one.
55 if ( requires.split )
56 requires = requires.split( ',' );
57
58 for ( var i = 0; i < requires.length; i++ ) {
59 if ( !allPlugins[ requires[ i ] ] )
60 requiredPlugins.push( requires[ i ] );
61 }
62 }
63 }
64
65 if ( requiredPlugins.length )
66 loadPlugins.call( this, requiredPlugins );
67 else {
68 // Call the "onLoad" function for all plugins.
69 for ( pluginName in allPlugins ) {
70 plugin = allPlugins[ pluginName ];
71 if ( plugin.onLoad && !plugin.onLoad._called ) {
72 // Make it possible to return false from plugin::onLoad to disable it.
73 if ( plugin.onLoad() === false )
74 delete allPlugins[ pluginName ];
75
76 plugin.onLoad._called = 1;
77 }
78 }
79
80 // Call the callback.
81 if ( callback )
82 callback.call( scope || window, allPlugins );
83 }
84 }, this );
85
86 };
87
88 loadPlugins.call( this, name );
89 };
90} );
91
92/**
93 * Loads a specific language file, or auto detect it. A callback is
94 * then called when the file gets loaded.
95 *
96 * CKEDITOR.plugins.setLang( 'myPlugin', 'en', {
97 * title: 'My plugin',
98 * selectOption: 'Please select an option'
99 * } );
100 *
101 * @param {String} pluginName The name of the plugin to which the provided translation
102 * should be attached.
103 * @param {String} languageCode The code of the language translation provided.
104 * @param {Object} languageEntries An object that contains pairs of label and
105 * the respective translation.
106 */
107CKEDITOR.plugins.setLang = function( pluginName, languageCode, languageEntries ) {
108 var plugin = this.get( pluginName ),
109 pluginLangEntries = plugin.langEntries || ( plugin.langEntries = {} ),
110 pluginLang = plugin.lang || ( plugin.lang = [] );
111
112 if ( pluginLang.split )
113 pluginLang = pluginLang.split( ',' );
114
115 if ( CKEDITOR.tools.indexOf( pluginLang, languageCode ) == -1 )
116 pluginLang.push( languageCode );
117
118 pluginLangEntries[ languageCode ] = languageEntries;
119};
diff --git a/sources/core/resourcemanager.js b/sources/core/resourcemanager.js
new file mode 100644
index 0000000..c33c0f8
--- /dev/null
+++ b/sources/core/resourcemanager.js
@@ -0,0 +1,228 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.resourceManager} class, which is
8 * the base for resource managers, like plugins.
9 */
10
11/**
12 * Base class for resource managers, like plugins. This class is not
13 * intended to be used out of the CKEditor core code.
14 *
15 * @class
16 * @constructor Creates a resourceManager class instance.
17 * @param {String} basePath The path for the resources folder.
18 * @param {String} fileName The name used for resource files.
19 */
20CKEDITOR.resourceManager = function( basePath, fileName ) {
21 /**
22 * The base directory containing all resources.
23 *
24 * @property {String}
25 */
26 this.basePath = basePath;
27
28 /**
29 * The name used for resource files.
30 *
31 * @property {String}
32 */
33 this.fileName = fileName;
34
35 /**
36 * Contains references to all resources that have already been registered
37 * with {@link #add}.
38 */
39 this.registered = {};
40
41 /**
42 * Contains references to all resources that have already been loaded
43 * with {@link #load}.
44 */
45 this.loaded = {};
46
47 /**
48 * Contains references to all resources that have already been registered
49 * with {@link #addExternal}.
50 */
51 this.externals = {};
52
53 /**
54 * @private
55 */
56 this._ = {
57 // List of callbacks waiting for plugins to be loaded.
58 waitingList: {}
59 };
60};
61
62CKEDITOR.resourceManager.prototype = {
63 /**
64 * Registers a resource.
65 *
66 * CKEDITOR.plugins.add( 'sample', { ... plugin definition ... } );
67 *
68 * @param {String} name The resource name.
69 * @param {Object} [definition] The resource definition.
70 * @see CKEDITOR.pluginDefinition
71 */
72 add: function( name, definition ) {
73 if ( this.registered[ name ] )
74 throw new Error( '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.' );
75
76 var resource = this.registered[ name ] = definition || {};
77 resource.name = name;
78 resource.path = this.getPath( name );
79
80 CKEDITOR.fire( name + CKEDITOR.tools.capitalize( this.fileName ) + 'Ready', resource );
81
82 return this.get( name );
83 },
84
85 /**
86 * Gets the definition of a specific resource.
87 *
88 * var definition = CKEDITOR.plugins.get( 'sample' );
89 *
90 * @param {String} name The resource name.
91 * @returns {Object} The registered object.
92 */
93 get: function( name ) {
94 return this.registered[ name ] || null;
95 },
96
97 /**
98 * Get the folder path for a specific loaded resource.
99 *
100 * alert( CKEDITOR.plugins.getPath( 'sample' ) ); // '<editor path>/plugins/sample/'
101 *
102 * @param {String} name The resource name.
103 * @returns {String}
104 */
105 getPath: function( name ) {
106 var external = this.externals[ name ];
107 return CKEDITOR.getUrl( ( external && external.dir ) || this.basePath + name + '/' );
108 },
109
110 /**
111 * Get the file path for a specific loaded resource.
112 *
113 * alert( CKEDITOR.plugins.getFilePath( 'sample' ) ); // '<editor path>/plugins/sample/plugin.js'
114 *
115 * @param {String} name The resource name.
116 * @returns {String}
117 */
118 getFilePath: function( name ) {
119 var external = this.externals[ name ];
120 return CKEDITOR.getUrl( this.getPath( name ) + ( external ? external.file : this.fileName + '.js' ) );
121 },
122
123 /**
124 * Registers one or more resources to be loaded from an external path
125 * instead of the core base path.
126 *
127 * // Loads a plugin from '/myplugins/sample/plugin.js'.
128 * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/' );
129 *
130 * // Loads a plugin from '/myplugins/sample/my_plugin.js'.
131 * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/', 'my_plugin.js' );
132 *
133 * // Loads a plugin from '/myplugins/sample/my_plugin.js'.
134 * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/my_plugin.js', '' );
135 *
136 * @param {String} names The resource names, separated by commas.
137 * @param {String} path The path of the folder containing the resource.
138 * @param {String} [fileName] The resource file name. If not provided, the
139 * default name is used. If provided with a empty string, will implicitly indicates that `path` argument
140 * is already the full path.
141 */
142 addExternal: function( names, path, fileName ) {
143 names = names.split( ',' );
144 for ( var i = 0; i < names.length; i++ ) {
145 var name = names[ i ];
146
147 // If "fileName" is not provided, we assume that it may be available
148 // in "path". Try to extract it in this case.
149 if ( !fileName ) {
150 path = path.replace( /[^\/]+$/, function( match ) {
151 fileName = match;
152 return '';
153 } );
154 }
155
156 this.externals[ name ] = {
157 dir: path,
158
159 // Use the default file name if there is no "fileName" and it
160 // was not found in "path".
161 file: fileName || ( this.fileName + '.js' )
162 };
163 }
164 },
165
166 /**
167 * Loads one or more resources.
168 *
169 * CKEDITOR.plugins.load( 'myplugin', function( plugins ) {
170 * alert( plugins[ 'myplugin' ] ); // object
171 * } );
172 *
173 * @param {String/Array} name The name of the resource to load. It may be a
174 * string with a single resource name, or an array with several names.
175 * @param {Function} callback A function to be called when all resources
176 * are loaded. The callback will receive an array containing all loaded names.
177 * @param {Object} [scope] The scope object to be used for the callback call.
178 */
179 load: function( names, callback, scope ) {
180 // Ensure that we have an array of names.
181 if ( !CKEDITOR.tools.isArray( names ) )
182 names = names ? [ names ] : [];
183
184 var loaded = this.loaded,
185 registered = this.registered,
186 urls = [],
187 urlsNames = {},
188 resources = {};
189
190 // Loop through all names.
191 for ( var i = 0; i < names.length; i++ ) {
192 var name = names[ i ];
193
194 if ( !name )
195 continue;
196
197 // If not available yet.
198 if ( !loaded[ name ] && !registered[ name ] ) {
199 var url = this.getFilePath( name );
200 urls.push( url );
201 if ( !( url in urlsNames ) )
202 urlsNames[ url ] = [];
203 urlsNames[ url ].push( name );
204 } else {
205 resources[ name ] = this.get( name );
206 }
207 }
208
209 CKEDITOR.scriptLoader.load( urls, function( completed, failed ) {
210 if ( failed.length ) {
211 throw new Error( '[CKEDITOR.resourceManager.load] Resource name "' + urlsNames[ failed[ 0 ] ].join( ',' ) +
212 '" was not found at "' + failed[ 0 ] + '".' );
213 }
214
215 for ( var i = 0; i < completed.length; i++ ) {
216 var nameList = urlsNames[ completed[ i ] ];
217 for ( var j = 0; j < nameList.length; j++ ) {
218 var name = nameList[ j ];
219 resources[ name ] = this.get( name );
220
221 loaded[ name ] = 1;
222 }
223 }
224
225 callback.call( scope, resources );
226 }, this );
227 }
228};
diff --git a/sources/core/scriptloader.js b/sources/core/scriptloader.js
new file mode 100644
index 0000000..a2b9cca
--- /dev/null
+++ b/sources/core/scriptloader.js
@@ -0,0 +1,202 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.scriptLoader} object, used to load scripts
8 * asynchronously.
9 */
10
11/**
12 * Load scripts asynchronously.
13 *
14 * @class
15 * @singleton
16 */
17CKEDITOR.scriptLoader = ( function() {
18 var uniqueScripts = {},
19 waitingList = {};
20
21 return {
22 /**
23 * Loads one or more external script checking if not already loaded
24 * previously by this function.
25 *
26 * CKEDITOR.scriptLoader.load( '/myscript.js' );
27 *
28 * CKEDITOR.scriptLoader.load( '/myscript.js', function( success ) {
29 * // Alerts true if the script has been properly loaded.
30 * // HTTP error 404 should return false.
31 * alert( success );
32 * } );
33 *
34 * CKEDITOR.scriptLoader.load( [ '/myscript1.js', '/myscript2.js' ], function( completed, failed ) {
35 * alert( 'Number of scripts loaded: ' + completed.length );
36 * alert( 'Number of failures: ' + failed.length );
37 * } );
38 *
39 * @param {String/Array} scriptUrl One or more URLs pointing to the
40 * scripts to be loaded.
41 * @param {Function} [callback] A function to be called when the script
42 * is loaded and executed. If a string is passed to `scriptUrl`, a
43 * boolean parameter is passed to the callback, indicating the
44 * success of the load. If an array is passed instead, two arrays
45 * parameters are passed to the callback - the first contains the
46 * URLs that have been properly loaded and the second the failed ones.
47 * @param {Object} [scope] The scope (`this` reference) to be used for
48 * the callback call. Defaults to {@link CKEDITOR}.
49 * @param {Boolean} [showBusy] Changes the cursor of the document while
50 * the script is loaded.
51 */
52 load: function( scriptUrl, callback, scope, showBusy ) {
53 var isString = ( typeof scriptUrl == 'string' );
54
55 if ( isString )
56 scriptUrl = [ scriptUrl ];
57
58 if ( !scope )
59 scope = CKEDITOR;
60
61 var scriptCount = scriptUrl.length,
62 completed = [],
63 failed = [];
64
65 var doCallback = function( success ) {
66 if ( callback ) {
67 if ( isString )
68 callback.call( scope, success );
69 else
70 callback.call( scope, completed, failed );
71 }
72 };
73
74 if ( scriptCount === 0 ) {
75 doCallback( true );
76 return;
77 }
78
79 var checkLoaded = function( url, success ) {
80 ( success ? completed : failed ).push( url );
81
82 if ( --scriptCount <= 0 ) {
83 showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' );
84 doCallback( success );
85 }
86 };
87
88 var onLoad = function( url, success ) {
89 // Mark this script as loaded.
90 uniqueScripts[ url ] = 1;
91
92 // Get the list of callback checks waiting for this file.
93 var waitingInfo = waitingList[ url ];
94 delete waitingList[ url ];
95
96 // Check all callbacks waiting for this file.
97 for ( var i = 0; i < waitingInfo.length; i++ )
98 waitingInfo[ i ]( url, success );
99 };
100
101 var loadScript = function( url ) {
102 if ( uniqueScripts[ url ] ) {
103 checkLoaded( url, true );
104 return;
105 }
106
107 var waitingInfo = waitingList[ url ] || ( waitingList[ url ] = [] );
108 waitingInfo.push( checkLoaded );
109
110 // Load it only for the first request.
111 if ( waitingInfo.length > 1 )
112 return;
113
114 // Create the <script> element.
115 var script = new CKEDITOR.dom.element( 'script' );
116 script.setAttributes( {
117 type: 'text/javascript',
118 src: url
119 } );
120
121 if ( callback ) {
122 // The onload or onerror event does not fire in IE8 and IE9 Quirks Mode (#14849).
123 if ( CKEDITOR.env.ie && ( CKEDITOR.env.version <= 8 || CKEDITOR.env.ie9Compat ) ) {
124 script.$.onreadystatechange = function() {
125 if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' ) {
126 script.$.onreadystatechange = null;
127 onLoad( url, true );
128 }
129 };
130 } else {
131 script.$.onload = function() {
132 // Some browsers, such as Safari, may call the onLoad function
133 // immediately. Which will break the loading sequence. (#3661)
134 setTimeout( function() {
135 onLoad( url, true );
136 }, 0 );
137 };
138
139 script.$.onerror = function() {
140 onLoad( url, false );
141 };
142 }
143 }
144
145 // Append it to <head>.
146 script.appendTo( CKEDITOR.document.getHead() );
147
148 CKEDITOR.fire( 'download', url ); // %REMOVE_LINE%
149 };
150
151 showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' );
152 for ( var i = 0; i < scriptCount; i++ ) {
153 loadScript( scriptUrl[ i ] );
154 }
155 },
156
157 /**
158 * Loads a script in a queue, so only one is loaded at the same time.
159 *
160 * @since 4.1.2
161 * @param {String} scriptUrl URL pointing to the script to be loaded.
162 * @param {Function} [callback] A function to be called when the script
163 * is loaded and executed. A boolean parameter is passed to the callback,
164 * indicating the success of the load.
165 *
166 * @see CKEDITOR.scriptLoader#load
167 */
168 queue: ( function() {
169 var pending = [];
170
171 // Loads the very first script from queue and removes it.
172 function loadNext() {
173 var script;
174
175 if ( ( script = pending[ 0 ] ) )
176 this.load( script.scriptUrl, script.callback, CKEDITOR, 0 );
177 }
178
179 return function( scriptUrl, callback ) {
180 var that = this;
181
182 // This callback calls the standard callback for the script
183 // and loads the very next script from pending list.
184 function callbackWrapper() {
185 callback && callback.apply( this, arguments );
186
187 // Removed the just loaded script from the queue.
188 pending.shift();
189
190 loadNext.call( that );
191 }
192
193 // Let's add this script to the queue
194 pending.push( { scriptUrl: scriptUrl, callback: callbackWrapper } );
195
196 // If the queue was empty, then start loading.
197 if ( pending.length == 1 )
198 loadNext.call( this );
199 };
200 } )()
201 };
202} )();
diff --git a/sources/core/selection.js b/sources/core/selection.js
new file mode 100644
index 0000000..eef28a3
--- /dev/null
+++ b/sources/core/selection.js
@@ -0,0 +1,2204 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var isMSSelection = typeof window.getSelection != 'function',
8 nextRev = 1,
9 // #13816
10 fillingCharSequence = CKEDITOR.tools.repeat( '\u200b', 7 ),
11 fillingCharSequenceRegExp = new RegExp( fillingCharSequence + '( )?', 'g' );
12
13 // #### checkSelectionChange : START
14
15 // The selection change check basically saves the element parent tree of
16 // the current node and check it on successive requests. If there is any
17 // change on the tree, then the selectionChange event gets fired.
18 function checkSelectionChange() {
19 // A possibly available fake-selection.
20 var sel = this._.fakeSelection,
21 realSel;
22
23 if ( sel ) {
24 realSel = this.getSelection( 1 );
25
26 // If real (not locked/stored) selection was moved from hidden container,
27 // then the fake-selection must be invalidated.
28 if ( !realSel || !realSel.isHidden() ) {
29 // Remove the cache from fake-selection references in use elsewhere.
30 sel.reset();
31
32 // Have the code using the native selection.
33 sel = 0;
34 }
35 }
36
37 // If not fake-selection is available then get the native selection.
38 if ( !sel ) {
39 sel = realSel || this.getSelection( 1 );
40
41 // Editor may have no selection at all.
42 if ( !sel || sel.getType() == CKEDITOR.SELECTION_NONE )
43 return;
44 }
45
46 this.fire( 'selectionCheck', sel );
47
48 var currentPath = this.elementPath();
49 if ( !currentPath.compare( this._.selectionPreviousPath ) ) {
50 // Handle case when dialog inserts new element but parent block and path (so also focus context) does not change. (#13362)
51 var sameBlockParent = this._.selectionPreviousPath && this._.selectionPreviousPath.blockLimit.equals( currentPath.blockLimit );
52 // Cache the active element, which we'll eventually lose on Webkit.
53 if ( CKEDITOR.env.webkit && !sameBlockParent )
54 this._.previousActive = this.document.getActive();
55
56 this._.selectionPreviousPath = currentPath;
57 this.fire( 'selectionChange', { selection: sel, path: currentPath } );
58 }
59 }
60
61 var checkSelectionChangeTimer, checkSelectionChangeTimeoutPending;
62
63 function checkSelectionChangeTimeout() {
64 // Firing the "OnSelectionChange" event on every key press started to
65 // be too slow. This function guarantees that there will be at least
66 // 200ms delay between selection checks.
67
68 checkSelectionChangeTimeoutPending = true;
69
70 if ( checkSelectionChangeTimer )
71 return;
72
73 checkSelectionChangeTimeoutExec.call( this );
74
75 checkSelectionChangeTimer = CKEDITOR.tools.setTimeout( checkSelectionChangeTimeoutExec, 200, this );
76 }
77
78 function checkSelectionChangeTimeoutExec() {
79 checkSelectionChangeTimer = null;
80
81 if ( checkSelectionChangeTimeoutPending ) {
82 // Call this with a timeout so the browser properly moves the
83 // selection after the mouseup. It happened that the selection was
84 // being moved after the mouseup when clicking inside selected text
85 // with Firefox.
86 CKEDITOR.tools.setTimeout( checkSelectionChange, 0, this );
87
88 checkSelectionChangeTimeoutPending = false;
89 }
90 }
91
92 // #### checkSelectionChange : END
93
94 var isVisible = CKEDITOR.dom.walker.invisible( 1 );
95
96 // May absorb the caret if:
97 // * is a visible node,
98 // * is a non-empty element (this rule will accept elements like <strong></strong> because they
99 // they were not accepted by the isVisible() check, not not <br> which cannot absorb the caret).
100 // See #12621.
101 function mayAbsorbCaret( node ) {
102 if ( isVisible( node ) )
103 return true;
104
105 if ( node.type == CKEDITOR.NODE_ELEMENT && !node.is( CKEDITOR.dtd.$empty ) )
106 return true;
107
108 return false;
109 }
110
111 function rangeRequiresFix( range ) {
112 // Whether we must prevent from absorbing caret by this context node.
113 // Also checks whether there's an editable position next to that node.
114 function ctxRequiresFix( node, isAtEnd ) {
115 // It's ok for us if a text node absorbs the caret, because
116 // the caret container element isn't changed then.
117 if ( !node || node.type == CKEDITOR.NODE_TEXT )
118 return false;
119
120 var testRng = range.clone();
121 return testRng[ 'moveToElementEdit' + ( isAtEnd ? 'End' : 'Start' ) ]( node );
122 }
123
124 // Range root must be the editable element, it's to avoid creating filler char
125 // on any temporary internal selection.
126 if ( !( range.root instanceof CKEDITOR.editable ) )
127 return false;
128
129 var ct = range.startContainer;
130
131 var previous = range.getPreviousNode( mayAbsorbCaret, null, ct ),
132 next = range.getNextNode( mayAbsorbCaret, null, ct );
133
134 // Any adjacent text container may absorb the caret, e.g.
135 // <p><strong>text</strong>^foo</p>
136 // <p>foo^<strong>text</strong></p>
137 // <div>^<p>foo</p></div>
138 if ( ctxRequiresFix( previous ) || ctxRequiresFix( next, 1 ) )
139 return true;
140
141 // Empty block/inline element is also affected. <span>^</span>, <p>^</p> (#7222)
142 // If you found this line confusing check #12655.
143 if ( !( previous || next ) && !( ct.type == CKEDITOR.NODE_ELEMENT && ct.isBlockBoundary() && ct.getBogus() ) )
144 return true;
145
146 return false;
147 }
148
149 function createFillingCharSequenceNode( editable ) {
150 removeFillingCharSequenceNode( editable, false );
151
152 var fillingChar = editable.getDocument().createText( fillingCharSequence );
153 editable.setCustomData( 'cke-fillingChar', fillingChar );
154
155 return fillingChar;
156 }
157
158 // Checks if a filling char has been used, eventualy removing it (#1272).
159 function checkFillingCharSequenceNodeReady( editable ) {
160 var fillingChar = editable.getCustomData( 'cke-fillingChar' );
161
162 if ( fillingChar ) {
163 // Use this flag to avoid removing the filling char right after
164 // creating it.
165 if ( fillingChar.getCustomData( 'ready' ) ) {
166 removeFillingCharSequenceNode( editable );
167 } else {
168 fillingChar.setCustomData( 'ready', 1 );
169 }
170 }
171 }
172
173 function removeFillingCharSequenceNode( editable, keepSelection ) {
174 var fillingChar = editable && editable.removeCustomData( 'cke-fillingChar' );
175
176 if ( fillingChar ) {
177 // Text selection position might get mangled by
178 // subsequent dom modification, save it now for restoring. (#8617)
179 if ( keepSelection !== false ) {
180 var sel = editable.getDocument().getSelection().getNative(),
181 // Be error proof.
182 range = sel && sel.type != 'None' && sel.getRangeAt( 0 ),
183 fillingCharSeqLength = fillingCharSequence.length;
184
185 // If there's some text other than the sequence in the FC text node and the range
186 // intersects with that node...
187 if ( fillingChar.getLength() > fillingCharSeqLength && range && range.intersectsNode( fillingChar.$ ) ) {
188 var bm = createNativeSelectionBookmark( sel );
189
190 // Correct start offset anticipating the removal of FC.
191 if ( sel.anchorNode == fillingChar.$ && sel.anchorOffset > fillingCharSeqLength ) {
192 bm[ 0 ].offset -= fillingCharSeqLength;
193 }
194
195 // Correct end offset anticipating the removal of FC.
196 if ( sel.focusNode == fillingChar.$ && sel.focusOffset > fillingCharSeqLength ) {
197 bm[ 1 ].offset -= fillingCharSeqLength;
198 }
199 }
200 }
201
202 // We can't simply remove the filling node because the user
203 // will actually enlarge it when typing, so we just remove the
204 // invisible char from it.
205 fillingChar.setText( removeFillingCharSequenceString( fillingChar.getText(), 1 ) );
206
207 // Restore the bookmark preserving selection's direction.
208 if ( bm ) {
209 moveNativeSelectionToBookmark( editable.getDocument().$, bm );
210 }
211 }
212 }
213
214 // #13816
215 function removeFillingCharSequenceString( str, nbspAware ) {
216 if ( nbspAware ) {
217 return str.replace( fillingCharSequenceRegExp, function( m, p ) {
218 // #10291 if filling char is followed by a space replace it with NBSP.
219 return p ? '\xa0' : '';
220 } );
221 } else {
222 return str.replace( fillingCharSequence, '' );
223 }
224 }
225
226 function createNativeSelectionBookmark( sel ) {
227 return [
228 { node: sel.anchorNode, offset: sel.anchorOffset },
229 { node: sel.focusNode, offset: sel.focusOffset }
230 ];
231 }
232
233 function moveNativeSelectionToBookmark( document, bm ) {
234 var sel = document.getSelection(),
235 range = document.createRange();
236
237 range.setStart( bm[ 0 ].node, bm[ 0 ].offset );
238 range.collapse( true );
239 sel.removeAllRanges();
240 sel.addRange( range );
241 sel.extend( bm[ 1 ].node, bm[ 1 ].offset );
242 }
243
244 // Creates cke_hidden_sel container and puts real selection there.
245 function hideSelection( editor, ariaLabel ) {
246 var content = ariaLabel || '&nbsp;',
247 style = CKEDITOR.env.ie && CKEDITOR.env.version < 14 ? 'display:none' : 'position:fixed;top:0;left:-1000px',
248 hiddenEl = CKEDITOR.dom.element.createFromHtml(
249 '<div data-cke-hidden-sel="1" data-cke-temp="1" style="' + style + '">' + content + '</div>',
250 editor.document );
251
252 editor.fire( 'lockSnapshot' );
253
254 editor.editable().append( hiddenEl );
255
256 // Always use real selection to avoid overriding locked one (http://dev.ckeditor.com/ticket/11104#comment:13).
257 var sel = editor.getSelection( 1 ),
258 range = editor.createRange(),
259 // Cancel selectionchange fired by selectRanges - prevent from firing selectionChange.
260 listener = sel.root.on( 'selectionchange', function( evt ) {
261 evt.cancel();
262 }, null, null, 0 );
263
264 range.setStartAt( hiddenEl, CKEDITOR.POSITION_AFTER_START );
265 range.setEndAt( hiddenEl, CKEDITOR.POSITION_BEFORE_END );
266 sel.selectRanges( [ range ] );
267
268 listener.removeListener();
269
270 editor.fire( 'unlockSnapshot' );
271
272 // Set this value at the end, so reset() executed by selectRanges()
273 // will clean up old hidden selection container.
274 editor._.hiddenSelectionContainer = hiddenEl;
275 }
276
277 function removeHiddenSelectionContainer( editor ) {
278 var hiddenEl = editor._.hiddenSelectionContainer;
279
280 if ( hiddenEl ) {
281 var isDirty = editor.checkDirty();
282
283 editor.fire( 'lockSnapshot' );
284 hiddenEl.remove();
285 editor.fire( 'unlockSnapshot' );
286
287 !isDirty && editor.resetDirty();
288 }
289
290 delete editor._.hiddenSelectionContainer;
291 }
292
293 // Object containing keystroke handlers for fake selection.
294 var fakeSelectionDefaultKeystrokeHandlers = ( function() {
295 function leave( right ) {
296 return function( evt ) {
297 var range = evt.editor.createRange();
298
299 // Move selection only if there's a editable place for it.
300 // It no, then do nothing (keystroke will be blocked, widget selection kept).
301 if ( range.moveToClosestEditablePosition( evt.selected, right ) )
302 evt.editor.getSelection().selectRanges( [ range ] );
303
304 // Prevent default.
305 return false;
306 };
307 }
308
309 function del( right ) {
310 return function( evt ) {
311 var editor = evt.editor,
312 range = editor.createRange(),
313 found;
314
315 // If haven't found place for caret on the default side,
316 // try to find it on the other side.
317 if ( !( found = range.moveToClosestEditablePosition( evt.selected, right ) ) )
318 found = range.moveToClosestEditablePosition( evt.selected, !right );
319
320 if ( found )
321 editor.getSelection().selectRanges( [ range ] );
322
323 // Save the state before removing selected element.
324 editor.fire( 'saveSnapshot' );
325
326 evt.selected.remove();
327
328 // Haven't found any editable space before removing element,
329 // try to place the caret anywhere (most likely, in empty editable).
330 if ( !found ) {
331 range.moveToElementEditablePosition( editor.editable() );
332 editor.getSelection().selectRanges( [ range ] );
333 }
334
335 editor.fire( 'saveSnapshot' );
336
337 // Prevent default.
338 return false;
339 };
340 }
341
342 var leaveLeft = leave(),
343 leaveRight = leave( 1 );
344
345 return {
346 37: leaveLeft, // LEFT
347 38: leaveLeft, // UP
348 39: leaveRight, // RIGHT
349 40: leaveRight, // DOWN
350 8: del(), // BACKSPACE
351 46: del( 1 ) // DELETE
352 };
353 } )();
354
355 // Handle left, right, delete and backspace keystrokes next to non-editable elements
356 // by faking selection on them.
357 function getOnKeyDownListener( editor ) {
358 var keystrokes = { 37: 1, 39: 1, 8: 1, 46: 1 };
359
360 return function( evt ) {
361 var keystroke = evt.data.getKeystroke();
362
363 // Handle only left/right/del/bspace keys.
364 if ( !keystrokes[ keystroke ] )
365 return;
366
367 var sel = editor.getSelection(),
368 ranges = sel.getRanges(),
369 range = ranges[ 0 ];
370
371 // Handle only single range and it has to be collapsed.
372 if ( ranges.length != 1 || !range.collapsed )
373 return;
374
375 var next = range[ keystroke < 38 ? 'getPreviousEditableNode' : 'getNextEditableNode' ]();
376
377 if ( next && next.type == CKEDITOR.NODE_ELEMENT && next.getAttribute( 'contenteditable' ) == 'false' ) {
378 editor.getSelection().fake( next );
379 evt.data.preventDefault();
380 evt.cancel();
381 }
382 };
383 }
384
385 // If fake selection should be applied this function will return instance of
386 // CKEDITOR.dom.element which should gain fake selection.
387 function getNonEditableFakeSelectionReceiver( ranges ) {
388 var enclosedNode, shrinkedNode, clone, range;
389
390 if ( ranges.length == 1 && !( range = ranges[ 0 ] ).collapsed &&
391 ( enclosedNode = range.getEnclosedNode() ) && enclosedNode.type == CKEDITOR.NODE_ELEMENT ) {
392 // So far we can't say that enclosed element is non-editable. Before checking,
393 // we'll shrink range (clone). Shrinking will stop on non-editable range, or
394 // innermost element (#11114).
395 clone = range.clone();
396 clone.shrink( CKEDITOR.SHRINK_ELEMENT, true );
397
398 // If shrinked range still encloses an element, check this one (shrink stops only on non-editable elements).
399 if ( ( shrinkedNode = clone.getEnclosedNode() ) && shrinkedNode.type == CKEDITOR.NODE_ELEMENT )
400 enclosedNode = shrinkedNode;
401
402 if ( enclosedNode.getAttribute( 'contenteditable' ) == 'false' )
403 return enclosedNode;
404 }
405 }
406
407 // Fix ranges which may end after hidden selection container.
408 // Note: this function may only be used if hidden selection container
409 // is not in DOM any more.
410 function fixRangesAfterHiddenSelectionContainer( ranges, root ) {
411 var range;
412 for ( var i = 0; i < ranges.length; ++i ) {
413 range = ranges[ i ];
414 if ( range.endContainer.equals( root ) ) {
415 // We can use getChildCount() because hidden selection container is not in DOM.
416 range.endOffset = Math.min( range.endOffset, root.getChildCount() );
417 }
418 }
419 }
420
421 // Extract only editable part or ranges.
422 // Note: this function modifies ranges list!
423 // @param {CKEDITOR.dom.rangeList} ranges
424 function extractEditableRanges( ranges ) {
425 for ( var i = 0; i < ranges.length; i++ ) {
426 var range = ranges[ i ];
427
428 // Drop range spans inside one ready-only node.
429 var parent = range.getCommonAncestor();
430 if ( parent.isReadOnly() )
431 ranges.splice( i, 1 );
432
433 if ( range.collapsed )
434 continue;
435
436 // Range may start inside a non-editable element,
437 // replace the range start after it.
438 if ( range.startContainer.isReadOnly() ) {
439 var current = range.startContainer,
440 isElement;
441
442 while ( current ) {
443 isElement = current.type == CKEDITOR.NODE_ELEMENT;
444
445 if ( ( isElement && current.is( 'body' ) ) || !current.isReadOnly() )
446 break;
447
448 if ( isElement && current.getAttribute( 'contentEditable' ) == 'false' )
449 range.setStartAfter( current );
450
451 current = current.getParent();
452 }
453 }
454
455 var startContainer = range.startContainer,
456 endContainer = range.endContainer,
457 startOffset = range.startOffset,
458 endOffset = range.endOffset,
459 walkerRange = range.clone();
460
461 // Enlarge range start/end with text node to avoid walker
462 // being DOM destructive, it doesn't interfere our checking
463 // of elements below as well.
464 if ( startContainer && startContainer.type == CKEDITOR.NODE_TEXT ) {
465 if ( startOffset >= startContainer.getLength() )
466 walkerRange.setStartAfter( startContainer );
467 else
468 walkerRange.setStartBefore( startContainer );
469 }
470
471 if ( endContainer && endContainer.type == CKEDITOR.NODE_TEXT ) {
472 if ( !endOffset )
473 walkerRange.setEndBefore( endContainer );
474 else
475 walkerRange.setEndAfter( endContainer );
476 }
477
478 // Looking for non-editable element inside the range.
479 var walker = new CKEDITOR.dom.walker( walkerRange );
480 walker.evaluator = function( node ) {
481 if ( node.type == CKEDITOR.NODE_ELEMENT && node.isReadOnly() ) {
482 var newRange = range.clone();
483 range.setEndBefore( node );
484
485 // Drop collapsed range around read-only elements,
486 // it make sure the range list empty when selecting
487 // only non-editable elements.
488 if ( range.collapsed )
489 ranges.splice( i--, 1 );
490
491 // Avoid creating invalid range.
492 if ( !( node.getPosition( walkerRange.endContainer ) & CKEDITOR.POSITION_CONTAINS ) ) {
493 newRange.setStartAfter( node );
494 if ( !newRange.collapsed )
495 ranges.splice( i + 1, 0, newRange );
496 }
497
498 return true;
499 }
500
501 return false;
502 };
503
504 walker.next();
505 }
506
507 return ranges;
508 }
509
510 // Setup all editor instances for the necessary selection hooks.
511 CKEDITOR.on( 'instanceCreated', function( ev ) {
512 var editor = ev.editor;
513
514 editor.on( 'contentDom', function() {
515 var doc = editor.document,
516 outerDoc = CKEDITOR.document,
517 editable = editor.editable(),
518 body = doc.getBody(),
519 html = doc.getDocumentElement();
520
521 var isInline = editable.isInline();
522
523 var restoreSel,
524 lastSel;
525
526 // Give the editable an initial selection on first focus,
527 // put selection at a consistent position at the start
528 // of the contents. (#9507)
529 if ( CKEDITOR.env.gecko ) {
530 editable.attachListener( editable, 'focus', function( evt ) {
531 evt.removeListener();
532
533 if ( restoreSel !== 0 ) {
534 var nativ = editor.getSelection().getNative();
535 // Do it only if the native selection is at an unwanted
536 // place (at the very start of the editable). #10119
537 if ( nativ && nativ.isCollapsed && nativ.anchorNode == editable.$ ) {
538 var rng = editor.createRange();
539 rng.moveToElementEditStart( editable );
540 rng.select();
541 }
542 }
543 }, null, null, -2 );
544 }
545
546 // Plays the magic here to restore/save dom selection on editable focus/blur.
547 editable.attachListener( editable, CKEDITOR.env.webkit ? 'DOMFocusIn' : 'focus', function() {
548 // On Webkit we use DOMFocusIn which is fired more often than focus - e.g. when moving from main editable
549 // to nested editable (or the opposite). Unlock selection all, but restore only when it was locked
550 // for the same active element, what will e.g. mean restoring after displaying dialog.
551 if ( restoreSel && CKEDITOR.env.webkit ) {
552 restoreSel = editor._.previousActive && editor._.previousActive.equals( doc.getActive() );
553
554 // On Webkit when editor uses divarea, native focus causes editable viewport to scroll
555 // to the top (when there is no active selection inside while focusing) so the scroll
556 // position should be restored after focusing back editable area. (#14659)
557 if ( restoreSel && editor._.previousScrollTop != null && editor._.previousScrollTop != editable.$.scrollTop ) {
558 editable.$.scrollTop = editor._.previousScrollTop;
559 }
560 }
561
562 editor.unlockSelection( restoreSel );
563 restoreSel = 0;
564 }, null, null, -1 );
565
566 // Disable selection restoring when clicking in.
567 editable.attachListener( editable, 'mousedown', function() {
568 restoreSel = 0;
569 } );
570
571 // Save a cloned version of current selection.
572 function saveSel() {
573 lastSel = new CKEDITOR.dom.selection( editor.getSelection() );
574 lastSel.lock();
575 }
576
577 // Browsers could loose the selection once the editable lost focus,
578 // in such case we need to reproduce it by saving a locked selection
579 // and restoring it upon focus gain.
580 if ( CKEDITOR.env.ie || isInline ) {
581 // For old IEs, we can retrieve the last correct DOM selection upon the "beforedeactivate" event.
582 // For the rest, a more frequent check is required for each selection change made.
583 if ( isMSSelection )
584 editable.attachListener( editable, 'beforedeactivate', saveSel, null, null, -1 );
585 else
586 editable.attachListener( editor, 'selectionCheck', saveSel, null, null, -1 );
587
588 // Lock the selection and mark it to be restored.
589 // On Webkit we use DOMFocusOut which is fired more often than blur. I.e. it will also be
590 // fired when nested editable is blurred.
591 editable.attachListener( editable, CKEDITOR.env.webkit ? 'DOMFocusOut' : 'blur', function() {
592 editor.lockSelection( lastSel );
593 restoreSel = 1;
594 }, null, null, -1 );
595
596 // Disable selection restoring when clicking in.
597 editable.attachListener( editable, 'mousedown', function() {
598 restoreSel = 0;
599 } );
600 }
601
602 // The following selection-related fixes only apply to classic (`iframe`-based) editable.
603 if ( CKEDITOR.env.ie && !isInline ) {
604 var scroll;
605 editable.attachListener( editable, 'mousedown', function( evt ) {
606 // IE scrolls document to top on right mousedown
607 // when editor has no focus, remember this scroll
608 // position and revert it before context menu opens. (#5778)
609 if ( evt.data.$.button == 2 ) {
610 var sel = editor.document.getSelection();
611 if ( !sel || sel.getType() == CKEDITOR.SELECTION_NONE )
612 scroll = editor.window.getScrollPosition();
613 }
614 } );
615
616 editable.attachListener( editable, 'mouseup', function( evt ) {
617 // Restore recorded scroll position when needed on right mouseup.
618 if ( evt.data.$.button == 2 && scroll ) {
619 editor.document.$.documentElement.scrollLeft = scroll.x;
620 editor.document.$.documentElement.scrollTop = scroll.y;
621 }
622 scroll = null;
623 } );
624
625 // When content doc is in standards mode, IE doesn't focus the editor when
626 // clicking at the region below body (on html element) content, we emulate
627 // the normal behavior on old IEs. (#1659, #7932)
628 if ( doc.$.compatMode != 'BackCompat' ) {
629 if ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) {
630 var textRng,
631 startRng;
632
633 html.on( 'mousedown', function( evt ) {
634 evt = evt.data;
635
636 // Expand the text range along with mouse move.
637 function onHover( evt ) {
638 evt = evt.data.$;
639 if ( textRng ) {
640 // Read the current cursor.
641 var rngEnd = body.$.createTextRange();
642
643 moveRangeToPoint( rngEnd, evt.clientX, evt.clientY );
644
645 // Handle drag directions.
646 textRng.setEndPoint(
647 startRng.compareEndPoints( 'StartToStart', rngEnd ) < 0 ?
648 'EndToEnd' : 'StartToStart', rngEnd );
649
650 // Update selection with new range.
651 textRng.select();
652 }
653 }
654
655 function removeListeners() {
656 outerDoc.removeListener( 'mouseup', onSelectEnd );
657 html.removeListener( 'mouseup', onSelectEnd );
658 }
659
660 function onSelectEnd() {
661 html.removeListener( 'mousemove', onHover );
662 removeListeners();
663
664 // Make it in effect on mouse up. (#9022)
665 textRng.select();
666 }
667
668
669 // We're sure that the click happens at the region
670 // below body, but not on scrollbar.
671 if ( evt.getTarget().is( 'html' ) &&
672 evt.$.y < html.$.clientHeight &&
673 evt.$.x < html.$.clientWidth ) {
674 // Start to build the text range.
675 textRng = body.$.createTextRange();
676 moveRangeToPoint( textRng, evt.$.clientX, evt.$.clientY );
677
678 // Records the dragging start of the above text range.
679 startRng = textRng.duplicate();
680
681 html.on( 'mousemove', onHover );
682 outerDoc.on( 'mouseup', onSelectEnd );
683 html.on( 'mouseup', onSelectEnd );
684 }
685 } );
686 }
687
688 // It's much simpler for IE8+, we just need to reselect the reported range.
689 // This hack does not work on IE>=11 because there's no old selection&range APIs.
690 if ( CKEDITOR.env.version > 7 && CKEDITOR.env.version < 11 ) {
691 html.on( 'mousedown', function( evt ) {
692 if ( evt.data.getTarget().is( 'html' ) ) {
693 // Limit the text selection mouse move inside of editable. (#9715)
694 outerDoc.on( 'mouseup', onSelectEnd );
695 html.on( 'mouseup', onSelectEnd );
696 }
697 } );
698 }
699 }
700 }
701
702 // We check the selection change:
703 // 1. Upon "selectionchange" event from the editable element. (which might be faked event fired by our code)
704 // 2. After the accomplish of keyboard and mouse events.
705 editable.attachListener( editable, 'selectionchange', checkSelectionChange, editor );
706 editable.attachListener( editable, 'keyup', checkSelectionChangeTimeout, editor );
707 // Always fire the selection change on focus gain.
708 // On Webkit do this on DOMFocusIn, because the selection is unlocked on it too and
709 // we need synchronization between those listeners to not lost cached editor._.previousActive property
710 // (which is updated on selectionCheck).
711 editable.attachListener( editable, CKEDITOR.env.webkit ? 'DOMFocusIn' : 'focus', function() {
712 editor.forceNextSelectionCheck();
713 editor.selectionChange( 1 );
714 } );
715
716 // #9699: On Webkit&Gecko in inline editor we have to check selection when it was changed
717 // by dragging and releasing mouse button outside editable. Dragging (mousedown)
718 // has to be initialized in editable, but for mouseup we listen on document element.
719 if ( isInline && ( CKEDITOR.env.webkit || CKEDITOR.env.gecko ) ) {
720 var mouseDown;
721 editable.attachListener( editable, 'mousedown', function() {
722 mouseDown = 1;
723 } );
724 editable.attachListener( doc.getDocumentElement(), 'mouseup', function() {
725 if ( mouseDown )
726 checkSelectionChangeTimeout.call( editor );
727 mouseDown = 0;
728 } );
729 }
730 // In all other cases listen on simple mouseup over editable, as we did before #9699.
731 //
732 // Use document instead of editable in non-IEs for observing mouseup
733 // since editable won't fire the event if selection process started within iframe and ended out
734 // of the editor (#9851).
735 else {
736 editable.attachListener( CKEDITOR.env.ie ? editable : doc.getDocumentElement(), 'mouseup', checkSelectionChangeTimeout, editor );
737 }
738
739 if ( CKEDITOR.env.webkit ) {
740 // Before keystroke is handled by editor, check to remove the filling char.
741 editable.attachListener( doc, 'keydown', function( evt ) {
742 var key = evt.data.getKey();
743 // Remove the filling char before some keys get
744 // executed, so they'll not get blocked by it.
745 switch ( key ) {
746 case 13: // ENTER
747 case 33: // PAGEUP
748 case 34: // PAGEDOWN
749 case 35: // HOME
750 case 36: // END
751 case 37: // LEFT-ARROW
752 case 39: // RIGHT-ARROW
753 case 8: // BACKSPACE
754 case 45: // INS
755 case 46: // DEl
756 removeFillingCharSequenceNode( editable );
757 }
758
759 }, null, null, -1 );
760 }
761
762 // Automatically select non-editable element when navigating into
763 // it by left/right or backspace/del keys.
764 editable.attachListener( editable, 'keydown', getOnKeyDownListener( editor ), null, null, -1 );
765
766 function moveRangeToPoint( range, x, y ) {
767 // Error prune in IE7. (#9034, #9110)
768 try {
769 range.moveToPoint( x, y );
770 } catch ( e ) {}
771 }
772
773 function removeListeners() {
774 outerDoc.removeListener( 'mouseup', onSelectEnd );
775 html.removeListener( 'mouseup', onSelectEnd );
776 }
777
778 function onSelectEnd() {
779 removeListeners();
780
781 // The event is not fired when clicking on the scrollbars,
782 // so we can safely check the following to understand
783 // whether the empty space following <body> has been clicked.
784 var sel = CKEDITOR.document.$.selection,
785 range = sel.createRange();
786
787 // The selection range is reported on host, but actually it should applies to the content doc.
788 if ( sel.type != 'None' && range.parentElement().ownerDocument == doc.$ )
789 range.select();
790 }
791 } );
792
793 editor.on( 'setData', function() {
794 // Invalidate locked selection when unloading DOM.
795 // (#9521, #5217#comment:32 and #11500#comment:11)
796 editor.unlockSelection();
797
798 // Webkit's selection will mess up after the data loading.
799 if ( CKEDITOR.env.webkit )
800 clearSelection();
801 } );
802
803 // Catch all the cases which above setData listener couldn't catch.
804 // For example: switching to source mode and destroying editor.
805 editor.on( 'contentDomUnload', function() {
806 editor.unlockSelection();
807 } );
808
809 // IE9 might cease to work if there's an object selection inside the iframe (#7639).
810 if ( CKEDITOR.env.ie9Compat )
811 editor.on( 'beforeDestroy', clearSelection, null, null, 9 );
812
813 // Check selection change on data reload.
814 editor.on( 'dataReady', function() {
815 // Clean up fake selection after setting data.
816 delete editor._.fakeSelection;
817 delete editor._.hiddenSelectionContainer;
818
819 editor.selectionChange( 1 );
820 } );
821
822 // When loaded data are ready check whether hidden selection container was not loaded.
823 editor.on( 'loadSnapshot', function() {
824 var isElement = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_ELEMENT ),
825 // TODO replace with el.find() which will be introduced in #9764,
826 // because it may happen that hidden sel container won't be the last element.
827 last = editor.editable().getLast( isElement );
828
829 if ( last && last.hasAttribute( 'data-cke-hidden-sel' ) ) {
830 last.remove();
831
832 // Firefox does a very unfortunate thing. When a non-editable element is the only
833 // element in the editable, when we remove the hidden selection container, Firefox
834 // will insert a bogus <br> at the beginning of the editable...
835 // See: https://bugzilla.mozilla.org/show_bug.cgi?id=911201
836 //
837 // This behavior is never desired because this <br> pushes the content lower, but in
838 // this case it is especially dangerous, because it happens when a bookmark is being restored.
839 // Since this <br> is inserted at the beginning it changes indexes and thus breaks the bookmark2
840 // what results in errors.
841 //
842 // So... let's revert what Firefox broke.
843 if ( CKEDITOR.env.gecko ) {
844 var first = editor.editable().getFirst( isElement );
845 if ( first && first.is( 'br' ) && first.getAttribute( '_moz_editor_bogus_node' ) ) {
846 first.remove();
847 }
848 }
849 }
850 }, null, null, 100 );
851
852 editor.on( 'key', function( evt ) {
853 if ( editor.mode != 'wysiwyg' )
854 return;
855
856 var sel = editor.getSelection();
857 if ( !sel.isFake )
858 return;
859
860 var handler = fakeSelectionDefaultKeystrokeHandlers[ evt.data.keyCode ];
861 if ( handler )
862 return handler( { editor: editor, selected: sel.getSelectedElement(), selection: sel, keyEvent: evt } );
863 } );
864
865 function clearSelection() {
866 var sel = editor.getSelection();
867 sel && sel.removeAllRanges();
868 }
869 } );
870
871 // On WebKit only, we need a special "filling" char on some situations
872 // (#1272). Here we set the events that should invalidate that char.
873 if ( CKEDITOR.env.webkit ) {
874 CKEDITOR.on( 'instanceReady', function( evt ) {
875 var editor = evt.editor;
876
877 editor.on( 'selectionChange', function() {
878 checkFillingCharSequenceNodeReady( editor.editable() );
879 }, null, null, -1 );
880
881 editor.on( 'beforeSetMode', function() {
882 removeFillingCharSequenceNode( editor.editable() );
883 }, null, null, -1 );
884
885 // Filter Undo snapshot's HTML to get rid of Filling Char Sequence.
886 // Note: CKEDITOR.dom.range.createBookmark2() normalizes snapshot's
887 // bookmarks to anticipate the removal of FCSeq from the snapshot's HTML (#13816).
888 editor.on( 'getSnapshot', function( evt ) {
889 if ( evt.data ) {
890 evt.data = removeFillingCharSequenceString( evt.data );
891 }
892 }, editor, null, 20 );
893
894 // Filter data to get rid of Filling Char Sequence. Filter on #toDataFormat
895 // instead of #getData because once removed, FCSeq may leave an empty element,
896 // which should be pruned by the dataProcessor (#13816).
897 // Note: Used low priority to filter when dataProcessor works on strings,
898 // not pseudo–DOM.
899 editor.on( 'toDataFormat', function( evt ) {
900 evt.data.dataValue = removeFillingCharSequenceString( evt.data.dataValue );
901 }, null, null, 0 );
902 } );
903 }
904
905 /**
906 * Check the selection change in editor and potentially fires
907 * the {@link CKEDITOR.editor#event-selectionChange} event.
908 *
909 * @method
910 * @member CKEDITOR.editor
911 * @param {Boolean} [checkNow=false] Force the check to happen immediately
912 * instead of coming with a timeout delay (default).
913 */
914 CKEDITOR.editor.prototype.selectionChange = function( checkNow ) {
915 ( checkNow ? checkSelectionChange : checkSelectionChangeTimeout ).call( this );
916 };
917
918 /**
919 * Retrieve the editor selection in scope of editable element.
920 *
921 * **Note:** Since the native browser selection provides only one single
922 * selection at a time per document, so if editor's editable element has lost focus,
923 * this method will return a null value unless the {@link CKEDITOR.editor#lockSelection}
924 * has been called beforehand so the saved selection is retrieved.
925 *
926 * var selection = CKEDITOR.instances.editor1.getSelection();
927 * alert( selection.getType() );
928 *
929 * @method
930 * @member CKEDITOR.editor
931 * @param {Boolean} forceRealSelection Return real selection, instead of saved or fake one.
932 * @returns {CKEDITOR.dom.selection} A selection object or null if not available for the moment.
933 */
934 CKEDITOR.editor.prototype.getSelection = function( forceRealSelection ) {
935
936 // Check if there exists a locked or fake selection.
937 if ( ( this._.savedSelection || this._.fakeSelection ) && !forceRealSelection )
938 return this._.savedSelection || this._.fakeSelection;
939
940 // Editable element might be absent or editor might not be in a wysiwyg mode.
941 var editable = this.editable();
942 return editable && this.mode == 'wysiwyg' ? new CKEDITOR.dom.selection( editable ) : null;
943 };
944
945 /**
946 * Locks the selection made in the editor in order to make it possible to
947 * manipulate it without browser interference. A locked selection is
948 * cached and remains unchanged until it is released with the
949 * {@link CKEDITOR.editor#unlockSelection} method.
950 *
951 * @method
952 * @member CKEDITOR.editor
953 * @param {CKEDITOR.dom.selection} [sel] Specify the selection to be locked.
954 * @returns {Boolean} `true` if selection was locked.
955 */
956 CKEDITOR.editor.prototype.lockSelection = function( sel ) {
957 sel = sel || this.getSelection( 1 );
958 if ( sel.getType() != CKEDITOR.SELECTION_NONE ) {
959 !sel.isLocked && sel.lock();
960 this._.savedSelection = sel;
961 return true;
962 }
963 return false;
964 };
965
966 /**
967 * Unlocks the selection made in the editor and locked with the
968 * {@link CKEDITOR.editor#unlockSelection} method. An unlocked selection
969 * is no longer cached and can be changed.
970 *
971 * @method
972 * @member CKEDITOR.editor
973 * @param {Boolean} [restore] If set to `true`, the selection is
974 * restored back to the selection saved earlier by using the
975 * {@link CKEDITOR.dom.selection#lock} method.
976 */
977 CKEDITOR.editor.prototype.unlockSelection = function( restore ) {
978 var sel = this._.savedSelection;
979 if ( sel ) {
980 sel.unlock( restore );
981 delete this._.savedSelection;
982 return true;
983 }
984
985 return false;
986 };
987
988 /**
989 * @method
990 * @member CKEDITOR.editor
991 * @todo
992 */
993 CKEDITOR.editor.prototype.forceNextSelectionCheck = function() {
994 delete this._.selectionPreviousPath;
995 };
996
997 /**
998 * Gets the current selection in context of the document's body element.
999 *
1000 * var selection = CKEDITOR.instances.editor1.document.getSelection();
1001 * alert( selection.getType() );
1002 *
1003 * @method
1004 * @member CKEDITOR.dom.document
1005 * @returns {CKEDITOR.dom.selection} A selection object.
1006 */
1007 CKEDITOR.dom.document.prototype.getSelection = function() {
1008 return new CKEDITOR.dom.selection( this );
1009 };
1010
1011 /**
1012 * Select this range as the only one with {@link CKEDITOR.dom.selection#selectRanges}.
1013 *
1014 * @method
1015 * @returns {CKEDITOR.dom.selection}
1016 * @member CKEDITOR.dom.range
1017 */
1018 CKEDITOR.dom.range.prototype.select = function() {
1019 var sel = this.root instanceof CKEDITOR.editable ? this.root.editor.getSelection() : new CKEDITOR.dom.selection( this.root );
1020
1021 sel.selectRanges( [ this ] );
1022
1023 return sel;
1024 };
1025
1026 /**
1027 * No selection.
1028 *
1029 * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
1030 * alert( 'Nothing is selected' );
1031 *
1032 * @readonly
1033 * @property {Number} [=1]
1034 * @member CKEDITOR
1035 */
1036 CKEDITOR.SELECTION_NONE = 1;
1037
1038 /**
1039 * A text or a collapsed selection.
1040 *
1041 * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
1042 * alert( 'A text is selected' );
1043 *
1044 * @readonly
1045 * @property {Number} [=2]
1046 * @member CKEDITOR
1047 */
1048 CKEDITOR.SELECTION_TEXT = 2;
1049
1050 /**
1051 * Element selection.
1052 *
1053 * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
1054 * alert( 'An element is selected' );
1055 *
1056 * @readonly
1057 * @property {Number} [=3]
1058 * @member CKEDITOR
1059 */
1060 CKEDITOR.SELECTION_ELEMENT = 3;
1061
1062 /**
1063 * Manipulates the selection within a DOM element. If the current browser selection
1064 * spans outside of the element, an empty selection object is returned.
1065 *
1066 * Despite the fact that selection's constructor allows to create selection instances,
1067 * usually it's better to get selection from the editor instance:
1068 *
1069 * var sel = editor.getSelection();
1070 *
1071 * See {@link CKEDITOR.editor#getSelection}.
1072 *
1073 * @class
1074 * @constructor Creates a selection class instance.
1075 *
1076 * // Selection scoped in document.
1077 * var sel = new CKEDITOR.dom.selection( CKEDITOR.document );
1078 *
1079 * // Selection scoped in element with 'editable' id.
1080 * var sel = new CKEDITOR.dom.selection( CKEDITOR.document.getById( 'editable' ) );
1081 *
1082 * // Cloning selection.
1083 * var clone = new CKEDITOR.dom.selection( sel );
1084 *
1085 * @param {CKEDITOR.dom.document/CKEDITOR.dom.element/CKEDITOR.dom.selection} target
1086 * The DOM document/element that the DOM selection is restrained to. Only selection which spans
1087 * within the target element is considered as valid.
1088 *
1089 * If {@link CKEDITOR.dom.selection} is passed, then its clone will be created.
1090 */
1091 CKEDITOR.dom.selection = function( target ) {
1092 // Target is a selection - clone it.
1093 if ( target instanceof CKEDITOR.dom.selection ) {
1094 var selection = target;
1095 target = target.root;
1096 }
1097
1098 var isElement = target instanceof CKEDITOR.dom.element,
1099 root;
1100
1101 this.rev = selection ? selection.rev : nextRev++;
1102 this.document = target instanceof CKEDITOR.dom.document ? target : target.getDocument();
1103 this.root = root = isElement ? target : this.document.getBody();
1104 this.isLocked = 0;
1105 this._ = {
1106 cache: {}
1107 };
1108
1109 // Clone selection.
1110 if ( selection ) {
1111 CKEDITOR.tools.extend( this._.cache, selection._.cache );
1112 this.isFake = selection.isFake;
1113 this.isLocked = selection.isLocked;
1114 return this;
1115 }
1116
1117 // Check whether browser focus is really inside of the editable element.
1118
1119 var nativeSel = this.getNative(),
1120 rangeParent,
1121 range;
1122
1123 if ( nativeSel ) {
1124 if ( nativeSel.getRangeAt ) {
1125 range = nativeSel.rangeCount && nativeSel.getRangeAt( 0 );
1126 rangeParent = range && new CKEDITOR.dom.node( range.commonAncestorContainer );
1127 }
1128 // For old IEs.
1129 else {
1130 // Sometimes, mostly when selection is close to the table or hr,
1131 // IE throws "Unspecified error".
1132 try {
1133 range = nativeSel.createRange();
1134 } catch ( err ) {}
1135 rangeParent = range && CKEDITOR.dom.element.get( range.item && range.item( 0 ) || range.parentElement() );
1136 }
1137 }
1138
1139 // Selection out of concerned range, empty the selection.
1140 // TODO check whether this condition cannot be reverted to its old
1141 // form (commented out) after we closed #10438.
1142 //if ( !( rangeParent && ( root.equals( rangeParent ) || root.contains( rangeParent ) ) ) ) {
1143 if ( !(
1144 rangeParent &&
1145 ( rangeParent.type == CKEDITOR.NODE_ELEMENT || rangeParent.type == CKEDITOR.NODE_TEXT ) &&
1146 ( this.root.equals( rangeParent ) || this.root.contains( rangeParent ) )
1147 ) ) {
1148
1149 this._.cache.type = CKEDITOR.SELECTION_NONE;
1150 this._.cache.startElement = null;
1151 this._.cache.selectedElement = null;
1152 this._.cache.selectedText = '';
1153 this._.cache.ranges = new CKEDITOR.dom.rangeList();
1154 }
1155
1156 return this;
1157 };
1158
1159 var styleObjectElements = { img: 1, hr: 1, li: 1, table: 1, tr: 1, td: 1, th: 1, embed: 1, object: 1, ol: 1, ul: 1,
1160 a: 1, input: 1, form: 1, select: 1, textarea: 1, button: 1, fieldset: 1, thead: 1, tfoot: 1 };
1161
1162 CKEDITOR.tools.extend( CKEDITOR.dom.selection, {
1163 _removeFillingCharSequenceString: removeFillingCharSequenceString,
1164 _createFillingCharSequenceNode: createFillingCharSequenceNode,
1165
1166 /**
1167 * The sequence used in a WebKit-based browser to create a Filling Character. By default it is
1168 * a string of 7 zero-width space characters (U+200B).
1169 *
1170 * @since 4.5.7
1171 * @readonly
1172 * @property {String}
1173 */
1174 FILLING_CHAR_SEQUENCE: fillingCharSequence
1175 } );
1176
1177 CKEDITOR.dom.selection.prototype = {
1178 /**
1179 * Gets the native selection object from the browser.
1180 *
1181 * var selection = editor.getSelection().getNative();
1182 *
1183 * @returns {Object} The native browser selection object.
1184 */
1185 getNative: function() {
1186 if ( this._.cache.nativeSel !== undefined )
1187 return this._.cache.nativeSel;
1188
1189 return ( this._.cache.nativeSel = isMSSelection ? this.document.$.selection : this.document.getWindow().$.getSelection() );
1190 },
1191
1192 /**
1193 * Gets the type of the current selection. The following values are
1194 * available:
1195 *
1196 * * {@link CKEDITOR#SELECTION_NONE} (1): No selection.
1197 * * {@link CKEDITOR#SELECTION_TEXT} (2): A text or a collapsed selection is selected.
1198 * * {@link CKEDITOR#SELECTION_ELEMENT} (3): An element is selected.
1199 *
1200 * Example:
1201 *
1202 * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
1203 * alert( 'A text is selected' );
1204 *
1205 * @method
1206 * @returns {Number} One of the following constant values: {@link CKEDITOR#SELECTION_NONE},
1207 * {@link CKEDITOR#SELECTION_TEXT} or {@link CKEDITOR#SELECTION_ELEMENT}.
1208 */
1209 getType: isMSSelection ?
1210 function() {
1211 var cache = this._.cache;
1212 if ( cache.type )
1213 return cache.type;
1214
1215 var type = CKEDITOR.SELECTION_NONE;
1216
1217 try {
1218 var sel = this.getNative(),
1219 ieType = sel.type;
1220
1221 if ( ieType == 'Text' )
1222 type = CKEDITOR.SELECTION_TEXT;
1223
1224 if ( ieType == 'Control' )
1225 type = CKEDITOR.SELECTION_ELEMENT;
1226
1227 // It is possible that we can still get a text range
1228 // object even when type == 'None' is returned by IE.
1229 // So we'd better check the object returned by
1230 // createRange() rather than by looking at the type.
1231 if ( sel.createRange().parentElement() )
1232 type = CKEDITOR.SELECTION_TEXT;
1233 } catch ( e ) {}
1234
1235 return ( cache.type = type );
1236 } : function() {
1237 var cache = this._.cache;
1238 if ( cache.type )
1239 return cache.type;
1240
1241 var type = CKEDITOR.SELECTION_TEXT;
1242
1243 var sel = this.getNative();
1244
1245 if ( !( sel && sel.rangeCount ) )
1246 type = CKEDITOR.SELECTION_NONE;
1247 else if ( sel.rangeCount == 1 ) {
1248 // Check if the actual selection is a control (IMG,
1249 // TABLE, HR, etc...).
1250
1251 var range = sel.getRangeAt( 0 ),
1252 startContainer = range.startContainer;
1253
1254 if ( startContainer == range.endContainer && startContainer.nodeType == 1 &&
1255 ( range.endOffset - range.startOffset ) == 1 &&
1256 styleObjectElements[ startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] ) {
1257 type = CKEDITOR.SELECTION_ELEMENT;
1258 }
1259
1260 }
1261
1262 return ( cache.type = type );
1263 },
1264
1265 /**
1266 * Retrieves the {@link CKEDITOR.dom.range} instances that represent the current selection.
1267 *
1268 * Note: Some browsers return multiple ranges even for a continuous selection. Firefox, for example, returns
1269 * one range for each table cell when one or more table rows are selected.
1270 *
1271 * var ranges = selection.getRanges();
1272 * alert( ranges.length );
1273 *
1274 * @method
1275 * @param {Boolean} [onlyEditables] If set to `true`, this function retrives editable ranges only.
1276 * @returns {Array} Range instances that represent the current selection.
1277 */
1278 getRanges: ( function() {
1279 var func = isMSSelection ? ( function() {
1280 function getNodeIndex( node ) {
1281 return new CKEDITOR.dom.node( node ).getIndex();
1282 }
1283
1284 // Finds the container and offset for a specific boundary
1285 // of an IE range.
1286 var getBoundaryInformation = function( range, start ) {
1287 // Creates a collapsed range at the requested boundary.
1288 range = range.duplicate();
1289 range.collapse( start );
1290
1291 // Gets the element that encloses the range entirely.
1292 var parent = range.parentElement();
1293
1294 // Empty parent element, e.g. <i>^</i>
1295 if ( !parent.hasChildNodes() )
1296 return { container: parent, offset: 0 };
1297
1298 var siblings = parent.children,
1299 child, sibling,
1300 testRange = range.duplicate(),
1301 startIndex = 0,
1302 endIndex = siblings.length - 1,
1303 index = -1,
1304 position, distance, container;
1305
1306 // Binary search over all element childs to test the range to see whether
1307 // range is right on the boundary of one element.
1308 while ( startIndex <= endIndex ) {
1309 index = Math.floor( ( startIndex + endIndex ) / 2 );
1310 child = siblings[ index ];
1311 testRange.moveToElementText( child );
1312 position = testRange.compareEndPoints( 'StartToStart', range );
1313
1314 if ( position > 0 )
1315 endIndex = index - 1;
1316 else if ( position < 0 )
1317 startIndex = index + 1;
1318 else
1319 return { container: parent, offset: getNodeIndex( child ) };
1320 }
1321
1322 // All childs are text nodes,
1323 // or to the right hand of test range are all text nodes. (#6992)
1324 if ( index == -1 || index == siblings.length - 1 && position < 0 ) {
1325 // Adapt test range to embrace the entire parent contents.
1326 testRange.moveToElementText( parent );
1327 testRange.setEndPoint( 'StartToStart', range );
1328
1329 // IE report line break as CRLF with range.text but
1330 // only LF with textnode.nodeValue, normalize them to avoid
1331 // breaking character counting logic below. (#3949)
1332 distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
1333
1334 siblings = parent.childNodes;
1335
1336 // Actual range anchor right beside test range at the boundary of text node.
1337 if ( !distance ) {
1338 child = siblings[ siblings.length - 1 ];
1339
1340 if ( child.nodeType != CKEDITOR.NODE_TEXT )
1341 return { container: parent, offset: siblings.length };
1342 else
1343 return { container: child, offset: child.nodeValue.length };
1344 }
1345
1346 // Start the measuring until distance overflows, meanwhile count the text nodes.
1347 var i = siblings.length;
1348 while ( distance > 0 && i > 0 ) {
1349 sibling = siblings[ --i ];
1350 if ( sibling.nodeType == CKEDITOR.NODE_TEXT ) {
1351 container = sibling;
1352 distance -= sibling.nodeValue.length;
1353 }
1354 }
1355
1356 return { container: container, offset: -distance };
1357 }
1358 // Test range was one offset beyond OR behind the anchored text node.
1359 else {
1360 // Adapt one side of test range to the actual range
1361 // for measuring the offset between them.
1362 testRange.collapse( position > 0 ? true : false );
1363 testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range );
1364
1365 // IE report line break as CRLF with range.text but
1366 // only LF with textnode.nodeValue, normalize them to avoid
1367 // breaking character counting logic below. (#3949)
1368 distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
1369
1370 // Actual range anchor right beside test range at the inner boundary of text node.
1371 if ( !distance )
1372 return { container: parent, offset: getNodeIndex( child ) + ( position > 0 ? 0 : 1 ) };
1373
1374 // Start the measuring until distance overflows, meanwhile count the text nodes.
1375 while ( distance > 0 ) {
1376 try {
1377 sibling = child[ position > 0 ? 'previousSibling' : 'nextSibling' ];
1378 if ( sibling.nodeType == CKEDITOR.NODE_TEXT ) {
1379 distance -= sibling.nodeValue.length;
1380 container = sibling;
1381 }
1382 child = sibling;
1383 }
1384 // Measurement in IE could be somtimes wrong because of <select> element. (#4611)
1385 catch ( e ) {
1386 return { container: parent, offset: getNodeIndex( child ) };
1387 }
1388 }
1389
1390 return { container: container, offset: position > 0 ? -distance : container.nodeValue.length + distance };
1391 }
1392 };
1393
1394 return function() {
1395 // IE doesn't have range support (in the W3C way), so we
1396 // need to do some magic to transform selections into
1397 // CKEDITOR.dom.range instances.
1398
1399 var sel = this.getNative(),
1400 nativeRange = sel && sel.createRange(),
1401 type = this.getType(),
1402 range;
1403
1404 if ( !sel )
1405 return [];
1406
1407 if ( type == CKEDITOR.SELECTION_TEXT ) {
1408 range = new CKEDITOR.dom.range( this.root );
1409
1410 var boundaryInfo = getBoundaryInformation( nativeRange, true );
1411 range.setStart( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
1412
1413 boundaryInfo = getBoundaryInformation( nativeRange );
1414 range.setEnd( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
1415
1416 // Correct an invalid IE range case on empty list item. (#5850)
1417 if ( range.endContainer.getPosition( range.startContainer ) & CKEDITOR.POSITION_PRECEDING && range.endOffset <= range.startContainer.getIndex() )
1418 range.collapse();
1419
1420 return [ range ];
1421 } else if ( type == CKEDITOR.SELECTION_ELEMENT ) {
1422 var retval = [];
1423
1424 for ( var i = 0; i < nativeRange.length; i++ ) {
1425 var element = nativeRange.item( i ),
1426 parentElement = element.parentNode,
1427 j = 0;
1428
1429 range = new CKEDITOR.dom.range( this.root );
1430
1431 for ( ; j < parentElement.childNodes.length && parentElement.childNodes[ j ] != element; j++ ) {
1432
1433 }
1434
1435 range.setStart( new CKEDITOR.dom.node( parentElement ), j );
1436 range.setEnd( new CKEDITOR.dom.node( parentElement ), j + 1 );
1437 retval.push( range );
1438 }
1439
1440 return retval;
1441 }
1442
1443 return [];
1444 };
1445 } )() :
1446 function() {
1447 // On browsers implementing the W3C range, we simply
1448 // tranform the native ranges in CKEDITOR.dom.range
1449 // instances.
1450
1451 var ranges = [],
1452 range,
1453 sel = this.getNative();
1454
1455 if ( !sel )
1456 return ranges;
1457
1458 for ( var i = 0; i < sel.rangeCount; i++ ) {
1459 var nativeRange = sel.getRangeAt( i );
1460
1461 range = new CKEDITOR.dom.range( this.root );
1462
1463 range.setStart( new CKEDITOR.dom.node( nativeRange.startContainer ), nativeRange.startOffset );
1464 range.setEnd( new CKEDITOR.dom.node( nativeRange.endContainer ), nativeRange.endOffset );
1465 ranges.push( range );
1466 }
1467 return ranges;
1468 };
1469
1470 return function( onlyEditables ) {
1471 var cache = this._.cache,
1472 ranges = cache.ranges;
1473
1474 if ( !ranges )
1475 cache.ranges = ranges = new CKEDITOR.dom.rangeList( func.call( this ) );
1476
1477 if ( !onlyEditables )
1478 return ranges;
1479
1480 // Split range into multiple by read-only nodes.
1481 // Clone ranges array to avoid changing cached ranges (#11493).
1482 return extractEditableRanges( new CKEDITOR.dom.rangeList( ranges.slice() ) );
1483 };
1484 } )(),
1485
1486 /**
1487 * Gets the DOM element in which the selection starts.
1488 *
1489 * var element = editor.getSelection().getStartElement();
1490 * alert( element.getName() );
1491 *
1492 * @returns {CKEDITOR.dom.element} The element at the beginning of the selection.
1493 */
1494 getStartElement: function() {
1495 var cache = this._.cache;
1496 if ( cache.startElement !== undefined )
1497 return cache.startElement;
1498
1499 var node;
1500
1501 switch ( this.getType() ) {
1502 case CKEDITOR.SELECTION_ELEMENT:
1503 return this.getSelectedElement();
1504
1505 case CKEDITOR.SELECTION_TEXT:
1506
1507 var range = this.getRanges()[ 0 ];
1508
1509 if ( range ) {
1510 if ( !range.collapsed ) {
1511 range.optimize();
1512
1513 // Decrease the range content to exclude particial
1514 // selected node on the start which doesn't have
1515 // visual impact. ( #3231 )
1516 while ( 1 ) {
1517 var startContainer = range.startContainer,
1518 startOffset = range.startOffset;
1519 // Limit the fix only to non-block elements.(#3950)
1520 if ( startOffset == ( startContainer.getChildCount ? startContainer.getChildCount() : startContainer.getLength() ) && !startContainer.isBlockBoundary() )
1521 range.setStartAfter( startContainer );
1522 else
1523 break;
1524 }
1525
1526 node = range.startContainer;
1527
1528 if ( node.type != CKEDITOR.NODE_ELEMENT )
1529 return node.getParent();
1530
1531 node = node.getChild( range.startOffset );
1532
1533 if ( !node || node.type != CKEDITOR.NODE_ELEMENT )
1534 node = range.startContainer;
1535 else {
1536 var child = node.getFirst();
1537 while ( child && child.type == CKEDITOR.NODE_ELEMENT ) {
1538 node = child;
1539 child = child.getFirst();
1540 }
1541 }
1542 } else {
1543 node = range.startContainer;
1544 if ( node.type != CKEDITOR.NODE_ELEMENT )
1545 node = node.getParent();
1546 }
1547
1548 node = node.$;
1549 }
1550 }
1551
1552 return cache.startElement = ( node ? new CKEDITOR.dom.element( node ) : null );
1553 },
1554
1555 /**
1556 * Gets the currently selected element.
1557 *
1558 * var element = editor.getSelection().getSelectedElement();
1559 * alert( element.getName() );
1560 *
1561 * @returns {CKEDITOR.dom.element} The selected element. Null if no
1562 * selection is available or the selection type is not {@link CKEDITOR#SELECTION_ELEMENT}.
1563 */
1564 getSelectedElement: function() {
1565 var cache = this._.cache;
1566 if ( cache.selectedElement !== undefined )
1567 return cache.selectedElement;
1568
1569 var self = this;
1570
1571 var node = CKEDITOR.tools.tryThese(
1572 // Is it native IE control type selection?
1573 function() {
1574 return self.getNative().createRange().item( 0 );
1575 },
1576 // Figure it out by checking if there's a single enclosed
1577 // node of the range.
1578 function() {
1579 var range = self.getRanges()[ 0 ].clone(),
1580 enclosed, selected;
1581
1582 // Check first any enclosed element, e.g. <ul>[<li><a href="#">item</a></li>]</ul>
1583 for ( var i = 2; i && !( ( enclosed = range.getEnclosedNode() ) && ( enclosed.type == CKEDITOR.NODE_ELEMENT ) && styleObjectElements[ enclosed.getName() ] && ( selected = enclosed ) ); i-- ) {
1584 // Then check any deep wrapped element, e.g. [<b><i><img /></i></b>]
1585 range.shrink( CKEDITOR.SHRINK_ELEMENT );
1586 }
1587
1588 return selected && selected.$;
1589 }
1590 );
1591
1592 return cache.selectedElement = ( node ? new CKEDITOR.dom.element( node ) : null );
1593 },
1594
1595 /**
1596 * Retrieves the text contained within the range. An empty string is returned for non-text selection.
1597 *
1598 * var text = editor.getSelection().getSelectedText();
1599 * alert( text );
1600 *
1601 * @since 3.6.1
1602 * @returns {String} A string of text within the current selection.
1603 */
1604 getSelectedText: function() {
1605 var cache = this._.cache;
1606 if ( cache.selectedText !== undefined )
1607 return cache.selectedText;
1608
1609 var nativeSel = this.getNative(),
1610 text = isMSSelection ? nativeSel.type == 'Control' ? '' : nativeSel.createRange().text : nativeSel.toString();
1611
1612 return ( cache.selectedText = text );
1613 },
1614
1615 /**
1616 * Locks the selection made in the editor in order to make it possible to
1617 * manipulate it without browser interference. A locked selection is
1618 * cached and remains unchanged until it is released with the {@link #unlock} method.
1619 *
1620 * editor.getSelection().lock();
1621 */
1622 lock: function() {
1623 // Call all cacheable function.
1624 this.getRanges();
1625 this.getStartElement();
1626 this.getSelectedElement();
1627 this.getSelectedText();
1628
1629 // The native selection is not available when locked.
1630 this._.cache.nativeSel = null;
1631
1632 this.isLocked = 1;
1633 },
1634
1635 /**
1636 * @todo
1637 */
1638 unlock: function( restore ) {
1639 if ( !this.isLocked )
1640 return;
1641
1642 if ( restore ) {
1643 var selectedElement = this.getSelectedElement(),
1644 ranges = !selectedElement && this.getRanges(),
1645 faked = this.isFake;
1646 }
1647
1648 this.isLocked = 0;
1649 this.reset();
1650
1651 if ( restore ) {
1652 // Saved selection may be outdated (e.g. anchored in offline nodes).
1653 // Avoid getting broken by such.
1654 var common = selectedElement || ranges[ 0 ] && ranges[ 0 ].getCommonAncestor();
1655 if ( !( common && common.getAscendant( 'body', 1 ) ) )
1656 return;
1657
1658 if ( faked )
1659 this.fake( selectedElement );
1660 else if ( selectedElement )
1661 this.selectElement( selectedElement );
1662 else
1663 this.selectRanges( ranges );
1664 }
1665 },
1666
1667 /**
1668 * Clears the selection cache.
1669 *
1670 * editor.getSelection().reset();
1671 */
1672 reset: function() {
1673 this._.cache = {};
1674 this.isFake = 0;
1675
1676 var editor = this.root.editor;
1677
1678 // Invalidate any fake selection available in the editor.
1679 if ( editor && editor._.fakeSelection ) {
1680 // Test whether this selection is the one that was
1681 // faked or its clone.
1682 if ( this.rev == editor._.fakeSelection.rev ) {
1683 delete editor._.fakeSelection;
1684
1685 removeHiddenSelectionContainer( editor );
1686 }
1687 else {
1688 CKEDITOR.warn( 'selection-fake-reset' );
1689 }
1690 }
1691
1692 this.rev = nextRev++;
1693 },
1694
1695 /**
1696 * Makes the current selection of type {@link CKEDITOR#SELECTION_ELEMENT} by enclosing the specified element.
1697 *
1698 * var element = editor.document.getById( 'sampleElement' );
1699 * editor.getSelection().selectElement( element );
1700 *
1701 * @param {CKEDITOR.dom.element} element The element to enclose in the selection.
1702 */
1703 selectElement: function( element ) {
1704 var range = new CKEDITOR.dom.range( this.root );
1705 range.setStartBefore( element );
1706 range.setEndAfter( element );
1707 this.selectRanges( [ range ] );
1708 },
1709
1710 /**
1711 * Clears the original selection and adds the specified ranges to the document selection.
1712 *
1713 * // Move selection to the end of the editable element.
1714 * var range = editor.createRange();
1715 * range.moveToPosition( range.root, CKEDITOR.POSITION_BEFORE_END );
1716 * editor.getSelection().selectRanges( [ ranges ] );
1717 *
1718 * @param {Array} ranges An array of {@link CKEDITOR.dom.range} instances
1719 * representing ranges to be added to the document.
1720 */
1721 selectRanges: function( ranges ) {
1722 var editor = this.root.editor,
1723 hadHiddenSelectionContainer = editor && editor._.hiddenSelectionContainer;
1724
1725 this.reset();
1726
1727 // Check if there's a hiddenSelectionContainer in editable at some index.
1728 // Some ranges may be anchored after the hiddenSelectionContainer and,
1729 // once the container is removed while resetting the selection, they
1730 // may need new endOffset (one element less within the range) (#11021 #11393).
1731 if ( hadHiddenSelectionContainer )
1732 fixRangesAfterHiddenSelectionContainer( ranges, this.root );
1733
1734 if ( !ranges.length )
1735 return;
1736
1737 // Refresh the locked selection.
1738 if ( this.isLocked ) {
1739 // making a new DOM selection will force the focus on editable in certain situation,
1740 // we have to save the currently focused element for later recovery.
1741 var focused = CKEDITOR.document.getActive();
1742 this.unlock();
1743 this.selectRanges( ranges );
1744 this.lock();
1745 // Return to the previously focused element.
1746 focused && !focused.equals( this.root ) && focused.focus();
1747 return;
1748 }
1749
1750 // Handle special case - automatic fake selection on non-editable elements.
1751 var receiver = getNonEditableFakeSelectionReceiver( ranges );
1752
1753 if ( receiver ) {
1754 this.fake( receiver );
1755 return;
1756 }
1757
1758 if ( isMSSelection ) {
1759 var notWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
1760 fillerTextRegex = /\ufeff|\u00a0/,
1761 nonCells = { table: 1, tbody: 1, tr: 1 };
1762
1763 if ( ranges.length > 1 ) {
1764 // IE doesn't accept multiple ranges selection, so we join all into one.
1765 var last = ranges[ ranges.length - 1 ];
1766 ranges[ 0 ].setEnd( last.endContainer, last.endOffset );
1767 }
1768
1769 var range = ranges[ 0 ];
1770 var collapsed = range.collapsed,
1771 isStartMarkerAlone, dummySpan, ieRange;
1772
1773 // Try to make a object selection, be careful with selecting phase element in IE
1774 // will breaks the selection in non-framed environment.
1775 var selected = range.getEnclosedNode();
1776 if ( selected && selected.type == CKEDITOR.NODE_ELEMENT && selected.getName() in styleObjectElements &&
1777 !( selected.is( 'a' ) && selected.getText() ) ) {
1778 try {
1779 ieRange = selected.$.createControlRange();
1780 ieRange.addElement( selected.$ );
1781 ieRange.select();
1782 return;
1783 } catch ( er ) {}
1784 }
1785
1786 // IE doesn't support selecting the entire table row/cell, move the selection into cells, e.g.
1787 // <table><tbody><tr>[<td>cell</b></td>... => <table><tbody><tr><td>[cell</td>...
1788 if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT && range.startContainer.getName() in nonCells ||
1789 range.endContainer.type == CKEDITOR.NODE_ELEMENT && range.endContainer.getName() in nonCells ) {
1790 range.shrink( CKEDITOR.NODE_ELEMENT, true );
1791 // The range might get collapsed (#7975). Update cached variable.
1792 collapsed = range.collapsed;
1793 }
1794
1795 var bookmark = range.createBookmark();
1796
1797 // Create marker tags for the start and end boundaries.
1798 var startNode = bookmark.startNode;
1799
1800 var endNode;
1801 if ( !collapsed )
1802 endNode = bookmark.endNode;
1803
1804 // Create the main range which will be used for the selection.
1805 ieRange = range.document.$.body.createTextRange();
1806
1807 // Position the range at the start boundary.
1808 ieRange.moveToElementText( startNode.$ );
1809 ieRange.moveStart( 'character', 1 );
1810
1811 if ( endNode ) {
1812 // Create a tool range for the end.
1813 var ieRangeEnd = range.document.$.body.createTextRange();
1814
1815 // Position the tool range at the end.
1816 ieRangeEnd.moveToElementText( endNode.$ );
1817
1818 // Move the end boundary of the main range to match the tool range.
1819 ieRange.setEndPoint( 'EndToEnd', ieRangeEnd );
1820 ieRange.moveEnd( 'character', -1 );
1821 } else {
1822 // The isStartMarkerAlone logic comes from V2. It guarantees that the lines
1823 // will expand and that the cursor will be blinking on the right place.
1824 // Actually, we are using this flag just to avoid using this hack in all
1825 // situations, but just on those needed.
1826 var next = startNode.getNext( notWhitespaces );
1827 var inPre = startNode.hasAscendant( 'pre' );
1828 isStartMarkerAlone = ( !( next && next.getText && next.getText().match( fillerTextRegex ) ) && // already a filler there?
1829 ( inPre || !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) ) );
1830
1831 // Append a temporary <span>&#65279;</span> before the selection.
1832 // This is needed to avoid IE destroying selections inside empty
1833 // inline elements, like <b></b> (#253).
1834 // It is also needed when placing the selection right after an inline
1835 // element to avoid the selection moving inside of it.
1836 dummySpan = range.document.createElement( 'span' );
1837 dummySpan.setHtml( '&#65279;' ); // Zero Width No-Break Space (U+FEFF). See #1359.
1838 dummySpan.insertBefore( startNode );
1839
1840 if ( isStartMarkerAlone ) {
1841 // To expand empty blocks or line spaces after <br>, we need
1842 // instead to have any char, which will be later deleted using the
1843 // selection.
1844 // \ufeff = Zero Width No-Break Space (U+FEFF). (#1359)
1845 range.document.createText( '\ufeff' ).insertBefore( startNode );
1846 }
1847 }
1848
1849 // Remove the markers (reset the position, because of the changes in the DOM tree).
1850 range.setStartBefore( startNode );
1851 startNode.remove();
1852
1853 if ( collapsed ) {
1854 if ( isStartMarkerAlone ) {
1855 // Move the selection start to include the temporary \ufeff.
1856 ieRange.moveStart( 'character', -1 );
1857
1858 ieRange.select();
1859
1860 // Remove our temporary stuff.
1861 range.document.$.selection.clear();
1862 } else {
1863 ieRange.select();
1864 }
1865
1866 range.moveToPosition( dummySpan, CKEDITOR.POSITION_BEFORE_START );
1867 dummySpan.remove();
1868 } else {
1869 range.setEndBefore( endNode );
1870 endNode.remove();
1871 ieRange.select();
1872 }
1873 } else {
1874 var sel = this.getNative();
1875
1876 // getNative() returns null if iframe is "display:none" in FF. (#6577)
1877 if ( !sel )
1878 return;
1879
1880 this.removeAllRanges();
1881
1882 for ( var i = 0; i < ranges.length; i++ ) {
1883 // Joining sequential ranges introduced by
1884 // readonly elements protection.
1885 if ( i < ranges.length - 1 ) {
1886 var left = ranges[ i ],
1887 right = ranges[ i + 1 ],
1888 between = left.clone();
1889 between.setStart( left.endContainer, left.endOffset );
1890 between.setEnd( right.startContainer, right.startOffset );
1891
1892 // Don't confused by Firefox adjancent multi-ranges
1893 // introduced by table cells selection.
1894 if ( !between.collapsed ) {
1895 between.shrink( CKEDITOR.NODE_ELEMENT, true );
1896 var ancestor = between.getCommonAncestor(),
1897 enclosed = between.getEnclosedNode();
1898
1899 // The following cases has to be considered:
1900 // 1. <span contenteditable="false">[placeholder]</span>
1901 // 2. <input contenteditable="false" type="radio"/> (#6621)
1902 if ( ancestor.isReadOnly() || enclosed && enclosed.isReadOnly() ) {
1903 right.setStart( left.startContainer, left.startOffset );
1904 ranges.splice( i--, 1 );
1905 continue;
1906 }
1907 }
1908 }
1909
1910 range = ranges[ i ];
1911
1912 var nativeRange = this.document.$.createRange();
1913
1914 if ( range.collapsed && CKEDITOR.env.webkit && rangeRequiresFix( range ) ) {
1915 // Append a zero-width space so WebKit will not try to
1916 // move the selection by itself (#1272).
1917 var fillingChar = createFillingCharSequenceNode( this.root );
1918 range.insertNode( fillingChar );
1919
1920 next = fillingChar.getNext();
1921
1922 // If the filling char is followed by a <br>, whithout
1923 // having something before it, it'll not blink.
1924 // Let's remove it in this case.
1925 if ( next && !fillingChar.getPrevious() && next.type == CKEDITOR.NODE_ELEMENT && next.getName() == 'br' ) {
1926 removeFillingCharSequenceNode( this.root );
1927 range.moveToPosition( next, CKEDITOR.POSITION_BEFORE_START );
1928 } else {
1929 range.moveToPosition( fillingChar, CKEDITOR.POSITION_AFTER_END );
1930 }
1931 }
1932
1933 nativeRange.setStart( range.startContainer.$, range.startOffset );
1934
1935 try {
1936 nativeRange.setEnd( range.endContainer.$, range.endOffset );
1937 } catch ( e ) {
1938 // There is a bug in Firefox implementation (it would be too easy
1939 // otherwise). The new start can't be after the end (W3C says it can).
1940 // So, let's create a new range and collapse it to the desired point.
1941 if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 ) {
1942 range.collapse( 1 );
1943 nativeRange.setEnd( range.endContainer.$, range.endOffset );
1944 } else {
1945 throw e;
1946 }
1947 }
1948
1949 // Select the range.
1950 sel.addRange( nativeRange );
1951 }
1952 }
1953
1954 this.reset();
1955
1956 // Fakes the IE DOM event "selectionchange" on editable.
1957 this.root.fire( 'selectionchange' );
1958 },
1959
1960 /**
1961 * Makes a "fake selection" of an element.
1962 *
1963 * A fake selection does not render UI artifacts over the selected
1964 * element. Additionally, the browser native selection system is not
1965 * aware of the fake selection. In practice, the native selection is
1966 * moved to a hidden place where no native selection UI artifacts are
1967 * displayed to the user.
1968 *
1969 * @param {CKEDITOR.dom.element} element The element to be "selected".
1970 * @param {String} [ariaLabel] A string to be used by the screen reader to describe the selection.
1971 */
1972 fake: function( element, ariaLabel ) {
1973 var editor = this.root.editor;
1974
1975 // Attempt to retreive aria-label if possible (#14539).
1976 if ( ariaLabel === undefined && element.hasAttribute( 'aria-label' ) ) {
1977 ariaLabel = element.getAttribute( 'aria-label' );
1978 }
1979
1980 // Cleanup after previous selection - e.g. remove hidden sel container.
1981 this.reset();
1982
1983 hideSelection( editor, ariaLabel );
1984
1985 // Set this value after executing hiseSelection, because it may
1986 // cause reset() which overwrites cache.
1987 var cache = this._.cache;
1988
1989 // Caches a range than holds the element.
1990 var range = new CKEDITOR.dom.range( this.root );
1991 range.setStartBefore( element );
1992 range.setEndAfter( element );
1993 cache.ranges = new CKEDITOR.dom.rangeList( range );
1994
1995 // Put this element in the cache.
1996 cache.selectedElement = cache.startElement = element;
1997 cache.type = CKEDITOR.SELECTION_ELEMENT;
1998
1999 // Properties that will not be available when isFake.
2000 cache.selectedText = cache.nativeSel = null;
2001
2002 this.isFake = 1;
2003 this.rev = nextRev++;
2004
2005 // Save this selection, so it can be returned by editor.getSelection().
2006 editor._.fakeSelection = this;
2007
2008 // Fire selectionchange, just like a normal selection.
2009 this.root.fire( 'selectionchange' );
2010 },
2011
2012 /**
2013 * Checks whether selection is placed in hidden element.
2014 *
2015 * This method is to be used to verify whether fake selection
2016 * (see {@link #fake}) is still hidden.
2017 *
2018 * **Note:** this method should be executed on real selection - e.g.:
2019 *
2020 * editor.getSelection( true ).isHidden();
2021 *
2022 * @returns {Boolean}
2023 */
2024 isHidden: function() {
2025 var el = this.getCommonAncestor();
2026
2027 if ( el && el.type == CKEDITOR.NODE_TEXT )
2028 el = el.getParent();
2029
2030 return !!( el && el.data( 'cke-hidden-sel' ) );
2031 },
2032
2033 /**
2034 * Creates a bookmark for each range of this selection (from {@link #getRanges})
2035 * by calling the {@link CKEDITOR.dom.range#createBookmark} method,
2036 * with extra care taken to avoid interference among those ranges. The arguments
2037 * received are the same as with the underlying range method.
2038 *
2039 * var bookmarks = editor.getSelection().createBookmarks();
2040 *
2041 * @returns {Array} Array of bookmarks for each range.
2042 */
2043 createBookmarks: function( serializable ) {
2044 var bookmark = this.getRanges().createBookmarks( serializable );
2045 this.isFake && ( bookmark.isFake = 1 );
2046 return bookmark;
2047 },
2048
2049 /**
2050 * Creates a bookmark for each range of this selection (from {@link #getRanges})
2051 * by calling the {@link CKEDITOR.dom.range#createBookmark2} method,
2052 * with extra care taken to avoid interference among those ranges. The arguments
2053 * received are the same as with the underlying range method.
2054 *
2055 * var bookmarks = editor.getSelection().createBookmarks2();
2056 *
2057 * @returns {Array} Array of bookmarks for each range.
2058 */
2059 createBookmarks2: function( normalized ) {
2060 var bookmark = this.getRanges().createBookmarks2( normalized );
2061 this.isFake && ( bookmark.isFake = 1 );
2062 return bookmark;
2063 },
2064
2065 /**
2066 * Selects the virtual ranges denoted by the bookmarks by calling {@link #selectRanges}.
2067 *
2068 * var bookmarks = editor.getSelection().createBookmarks();
2069 * editor.getSelection().selectBookmarks( bookmarks );
2070 *
2071 * @param {Array} bookmarks The bookmarks representing ranges to be selected.
2072 * @returns {CKEDITOR.dom.selection} This selection object, after the ranges were selected.
2073 */
2074 selectBookmarks: function( bookmarks ) {
2075 var ranges = [],
2076 node;
2077
2078 for ( var i = 0; i < bookmarks.length; i++ ) {
2079 var range = new CKEDITOR.dom.range( this.root );
2080 range.moveToBookmark( bookmarks[ i ] );
2081 ranges.push( range );
2082 }
2083
2084 // It may happen that the content change during loading, before selection is set so bookmark leads to text node.
2085 if ( bookmarks.isFake ) {
2086 node = ranges[ 0 ].getEnclosedNode();
2087 if ( !node || node.type != CKEDITOR.NODE_ELEMENT ) {
2088 CKEDITOR.warn( 'selection-not-fake' );
2089 bookmarks.isFake = 0;
2090 }
2091 }
2092
2093 if ( bookmarks.isFake )
2094 this.fake( node );
2095 else
2096 this.selectRanges( ranges );
2097
2098 return this;
2099 },
2100
2101 /**
2102 * Retrieves the common ancestor node of the first range and the last range.
2103 *
2104 * var ancestor = editor.getSelection().getCommonAncestor();
2105 *
2106 * @returns {CKEDITOR.dom.element} The common ancestor of the selection or `null` if selection is empty.
2107 */
2108 getCommonAncestor: function() {
2109 var ranges = this.getRanges();
2110 if ( !ranges.length )
2111 return null;
2112
2113 var startNode = ranges[ 0 ].startContainer,
2114 endNode = ranges[ ranges.length - 1 ].endContainer;
2115 return startNode.getCommonAncestor( endNode );
2116 },
2117
2118 /**
2119 * Moves the scrollbar to the starting position of the current selection.
2120 *
2121 * editor.getSelection().scrollIntoView();
2122 */
2123 scrollIntoView: function() {
2124 // Scrolls the first range into view.
2125 if ( this.type != CKEDITOR.SELECTION_NONE )
2126 this.getRanges()[ 0 ].scrollIntoView();
2127 },
2128
2129 /**
2130 * Remove all the selection ranges from the document.
2131 */
2132 removeAllRanges: function() {
2133 // Don't clear selection outside this selection's root (#11500).
2134 if ( this.getType() == CKEDITOR.SELECTION_NONE )
2135 return;
2136
2137 var nativ = this.getNative();
2138
2139 try {
2140 nativ && nativ[ isMSSelection ? 'empty' : 'removeAllRanges' ]();
2141 } catch ( er ) {}
2142
2143 this.reset();
2144 }
2145 };
2146
2147} )();
2148
2149
2150/**
2151 * Fired when selection inside editor has been changed. Note that this event
2152 * is fired only when selection's start element (container of a selecion start)
2153 * changes, not on every possible selection change. Thanks to that `selectionChange`
2154 * is fired less frequently, but on every context
2155 * (the {@link CKEDITOR.editor#elementPath elements path} holding selection's start) change.
2156 *
2157 * @event selectionChange
2158 * @member CKEDITOR.editor
2159 * @param {CKEDITOR.editor} editor This editor instance.
2160 * @param data
2161 * @param {CKEDITOR.dom.selection} data.selection
2162 * @param {CKEDITOR.dom.elementPath} data.path
2163 */
2164
2165/**
2166 * Selection's revision. This value is incremented every time new
2167 * selection is created or existing one is modified.
2168 *
2169 * @since 4.3
2170 * @readonly
2171 * @property {Number} rev
2172 */
2173
2174/**
2175 * Document in which selection is anchored.
2176 *
2177 * @readonly
2178 * @property {CKEDITOR.dom.document} document
2179 */
2180
2181/**
2182 * Selection's root element.
2183 *
2184 * @readonly
2185 * @property {CKEDITOR.dom.element} root
2186 */
2187
2188/**
2189 * Whether selection is locked (cannot be modified).
2190 *
2191 * See {@link #lock} and {@link #unlock} methods.
2192 *
2193 * @readonly
2194 * @property {Boolean} isLocked
2195 */
2196
2197/**
2198 * Whether selection is a fake selection.
2199 *
2200 * See {@link #fake} method.
2201 *
2202 * @readonly
2203 * @property {Boolean} isFake
2204 */
diff --git a/sources/core/skin.js b/sources/core/skin.js
new file mode 100644
index 0000000..4f0ee7c
--- /dev/null
+++ b/sources/core/skin.js
@@ -0,0 +1,350 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.skin} class that is used to manage skin parts.
8 */
9
10( function() {
11 var cssLoaded = {};
12
13 function getName() {
14 return CKEDITOR.skinName.split( ',' )[ 0 ];
15 }
16
17 function getConfigPath() {
18 return CKEDITOR.getUrl( CKEDITOR.skinName.split( ',' )[ 1 ] || ( 'skins/' + getName() + '/' ) );
19 }
20
21 /**
22 * Manages the loading of skin parts among all editor instances.
23 *
24 * @class
25 * @singleton
26 */
27 CKEDITOR.skin = {
28 /**
29 * Returns the root path to the skin directory.
30 *
31 * @method
32 * @todo
33 */
34 path: getConfigPath,
35
36 /**
37 * Loads a skin part into the page. Does nothing if the part has already been loaded.
38 *
39 * **Note:** The "editor" part is always auto loaded upon instance creation,
40 * thus this function is mainly used to **lazy load** other parts of the skin
41 * that do not have to be displayed until requested.
42 *
43 * // Load the dialog part.
44 * editor.skin.loadPart( 'dialog' );
45 *
46 * @param {String} part The name of the skin part CSS file that resides in the skin directory.
47 * @param {Function} fn The provided callback function which is invoked after the part is loaded.
48 */
49 loadPart: function( part, fn ) {
50 if ( CKEDITOR.skin.name != getName() ) {
51 CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( getConfigPath() + 'skin.js' ), function() {
52 loadCss( part, fn );
53 } );
54 } else {
55 loadCss( part, fn );
56 }
57 },
58
59 /**
60 * Retrieves the real URL of a (CSS) skin part.
61 *
62 * @param {String} part
63 */
64 getPath: function( part ) {
65 return CKEDITOR.getUrl( getCssPath( part ) );
66 },
67
68 /**
69 * The list of registered icons. To add new icons to this list, use {@link #addIcon}.
70 */
71 icons: {},
72
73 /**
74 * Registers an icon.
75 *
76 * @param {String} name The icon name.
77 * @param {String} path The path to the icon image file.
78 * @param {Number} [offset] The vertical offset position of the icon, if
79 * available inside a strip image.
80 * @param {String} [bgsize] The value of the CSS "background-size" property to
81 * use for this icon
82 */
83 addIcon: function( name, path, offset, bgsize ) {
84 name = name.toLowerCase();
85 if ( !this.icons[ name ] ) {
86 this.icons[ name ] = {
87 path: path,
88 offset: offset || 0,
89 bgsize: bgsize || '16px'
90 };
91 }
92 },
93
94 /**
95 * Gets the CSS background styles to be used to render a specific icon.
96 *
97 * @param {String} name The icon name, as registered with {@link #addIcon}.
98 * @param {Boolean} [rtl] Indicates that the RTL version of the icon is
99 * to be used, if available.
100 * @param {String} [overridePath] The path to the icon image file. It
101 * overrides the path defined by the named icon, if available, and is
102 * used if the named icon was not registered.
103 * @param {Number} [overrideOffset] The vertical offset position of the
104 * icon. It overrides the offset defined by the named icon, if
105 * available, and is used if the named icon was not registered.
106 * @param {String} [overrideBgsize] The value of the CSS "background-size" property
107 * to use for the icon. It overrides the value defined by the named icon,
108 * if available, and is used if the named icon was not registered.
109 */
110 getIconStyle: function( name, rtl, overridePath, overrideOffset, overrideBgsize ) {
111 var icon, path, offset, bgsize;
112
113 if ( name ) {
114 name = name.toLowerCase();
115 // If we're in RTL, try to get the RTL version of the icon.
116 if ( rtl )
117 icon = this.icons[ name + '-rtl' ];
118
119 // If not in LTR or no RTL version available, get the generic one.
120 if ( !icon )
121 icon = this.icons[ name ];
122 }
123
124 path = overridePath || ( icon && icon.path ) || '';
125 offset = overrideOffset || ( icon && icon.offset );
126 bgsize = overrideBgsize || ( icon && icon.bgsize ) || '16px';
127
128 // If we use apostrophes in background-image, we must escape apostrophes in path (just to be sure). (#13361)
129 if ( path )
130 path = path.replace( /'/g, '\\\'' );
131
132 return path &&
133 ( 'background-image:url(\'' + CKEDITOR.getUrl( path ) + '\');background-position:0 ' + offset + 'px;background-size:' + bgsize + ';' );
134 }
135 };
136
137 function getCssPath( part ) {
138 // Check for ua-specific version of skin part.
139 var uas = CKEDITOR.skin[ 'ua_' + part ], env = CKEDITOR.env;
140 if ( uas ) {
141
142 // Having versioned UA checked first.
143 uas = uas.split( ',' ).sort( function( a, b ) {
144 return a > b ? -1 : 1;
145 } );
146
147 // Loop through all ua entries, checking is any of them match the current ua.
148 for ( var i = 0, ua; i < uas.length; i++ ) {
149 ua = uas[ i ];
150
151 if ( env.ie ) {
152 if ( ( ua.replace( /^ie/, '' ) == env.version ) || ( env.quirks && ua == 'iequirks' ) )
153 ua = 'ie';
154 }
155
156 if ( env[ ua ] ) {
157 part += '_' + uas[ i ];
158 break;
159 }
160 }
161 }
162 return CKEDITOR.getUrl( getConfigPath() + part + '.css' );
163 }
164
165 function loadCss( part, callback ) {
166 // Avoid reload.
167 if ( !cssLoaded[ part ] ) {
168 CKEDITOR.document.appendStyleSheet( getCssPath( part ) );
169 cssLoaded[ part ] = 1;
170 }
171
172 // CSS loading should not be blocking.
173 callback && callback();
174 }
175
176 CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
177 /** Gets the color of the editor user interface.
178 *
179 * CKEDITOR.instances.editor1.getUiColor();
180 *
181 * @method
182 * @member CKEDITOR.editor
183 * @returns {String} uiColor The editor UI color or `undefined` if the UI color is not set.
184 */
185 getUiColor: function() {
186 return this.uiColor;
187 },
188
189 /** Sets the color of the editor user interface. This method accepts a color value in
190 * hexadecimal notation, with a `#` character (e.g. #ffffff).
191 *
192 * CKEDITOR.instances.editor1.setUiColor( '#ff00ff' );
193 *
194 * @method
195 * @member CKEDITOR.editor
196 * @param {String} color The desired editor UI color in hexadecimal notation.
197 */
198 setUiColor: function( color ) {
199 var uiStyle = getStylesheet( CKEDITOR.document );
200
201 return ( this.setUiColor = function( color ) {
202 this.uiColor = color;
203
204 var chameleon = CKEDITOR.skin.chameleon,
205 editorStyleContent = '',
206 panelStyleContent = '';
207
208 if ( typeof chameleon == 'function' ) {
209 editorStyleContent = chameleon( this, 'editor' );
210 panelStyleContent = chameleon( this, 'panel' );
211 }
212
213 var replace = [ [ uiColorRegexp, color ] ];
214
215 // Update general style.
216 updateStylesheets( [ uiStyle ], editorStyleContent, replace );
217
218 // Update panel styles.
219 updateStylesheets( uiColorMenus, panelStyleContent, replace );
220 } ).call( this, color );
221 }
222 } );
223
224 var uiColorStylesheetId = 'cke_ui_color',
225 uiColorMenus = [],
226 uiColorRegexp = /\$color/g;
227
228 function getStylesheet( document ) {
229 var node = document.getById( uiColorStylesheetId );
230 if ( !node ) {
231 node = document.getHead().append( 'style' );
232 node.setAttribute( 'id', uiColorStylesheetId );
233 node.setAttribute( 'type', 'text/css' );
234 }
235 return node;
236 }
237
238 function updateStylesheets( styleNodes, styleContent, replace ) {
239 var r, i, content;
240
241 // We have to split CSS declarations for webkit.
242 if ( CKEDITOR.env.webkit ) {
243 styleContent = styleContent.split( '}' ).slice( 0, -1 );
244 for ( i = 0; i < styleContent.length; i++ )
245 styleContent[ i ] = styleContent[ i ].split( '{' );
246 }
247
248 for ( var id = 0; id < styleNodes.length; id++ ) {
249 if ( CKEDITOR.env.webkit ) {
250 for ( i = 0; i < styleContent.length; i++ ) {
251 content = styleContent[ i ][ 1 ];
252 for ( r = 0; r < replace.length; r++ )
253 content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
254
255 styleNodes[ id ].$.sheet.addRule( styleContent[ i ][ 0 ], content );
256 }
257 } else {
258 content = styleContent;
259 for ( r = 0; r < replace.length; r++ )
260 content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
261
262 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 )
263 styleNodes[ id ].$.styleSheet.cssText += content;
264 else
265 styleNodes[ id ].$.innerHTML += content;
266 }
267 }
268 }
269
270 CKEDITOR.on( 'instanceLoaded', function( evt ) {
271 // The chameleon feature is not for IE quirks.
272 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks )
273 return;
274
275 var editor = evt.editor,
276 showCallback = function( event ) {
277 var panel = event.data[ 0 ] || event.data;
278 var iframe = panel.element.getElementsByTag( 'iframe' ).getItem( 0 ).getFrameDocument();
279
280 // Add stylesheet if missing.
281 if ( !iframe.getById( 'cke_ui_color' ) ) {
282 var node = getStylesheet( iframe );
283 uiColorMenus.push( node );
284
285 var color = editor.getUiColor();
286 // Set uiColor for new panel.
287 if ( color )
288 updateStylesheets( [ node ], CKEDITOR.skin.chameleon( editor, 'panel' ), [ [ uiColorRegexp, color ] ] );
289
290 }
291 };
292
293 editor.on( 'panelShow', showCallback );
294 editor.on( 'menuShow', showCallback );
295
296 // Apply UI color if specified in config.
297 if ( editor.config.uiColor )
298 editor.setUiColor( editor.config.uiColor );
299 } );
300} )();
301
302/**
303 * The list of file names matching the browser user agent string from
304 * {@link CKEDITOR.env}. This is used to load the skin part file in addition
305 * to the "main" skin file for a particular browser.
306 *
307 * **Note:** For each of the defined skin parts the corresponding
308 * CSS file with the same name as the user agent must exist inside
309 * the skin directory.
310 *
311 * @property ua
312 * @todo type?
313 */
314
315/**
316 * The name of the skin that is currently used.
317 *
318 * @property {String} name
319 * @todo
320 */
321
322/**
323 * The editor skin name. Note that it is not possible to have editors with
324 * different skin settings in the same page. In such case just one of the
325 * skins will be used for all editors.
326 *
327 * This is a shortcut to {@link CKEDITOR#skinName}.
328 *
329 * It is possible to install skins outside the default `skin` folder in the
330 * editor installation. In that case, the absolute URL path to that folder
331 * should be provided, separated by a comma (`'skin_name,skin_path'`).
332 *
333 * config.skin = 'moono';
334 *
335 * config.skin = 'myskin,/customstuff/myskin/';
336 *
337 * @cfg {String} skin
338 * @member CKEDITOR.config
339 */
340
341/**
342 * A function that supports the chameleon (skin color switch) feature, providing
343 * the skin color style updates to be applied in runtime.
344 *
345 * **Note:** The embedded `$color` variable is to be substituted with a specific UI color.
346 *
347 * @method chameleon
348 * @param {String} editor The editor instance that the color changes apply to.
349 * @param {String} part The name of the skin part where the color changes take place.
350 */
diff --git a/sources/core/style.js b/sources/core/style.js
new file mode 100644
index 0000000..efb9d7f
--- /dev/null
+++ b/sources/core/style.js
@@ -0,0 +1,2102 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8/**
9 * Block style type.
10 *
11 * Read more in the {@link CKEDITOR.style} class documentation.
12 *
13 * @readonly
14 * @property {Number} [=1]
15 * @member CKEDITOR
16 */
17CKEDITOR.STYLE_BLOCK = 1;
18
19/**
20 * Inline style type.
21 *
22 * Read more in the {@link CKEDITOR.style} class documentation.
23 *
24 * @readonly
25 * @property {Number} [=2]
26 * @member CKEDITOR
27 */
28CKEDITOR.STYLE_INLINE = 2;
29
30/**
31 * Object style type.
32 *
33 * Read more in the {@link CKEDITOR.style} class documentation.
34 *
35 * @readonly
36 * @property {Number} [=3]
37 * @member CKEDITOR
38 */
39CKEDITOR.STYLE_OBJECT = 3;
40
41( function() {
42 var blockElements = {
43 address: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, p: 1,
44 pre: 1, section: 1, header: 1, footer: 1, nav: 1, article: 1, aside: 1, figure: 1,
45 dialog: 1, hgroup: 1, time: 1, meter: 1, menu: 1, command: 1, keygen: 1, output: 1,
46 progress: 1, details: 1, datagrid: 1, datalist: 1
47 },
48
49 objectElements = {
50 a: 1, blockquote: 1, embed: 1, hr: 1, img: 1, li: 1, object: 1, ol: 1, table: 1, td: 1,
51 tr: 1, th: 1, ul: 1, dl: 1, dt: 1, dd: 1, form: 1, audio: 1, video: 1
52 };
53
54 var semicolonFixRegex = /\s*(?:;\s*|$)/,
55 varRegex = /#\((.+?)\)/g;
56
57 var notBookmark = CKEDITOR.dom.walker.bookmark( 0, 1 ),
58 nonWhitespaces = CKEDITOR.dom.walker.whitespaces( 1 );
59
60 /**
61 * A class representing a style instance for the specific style definition.
62 * In this approach, a style is a set of properties, like attributes and styles,
63 * which can be applied to and removed from a {@link CKEDITOR.dom.selection selection} through
64 * {@link CKEDITOR.editor editor} methods: {@link CKEDITOR.editor#applyStyle} and {@link CKEDITOR.editor#removeStyle},
65 * respectively.
66 *
67 * Three default style types are available: {@link CKEDITOR#STYLE_BLOCK STYLE_BLOCK}, {@link CKEDITOR#STYLE_INLINE STYLE_INLINE},
68 * and {@link CKEDITOR#STYLE_OBJECT STYLE_OBJECT}. Based on its type, a style heavily changes its behavior.
69 * You can read more about style types in the [Style Types section of the Styles guide](#!/guide/dev_styles-section-style-types).
70 *
71 * It is possible to define a custom style type by subclassing this class by using the {@link #addCustomHandler} method.
72 * However, because of great complexity of the styles handling job, it is only possible in very specific cases.
73 *
74 * ### Usage
75 *
76 * Basic usage:
77 *
78 * // Define a block style.
79 * var style = new CKEDITOR.style( { element: 'h1' } );
80 *
81 * // Considering the following selection:
82 * // <p>Foo</p><p>Bar^</p>
83 * // Executing:
84 * editor.applyStyle( style );
85 * // Will give:
86 * // <p>Foo</p><h1>Bar^</h1>
87 * style.checkActive( editor.elementPath(), editor ); // -> true
88 *
89 * editor.removeStyle( style );
90 * // Will give:
91 * // <p>Foo</p><p>Bar^</p>
92 *
93 * style.checkActive( editor.elementPath(), editor ); // -> false
94 *
95 * Object style:
96 *
97 * // Define an object style.
98 * var style = new CKEDITOR.style( { element: 'img', attributes: { 'class': 'foo' } } );
99 *
100 * // Considering the following selection:
101 * // <p><img src="bar.png" alt="" />Foo^</p>
102 * // Executing:
103 * editor.applyStyle( style );
104 * // Will not apply the style, because the image is not selected.
105 * // You can check if a style can be applied on the current selection with:
106 * style.checkApplicable( editor.elementPath(), editor ); // -> false
107 *
108 * // Considering the following selection:
109 * // <p>[<img src="bar.png" alt="" />]Foo</p>
110 * // Executing
111 * editor.applyStyle( style );
112 * // Will give:
113 * // <p>[<img src="bar.png" alt="" class="foo" />]Foo</p>
114 *
115 * ### API changes introduced in CKEditor 4.4
116 *
117 * Before CKEditor 4.4 all style instances had no access at all to the {@link CKEDITOR.editor editor instance}
118 * within which the style is used. Neither the style constructor, nor style methods were requiring
119 * passing the editor instance which made styles independent of the editor and hence its settings and state.
120 * This design decision came from CKEditor 3; it started causing problems and became an unsolvable obstacle for
121 * the {@link CKEDITOR.style.customHandlers.widget widget style handler} which we introduced in CKEditor 4.4.
122 *
123 * There were two possible solutions. Passing an editor instance to the style constructor or to every method.
124 * The first approach would be clean, however, having in mind the backward compatibility, we did not decide
125 * to go for it. It would bind the style to one editor instance, making it unusable with other editor instances.
126 * That could break many implementations reusing styles between editors. Therefore, we decided to take the longer
127 * but safer path &mdash; the editor instance became an argument for nearly all style methods, however,
128 * for backward compatibility reasons, all these methods will work without it. Even the newly
129 * implemented {@link CKEDITOR.style.customHandlers.widget widget style handler}'s methods will not fail,
130 * although they will also not work by aborting at an early stage.
131 *
132 * Therefore, you can safely upgrade to CKEditor 4.4 even if you use style methods without providing
133 * the editor instance. You must only align your code if your implementation should handle widget styles
134 * or any other custom style handler. Of course, we recommend doing this in any case to avoid potential
135 * problems in the future.
136 *
137 * @class
138 * @constructor Creates a style class instance.
139 * @param styleDefinition
140 * @param variablesValues
141 */
142 CKEDITOR.style = function( styleDefinition, variablesValues ) {
143 if ( typeof styleDefinition.type == 'string' )
144 return new CKEDITOR.style.customHandlers[ styleDefinition.type ]( styleDefinition );
145
146 // Inline style text as attribute should be converted
147 // to styles object.
148 var attrs = styleDefinition.attributes;
149 if ( attrs && attrs.style ) {
150 styleDefinition.styles = CKEDITOR.tools.extend( {},
151 styleDefinition.styles, CKEDITOR.tools.parseCssText( attrs.style ) );
152 delete attrs.style;
153 }
154
155 if ( variablesValues ) {
156 styleDefinition = CKEDITOR.tools.clone( styleDefinition );
157
158 replaceVariables( styleDefinition.attributes, variablesValues );
159 replaceVariables( styleDefinition.styles, variablesValues );
160 }
161
162 var element = this.element = styleDefinition.element ?
163 (
164 typeof styleDefinition.element == 'string' ?
165 styleDefinition.element.toLowerCase() : styleDefinition.element
166 ) : '*';
167
168 this.type = styleDefinition.type ||
169 (
170 blockElements[ element ] ? CKEDITOR.STYLE_BLOCK :
171 objectElements[ element ] ? CKEDITOR.STYLE_OBJECT :
172 CKEDITOR.STYLE_INLINE
173 );
174
175 // If the 'element' property is an object with a set of possible element, it will be applied like an object style: only to existing elements
176 if ( typeof this.element == 'object' )
177 this.type = CKEDITOR.STYLE_OBJECT;
178
179 this._ = {
180 definition: styleDefinition
181 };
182 };
183
184 CKEDITOR.style.prototype = {
185 /**
186 * Applies the style on the editor's current selection.
187 *
188 * Before the style is applied, the method checks if the {@link #checkApplicable style is applicable}.
189 *
190 * **Note:** The recommended way of applying the style is by using the
191 * {@link CKEDITOR.editor#applyStyle} method, which is a shorthand for this method.
192 *
193 * @param {CKEDITOR.editor/CKEDITOR.dom.document} editor The editor instance in which
194 * the style will be applied.
195 * A {@link CKEDITOR.dom.document} instance is accepted for backward compatibility
196 * reasons, although since CKEditor 4.4 this type of argument is deprecated. Read more about
197 * the signature change in the {@link CKEDITOR.style} documentation.
198 */
199 apply: function( editor ) {
200 // Backward compatibility.
201 if ( editor instanceof CKEDITOR.dom.document )
202 return applyStyleOnSelection.call( this, editor.getSelection() );
203
204 if ( this.checkApplicable( editor.elementPath(), editor ) ) {
205 var initialEnterMode = this._.enterMode;
206
207 // See comment in removeStyle.
208 if ( !initialEnterMode )
209 this._.enterMode = editor.activeEnterMode;
210 applyStyleOnSelection.call( this, editor.getSelection(), 0, editor );
211 this._.enterMode = initialEnterMode;
212 }
213 },
214
215 /**
216 * Removes the style from the editor's current selection.
217 *
218 * Before the style is applied, the method checks if {@link #checkApplicable style could be applied}.
219 *
220 * **Note:** The recommended way of removing the style is by using the
221 * {@link CKEDITOR.editor#removeStyle} method, which is a shorthand for this method.
222 *
223 * @param {CKEDITOR.editor/CKEDITOR.dom.document} editor The editor instance in which
224 * the style will be removed.
225 * A {@link CKEDITOR.dom.document} instance is accepted for backward compatibility
226 * reasons, although since CKEditor 4.4 this type of argument is deprecated. Read more about
227 * the signature change in the {@link CKEDITOR.style} documentation.
228 */
229 remove: function( editor ) {
230 // Backward compatibility.
231 if ( editor instanceof CKEDITOR.dom.document )
232 return applyStyleOnSelection.call( this, editor.getSelection(), 1 );
233
234 if ( this.checkApplicable( editor.elementPath(), editor ) ) {
235 var initialEnterMode = this._.enterMode;
236
237 // Before CKEditor 4.4 style knew nothing about editor, so in order to provide enterMode
238 // which should be used developers were forced to hack the style object (see #10190).
239 // Since CKEditor 4.4 style knows about editor (at least when it's being applied/removed), but we
240 // use _.enterMode for backward compatibility with those hacks.
241 // Note: we should not change style's enter mode if it was already set.
242 if ( !initialEnterMode )
243 this._.enterMode = editor.activeEnterMode;
244 applyStyleOnSelection.call( this, editor.getSelection(), 1, editor );
245 this._.enterMode = initialEnterMode;
246 }
247 },
248
249 /**
250 * Applies the style on the provided range. Unlike {@link #apply} this
251 * method does not take care of setting the selection, however, the range
252 * is updated to the correct place.
253 *
254 * **Note:** If you want to apply the style on the editor selection,
255 * you probably want to use {@link CKEDITOR.editor#applyStyle}.
256 *
257 * @param {CKEDITOR.dom.range} range
258 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
259 * CKEditor 4.4. The style system will work without it, but it is highly
260 * recommended to provide it for integration with all features. Read more about
261 * the signature change in the {@link CKEDITOR.style} documentation.
262 */
263 applyToRange: function( range ) {
264 this.applyToRange =
265 this.type == CKEDITOR.STYLE_INLINE ? applyInlineStyle :
266 this.type == CKEDITOR.STYLE_BLOCK ? applyBlockStyle :
267 this.type == CKEDITOR.STYLE_OBJECT ? applyObjectStyle :
268 null;
269
270 return this.applyToRange( range );
271 },
272
273 /**
274 * Removes the style from the provided range. Unlike {@link #remove} this
275 * method does not take care of setting the selection, however, the range
276 * is updated to the correct place.
277 *
278 * **Note:** If you want to remove the style from the editor selection,
279 * you probably want to use {@link CKEDITOR.editor#removeStyle}.
280 *
281 * @param {CKEDITOR.dom.range} range
282 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
283 * CKEditor 4.4. The style system will work without it, but it is highly
284 * recommended to provide it for integration with all features. Read more about
285 * the signature change in the {@link CKEDITOR.style} documentation.
286 */
287 removeFromRange: function( range ) {
288 this.removeFromRange =
289 this.type == CKEDITOR.STYLE_INLINE ? removeInlineStyle :
290 this.type == CKEDITOR.STYLE_BLOCK ? removeBlockStyle :
291 this.type == CKEDITOR.STYLE_OBJECT ? removeObjectStyle :
292 null;
293
294 return this.removeFromRange( range );
295 },
296
297 /**
298 * Applies the style to the element. This method bypasses all checks
299 * and applies the style attributes directly on the provided element. Use with caution.
300 *
301 * See {@link CKEDITOR.editor#applyStyle}.
302 *
303 * @param {CKEDITOR.dom.element} element
304 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
305 * CKEditor 4.4. The style system will work without it, but it is highly
306 * recommended to provide it for integration with all features. Read more about
307 * the signature change in the {@link CKEDITOR.style} documentation.
308 */
309 applyToObject: function( element ) {
310 setupElement( element, this );
311 },
312
313 /**
314 * Gets the style state inside the elements path.
315 *
316 * @param {CKEDITOR.dom.elementPath} elementPath
317 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
318 * CKEditor 4.4. The style system will work without it, but it is highly
319 * recommended to provide it for integration with all features. Read more about
320 * the signature change in the {@link CKEDITOR.style} documentation.
321 * @returns {Boolean} `true` if the element is active in the elements path.
322 */
323 checkActive: function( elementPath, editor ) {
324 switch ( this.type ) {
325 case CKEDITOR.STYLE_BLOCK:
326 return this.checkElementRemovable( elementPath.block || elementPath.blockLimit, true, editor );
327
328 case CKEDITOR.STYLE_OBJECT:
329 case CKEDITOR.STYLE_INLINE:
330
331 var elements = elementPath.elements;
332
333 for ( var i = 0, element; i < elements.length; i++ ) {
334 element = elements[ i ];
335
336 if ( this.type == CKEDITOR.STYLE_INLINE && ( element == elementPath.block || element == elementPath.blockLimit ) )
337 continue;
338
339 if ( this.type == CKEDITOR.STYLE_OBJECT ) {
340 var name = element.getName();
341 if ( !( typeof this.element == 'string' ? name == this.element : name in this.element ) )
342 continue;
343 }
344
345 if ( this.checkElementRemovable( element, true, editor ) )
346 return true;
347 }
348 }
349 return false;
350 },
351
352 /**
353 * Whether this style can be applied at the specified elements path.
354 *
355 * @param {CKEDITOR.dom.elementPath} elementPath The elements path to
356 * check the style against.
357 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
358 * CKEditor 4.4. The style system will work without it, but it is highly
359 * recommended to provide it for integration with all features. Read more about
360 * the signature change in the {@link CKEDITOR.style} documentation.
361 * @param {CKEDITOR.filter} [filter] If defined, the style will be
362 * checked against this filter as well.
363 * @returns {Boolean} `true` if this style can be applied at the elements path.
364 */
365 checkApplicable: function( elementPath, editor, filter ) {
366 // Backward compatibility.
367 if ( editor && editor instanceof CKEDITOR.filter )
368 filter = editor;
369
370 if ( filter && !filter.check( this ) )
371 return false;
372
373 switch ( this.type ) {
374 case CKEDITOR.STYLE_OBJECT:
375 return !!elementPath.contains( this.element );
376 case CKEDITOR.STYLE_BLOCK:
377 return !!elementPath.blockLimit.getDtd()[ this.element ];
378 }
379
380 return true;
381 },
382
383 /**
384 * Checks if the element matches the current style definition.
385 *
386 * @param {CKEDITOR.dom.element} element
387 * @param {Boolean} fullMatch
388 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
389 * CKEditor 4.4. The style system will work without it, but it is highly
390 * recommended to provide it for integration with all features. Read more about
391 * the signature change in the {@link CKEDITOR.style} documentation.
392 * @returns {Boolean}
393 */
394 checkElementMatch: function( element, fullMatch ) {
395 var def = this._.definition;
396
397 if ( !element || !def.ignoreReadonly && element.isReadOnly() )
398 return false;
399
400 var attribs,
401 name = element.getName();
402
403 // If the element name is the same as the style name.
404 if ( typeof this.element == 'string' ? name == this.element : name in this.element ) {
405 // If no attributes are defined in the element.
406 if ( !fullMatch && !element.hasAttributes() )
407 return true;
408
409 attribs = getAttributesForComparison( def );
410
411 if ( attribs._length ) {
412 for ( var attName in attribs ) {
413 if ( attName == '_length' )
414 continue;
415
416 var elementAttr = element.getAttribute( attName ) || '';
417
418 // Special treatment for 'style' attribute is required.
419 if ( attName == 'style' ? compareCssText( attribs[ attName ], elementAttr ) : attribs[ attName ] == elementAttr ) {
420 if ( !fullMatch )
421 return true;
422 } else if ( fullMatch ) {
423 return false;
424 }
425 }
426 if ( fullMatch )
427 return true;
428 } else {
429 return true;
430 }
431 }
432
433 return false;
434 },
435
436 /**
437 * Checks if an element, or any of its attributes, is removable by the
438 * current style definition.
439 *
440 * @param {CKEDITOR.dom.element} element
441 * @param {Boolean} fullMatch
442 * @param {CKEDITOR.editor} editor The editor instance. Required argument since
443 * CKEditor 4.4. The style system will work without it, but it is highly
444 * recommended to provide it for integration with all features. Read more about
445 * the signature change in the {@link CKEDITOR.style} documentation.
446 * @returns {Boolean}
447 */
448 checkElementRemovable: function( element, fullMatch, editor ) {
449 // Check element matches the style itself.
450 if ( this.checkElementMatch( element, fullMatch, editor ) )
451 return true;
452
453 // Check if the element matches the style overrides.
454 var override = getOverrides( this )[ element.getName() ];
455 if ( override ) {
456 var attribs, attName;
457
458 // If no attributes have been defined, remove the element.
459 if ( !( attribs = override.attributes ) )
460 return true;
461
462 for ( var i = 0; i < attribs.length; i++ ) {
463 attName = attribs[ i ][ 0 ];
464 var actualAttrValue = element.getAttribute( attName );
465 if ( actualAttrValue ) {
466 var attValue = attribs[ i ][ 1 ];
467
468 // Remove the attribute if:
469 // - The override definition value is null;
470 // - The override definition value is a string that
471 // matches the attribute value exactly.
472 // - The override definition value is a regex that
473 // has matches in the attribute value.
474 if ( attValue === null )
475 return true;
476 if ( typeof attValue == 'string' ) {
477 if ( actualAttrValue == attValue )
478 return true;
479 } else if ( attValue.test( actualAttrValue ) ) {
480 return true;
481 }
482 }
483 }
484 }
485 return false;
486 },
487
488 /**
489 * Builds the preview HTML based on the styles definition.
490 *
491 * @param {String} [label] The label used in the style preview.
492 * @return {String} The HTML of preview.
493 */
494 buildPreview: function( label ) {
495 var styleDefinition = this._.definition,
496 html = [],
497 elementName = styleDefinition.element;
498
499 // Avoid <bdo> in the preview.
500 if ( elementName == 'bdo' )
501 elementName = 'span';
502
503 html = [ '<', elementName ];
504
505 // Assign all defined attributes.
506 var attribs = styleDefinition.attributes;
507 if ( attribs ) {
508 for ( var att in attribs )
509 html.push( ' ', att, '="', attribs[ att ], '"' );
510 }
511
512 // Assign the style attribute.
513 var cssStyle = CKEDITOR.style.getStyleText( styleDefinition );
514 if ( cssStyle )
515 html.push( ' style="', cssStyle, '"' );
516
517 html.push( '>', ( label || styleDefinition.name ), '</', elementName, '>' );
518
519 return html.join( '' );
520 },
521
522 /**
523 * Returns the style definition.
524 *
525 * @since 4.1
526 * @returns {Object}
527 */
528 getDefinition: function() {
529 return this._.definition;
530 }
531
532 /**
533 * If defined (for example by {@link CKEDITOR.style#addCustomHandler custom style handler}), it returns
534 * the {@link CKEDITOR.filter.allowedContentRules allowed content rules} which should be added to the
535 * {@link CKEDITOR.filter} when enabling this style.
536 *
537 * **Note:** This method is not defined in the {@link CKEDITOR.style} class.
538 *
539 * @since 4.4
540 * @method toAllowedContentRules
541 * @param {CKEDITOR.editor} [editor] The editor instance.
542 * @returns {CKEDITOR.filter.allowedContentRules} The rules that should represent this style in the {@link CKEDITOR.filter}.
543 */
544 };
545
546 /**
547 * Builds the inline style text based on the style definition.
548 *
549 * @static
550 * @param styleDefinition
551 * @returns {String} Inline style text.
552 */
553 CKEDITOR.style.getStyleText = function( styleDefinition ) {
554 // If we have already computed it, just return it.
555 var stylesDef = styleDefinition._ST;
556 if ( stylesDef )
557 return stylesDef;
558
559 stylesDef = styleDefinition.styles;
560
561 // Builds the StyleText.
562 var stylesText = ( styleDefinition.attributes && styleDefinition.attributes.style ) || '',
563 specialStylesText = '';
564
565 if ( stylesText.length )
566 stylesText = stylesText.replace( semicolonFixRegex, ';' );
567
568 for ( var style in stylesDef ) {
569 var styleVal = stylesDef[ style ],
570 text = ( style + ':' + styleVal ).replace( semicolonFixRegex, ';' );
571
572 // Some browsers don't support 'inherit' property value, leave them intact. (#5242)
573 if ( styleVal == 'inherit' )
574 specialStylesText += text;
575 else
576 stylesText += text;
577 }
578
579 // Browsers make some changes to the style when applying them. So, here
580 // we normalize it to the browser format.
581 if ( stylesText.length )
582 stylesText = CKEDITOR.tools.normalizeCssText( stylesText, true );
583
584 stylesText += specialStylesText;
585
586 // Return it, saving it to the next request.
587 return ( styleDefinition._ST = stylesText );
588 };
589
590 /**
591 * Namespace containing custom style handlers added with {@link CKEDITOR.style#addCustomHandler}.
592 *
593 * @since 4.4
594 * @class
595 * @singleton
596 */
597 CKEDITOR.style.customHandlers = {};
598
599 /**
600 * Creates a {@link CKEDITOR.style} subclass and registers it in the style system.
601 * Registered class will be used as a handler for a style of this type. This allows
602 * to extend the styles system, which by default uses only the {@link CKEDITOR.style}, with
603 * new functionality. Registered classes are accessible in the {@link CKEDITOR.style.customHandlers}.
604 *
605 * ### The Style Class Definition
606 *
607 * The definition object is used to override properties in a prototype inherited
608 * from the {@link CKEDITOR.style} class. It must contain a `type` property which is
609 * a name of the new type and therefore it must be unique. The default style types
610 * ({@link CKEDITOR#STYLE_BLOCK STYLE_BLOCK}, {@link CKEDITOR#STYLE_INLINE STYLE_INLINE},
611 * and {@link CKEDITOR#STYLE_OBJECT STYLE_OBJECT}) are integers, but for easier identification
612 * it is recommended to use strings as custom type names.
613 *
614 * Besides `type`, the definition may contain two more special properties:
615 *
616 * * `setup {Function}` &ndash; An optional callback executed when a style instance is created.
617 * Like the style constructor, it is executed in style context and with the style definition as an argument.
618 * * `assignedTo {Number}` &ndash; Can be set to one of the default style types. Some editor
619 * features like the Styles drop-down assign styles to one of the default groups based on
620 * the style type. By using this property it is possible to notify them to which group this
621 * custom style should be assigned. It defaults to the {@link CKEDITOR#STYLE_OBJECT}.
622 *
623 * Other properties of the definition object will just be used to extend the prototype inherited
624 * from the {@link CKEDITOR.style} class. So if the definition contains an `apply` method, it will
625 * override the {@link CKEDITOR.style#apply} method.
626 *
627 * ### Usage
628 *
629 * Registering a basic handler:
630 *
631 * var styleClass = CKEDITOR.style.addCustomHandler( {
632 * type: 'custom'
633 * } );
634 *
635 * var style = new styleClass( { ... } );
636 * style instanceof styleClass; // -> true
637 * style instanceof CKEDITOR.style; // -> true
638 * style.type; // -> 'custom'
639 *
640 * The {@link CKEDITOR.style} constructor used as a factory:
641 *
642 * var styleClass = CKEDITOR.style.addCustomHandler( {
643 * type: 'custom'
644 * } );
645 *
646 * // Style constructor accepts style definition (do not confuse with style class definition).
647 * var style = new CKEDITOR.style( { type: 'custom', attributes: ... } );
648 * style instanceof styleClass; // -> true
649 *
650 * Thanks to that, integration code using styles does not need to know
651 * which style handler it should use. It is determined by the {@link CKEDITOR.style} constructor.
652 *
653 * Overriding existing {@link CKEDITOR.style} methods:
654 *
655 * var styleClass = CKEDITOR.style.addCustomHandler( {
656 * type: 'custom',
657 * apply: function( editor ) {
658 * console.log( 'apply' );
659 * },
660 * remove: function( editor ) {
661 * console.log( 'remove' );
662 * }
663 * } );
664 *
665 * var style = new CKEDITOR.style( { type: 'custom', attributes: ... } );
666 * editor.applyStyle( style ); // logged 'apply'
667 *
668 * style = new CKEDITOR.style( { element: 'img', attributes: { 'class': 'foo' } } );
669 * editor.applyStyle( style ); // style is really applied if image was selected
670 *
671 * ### Practical Recommendations
672 *
673 * The style handling job, which includes such tasks as applying, removing, checking state, and
674 * checking if a style can be applied, is very complex. Therefore without deep knowledge
675 * about DOM and especially {@link CKEDITOR.dom.range ranges} and {@link CKEDITOR.dom.walker DOM walker} it is impossible
676 * to implement a completely custom style handler able to handle block, inline, and object type styles.
677 * However, it is possible to customize the default implementation by overriding default methods and
678 * reusing them.
679 *
680 * The only style handler which can be implemented from scratch without huge effort is a style
681 * applicable to objects ([read more about types](http://docs.ckeditor.com/#!/guide/dev_styles-section-style-types)).
682 * Such style can only be applied when a specific object is selected. An example implementation can
683 * be found in the [widget plugin](https://github.com/ckeditor/ckeditor-dev/blob/master/plugins/widget/plugin.js).
684 *
685 * When implementing a style handler from scratch at least the following methods must be defined:
686 *
687 * * {@link CKEDITOR.style#apply apply} and {@link CKEDITOR.style#remove remove},
688 * * {@link CKEDITOR.style#checkElementRemovable checkElementRemovable} and
689 * {@link CKEDITOR.style#checkElementMatch checkElementMatch} &ndash; Note that both methods reuse the same logic,
690 * * {@link CKEDITOR.style#checkActive checkActive} &ndash; Reuses
691 * {@link CKEDITOR.style#checkElementMatch checkElementMatch},
692 * * {@link CKEDITOR.style#toAllowedContentRules toAllowedContentRules} &ndash; Not required, but very useful in
693 * case of a custom style that has to notify the {@link CKEDITOR.filter} which rules it allows when registered.
694 *
695 * @since 4.4
696 * @static
697 * @member CKEDITOR.style
698 * @param definition The style class definition.
699 * @returns {CKEDITOR.style} The new style class created for the provided definition.
700 */
701 CKEDITOR.style.addCustomHandler = function( definition ) {
702 var styleClass = function( styleDefinition ) {
703 this._ = {
704 definition: styleDefinition
705 };
706
707 if ( this.setup )
708 this.setup( styleDefinition );
709 };
710
711 styleClass.prototype = CKEDITOR.tools.extend(
712 // Prototype of CKEDITOR.style.
713 CKEDITOR.tools.prototypedCopy( CKEDITOR.style.prototype ),
714 // Defaults.
715 {
716 assignedTo: CKEDITOR.STYLE_OBJECT
717 },
718 // Passed definition - overrides.
719 definition,
720 true
721 );
722
723 this.customHandlers[ definition.type ] = styleClass;
724
725 return styleClass;
726 };
727
728 // Gets the parent element which blocks the styling for an element. This
729 // can be done through read-only elements (contenteditable=false) or
730 // elements with the "data-nostyle" attribute.
731 function getUnstylableParent( element, root ) {
732 var unstylable, editable;
733
734 while ( ( element = element.getParent() ) ) {
735 if ( element.equals( root ) )
736 break;
737
738 if ( element.getAttribute( 'data-nostyle' ) )
739 unstylable = element;
740 else if ( !editable ) {
741 var contentEditable = element.getAttribute( 'contentEditable' );
742
743 if ( contentEditable == 'false' )
744 unstylable = element;
745 else if ( contentEditable == 'true' )
746 editable = 1;
747 }
748 }
749
750 return unstylable;
751 }
752
753 var posPrecedingIdenticalContained =
754 CKEDITOR.POSITION_PRECEDING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED,
755 posFollowingIdenticalContained =
756 CKEDITOR.POSITION_FOLLOWING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED;
757
758 // Checks if the current node can be a child of the style element.
759 function checkIfNodeCanBeChildOfStyle( def, currentNode, lastNode, nodeName, dtd, nodeIsNoStyle, nodeIsReadonly, includeReadonly ) {
760 // Style can be applied to text node.
761 if ( !nodeName )
762 return 1;
763
764 // Style definitely cannot be applied if DTD or data-nostyle do not allow.
765 if ( !dtd[ nodeName ] || nodeIsNoStyle )
766 return 0;
767
768 // Non-editable element cannot be styled is we shouldn't include readonly elements.
769 if ( nodeIsReadonly && !includeReadonly )
770 return 0;
771
772 // Check that we haven't passed lastNode yet and that style's childRule allows this style on current element.
773 return checkPositionAndRule( currentNode, lastNode, def, posPrecedingIdenticalContained );
774 }
775
776 // Check if the style element can be a child of the current
777 // node parent or if the element is not defined in the DTD.
778 function checkIfStyleCanBeChildOf( def, currentParent, elementName, isUnknownElement ) {
779 return currentParent &&
780 ( ( currentParent.getDtd() || CKEDITOR.dtd.span )[ elementName ] || isUnknownElement ) &&
781 ( !def.parentRule || def.parentRule( currentParent ) );
782 }
783
784 function checkIfStartsRange( nodeName, currentNode, lastNode ) {
785 return (
786 !nodeName || !CKEDITOR.dtd.$removeEmpty[ nodeName ] ||
787 ( currentNode.getPosition( lastNode ) | posPrecedingIdenticalContained ) == posPrecedingIdenticalContained
788 );
789 }
790
791 function checkIfTextOrReadonlyOrEmptyElement( currentNode, nodeIsReadonly ) {
792 var nodeType = currentNode.type;
793 return nodeType == CKEDITOR.NODE_TEXT || nodeIsReadonly || ( nodeType == CKEDITOR.NODE_ELEMENT && !currentNode.getChildCount() );
794 }
795
796 // Checks if position is a subset of posBitFlags and that nodeA fulfills style def rule.
797 function checkPositionAndRule( nodeA, nodeB, def, posBitFlags ) {
798 return ( nodeA.getPosition( nodeB ) | posBitFlags ) == posBitFlags &&
799 ( !def.childRule || def.childRule( nodeA ) );
800 }
801
802 function applyInlineStyle( range ) {
803 var document = range.document;
804
805 if ( range.collapsed ) {
806 // Create the element to be inserted in the DOM.
807 var collapsedElement = getElement( this, document );
808
809 // Insert the empty element into the DOM at the range position.
810 range.insertNode( collapsedElement );
811
812 // Place the selection right inside the empty element.
813 range.moveToPosition( collapsedElement, CKEDITOR.POSITION_BEFORE_END );
814
815 return;
816 }
817
818 var elementName = this.element,
819 def = this._.definition,
820 isUnknownElement;
821
822 // Indicates that fully selected read-only elements are to be included in the styling range.
823 var ignoreReadonly = def.ignoreReadonly,
824 includeReadonly = ignoreReadonly || def.includeReadonly;
825
826 // If the read-only inclusion is not available in the definition, try
827 // to get it from the root data (most often it's the editable).
828 if ( includeReadonly == null )
829 includeReadonly = range.root.getCustomData( 'cke_includeReadonly' );
830
831 // Get the DTD definition for the element. Defaults to "span".
832 var dtd = CKEDITOR.dtd[ elementName ];
833 if ( !dtd ) {
834 isUnknownElement = true;
835 dtd = CKEDITOR.dtd.span;
836 }
837
838 // Expand the range.
839 range.enlarge( CKEDITOR.ENLARGE_INLINE, 1 );
840 range.trim();
841
842 // Get the first node to be processed and the last, which concludes the processing.
843 var boundaryNodes = range.createBookmark(),
844 firstNode = boundaryNodes.startNode,
845 lastNode = boundaryNodes.endNode,
846 currentNode = firstNode,
847 styleRange;
848
849 if ( !ignoreReadonly ) {
850 // Check if the boundaries are inside non stylable elements.
851 var root = range.getCommonAncestor(),
852 firstUnstylable = getUnstylableParent( firstNode, root ),
853 lastUnstylable = getUnstylableParent( lastNode, root );
854
855 // If the first element can't be styled, we'll start processing right
856 // after its unstylable root.
857 if ( firstUnstylable )
858 currentNode = firstUnstylable.getNextSourceNode( true );
859
860 // If the last element can't be styled, we'll stop processing on its
861 // unstylable root.
862 if ( lastUnstylable )
863 lastNode = lastUnstylable;
864 }
865
866 // Do nothing if the current node now follows the last node to be processed.
867 if ( currentNode.getPosition( lastNode ) == CKEDITOR.POSITION_FOLLOWING )
868 currentNode = 0;
869
870 while ( currentNode ) {
871 var applyStyle = false;
872
873 if ( currentNode.equals( lastNode ) ) {
874 currentNode = null;
875 applyStyle = true;
876 } else {
877 var nodeName = currentNode.type == CKEDITOR.NODE_ELEMENT ? currentNode.getName() : null,
878 nodeIsReadonly = nodeName && ( currentNode.getAttribute( 'contentEditable' ) == 'false' ),
879 nodeIsNoStyle = nodeName && currentNode.getAttribute( 'data-nostyle' );
880
881 // Skip bookmarks.
882 if ( nodeName && currentNode.data( 'cke-bookmark' ) ) {
883 currentNode = currentNode.getNextSourceNode( true );
884 continue;
885 }
886
887 // Find all nested editables of a non-editable block and apply this style inside them.
888 if ( nodeIsReadonly && includeReadonly && CKEDITOR.dtd.$block[ nodeName ] )
889 applyStyleOnNestedEditables.call( this, currentNode );
890
891 // Check if the current node can be a child of the style element.
892 if ( checkIfNodeCanBeChildOfStyle( def, currentNode, lastNode, nodeName, dtd, nodeIsNoStyle, nodeIsReadonly, includeReadonly ) ) {
893 var currentParent = currentNode.getParent();
894
895 // Check if the style element can be a child of the current
896 // node parent or if the element is not defined in the DTD.
897 if ( checkIfStyleCanBeChildOf( def, currentParent, elementName, isUnknownElement ) ) {
898 // This node will be part of our range, so if it has not
899 // been started, place its start right before the node.
900 // In the case of an element node, it will be included
901 // only if it is entirely inside the range.
902 if ( !styleRange && checkIfStartsRange( nodeName, currentNode, lastNode ) ) {
903 styleRange = range.clone();
904 styleRange.setStartBefore( currentNode );
905 }
906
907 // Non element nodes, readonly elements, or empty
908 // elements can be added completely to the range.
909 if ( checkIfTextOrReadonlyOrEmptyElement( currentNode, nodeIsReadonly ) ) {
910 var includedNode = currentNode;
911 var parentNode;
912
913 // This node is about to be included completelly, but,
914 // if this is the last node in its parent, we must also
915 // check if the parent itself can be added completelly
916 // to the range, otherwise apply the style immediately.
917 while (
918 ( applyStyle = !includedNode.getNext( notBookmark ) ) &&
919 ( parentNode = includedNode.getParent(), dtd[ parentNode.getName() ] ) &&
920 checkPositionAndRule( parentNode, firstNode, def, posFollowingIdenticalContained )
921 ) {
922 includedNode = parentNode;
923 }
924
925 styleRange.setEndAfter( includedNode );
926
927 }
928 } else {
929 applyStyle = true;
930 }
931 }
932 // Style isn't applicable to current element, so apply style to
933 // range ending at previously chosen position, or nowhere if we haven't
934 // yet started styleRange.
935 else {
936 applyStyle = true;
937 }
938
939 // Get the next node to be processed.
940 // If we're currently on a non-editable element or non-styleable element,
941 // then we'll be moved to current node's sibling (or even further), so we'll
942 // avoid messing up its content.
943 currentNode = currentNode.getNextSourceNode( nodeIsNoStyle || nodeIsReadonly );
944 }
945
946 // Apply the style if we have something to which apply it.
947 if ( applyStyle && styleRange && !styleRange.collapsed ) {
948 // Build the style element, based on the style object definition.
949 var styleNode = getElement( this, document ),
950 styleHasAttrs = styleNode.hasAttributes();
951
952 // Get the element that holds the entire range.
953 var parent = styleRange.getCommonAncestor();
954
955 var removeList = {
956 styles: {},
957 attrs: {},
958 // Styles cannot be removed.
959 blockedStyles: {},
960 // Attrs cannot be removed.
961 blockedAttrs: {}
962 };
963
964 var attName, styleName, value;
965
966 // Loop through the parents, removing the redundant attributes
967 // from the element to be applied.
968 while ( styleNode && parent ) {
969 if ( parent.getName() == elementName ) {
970 for ( attName in def.attributes ) {
971 if ( removeList.blockedAttrs[ attName ] || !( value = parent.getAttribute( styleName ) ) )
972 continue;
973
974 if ( styleNode.getAttribute( attName ) == value )
975 removeList.attrs[ attName ] = 1;
976 else
977 removeList.blockedAttrs[ attName ] = 1;
978 }
979
980 for ( styleName in def.styles ) {
981 if ( removeList.blockedStyles[ styleName ] || !( value = parent.getStyle( styleName ) ) )
982 continue;
983
984 if ( styleNode.getStyle( styleName ) == value )
985 removeList.styles[ styleName ] = 1;
986 else
987 removeList.blockedStyles[ styleName ] = 1;
988 }
989 }
990
991 parent = parent.getParent();
992 }
993
994 for ( attName in removeList.attrs )
995 styleNode.removeAttribute( attName );
996
997 for ( styleName in removeList.styles )
998 styleNode.removeStyle( styleName );
999
1000 if ( styleHasAttrs && !styleNode.hasAttributes() )
1001 styleNode = null;
1002
1003 if ( styleNode ) {
1004 // Move the contents of the range to the style element.
1005 styleRange.extractContents().appendTo( styleNode );
1006
1007 // Insert it into the range position (it is collapsed after
1008 // extractContents.
1009 styleRange.insertNode( styleNode );
1010
1011 // Here we do some cleanup, removing all duplicated
1012 // elements from the style element.
1013 removeFromInsideElement.call( this, styleNode );
1014
1015 // Let's merge our new style with its neighbors, if possible.
1016 styleNode.mergeSiblings();
1017
1018 // As the style system breaks text nodes constantly, let's normalize
1019 // things for performance.
1020 // With IE, some paragraphs get broken when calling normalize()
1021 // repeatedly. Also, for IE, we must normalize body, not documentElement.
1022 // IE is also known for having a "crash effect" with normalize().
1023 // We should try to normalize with IE too in some way, somewhere.
1024 if ( !CKEDITOR.env.ie )
1025 styleNode.$.normalize();
1026 }
1027 // Style already inherit from parents, left just to clear up any internal overrides. (#5931)
1028 else {
1029 styleNode = new CKEDITOR.dom.element( 'span' );
1030 styleRange.extractContents().appendTo( styleNode );
1031 styleRange.insertNode( styleNode );
1032 removeFromInsideElement.call( this, styleNode );
1033 styleNode.remove( true );
1034 }
1035
1036 // Style applied, let's release the range, so it gets
1037 // re-initialization in the next loop.
1038 styleRange = null;
1039 }
1040 }
1041
1042 // Remove the bookmark nodes.
1043 range.moveToBookmark( boundaryNodes );
1044
1045 // Minimize the result range to exclude empty text nodes. (#5374)
1046 range.shrink( CKEDITOR.SHRINK_TEXT );
1047
1048 // Get inside the remaining element if range.shrink( TEXT ) has failed because of non-editable elements inside.
1049 // E.g. range.shrink( TEXT ) will not get inside:
1050 // [<b><i contenteditable="false">x</i></b>]
1051 // but range.shrink( ELEMENT ) will.
1052 range.shrink( CKEDITOR.NODE_ELEMENT, true );
1053 }
1054
1055 function removeInlineStyle( range ) {
1056 // Make sure our range has included all "collpased" parent inline nodes so
1057 // that our operation logic can be simpler.
1058 range.enlarge( CKEDITOR.ENLARGE_INLINE, 1 );
1059
1060 var bookmark = range.createBookmark(),
1061 startNode = bookmark.startNode;
1062
1063 if ( range.collapsed ) {
1064 var startPath = new CKEDITOR.dom.elementPath( startNode.getParent(), range.root ),
1065 // The topmost element in elementspatch which we should jump out of.
1066 boundaryElement;
1067
1068
1069 for ( var i = 0, element; i < startPath.elements.length && ( element = startPath.elements[ i ] ); i++ ) {
1070 // 1. If it's collaped inside text nodes, try to remove the style from the whole element.
1071 //
1072 // 2. Otherwise if it's collapsed on element boundaries, moving the selection
1073 // outside the styles instead of removing the whole tag,
1074 // also make sure other inner styles were well preserverd.(#3309)
1075 if ( element == startPath.block || element == startPath.blockLimit )
1076 break;
1077
1078 if ( this.checkElementRemovable( element ) ) {
1079 var isStart;
1080
1081 if ( range.collapsed && ( range.checkBoundaryOfElement( element, CKEDITOR.END ) || ( isStart = range.checkBoundaryOfElement( element, CKEDITOR.START ) ) ) ) {
1082 boundaryElement = element;
1083 boundaryElement.match = isStart ? 'start' : 'end';
1084 } else {
1085 // Before removing the style node, there may be a sibling to the style node
1086 // that's exactly the same to the one to be removed. To the user, it makes
1087 // no difference that they're separate entities in the DOM tree. So, merge
1088 // them before removal.
1089 element.mergeSiblings();
1090 if ( element.is( this.element ) )
1091 removeFromElement.call( this, element );
1092 else
1093 removeOverrides( element, getOverrides( this )[ element.getName() ] );
1094 }
1095 }
1096 }
1097
1098 // Re-create the style tree after/before the boundary element,
1099 // the replication start from bookmark start node to define the
1100 // new range.
1101 if ( boundaryElement ) {
1102 var clonedElement = startNode;
1103 for ( i = 0; ; i++ ) {
1104 var newElement = startPath.elements[ i ];
1105 if ( newElement.equals( boundaryElement ) )
1106 break;
1107 // Avoid copying any matched element.
1108 else if ( newElement.match )
1109 continue;
1110 else
1111 newElement = newElement.clone();
1112 newElement.append( clonedElement );
1113 clonedElement = newElement;
1114 }
1115 clonedElement[ boundaryElement.match == 'start' ? 'insertBefore' : 'insertAfter' ]( boundaryElement );
1116 }
1117 } else {
1118 // Now our range isn't collapsed. Lets walk from the start node to the end
1119 // node via DFS and remove the styles one-by-one.
1120 var endNode = bookmark.endNode,
1121 me = this;
1122
1123 breakNodes();
1124
1125 // Now, do the DFS walk.
1126 var currentNode = startNode;
1127 while ( !currentNode.equals( endNode ) ) {
1128 // Need to get the next node first because removeFromElement() can remove
1129 // the current node from DOM tree.
1130 var nextNode = currentNode.getNextSourceNode();
1131 if ( currentNode.type == CKEDITOR.NODE_ELEMENT && this.checkElementRemovable( currentNode ) ) {
1132 // Remove style from element or overriding element.
1133 if ( currentNode.getName() == this.element )
1134 removeFromElement.call( this, currentNode );
1135 else
1136 removeOverrides( currentNode, getOverrides( this )[ currentNode.getName() ] );
1137
1138 // removeFromElement() may have merged the next node with something before
1139 // the startNode via mergeSiblings(). In that case, the nextNode would
1140 // contain startNode and we'll have to call breakNodes() again and also
1141 // reassign the nextNode to something after startNode.
1142 if ( nextNode.type == CKEDITOR.NODE_ELEMENT && nextNode.contains( startNode ) ) {
1143 breakNodes();
1144 nextNode = startNode.getNext();
1145 }
1146 }
1147 currentNode = nextNode;
1148 }
1149 }
1150
1151 range.moveToBookmark( bookmark );
1152 // See the comment for range.shrink in applyInlineStyle.
1153 range.shrink( CKEDITOR.NODE_ELEMENT, true );
1154
1155 // Find out the style ancestor that needs to be broken down at startNode
1156 // and endNode.
1157 function breakNodes() {
1158 var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ),
1159 endPath = new CKEDITOR.dom.elementPath( endNode.getParent() ),
1160 breakStart = null,
1161 breakEnd = null;
1162
1163 for ( var i = 0; i < startPath.elements.length; i++ ) {
1164 var element = startPath.elements[ i ];
1165
1166 if ( element == startPath.block || element == startPath.blockLimit )
1167 break;
1168
1169 if ( me.checkElementRemovable( element, true ) )
1170 breakStart = element;
1171 }
1172
1173 for ( i = 0; i < endPath.elements.length; i++ ) {
1174 element = endPath.elements[ i ];
1175
1176 if ( element == endPath.block || element == endPath.blockLimit )
1177 break;
1178
1179 if ( me.checkElementRemovable( element, true ) )
1180 breakEnd = element;
1181 }
1182
1183 if ( breakEnd )
1184 endNode.breakParent( breakEnd );
1185 if ( breakStart )
1186 startNode.breakParent( breakStart );
1187 }
1188 }
1189
1190 // Apply style to nested editables inside editablesContainer.
1191 // @param {CKEDITOR.dom.element} editablesContainer
1192 // @context CKEDITOR.style
1193 function applyStyleOnNestedEditables( editablesContainer ) {
1194 var editables = findNestedEditables( editablesContainer ),
1195 editable,
1196 l = editables.length,
1197 i = 0,
1198 range = l && new CKEDITOR.dom.range( editablesContainer.getDocument() );
1199
1200 for ( ; i < l; ++i ) {
1201 editable = editables[ i ];
1202 // Check if style is allowed by this editable's ACF.
1203 if ( checkIfAllowedInEditable( editable, this ) ) {
1204 range.selectNodeContents( editable );
1205 applyInlineStyle.call( this, range );
1206 }
1207 }
1208 }
1209
1210 // Finds nested editables within container. Does not return
1211 // editables nested in another editable (twice).
1212 function findNestedEditables( container ) {
1213 var editables = [];
1214
1215 container.forEach( function( element ) {
1216 if ( element.getAttribute( 'contenteditable' ) == 'true' ) {
1217 editables.push( element );
1218 return false; // Skip children.
1219 }
1220 }, CKEDITOR.NODE_ELEMENT, true );
1221
1222 return editables;
1223 }
1224
1225 // Checks if style is allowed in this editable.
1226 function checkIfAllowedInEditable( editable, style ) {
1227 var filter = CKEDITOR.filter.instances[ editable.data( 'cke-filter' ) ];
1228
1229 return filter ? filter.check( style ) : 1;
1230 }
1231
1232 // Checks if style is allowed by iterator's active filter.
1233 function checkIfAllowedByIterator( iterator, style ) {
1234 return iterator.activeFilter ? iterator.activeFilter.check( style ) : 1;
1235 }
1236
1237 function applyObjectStyle( range ) {
1238 // Selected or parent element. (#9651)
1239 var start = range.getEnclosedNode() || range.getCommonAncestor( false, true ),
1240 element = new CKEDITOR.dom.elementPath( start, range.root ).contains( this.element, 1 );
1241
1242 element && !element.isReadOnly() && setupElement( element, this );
1243 }
1244
1245 function removeObjectStyle( range ) {
1246 var parent = range.getCommonAncestor( true, true ),
1247 element = new CKEDITOR.dom.elementPath( parent, range.root ).contains( this.element, 1 );
1248
1249 if ( !element )
1250 return;
1251
1252 var style = this,
1253 def = style._.definition,
1254 attributes = def.attributes;
1255
1256 // Remove all defined attributes.
1257 if ( attributes ) {
1258 for ( var att in attributes )
1259 element.removeAttribute( att, attributes[ att ] );
1260 }
1261
1262 // Assign all defined styles.
1263 if ( def.styles ) {
1264 for ( var i in def.styles ) {
1265 if ( def.styles.hasOwnProperty( i ) )
1266 element.removeStyle( i );
1267 }
1268 }
1269 }
1270
1271 function applyBlockStyle( range ) {
1272 // Serializible bookmarks is needed here since
1273 // elements may be merged.
1274 var bookmark = range.createBookmark( true );
1275
1276 var iterator = range.createIterator();
1277 iterator.enforceRealBlocks = true;
1278
1279 // make recognize <br /> tag as a separator in ENTER_BR mode (#5121)
1280 if ( this._.enterMode )
1281 iterator.enlargeBr = ( this._.enterMode != CKEDITOR.ENTER_BR );
1282
1283 var block,
1284 doc = range.document,
1285 newBlock;
1286
1287 while ( ( block = iterator.getNextParagraph() ) ) {
1288 if ( !block.isReadOnly() && checkIfAllowedByIterator( iterator, this ) ) {
1289 newBlock = getElement( this, doc, block );
1290 replaceBlock( block, newBlock );
1291 }
1292 }
1293
1294 range.moveToBookmark( bookmark );
1295 }
1296
1297 function removeBlockStyle( range ) {
1298 // Serializible bookmarks is needed here since
1299 // elements may be merged.
1300 var bookmark = range.createBookmark( 1 );
1301
1302 var iterator = range.createIterator();
1303 iterator.enforceRealBlocks = true;
1304 iterator.enlargeBr = this._.enterMode != CKEDITOR.ENTER_BR;
1305
1306 var block,
1307 newBlock;
1308
1309 while ( ( block = iterator.getNextParagraph() ) ) {
1310 if ( this.checkElementRemovable( block ) ) {
1311 // <pre> get special treatment.
1312 if ( block.is( 'pre' ) ) {
1313 newBlock = this._.enterMode == CKEDITOR.ENTER_BR ? null :
1314 range.document.createElement( this._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
1315
1316 newBlock && block.copyAttributes( newBlock );
1317 replaceBlock( block, newBlock );
1318 } else {
1319 removeFromElement.call( this, block );
1320 }
1321 }
1322 }
1323
1324 range.moveToBookmark( bookmark );
1325 }
1326
1327 // Replace the original block with new one, with special treatment
1328 // for <pre> blocks to make sure content format is well preserved, and merging/splitting adjacent
1329 // when necessary. (#3188)
1330 function replaceBlock( block, newBlock ) {
1331 // Block is to be removed, create a temp element to
1332 // save contents.
1333 var removeBlock = !newBlock;
1334 if ( removeBlock ) {
1335 newBlock = block.getDocument().createElement( 'div' );
1336 block.copyAttributes( newBlock );
1337 }
1338
1339 var newBlockIsPre = newBlock && newBlock.is( 'pre' ),
1340 blockIsPre = block.is( 'pre' ),
1341 isToPre = newBlockIsPre && !blockIsPre,
1342 isFromPre = !newBlockIsPre && blockIsPre;
1343
1344 if ( isToPre )
1345 newBlock = toPre( block, newBlock );
1346 else if ( isFromPre )
1347 // Split big <pre> into pieces before start to convert.
1348 newBlock = fromPres( removeBlock ? [ block.getHtml() ] : splitIntoPres( block ), newBlock );
1349 else
1350 block.moveChildren( newBlock );
1351
1352 newBlock.replace( block );
1353
1354 if ( newBlockIsPre ) {
1355 // Merge previous <pre> blocks.
1356 mergePre( newBlock );
1357 } else if ( removeBlock ) {
1358 removeNoAttribsElement( newBlock );
1359 }
1360 }
1361
1362 // Merge a <pre> block with a previous sibling if available.
1363 function mergePre( preBlock ) {
1364 var previousBlock;
1365 if ( !( ( previousBlock = preBlock.getPrevious( nonWhitespaces ) ) && previousBlock.type == CKEDITOR.NODE_ELEMENT && previousBlock.is( 'pre' ) ) )
1366 return;
1367
1368 // Merge the previous <pre> block contents into the current <pre>
1369 // block.
1370 //
1371 // Another thing to be careful here is that currentBlock might contain
1372 // a '\n' at the beginning, and previousBlock might contain a '\n'
1373 // towards the end. These new lines are not normally displayed but they
1374 // become visible after merging.
1375 var mergedHtml = replace( previousBlock.getHtml(), /\n$/, '' ) + '\n\n' +
1376 replace( preBlock.getHtml(), /^\n/, '' );
1377
1378 // Krugle: IE normalizes innerHTML from <pre>, breaking whitespaces.
1379 if ( CKEDITOR.env.ie )
1380 preBlock.$.outerHTML = '<pre>' + mergedHtml + '</pre>';
1381 else
1382 preBlock.setHtml( mergedHtml );
1383
1384 previousBlock.remove();
1385 }
1386
1387 // Split into multiple <pre> blocks separated by double line-break.
1388 function splitIntoPres( preBlock ) {
1389 // Exclude the ones at header OR at tail,
1390 // and ignore bookmark content between them.
1391 var duoBrRegex = /(\S\s*)\n(?:\s|(<span[^>]+data-cke-bookmark.*?\/span>))*\n(?!$)/gi,
1392 pres = [],
1393 splitedHtml = replace( preBlock.getOuterHtml(), duoBrRegex, function( match, charBefore, bookmark ) {
1394 return charBefore + '</pre>' + bookmark + '<pre>';
1395 } );
1396
1397 splitedHtml.replace( /<pre\b.*?>([\s\S]*?)<\/pre>/gi, function( match, preContent ) {
1398 pres.push( preContent );
1399 } );
1400 return pres;
1401 }
1402
1403 // Wrapper function of String::replace without considering of head/tail bookmarks nodes.
1404 function replace( str, regexp, replacement ) {
1405 var headBookmark = '',
1406 tailBookmark = '';
1407
1408 str = str.replace( /(^<span[^>]+data-cke-bookmark.*?\/span>)|(<span[^>]+data-cke-bookmark.*?\/span>$)/gi, function( str, m1, m2 ) {
1409 m1 && ( headBookmark = m1 );
1410 m2 && ( tailBookmark = m2 );
1411 return '';
1412 } );
1413 return headBookmark + str.replace( regexp, replacement ) + tailBookmark;
1414 }
1415
1416 // Converting a list of <pre> into blocks with format well preserved.
1417 function fromPres( preHtmls, newBlock ) {
1418 var docFrag;
1419 if ( preHtmls.length > 1 )
1420 docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() );
1421
1422 for ( var i = 0; i < preHtmls.length; i++ ) {
1423 var blockHtml = preHtmls[ i ];
1424
1425 // 1. Trim the first and last line-breaks immediately after and before <pre>,
1426 // they're not visible.
1427 blockHtml = blockHtml.replace( /(\r\n|\r)/g, '\n' );
1428 blockHtml = replace( blockHtml, /^[ \t]*\n/, '' );
1429 blockHtml = replace( blockHtml, /\n$/, '' );
1430 // 2. Convert spaces or tabs at the beginning or at the end to &nbsp;
1431 blockHtml = replace( blockHtml, /^[ \t]+|[ \t]+$/g, function( match, offset ) {
1432 if ( match.length == 1 ) // one space, preserve it
1433 return '&nbsp;';
1434 else if ( !offset ) // beginning of block
1435 return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ';
1436 else // end of block
1437 return ' ' + CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 );
1438 } );
1439
1440 // 3. Convert \n to <BR>.
1441 // 4. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;
1442 blockHtml = blockHtml.replace( /\n/g, '<br>' );
1443 blockHtml = blockHtml.replace( /[ \t]{2,}/g, function( match ) {
1444 return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ';
1445 } );
1446
1447 if ( docFrag ) {
1448 var newBlockClone = newBlock.clone();
1449 newBlockClone.setHtml( blockHtml );
1450 docFrag.append( newBlockClone );
1451 } else {
1452 newBlock.setHtml( blockHtml );
1453 }
1454 }
1455
1456 return docFrag || newBlock;
1457 }
1458
1459 // Converting from a non-PRE block to a PRE block in formatting operations.
1460 function toPre( block, newBlock ) {
1461 var bogus = block.getBogus();
1462 bogus && bogus.remove();
1463
1464 // First trim the block content.
1465 var preHtml = block.getHtml();
1466
1467 // 1. Trim head/tail spaces, they're not visible.
1468 preHtml = replace( preHtml, /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '' );
1469 // 2. Delete ANSI whitespaces immediately before and after <BR> because
1470 // they are not visible.
1471 preHtml = preHtml.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '$1' );
1472 // 3. Compress other ANSI whitespaces since they're only visible as one
1473 // single space previously.
1474 // 4. Convert &nbsp; to spaces since &nbsp; is no longer needed in <PRE>.
1475 preHtml = preHtml.replace( /([ \t\n\r]+|&nbsp;)/g, ' ' );
1476 // 5. Convert any <BR /> to \n. This must not be done earlier because
1477 // the \n would then get compressed.
1478 preHtml = preHtml.replace( /<br\b[^>]*>/gi, '\n' );
1479
1480 // Krugle: IE normalizes innerHTML to <pre>, breaking whitespaces.
1481 if ( CKEDITOR.env.ie ) {
1482 var temp = block.getDocument().createElement( 'div' );
1483 temp.append( newBlock );
1484 newBlock.$.outerHTML = '<pre>' + preHtml + '</pre>';
1485 newBlock.copyAttributes( temp.getFirst() );
1486 newBlock = temp.getFirst().remove();
1487 } else {
1488 newBlock.setHtml( preHtml );
1489 }
1490
1491 return newBlock;
1492 }
1493
1494 // Removes a style from an element itself, don't care about its subtree.
1495 function removeFromElement( element, keepDataAttrs ) {
1496 var def = this._.definition,
1497 attributes = def.attributes,
1498 styles = def.styles,
1499 overrides = getOverrides( this )[ element.getName() ],
1500 // If the style is only about the element itself, we have to remove the element.
1501 removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );
1502
1503 // Remove definition attributes/style from the elemnt.
1504 for ( var attName in attributes ) {
1505 // The 'class' element value must match (#1318).
1506 if ( ( attName == 'class' || this._.definition.fullMatch ) && element.getAttribute( attName ) != normalizeProperty( attName, attributes[ attName ] ) )
1507 continue;
1508
1509 // Do not touch data-* attributes (#11011) (#11258).
1510 if ( keepDataAttrs && attName.slice( 0, 5 ) == 'data-' )
1511 continue;
1512
1513 removeEmpty = element.hasAttribute( attName );
1514 element.removeAttribute( attName );
1515 }
1516
1517 for ( var styleName in styles ) {
1518 // Full match style insist on having fully equivalence. (#5018)
1519 if ( this._.definition.fullMatch && element.getStyle( styleName ) != normalizeProperty( styleName, styles[ styleName ], true ) )
1520 continue;
1521
1522 removeEmpty = removeEmpty || !!element.getStyle( styleName );
1523 element.removeStyle( styleName );
1524 }
1525
1526 // Remove overrides, but don't remove the element if it's a block element
1527 removeOverrides( element, overrides, blockElements[ element.getName() ] );
1528
1529 if ( removeEmpty ) {
1530 if ( this._.definition.alwaysRemoveElement )
1531 removeNoAttribsElement( element, 1 );
1532 else {
1533 if ( !CKEDITOR.dtd.$block[ element.getName() ] || this._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() )
1534 removeNoAttribsElement( element );
1535 else
1536 element.renameNode( this._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
1537 }
1538 }
1539 }
1540
1541 // Removes a style from inside an element. Called on applyStyle to make cleanup
1542 // before apply. During clean up this function keep data-* attribute in contrast
1543 // to removeFromElement.
1544 function removeFromInsideElement( element ) {
1545 var overrides = getOverrides( this ),
1546 innerElements = element.getElementsByTag( this.element ),
1547 innerElement;
1548
1549 for ( var i = innerElements.count(); --i >= 0; ) {
1550 innerElement = innerElements.getItem( i );
1551
1552 // Do not remove elements which are read only (e.g. duplicates inside widgets).
1553 if ( !innerElement.isReadOnly() )
1554 removeFromElement.call( this, innerElement, true );
1555 }
1556
1557 // Now remove any other element with different name that is
1558 // defined to be overriden.
1559 for ( var overrideElement in overrides ) {
1560 if ( overrideElement != this.element ) {
1561 innerElements = element.getElementsByTag( overrideElement );
1562
1563 for ( i = innerElements.count() - 1; i >= 0; i-- ) {
1564 innerElement = innerElements.getItem( i );
1565
1566 // Do not remove elements which are read only (e.g. duplicates inside widgets).
1567 if ( !innerElement.isReadOnly() )
1568 removeOverrides( innerElement, overrides[ overrideElement ] );
1569 }
1570 }
1571 }
1572 }
1573
1574 // Remove overriding styles/attributes from the specific element.
1575 // Note: Remove the element if no attributes remain.
1576 // @param {Object} element
1577 // @param {Object} overrides
1578 // @param {Boolean} Don't remove the element
1579 function removeOverrides( element, overrides, dontRemove ) {
1580 var attributes = overrides && overrides.attributes;
1581
1582 if ( attributes ) {
1583 for ( var i = 0; i < attributes.length; i++ ) {
1584 var attName = attributes[ i ][ 0 ],
1585 actualAttrValue;
1586
1587 if ( ( actualAttrValue = element.getAttribute( attName ) ) ) {
1588 var attValue = attributes[ i ][ 1 ];
1589
1590 // Remove the attribute if:
1591 // - The override definition value is null ;
1592 // - The override definition valie is a string that
1593 // matches the attribute value exactly.
1594 // - The override definition value is a regex that
1595 // has matches in the attribute value.
1596 if ( attValue === null || ( attValue.test && attValue.test( actualAttrValue ) ) || ( typeof attValue == 'string' && actualAttrValue == attValue ) )
1597 element.removeAttribute( attName );
1598 }
1599 }
1600 }
1601
1602 if ( !dontRemove )
1603 removeNoAttribsElement( element );
1604 }
1605
1606 // If the element has no more attributes, remove it.
1607 function removeNoAttribsElement( element, forceRemove ) {
1608 // If no more attributes remained in the element, remove it,
1609 // leaving its children.
1610 if ( !element.hasAttributes() || forceRemove ) {
1611 if ( CKEDITOR.dtd.$block[ element.getName() ] ) {
1612 var previous = element.getPrevious( nonWhitespaces ),
1613 next = element.getNext( nonWhitespaces );
1614
1615 if ( previous && ( previous.type == CKEDITOR.NODE_TEXT || !previous.isBlockBoundary( { br: 1 } ) ) )
1616 element.append( 'br', 1 );
1617 if ( next && ( next.type == CKEDITOR.NODE_TEXT || !next.isBlockBoundary( { br: 1 } ) ) )
1618 element.append( 'br' );
1619
1620 element.remove( true );
1621 } else {
1622 // Removing elements may open points where merging is possible,
1623 // so let's cache the first and last nodes for later checking.
1624 var firstChild = element.getFirst();
1625 var lastChild = element.getLast();
1626
1627 element.remove( true );
1628
1629 if ( firstChild ) {
1630 // Check the cached nodes for merging.
1631 firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.mergeSiblings();
1632
1633 if ( lastChild && !firstChild.equals( lastChild ) && lastChild.type == CKEDITOR.NODE_ELEMENT )
1634 lastChild.mergeSiblings();
1635 }
1636
1637 }
1638 }
1639 }
1640
1641 function getElement( style, targetDocument, element ) {
1642 var el,
1643 elementName = style.element;
1644
1645 // The "*" element name will always be a span for this function.
1646 if ( elementName == '*' )
1647 elementName = 'span';
1648
1649 // Create the element.
1650 el = new CKEDITOR.dom.element( elementName, targetDocument );
1651
1652 // #6226: attributes should be copied before the new ones are applied
1653 if ( element )
1654 element.copyAttributes( el );
1655
1656 el = setupElement( el, style );
1657
1658 // Avoid ID duplication.
1659 if ( targetDocument.getCustomData( 'doc_processing_style' ) && el.hasAttribute( 'id' ) )
1660 el.removeAttribute( 'id' );
1661 else
1662 targetDocument.setCustomData( 'doc_processing_style', 1 );
1663
1664 return el;
1665 }
1666
1667 function setupElement( el, style ) {
1668 var def = style._.definition,
1669 attributes = def.attributes,
1670 styles = CKEDITOR.style.getStyleText( def );
1671
1672 // Assign all defined attributes.
1673 if ( attributes ) {
1674 for ( var att in attributes )
1675 el.setAttribute( att, attributes[ att ] );
1676 }
1677
1678 // Assign all defined styles.
1679 if ( styles )
1680 el.setAttribute( 'style', styles );
1681
1682 return el;
1683 }
1684
1685 function replaceVariables( list, variablesValues ) {
1686 for ( var item in list ) {
1687 list[ item ] = list[ item ].replace( varRegex, function( match, varName ) {
1688 return variablesValues[ varName ];
1689 } );
1690 }
1691 }
1692
1693 // Returns an object that can be used for style matching comparison.
1694 // Attributes names and values are all lowercased, and the styles get
1695 // merged with the style attribute.
1696 function getAttributesForComparison( styleDefinition ) {
1697 // If we have already computed it, just return it.
1698 var attribs = styleDefinition._AC;
1699 if ( attribs )
1700 return attribs;
1701
1702 attribs = {};
1703
1704 var length = 0;
1705
1706 // Loop through all defined attributes.
1707 var styleAttribs = styleDefinition.attributes;
1708 if ( styleAttribs ) {
1709 for ( var styleAtt in styleAttribs ) {
1710 length++;
1711 attribs[ styleAtt ] = styleAttribs[ styleAtt ];
1712 }
1713 }
1714
1715 // Includes the style definitions.
1716 var styleText = CKEDITOR.style.getStyleText( styleDefinition );
1717 if ( styleText ) {
1718 if ( !attribs.style )
1719 length++;
1720 attribs.style = styleText;
1721 }
1722
1723 // Appends the "length" information to the object.
1724 attribs._length = length;
1725
1726 // Return it, saving it to the next request.
1727 return ( styleDefinition._AC = attribs );
1728 }
1729
1730 // Get the the collection used to compare the elements and attributes,
1731 // defined in this style overrides, with other element. All information in
1732 // it is lowercased.
1733 // @param {CKEDITOR.style} style
1734 function getOverrides( style ) {
1735 if ( style._.overrides )
1736 return style._.overrides;
1737
1738 var overrides = ( style._.overrides = {} ),
1739 definition = style._.definition.overrides;
1740
1741 if ( definition ) {
1742 // The override description can be a string, object or array.
1743 // Internally, well handle arrays only, so transform it if needed.
1744 if ( !CKEDITOR.tools.isArray( definition ) )
1745 definition = [ definition ];
1746
1747 // Loop through all override definitions.
1748 for ( var i = 0; i < definition.length; i++ ) {
1749 var override = definition[ i ],
1750 elementName,
1751 overrideEl,
1752 attrs;
1753
1754 // If can be a string with the element name.
1755 if ( typeof override == 'string' )
1756 elementName = override.toLowerCase();
1757 // Or an object.
1758 else {
1759 elementName = override.element ? override.element.toLowerCase() : style.element;
1760 attrs = override.attributes;
1761 }
1762
1763 // We can have more than one override definition for the same
1764 // element name, so we attempt to simply append information to
1765 // it if it already exists.
1766 overrideEl = overrides[ elementName ] || ( overrides[ elementName ] = {} );
1767
1768 if ( attrs ) {
1769 // The returning attributes list is an array, because we
1770 // could have different override definitions for the same
1771 // attribute name.
1772 var overrideAttrs = ( overrideEl.attributes = overrideEl.attributes || [] );
1773 for ( var attName in attrs ) {
1774 // Each item in the attributes array is also an array,
1775 // where [0] is the attribute name and [1] is the
1776 // override value.
1777 overrideAttrs.push( [ attName.toLowerCase(), attrs[ attName ] ] );
1778 }
1779 }
1780 }
1781 }
1782
1783 return overrides;
1784 }
1785
1786 // Make the comparison of attribute value easier by standardizing it.
1787 function normalizeProperty( name, value, isStyle ) {
1788 var temp = new CKEDITOR.dom.element( 'span' );
1789 temp[ isStyle ? 'setStyle' : 'setAttribute' ]( name, value );
1790 return temp[ isStyle ? 'getStyle' : 'getAttribute' ]( name );
1791 }
1792
1793 // Compare two bunch of styles, with the speciality that value 'inherit'
1794 // is treated as a wildcard which will match any value.
1795 // @param {Object/String} source
1796 // @param {Object/String} target
1797 // @returns {Boolean}
1798 function compareCssText( source, target ) {
1799 function filter( string, propertyName ) {
1800 // In case of font-families we'll skip quotes. (#10750)
1801 return propertyName.toLowerCase() == 'font-family' ? string.replace( /["']/g, '' ) : string;
1802 }
1803
1804 if ( typeof source == 'string' )
1805 source = CKEDITOR.tools.parseCssText( source );
1806 if ( typeof target == 'string' )
1807 target = CKEDITOR.tools.parseCssText( target, true );
1808
1809 for ( var name in source ) {
1810 if ( !( name in target ) ) {
1811 return false;
1812 }
1813
1814 if ( !( filter( target[ name ], name ) == filter( source[ name ], name ) ||
1815 source[ name ] == 'inherit' ||
1816 target[ name ] == 'inherit' ) ) {
1817 return false;
1818 }
1819 }
1820 return true;
1821 }
1822
1823 function applyStyleOnSelection( selection, remove, editor ) {
1824 var doc = selection.document,
1825 ranges = selection.getRanges(),
1826 func = remove ? this.removeFromRange : this.applyToRange,
1827 range;
1828
1829 var iterator = ranges.createIterator();
1830 while ( ( range = iterator.getNextRange() ) )
1831 func.call( this, range, editor );
1832
1833 selection.selectRanges( ranges );
1834 doc.removeCustomData( 'doc_processing_style' );
1835 }
1836} )();
1837
1838/**
1839 * Generic style command. It applies a specific style when executed.
1840 *
1841 * var boldStyle = new CKEDITOR.style( { element: 'strong' } );
1842 * // Register the "bold" command, which applies the bold style.
1843 * editor.addCommand( 'bold', new CKEDITOR.styleCommand( boldStyle ) );
1844 *
1845 * @class
1846 * @constructor Creates a styleCommand class instance.
1847 * @extends CKEDITOR.commandDefinition
1848 * @param {CKEDITOR.style} style The style to be applied when command is executed.
1849 * @param {Object} [ext] Additional command definition's properties.
1850 */
1851CKEDITOR.styleCommand = function( style, ext ) {
1852 this.style = style;
1853 this.allowedContent = style;
1854 this.requiredContent = style;
1855
1856 CKEDITOR.tools.extend( this, ext, true );
1857};
1858
1859/**
1860 * @param {CKEDITOR.editor} editor
1861 * @todo
1862 */
1863CKEDITOR.styleCommand.prototype.exec = function( editor ) {
1864 editor.focus();
1865
1866 if ( this.state == CKEDITOR.TRISTATE_OFF )
1867 editor.applyStyle( this.style );
1868 else if ( this.state == CKEDITOR.TRISTATE_ON )
1869 editor.removeStyle( this.style );
1870};
1871
1872/**
1873 * Manages styles registration and loading. See also {@link CKEDITOR.config#stylesSet}.
1874 *
1875 * // The set of styles for the <b>Styles</b> drop-down list.
1876 * CKEDITOR.stylesSet.add( 'default', [
1877 * // Block Styles
1878 * { name: 'Blue Title', element: 'h3', styles: { 'color': 'Blue' } },
1879 * { name: 'Red Title', element: 'h3', styles: { 'color': 'Red' } },
1880 *
1881 * // Inline Styles
1882 * { name: 'Marker: Yellow', element: 'span', styles: { 'background-color': 'Yellow' } },
1883 * { name: 'Marker: Green', element: 'span', styles: { 'background-color': 'Lime' } },
1884 *
1885 * // Object Styles
1886 * {
1887 * name: 'Image on Left',
1888 * element: 'img',
1889 * attributes: {
1890 * style: 'padding: 5px; margin-right: 5px',
1891 * border: '2',
1892 * align: 'left'
1893 * }
1894 * }
1895 * ] );
1896 *
1897 * @since 3.2
1898 * @class
1899 * @singleton
1900 * @extends CKEDITOR.resourceManager
1901 */
1902CKEDITOR.stylesSet = new CKEDITOR.resourceManager( '', 'stylesSet' );
1903
1904// Backward compatibility (#5025).
1905CKEDITOR.addStylesSet = CKEDITOR.tools.bind( CKEDITOR.stylesSet.add, CKEDITOR.stylesSet );
1906CKEDITOR.loadStylesSet = function( name, url, callback ) {
1907 CKEDITOR.stylesSet.addExternal( name, url, '' );
1908 CKEDITOR.stylesSet.load( name, callback );
1909};
1910
1911CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
1912 /**
1913 * Registers a function to be called whenever the selection position changes in the
1914 * editing area. The current state is passed to the function. The possible
1915 * states are {@link CKEDITOR#TRISTATE_ON} and {@link CKEDITOR#TRISTATE_OFF}.
1916 *
1917 * // Create a style object for the <b> element.
1918 * var style = new CKEDITOR.style( { element: 'b' } );
1919 * var editor = CKEDITOR.instances.editor1;
1920 * editor.attachStyleStateChange( style, function( state ) {
1921 * if ( state == CKEDITOR.TRISTATE_ON )
1922 * alert( 'The current state for the B element is ON' );
1923 * else
1924 * alert( 'The current state for the B element is OFF' );
1925 * } );
1926 *
1927 * @member CKEDITOR.editor
1928 * @param {CKEDITOR.style} style The style to be watched.
1929 * @param {Function} callback The function to be called.
1930 */
1931 attachStyleStateChange: function( style, callback ) {
1932 // Try to get the list of attached callbacks.
1933 var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
1934
1935 // If it doesn't exist, it means this is the first call. So, let's create
1936 // all the structure to manage the style checks and the callback calls.
1937 if ( !styleStateChangeCallbacks ) {
1938 // Create the callbacks array.
1939 styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
1940
1941 // Attach to the selectionChange event, so we can check the styles at
1942 // that point.
1943 this.on( 'selectionChange', function( ev ) {
1944 // Loop throw all registered callbacks.
1945 for ( var i = 0; i < styleStateChangeCallbacks.length; i++ ) {
1946 var callback = styleStateChangeCallbacks[ i ];
1947
1948 // Check the current state for the style defined for that callback.
1949 var currentState = callback.style.checkActive( ev.data.path, this ) ?
1950 CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
1951
1952 // Call the callback function, passing the current state to it.
1953 callback.fn.call( this, currentState );
1954 }
1955 } );
1956 }
1957
1958 // Save the callback info, so it can be checked on the next occurrence of
1959 // selectionChange.
1960 styleStateChangeCallbacks.push( { style: style, fn: callback } );
1961 },
1962
1963 /**
1964 * Applies the style upon the editor's current selection. Shorthand for
1965 * {@link CKEDITOR.style#apply}.
1966 *
1967 * @member CKEDITOR.editor
1968 * @param {CKEDITOR.style} style
1969 */
1970 applyStyle: function( style ) {
1971 style.apply( this );
1972 },
1973
1974 /**
1975 * Removes the style from the editor's current selection. Shorthand for
1976 * {@link CKEDITOR.style#remove}.
1977 *
1978 * @member CKEDITOR.editor
1979 * @param {CKEDITOR.style} style
1980 */
1981 removeStyle: function( style ) {
1982 style.remove( this );
1983 },
1984
1985 /**
1986 * Gets the current `stylesSet` for this instance.
1987 *
1988 * editor.getStylesSet( function( stylesDefinitions ) {} );
1989 *
1990 * See also {@link CKEDITOR.editor#stylesSet} event.
1991 *
1992 * @member CKEDITOR.editor
1993 * @param {Function} callback The function to be called with the styles data.
1994 */
1995 getStylesSet: function( callback ) {
1996 if ( !this._.stylesDefinitions ) {
1997 var editor = this,
1998 // Respect the backwards compatible definition entry
1999 configStyleSet = editor.config.stylesCombo_stylesSet || editor.config.stylesSet;
2000
2001 // The false value means that none styles should be loaded.
2002 if ( configStyleSet === false ) {
2003 callback( null );
2004 return;
2005 }
2006
2007 // #5352 Allow to define the styles directly in the config object
2008 if ( configStyleSet instanceof Array ) {
2009 editor._.stylesDefinitions = configStyleSet;
2010 callback( configStyleSet );
2011 return;
2012 }
2013
2014 // Default value is 'default'.
2015 if ( !configStyleSet )
2016 configStyleSet = 'default';
2017
2018 var partsStylesSet = configStyleSet.split( ':' ),
2019 styleSetName = partsStylesSet[ 0 ],
2020 externalPath = partsStylesSet[ 1 ];
2021
2022 CKEDITOR.stylesSet.addExternal( styleSetName, externalPath ? partsStylesSet.slice( 1 ).join( ':' ) : CKEDITOR.getUrl( 'styles.js' ), '' );
2023
2024 CKEDITOR.stylesSet.load( styleSetName, function( stylesSet ) {
2025 editor._.stylesDefinitions = stylesSet[ styleSetName ];
2026 callback( editor._.stylesDefinitions );
2027 } );
2028 } else {
2029 callback( this._.stylesDefinitions );
2030 }
2031 }
2032} );
2033
2034/**
2035 * Indicates that fully selected read-only elements will be included when
2036 * applying the style (for inline styles only).
2037 *
2038 * @since 3.5
2039 * @property {Boolean} [includeReadonly=false]
2040 * @member CKEDITOR.style
2041 */
2042
2043/**
2044 * Indicates that any matches element of this style will be eventually removed
2045 * when calling {@link CKEDITOR.editor#removeStyle}.
2046 *
2047 * @since 4.0
2048 * @property {Boolean} [alwaysRemoveElement=false]
2049 * @member CKEDITOR.style
2050 */
2051
2052/**
2053 * Disables inline styling on read-only elements.
2054 *
2055 * @since 3.5
2056 * @cfg {Boolean} [disableReadonlyStyling=false]
2057 * @member CKEDITOR.config
2058 */
2059
2060/**
2061 * The "styles definition set" to use in the editor. They will be used in the
2062 * styles combo and the style selector of the div container.
2063 *
2064 * The styles may be defined in the page containing the editor, or can be
2065 * loaded on demand from an external file. In the second case, if this setting
2066 * contains only a name, the `styles.js` file will be loaded from the
2067 * CKEditor root folder (what ensures backward compatibility with CKEditor 4.0).
2068 *
2069 * Otherwise, this setting has the `name:url` syntax, making it
2070 * possible to set the URL from which the styles file will be loaded.
2071 * Note that the `name` has to be equal to the name used in
2072 * {@link CKEDITOR.stylesSet#add} while registering the styles set.
2073 *
2074 * **Note**: Since 4.1 it is possible to set `stylesSet` to `false`
2075 * to prevent loading any styles set.
2076 *
2077 * Read more in the [documentation](#!/guide/dev_styles)
2078 * and see the [SDK sample](http://sdk.ckeditor.com/samples/styles.html).
2079 *
2080 * // Do not load any file. The styles set is empty.
2081 * config.stylesSet = false;
2082 *
2083 * // Load the 'mystyles' styles set from the styles.js file.
2084 * config.stylesSet = 'mystyles';
2085 *
2086 * // Load the 'mystyles' styles set from a relative URL.
2087 * config.stylesSet = 'mystyles:/editorstyles/styles.js';
2088 *
2089 * // Load the 'mystyles' styles set from a full URL.
2090 * config.stylesSet = 'mystyles:http://www.example.com/editorstyles/styles.js';
2091 *
2092 * // Load from a list of definitions.
2093 * config.stylesSet = [
2094 * { name: 'Strong Emphasis', element: 'strong' },
2095 * { name: 'Emphasis', element: 'em' },
2096 * ...
2097 * ];
2098 *
2099 * @since 3.3
2100 * @cfg {String/Array/Boolean} [stylesSet='default']
2101 * @member CKEDITOR.config
2102 */
diff --git a/sources/core/template.js b/sources/core/template.js
new file mode 100644
index 0000000..2b9e932
--- /dev/null
+++ b/sources/core/template.js
@@ -0,0 +1,68 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.template} class, which represents
8 * an UI template for an editor instance.
9 */
10
11( function() {
12 var cache = {},
13 rePlaceholder = /{([^}]+)}/g,
14 reEscapableChars = /([\\'])/g,
15 reNewLine = /\n/g,
16 reCarriageReturn = /\r/g;
17
18 /**
19 * Lightweight template used to build the output string from variables.
20 *
21 * // HTML template for presenting a label UI.
22 * var tpl = new CKEDITOR.template( '<div class="{cls}">{label}</div>' );
23 * alert( tpl.output( { cls: 'cke-label', label: 'foo'} ) ); // '<div class="cke-label">foo</div>'
24 *
25 * @class
26 * @constructor Creates a template class instance.
27 * @param {String} source The template source.
28 */
29 CKEDITOR.template = function( source ) {
30 // Builds an optimized function body for the output() method, focused on performance.
31 // For example, if we have this "source":
32 // '<div style="{style}">{editorName}</div>'
33 // ... the resulting function body will be (apart from the "buffer" handling):
34 // return [ '<div style="', data['style'] == undefined ? '{style}' : data['style'], '">', data['editorName'] == undefined ? '{editorName}' : data['editorName'], '</div>' ].join('');
35
36 // Try to read from the cache.
37 if ( cache[ source ] )
38 this.output = cache[ source ];
39 else {
40 var fn = source
41 // Escape chars like slash "\" or single quote "'".
42 .replace( reEscapableChars, '\\$1' )
43 .replace( reNewLine, '\\n' )
44 .replace( reCarriageReturn, '\\r' )
45 // Inject the template keys replacement.
46 .replace( rePlaceholder, function( m, key ) {
47 return "',data['" + key + "']==undefined?'{" + key + "}':data['" + key + "'],'";
48 } );
49
50 fn = "return buffer?buffer.push('" + fn + "'):['" + fn + "'].join('');";
51 this.output = cache[ source ] = Function( 'data', 'buffer', fn );
52 }
53 };
54} )();
55
56/**
57 * Processes the template, filling its variables with the provided data.
58 *
59 * @method output
60 * @param {Object} data An object containing properties which values will be
61 * used to fill the template variables. The property names must match the
62 * template variables names. Variables without matching properties will be
63 * kept untouched.
64 * @param {Array} [buffer] An array into which the output data will be pushed into.
65 * The number of entries appended to the array is unknown.
66 * @returns {String/Number} If `buffer` has not been provided, the processed
67 * template output data, otherwise the new length of `buffer`.
68 */
diff --git a/sources/core/tools.js b/sources/core/tools.js
new file mode 100644
index 0000000..7e0083f
--- /dev/null
+++ b/sources/core/tools.js
@@ -0,0 +1,1916 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.tools} object that contains
8 * utility functions.
9 */
10
11( function() {
12 var functions = [],
13 cssVendorPrefix =
14 CKEDITOR.env.gecko ? '-moz-' :
15 CKEDITOR.env.webkit ? '-webkit-' :
16 CKEDITOR.env.ie ? '-ms-' :
17 '',
18 ampRegex = /&/g,
19 gtRegex = />/g,
20 ltRegex = /</g,
21 quoteRegex = /"/g,
22 tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789',
23 TOKEN_COOKIE_NAME = 'ckCsrfToken',
24 TOKEN_LENGTH = 40,
25
26 allEscRegex = /&(lt|gt|amp|quot|nbsp|shy|#\d{1,5});/g,
27 namedEntities = {
28 lt: '<',
29 gt: '>',
30 amp: '&',
31 quot: '"',
32 nbsp: '\u00a0',
33 shy: '\u00ad'
34 },
35 allEscDecode = function( match, code ) {
36 if ( code[ 0 ] == '#' ) {
37 return String.fromCharCode( parseInt( code.slice( 1 ), 10 ) );
38 } else {
39 return namedEntities[ code ];
40 }
41 };
42
43 CKEDITOR.on( 'reset', function() {
44 functions = [];
45 } );
46
47 /**
48 * Utility functions.
49 *
50 * @class
51 * @singleton
52 */
53 CKEDITOR.tools = {
54 /**
55 * Compares the elements of two arrays.
56 *
57 * var a = [ 1, 'a', 3 ];
58 * var b = [ 1, 3, 'a' ];
59 * var c = [ 1, 'a', 3 ];
60 * var d = [ 1, 'a', 3, 4 ];
61 *
62 * alert( CKEDITOR.tools.arrayCompare( a, b ) ); // false
63 * alert( CKEDITOR.tools.arrayCompare( a, c ) ); // true
64 * alert( CKEDITOR.tools.arrayCompare( a, d ) ); // false
65 *
66 * @param {Array} arrayA An array to be compared.
67 * @param {Array} arrayB The other array to be compared.
68 * @returns {Boolean} `true` if the arrays have the same length and
69 * their elements match.
70 */
71 arrayCompare: function( arrayA, arrayB ) {
72 if ( !arrayA && !arrayB )
73 return true;
74
75 if ( !arrayA || !arrayB || arrayA.length != arrayB.length )
76 return false;
77
78 for ( var i = 0; i < arrayA.length; i++ ) {
79 if ( arrayA[ i ] != arrayB[ i ] )
80 return false;
81 }
82
83 return true;
84 },
85
86 /**
87 * Finds the index of the first element in an array for which the `compareFunction` returns `true`.
88 *
89 * CKEDITOR.tools.getIndex( [ 1, 2, 4, 3, 5 ], function( el ) {
90 * return el >= 3;
91 * } ); // 2
92 *
93 * @since 4.5
94 * @param {Array} array Array to search in.
95 * @param {Function} compareFunction Compare function.
96 * @returns {Number} The index of the first matching element or `-1` if none matches.
97 */
98 getIndex: function( arr, compareFunction ) {
99 for ( var i = 0; i < arr.length; ++i ) {
100 if ( compareFunction( arr[ i ] ) )
101 return i;
102 }
103 return -1;
104 },
105
106 /**
107 * Creates a deep copy of an object.
108 *
109 * **Note**: Recursive references are not supported.
110 *
111 * var obj = {
112 * name: 'John',
113 * cars: {
114 * Mercedes: { color: 'blue' },
115 * Porsche: { color: 'red' }
116 * }
117 * };
118 * var clone = CKEDITOR.tools.clone( obj );
119 * clone.name = 'Paul';
120 * clone.cars.Porsche.color = 'silver';
121 *
122 * alert( obj.name ); // 'John'
123 * alert( clone.name ); // 'Paul'
124 * alert( obj.cars.Porsche.color ); // 'red'
125 * alert( clone.cars.Porsche.color ); // 'silver'
126 *
127 * @param {Object} object The object to be cloned.
128 * @returns {Object} The object clone.
129 */
130 clone: function( obj ) {
131 var clone;
132
133 // Array.
134 if ( obj && ( obj instanceof Array ) ) {
135 clone = [];
136
137 for ( var i = 0; i < obj.length; i++ )
138 clone[ i ] = CKEDITOR.tools.clone( obj[ i ] );
139
140 return clone;
141 }
142
143 // "Static" types.
144 if ( obj === null || ( typeof obj != 'object' ) || ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean ) || ( obj instanceof Date ) || ( obj instanceof RegExp ) )
145 return obj;
146
147 // DOM objects and window.
148 if ( obj.nodeType || obj.window === obj )
149 return obj;
150
151 // Objects.
152 clone = new obj.constructor();
153
154 for ( var propertyName in obj ) {
155 var property = obj[ propertyName ];
156 clone[ propertyName ] = CKEDITOR.tools.clone( property );
157 }
158
159 return clone;
160 },
161
162 /**
163 * Turns the first letter of a string to upper-case.
164 *
165 * @param {String} str
166 * @param {Boolean} [keepCase] Keep the case of 2nd to last letter.
167 * @returns {String}
168 */
169 capitalize: function( str, keepCase ) {
170 return str.charAt( 0 ).toUpperCase() + ( keepCase ? str.slice( 1 ) : str.slice( 1 ).toLowerCase() );
171 },
172
173 /**
174 * Copies the properties from one object to another. By default, properties
175 * already present in the target object **are not** overwritten.
176 *
177 * // Create the sample object.
178 * var myObject = {
179 * prop1: true
180 * };
181 *
182 * // Extend the above object with two properties.
183 * CKEDITOR.tools.extend( myObject, {
184 * prop2: true,
185 * prop3: true
186 * } );
187 *
188 * // Alert 'prop1', 'prop2' and 'prop3'.
189 * for ( var p in myObject )
190 * alert( p );
191 *
192 * @param {Object} target The object to be extended.
193 * @param {Object...} source The object(s) from properties will be
194 * copied. Any number of objects can be passed to this function.
195 * @param {Boolean} [overwrite] If `true` is specified, it indicates that
196 * properties already present in the target object could be
197 * overwritten by subsequent objects.
198 * @param {Object} [properties] Only properties within the specified names
199 * list will be received from the source object.
200 * @returns {Object} The extended object (target).
201 */
202 extend: function( target ) {
203 var argsLength = arguments.length,
204 overwrite, propertiesList;
205
206 if ( typeof ( overwrite = arguments[ argsLength - 1 ] ) == 'boolean' )
207 argsLength--;
208 else if ( typeof ( overwrite = arguments[ argsLength - 2 ] ) == 'boolean' ) {
209 propertiesList = arguments[ argsLength - 1 ];
210 argsLength -= 2;
211 }
212 for ( var i = 1; i < argsLength; i++ ) {
213 var source = arguments[ i ];
214 for ( var propertyName in source ) {
215 // Only copy existed fields if in overwrite mode.
216 if ( overwrite === true || target[ propertyName ] == null ) {
217 // Only copy specified fields if list is provided.
218 if ( !propertiesList || ( propertyName in propertiesList ) )
219 target[ propertyName ] = source[ propertyName ];
220
221 }
222 }
223 }
224
225 return target;
226 },
227
228 /**
229 * Creates an object which is an instance of a class whose prototype is a
230 * predefined object. All properties defined in the source object are
231 * automatically inherited by the resulting object, including future
232 * changes to it.
233 *
234 * @param {Object} source The source object to be used as the prototype for
235 * the final object.
236 * @returns {Object} The resulting copy.
237 */
238 prototypedCopy: function( source ) {
239 var copy = function() {};
240 copy.prototype = source;
241 return new copy();
242 },
243
244 /**
245 * Makes fast (shallow) copy of an object.
246 * This method is faster than {@link #clone} which does
247 * a deep copy of an object (including arrays).
248 *
249 * @since 4.1
250 * @param {Object} source The object to be copied.
251 * @returns {Object} Copy of `source`.
252 */
253 copy: function( source ) {
254 var obj = {},
255 name;
256
257 for ( name in source )
258 obj[ name ] = source[ name ];
259
260 return obj;
261 },
262
263 /**
264 * Checks if an object is an Array.
265 *
266 * alert( CKEDITOR.tools.isArray( [] ) ); // true
267 * alert( CKEDITOR.tools.isArray( 'Test' ) ); // false
268 *
269 * @param {Object} object The object to be checked.
270 * @returns {Boolean} `true` if the object is an Array, otherwise `false`.
271 */
272 isArray: function( object ) {
273 return Object.prototype.toString.call( object ) == '[object Array]';
274 },
275
276 /**
277 * Whether the object contains no properties of its own.
278 *
279 * @param object
280 * @returns {Boolean}
281 */
282 isEmpty: function( object ) {
283 for ( var i in object ) {
284 if ( object.hasOwnProperty( i ) )
285 return false;
286 }
287 return true;
288 },
289
290 /**
291 * Generates an object or a string containing vendor-specific and vendor-free CSS properties.
292 *
293 * CKEDITOR.tools.cssVendorPrefix( 'border-radius', '0', true );
294 * // On Firefox: '-moz-border-radius:0;border-radius:0'
295 * // On Chrome: '-webkit-border-radius:0;border-radius:0'
296 *
297 * @param {String} property The CSS property name.
298 * @param {String} value The CSS value.
299 * @param {Boolean} [asString=false] If `true`, then the returned value will be a CSS string.
300 * @returns {Object/String} The object containing CSS properties or its stringified version.
301 */
302 cssVendorPrefix: function( property, value, asString ) {
303 if ( asString )
304 return cssVendorPrefix + property + ':' + value + ';' + property + ':' + value;
305
306 var ret = {};
307 ret[ property ] = value;
308 ret[ cssVendorPrefix + property ] = value;
309
310 return ret;
311 },
312
313 /**
314 * Transforms a CSS property name to its relative DOM style name.
315 *
316 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) ); // 'backgroundColor'
317 * alert( CKEDITOR.tools.cssStyleToDomStyle( 'float' ) ); // 'cssFloat'
318 *
319 * @method
320 * @param {String} cssName The CSS property name.
321 * @returns {String} The transformed name.
322 */
323 cssStyleToDomStyle: ( function() {
324 var test = document.createElement( 'div' ).style;
325
326 var cssFloat = ( typeof test.cssFloat != 'undefined' ) ? 'cssFloat' : ( typeof test.styleFloat != 'undefined' ) ? 'styleFloat' : 'float';
327
328 return function( cssName ) {
329 if ( cssName == 'float' )
330 return cssFloat;
331 else {
332 return cssName.replace( /-./g, function( match ) {
333 return match.substr( 1 ).toUpperCase();
334 } );
335 }
336 };
337 } )(),
338
339 /**
340 * Builds a HTML snippet from a set of `<style>/<link>`.
341 *
342 * @param {String/Array} css Each of which are URLs (absolute) of a CSS file or
343 * a trunk of style text.
344 * @returns {String}
345 */
346 buildStyleHtml: function( css ) {
347 css = [].concat( css );
348 var item,
349 retval = [];
350 for ( var i = 0; i < css.length; i++ ) {
351 if ( ( item = css[ i ] ) ) {
352 // Is CSS style text ?
353 if ( /@import|[{}]/.test( item ) )
354 retval.push( '<style>' + item + '</style>' );
355 else
356 retval.push( '<link type="text/css" rel=stylesheet href="' + item + '">' );
357 }
358 }
359 return retval.join( '' );
360 },
361
362 /**
363 * Replaces special HTML characters in a string with their relative HTML
364 * entity values.
365 *
366 * alert( CKEDITOR.tools.htmlEncode( 'A > B & C < D' ) ); // 'A &gt; B &amp; C &lt; D'
367 *
368 * @param {String} text The string to be encoded.
369 * @returns {String} The encoded string.
370 */
371 htmlEncode: function( text ) {
372 // Backwards compatibility - accept also non-string values (casting is done below).
373 // Since 4.4.8 we return empty string for null and undefined because these values make no sense.
374 if ( text === undefined || text === null ) {
375 return '';
376 }
377
378 return String( text ).replace( ampRegex, '&amp;' ).replace( gtRegex, '&gt;' ).replace( ltRegex, '&lt;' );
379 },
380
381 /**
382 * Decodes HTML entities that browsers tend to encode when used in text nodes.
383 *
384 * alert( CKEDITOR.tools.htmlDecode( '&lt;a &amp; b &gt;' ) ); // '<a & b >'
385 *
386 * Read more about chosen entities in the [research](http://dev.ckeditor.com/ticket/13105#comment:8).
387 *
388 * @param {String} The string to be decoded.
389 * @returns {String} The decoded string.
390 */
391 htmlDecode: function( text ) {
392 // See:
393 // * http://dev.ckeditor.com/ticket/13105#comment:8 and comment:9,
394 // * http://jsperf.com/wth-is-going-on-with-jsperf JSPerf has some serious problems, but you can observe
395 // that combined regexp tends to be quicker (except on V8). It will also not be prone to fail on '&amp;lt;'
396 // (see http://dev.ckeditor.com/ticket/13105#DXWTF:CKEDITOR.tools.htmlEnDecodeAttr).
397 return text.replace( allEscRegex, allEscDecode );
398 },
399
400 /**
401 * Replaces special HTML characters in HTMLElement attribute with their relative HTML entity values.
402 *
403 * alert( CKEDITOR.tools.htmlEncodeAttr( '<a " b >' ) ); // '&lt;a &quot; b &gt;'
404 *
405 * @param {String} The attribute value to be encoded.
406 * @returns {String} The encoded value.
407 */
408 htmlEncodeAttr: function( text ) {
409 return CKEDITOR.tools.htmlEncode( text ).replace( quoteRegex, '&quot;' );
410 },
411
412 /**
413 * Decodes HTML entities that browsers tend to encode when used in attributes.
414 *
415 * alert( CKEDITOR.tools.htmlDecodeAttr( '&lt;a &quot; b&gt;' ) ); // '<a " b>'
416 *
417 * Since CKEditor 4.5 this method simply executes {@link #htmlDecode} which covers
418 * all necessary entities.
419 *
420 * @param {String} text The text to be decoded.
421 * @returns {String} The decoded text.
422 */
423 htmlDecodeAttr: function( text ) {
424 return CKEDITOR.tools.htmlDecode( text );
425 },
426
427 /**
428 * Transforms text to valid HTML: creates paragraphs, replaces tabs with non-breaking spaces etc.
429 *
430 * @since 4.5
431 * @param {String} text Text to transform.
432 * @param {Number} enterMode Editor {@link CKEDITOR.config#enterMode Enter mode}.
433 * @returns {String} HTML generated from the text.
434 */
435 transformPlainTextToHtml: function( text, enterMode ) {
436 var isEnterBrMode = enterMode == CKEDITOR.ENTER_BR,
437 // CRLF -> LF
438 html = this.htmlEncode( text.replace( /\r\n/g, '\n' ) );
439
440 // Tab -> &nbsp x 4;
441 html = html.replace( /\t/g, '&nbsp;&nbsp; &nbsp;' );
442
443 var paragraphTag = enterMode == CKEDITOR.ENTER_P ? 'p' : 'div';
444
445 // Two line-breaks create one paragraphing block.
446 if ( !isEnterBrMode ) {
447 var duoLF = /\n{2}/g;
448 if ( duoLF.test( html ) ) {
449 var openTag = '<' + paragraphTag + '>', endTag = '</' + paragraphTag + '>';
450 html = openTag + html.replace( duoLF, function() {
451 return endTag + openTag;
452 } ) + endTag;
453 }
454 }
455
456 // One <br> per line-break.
457 html = html.replace( /\n/g, '<br>' );
458
459 // Compensate padding <br> at the end of block, avoid loosing them during insertion.
460 if ( !isEnterBrMode ) {
461 html = html.replace( new RegExp( '<br>(?=</' + paragraphTag + '>)' ), function( match ) {
462 return CKEDITOR.tools.repeat( match, 2 );
463 } );
464 }
465
466 // Preserve spaces at the ends, so they won't be lost after insertion (merged with adjacent ones).
467 html = html.replace( /^ | $/g, '&nbsp;' );
468
469 // Finally, preserve whitespaces that are to be lost.
470 html = html.replace( /(>|\s) /g, function( match, before ) {
471 return before + '&nbsp;';
472 } ).replace( / (?=<)/g, '&nbsp;' );
473
474 return html;
475 },
476
477 /**
478 * Gets a unique number for this CKEDITOR execution session. It returns
479 * consecutive numbers starting from 1.
480 *
481 * alert( CKEDITOR.tools.getNextNumber() ); // (e.g.) 1
482 * alert( CKEDITOR.tools.getNextNumber() ); // 2
483 *
484 * @method
485 * @returns {Number} A unique number.
486 */
487 getNextNumber: ( function() {
488 var last = 0;
489 return function() {
490 return ++last;
491 };
492 } )(),
493
494 /**
495 * Gets a unique ID for CKEditor interface elements. It returns a
496 * string with the "cke_" prefix and a consecutive number.
497 *
498 * alert( CKEDITOR.tools.getNextId() ); // (e.g.) 'cke_1'
499 * alert( CKEDITOR.tools.getNextId() ); // 'cke_2'
500 *
501 * @returns {String} A unique ID.
502 */
503 getNextId: function() {
504 return 'cke_' + this.getNextNumber();
505 },
506
507 /**
508 * Gets a universally unique ID. It returns a random string
509 * compliant with ISO/IEC 11578:1996, without dashes, with the "e" prefix to
510 * make sure that the ID does not start with a number.
511 *
512 * @returns {String} A global unique ID.
513 */
514 getUniqueId: function() {
515 var uuid = 'e'; // Make sure that id does not start with number.
516 for ( var i = 0; i < 8; i++ ) {
517 uuid += Math.floor( ( 1 + Math.random() ) * 0x10000 ).toString( 16 ).substring( 1 );
518 }
519 return uuid;
520 },
521
522 /**
523 * Creates a function override.
524 *
525 * var obj = {
526 * myFunction: function( name ) {
527 * alert( 'Name: ' + name );
528 * }
529 * };
530 *
531 * obj.myFunction = CKEDITOR.tools.override( obj.myFunction, function( myFunctionOriginal ) {
532 * return function( name ) {
533 * alert( 'Overriden name: ' + name );
534 * myFunctionOriginal.call( this, name );
535 * };
536 * } );
537 *
538 * @param {Function} originalFunction The function to be overridden.
539 * @param {Function} functionBuilder A function that returns the new
540 * function. The original function reference will be passed to this function.
541 * @returns {Function} The new function.
542 */
543 override: function( originalFunction, functionBuilder ) {
544 var newFn = functionBuilder( originalFunction );
545 newFn.prototype = originalFunction.prototype;
546 return newFn;
547 },
548
549 /**
550 * Executes a function after a specified delay.
551 *
552 * CKEDITOR.tools.setTimeout( function() {
553 * alert( 'Executed after 2 seconds' );
554 * }, 2000 );
555 *
556 * @param {Function} func The function to be executed.
557 * @param {Number} [milliseconds=0] The amount of time (in milliseconds) to wait
558 * to fire the function execution.
559 * @param {Object} [scope=window] The object to store the function execution scope
560 * (the `this` object).
561 * @param {Object/Array} [args] A single object, or an array of objects, to
562 * pass as argument to the function.
563 * @param {Object} [ownerWindow=window] The window that will be used to set the
564 * timeout.
565 * @returns {Object} A value that can be used to cancel the function execution.
566 */
567 setTimeout: function( func, milliseconds, scope, args, ownerWindow ) {
568 if ( !ownerWindow )
569 ownerWindow = window;
570
571 if ( !scope )
572 scope = ownerWindow;
573
574 return ownerWindow.setTimeout( function() {
575 if ( args )
576 func.apply( scope, [].concat( args ) );
577 else
578 func.apply( scope );
579 }, milliseconds || 0 );
580 },
581
582 /**
583 * Removes spaces from the start and the end of a string. The following
584 * characters are removed: space, tab, line break, line feed.
585 *
586 * alert( CKEDITOR.tools.trim( ' example ' ); // 'example'
587 *
588 * @method
589 * @param {String} str The text from which the spaces will be removed.
590 * @returns {String} The modified string without the boundary spaces.
591 */
592 trim: ( function() {
593 // We are not using \s because we don't want "non-breaking spaces" to be caught.
594 var trimRegex = /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;
595 return function( str ) {
596 return str.replace( trimRegex, '' );
597 };
598 } )(),
599
600 /**
601 * Removes spaces from the start (left) of a string. The following
602 * characters are removed: space, tab, line break, line feed.
603 *
604 * alert( CKEDITOR.tools.ltrim( ' example ' ); // 'example '
605 *
606 * @method
607 * @param {String} str The text from which the spaces will be removed.
608 * @returns {String} The modified string excluding the removed spaces.
609 */
610 ltrim: ( function() {
611 // We are not using \s because we don't want "non-breaking spaces" to be caught.
612 var trimRegex = /^[ \t\n\r]+/g;
613 return function( str ) {
614 return str.replace( trimRegex, '' );
615 };
616 } )(),
617
618 /**
619 * Removes spaces from the end (right) of a string. The following
620 * characters are removed: space, tab, line break, line feed.
621 *
622 * alert( CKEDITOR.tools.ltrim( ' example ' ); // ' example'
623 *
624 * @method
625 * @param {String} str The text from which spaces will be removed.
626 * @returns {String} The modified string excluding the removed spaces.
627 */
628 rtrim: ( function() {
629 // We are not using \s because we don't want "non-breaking spaces" to be caught.
630 var trimRegex = /[ \t\n\r]+$/g;
631 return function( str ) {
632 return str.replace( trimRegex, '' );
633 };
634 } )(),
635
636 /**
637 * Returns the index of an element in an array.
638 *
639 * var letters = [ 'a', 'b', 0, 'c', false ];
640 * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); // -1 because 0 !== '0'
641 * alert( CKEDITOR.tools.indexOf( letters, false ) ); // 4 because 0 !== false
642 *
643 * @param {Array} array The array to be searched.
644 * @param {Object/Function} value The element to be found. This can be an
645 * evaluation function which receives a single parameter call for
646 * each entry in the array, returning `true` if the entry matches.
647 * @returns {Number} The (zero-based) index of the first entry that matches
648 * the entry, or `-1` if not found.
649 */
650 indexOf: function( array, value ) {
651 if ( typeof value == 'function' ) {
652 for ( var i = 0, len = array.length; i < len; i++ ) {
653 if ( value( array[ i ] ) )
654 return i;
655 }
656 } else if ( array.indexOf )
657 return array.indexOf( value );
658 else {
659 for ( i = 0, len = array.length; i < len; i++ ) {
660 if ( array[ i ] === value )
661 return i;
662 }
663 }
664 return -1;
665 },
666
667 /**
668 * Returns the index of an element in an array.
669 *
670 * var obj = { prop: true };
671 * var letters = [ 'a', 'b', 0, obj, false ];
672 *
673 * alert( CKEDITOR.tools.indexOf( letters, '0' ) ); // null
674 * alert( CKEDITOR.tools.indexOf( letters, function( value ) {
675 * // Return true when passed value has property 'prop'.
676 * return value && 'prop' in value;
677 * } ) ); // obj
678 *
679 * @param {Array} array The array to be searched.
680 * @param {Object/Function} value The element to be found. Can be an
681 * evaluation function which receives a single parameter call for
682 * each entry in the array, returning `true` if the entry matches.
683 * @returns Object The value that was found in an array.
684 */
685 search: function( array, value ) {
686 var index = CKEDITOR.tools.indexOf( array, value );
687 return index >= 0 ? array[ index ] : null;
688 },
689
690 /**
691 * Creates a function that will always execute in the context of a
692 * specified object.
693 *
694 * var obj = { text: 'My Object' };
695 *
696 * function alertText() {
697 * alert( this.text );
698 * }
699 *
700 * var newFunc = CKEDITOR.tools.bind( alertText, obj );
701 * newFunc(); // Alerts 'My Object'.
702 *
703 * @param {Function} func The function to be executed.
704 * @param {Object} obj The object to which the execution context will be bound.
705 * @returns {Function} The function that can be used to execute the
706 * `func` function in the context of `obj`.
707 */
708 bind: function( func, obj ) {
709 return function() {
710 return func.apply( obj, arguments );
711 };
712 },
713
714 /**
715 * Class creation based on prototype inheritance which supports of the
716 * following features:
717 *
718 * * Static fields
719 * * Private fields
720 * * Public (prototype) fields
721 * * Chainable base class constructor
722 *
723 * @param {Object} definition The class definition object.
724 * @returns {Function} A class-like JavaScript function.
725 */
726 createClass: function( definition ) {
727 var $ = definition.$,
728 baseClass = definition.base,
729 privates = definition.privates || definition._,
730 proto = definition.proto,
731 statics = definition.statics;
732
733 // Create the constructor, if not present in the definition.
734 !$ && ( $ = function() {
735 baseClass && this.base.apply( this, arguments );
736 } );
737
738 if ( privates ) {
739 var originalConstructor = $;
740 $ = function() {
741 // Create (and get) the private namespace.
742 var _ = this._ || ( this._ = {} );
743
744 // Make some magic so "this" will refer to the main
745 // instance when coding private functions.
746 for ( var privateName in privates ) {
747 var priv = privates[ privateName ];
748
749 _[ privateName ] = ( typeof priv == 'function' ) ? CKEDITOR.tools.bind( priv, this ) : priv;
750 }
751
752 originalConstructor.apply( this, arguments );
753 };
754 }
755
756 if ( baseClass ) {
757 $.prototype = this.prototypedCopy( baseClass.prototype );
758 $.prototype.constructor = $;
759 // Super references.
760 $.base = baseClass;
761 $.baseProto = baseClass.prototype;
762 // Super constructor.
763 $.prototype.base = function() {
764 this.base = baseClass.prototype.base;
765 baseClass.apply( this, arguments );
766 this.base = arguments.callee;
767 };
768 }
769
770 if ( proto )
771 this.extend( $.prototype, proto, true );
772
773 if ( statics )
774 this.extend( $, statics, true );
775
776 return $;
777 },
778
779 /**
780 * Creates a function reference that can be called later using
781 * {@link #callFunction}. This approach is especially useful to
782 * make DOM attribute function calls to JavaScript-defined functions.
783 *
784 * var ref = CKEDITOR.tools.addFunction( function() {
785 * alert( 'Hello!');
786 * } );
787 * CKEDITOR.tools.callFunction( ref ); // 'Hello!'
788 *
789 * @param {Function} fn The function to be executed on call.
790 * @param {Object} [scope] The object to have the context on `fn` execution.
791 * @returns {Number} A unique reference to be used in conjuction with
792 * {@link #callFunction}.
793 */
794 addFunction: function( fn, scope ) {
795 return functions.push( function() {
796 return fn.apply( scope || this, arguments );
797 } ) - 1;
798 },
799
800 /**
801 * Removes the function reference created with {@link #addFunction}.
802 *
803 * @param {Number} ref The function reference created with
804 * {@link #addFunction}.
805 */
806 removeFunction: function( ref ) {
807 functions[ ref ] = null;
808 },
809
810 /**
811 * Executes a function based on the reference created with {@link #addFunction}.
812 *
813 * var ref = CKEDITOR.tools.addFunction( function() {
814 * alert( 'Hello!');
815 * } );
816 * CKEDITOR.tools.callFunction( ref ); // 'Hello!'
817 *
818 * @param {Number} ref The function reference created with {@link #addFunction}.
819 * @param {Mixed} params Any number of parameters to be passed to the executed function.
820 * @returns {Mixed} The return value of the function.
821 */
822 callFunction: function( ref ) {
823 var fn = functions[ ref ];
824 return fn && fn.apply( window, Array.prototype.slice.call( arguments, 1 ) );
825 },
826
827 /**
828 * Appends the `px` length unit to the size value if it is missing.
829 *
830 * var cssLength = CKEDITOR.tools.cssLength;
831 * cssLength( 42 ); // '42px'
832 * cssLength( '42' ); // '42px'
833 * cssLength( '42px' ); // '42px'
834 * cssLength( '42%' ); // '42%'
835 * cssLength( 'bold' ); // 'bold'
836 * cssLength( false ); // ''
837 * cssLength( NaN ); // ''
838 *
839 * @method
840 * @param {Number/String/Boolean} length
841 */
842 cssLength: ( function() {
843 var pixelRegex = /^-?\d+\.?\d*px$/,
844 lengthTrimmed;
845
846 return function( length ) {
847 lengthTrimmed = CKEDITOR.tools.trim( length + '' ) + 'px';
848
849 if ( pixelRegex.test( lengthTrimmed ) )
850 return lengthTrimmed;
851 else
852 return length || '';
853 };
854 } )(),
855
856 /**
857 * Converts the specified CSS length value to the calculated pixel length inside this page.
858 *
859 * **Note:** Percentage-based value is left intact.
860 *
861 * @method
862 * @param {String} cssLength CSS length value.
863 */
864 convertToPx: ( function() {
865 var calculator;
866
867 return function( cssLength ) {
868 if ( !calculator ) {
869 calculator = CKEDITOR.dom.element.createFromHtml( '<div style="position:absolute;left:-9999px;' +
870 'top:-9999px;margin:0px;padding:0px;border:0px;"' +
871 '></div>', CKEDITOR.document );
872 CKEDITOR.document.getBody().append( calculator );
873 }
874
875 if ( !( /%$/ ).test( cssLength ) ) {
876 calculator.setStyle( 'width', cssLength );
877 return calculator.$.clientWidth;
878 }
879
880 return cssLength;
881 };
882 } )(),
883
884 /**
885 * String specified by `str` repeats `times` times.
886 *
887 * @param {String} str
888 * @param {Number} times
889 * @returns {String}
890 */
891 repeat: function( str, times ) {
892 return new Array( times + 1 ).join( str );
893 },
894
895 /**
896 * Returns the first successfully executed return value of a function that
897 * does not throw any exception.
898 *
899 * @param {Function...} fn
900 * @returns {Mixed}
901 */
902 tryThese: function() {
903 var returnValue;
904 for ( var i = 0, length = arguments.length; i < length; i++ ) {
905 var lambda = arguments[ i ];
906 try {
907 returnValue = lambda();
908 break;
909 } catch ( e ) {}
910 }
911 return returnValue;
912 },
913
914 /**
915 * Generates a combined key from a series of params.
916 *
917 * var key = CKEDITOR.tools.genKey( 'key1', 'key2', 'key3' );
918 * alert( key ); // 'key1-key2-key3'.
919 *
920 * @param {String} subKey One or more strings used as subkeys.
921 * @returns {String}
922 */
923 genKey: function() {
924 return Array.prototype.slice.call( arguments ).join( '-' );
925 },
926
927 /**
928 * Creates a "deferred" function which will not run immediately,
929 * but rather runs as soon as the interpreter’s call stack is empty.
930 * Behaves much like `window.setTimeout` with a delay.
931 *
932 * **Note:** The return value of the original function will be lost.
933 *
934 * @param {Function} fn The callee function.
935 * @returns {Function} The new deferred function.
936 */
937 defer: function( fn ) {
938 return function() {
939 var args = arguments,
940 self = this;
941 window.setTimeout( function() {
942 fn.apply( self, args );
943 }, 0 );
944 };
945 },
946
947 /**
948 * Normalizes CSS data in order to avoid differences in the style attribute.
949 *
950 * @param {String} styleText The style data to be normalized.
951 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
952 * @returns {String} The normalized value.
953 */
954 normalizeCssText: function( styleText, nativeNormalize ) {
955 var props = [],
956 name,
957 parsedProps = CKEDITOR.tools.parseCssText( styleText, true, nativeNormalize );
958
959 for ( name in parsedProps )
960 props.push( name + ':' + parsedProps[ name ] );
961
962 props.sort();
963
964 return props.length ? ( props.join( ';' ) + ';' ) : '';
965 },
966
967 /**
968 * Finds and converts `rgb(x,x,x)` color definition to hexadecimal notation.
969 *
970 * @param {String} styleText The style data (or just a string containing RGB colors) to be converted.
971 * @returns {String} The style data with RGB colors converted to hexadecimal equivalents.
972 */
973 convertRgbToHex: function( styleText ) {
974 return styleText.replace( /(?:rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/gi, function( match, red, green, blue ) {
975 var color = [ red, green, blue ];
976 // Add padding zeros if the hex value is less than 0x10.
977 for ( var i = 0; i < 3; i++ )
978 color[ i ] = ( '0' + parseInt( color[ i ], 10 ).toString( 16 ) ).slice( -2 );
979 return '#' + color.join( '' );
980 } );
981 },
982
983 /**
984 * Normalizes hexadecimal notation so that the color string is always 6 characters long and lowercase.
985 *
986 * @param {String} styleText The style data (or just a string containing hex colors) to be converted.
987 * @returns {String} The style data with hex colors normalized.
988 */
989 normalizeHex: function( styleText ) {
990 return styleText.replace( /#(([0-9a-f]{3}){1,2})($|;|\s+)/gi, function( match, hexColor, hexColorPart, separator ) {
991 var normalizedHexColor = hexColor.toLowerCase();
992 if ( normalizedHexColor.length == 3 ) {
993 var parts = normalizedHexColor.split( '' );
994 normalizedHexColor = [ parts[ 0 ], parts[ 0 ], parts[ 1 ], parts[ 1 ], parts[ 2 ], parts[ 2 ] ].join( '' );
995 }
996 return '#' + normalizedHexColor + separator;
997 } );
998 },
999
1000 /**
1001 * Turns inline style text properties into one hash.
1002 *
1003 * @param {String} styleText The style data to be parsed.
1004 * @param {Boolean} [normalize=false] Normalize properties and values
1005 * (e.g. trim spaces, convert to lower case).
1006 * @param {Boolean} [nativeNormalize=false] Parse the data using the browser.
1007 * @returns {Object} The object containing parsed properties.
1008 */
1009 parseCssText: function( styleText, normalize, nativeNormalize ) {
1010 var retval = {};
1011
1012 if ( nativeNormalize ) {
1013 // Injects the style in a temporary span object, so the browser parses it,
1014 // retrieving its final format.
1015 var temp = new CKEDITOR.dom.element( 'span' );
1016 styleText = temp.setAttribute( 'style', styleText ).getAttribute( 'style' ) || '';
1017 }
1018
1019 // Normalize colors.
1020 if ( styleText ) {
1021 styleText = CKEDITOR.tools.normalizeHex( CKEDITOR.tools.convertRgbToHex( styleText ) );
1022 }
1023
1024 // IE will leave a single semicolon when failed to parse the style text. (#3891)
1025 if ( !styleText || styleText == ';' )
1026 return retval;
1027
1028 styleText.replace( /&quot;/g, '"' ).replace( /\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) {
1029 if ( normalize ) {
1030 name = name.toLowerCase();
1031 // Drop extra whitespacing from font-family.
1032 if ( name == 'font-family' )
1033 value = value.replace( /\s*,\s*/g, ',' );
1034 value = CKEDITOR.tools.trim( value );
1035 }
1036
1037 retval[ name ] = value;
1038 } );
1039 return retval;
1040 },
1041
1042 /**
1043 * Serializes the `style name => value` hash to a style text.
1044 *
1045 * var styleObj = CKEDITOR.tools.parseCssText( 'color: red; border: none' );
1046 * console.log( styleObj.color ); // -> 'red'
1047 * CKEDITOR.tools.writeCssText( styleObj ); // -> 'color:red; border:none'
1048 * CKEDITOR.tools.writeCssText( styleObj, true ); // -> 'border:none; color:red'
1049 *
1050 * @since 4.1
1051 * @param {Object} styles The object contaning style properties.
1052 * @param {Boolean} [sort] Whether to sort CSS properties.
1053 * @returns {String} The serialized style text.
1054 */
1055 writeCssText: function( styles, sort ) {
1056 var name,
1057 stylesArr = [];
1058
1059 for ( name in styles )
1060 stylesArr.push( name + ':' + styles[ name ] );
1061
1062 if ( sort )
1063 stylesArr.sort();
1064
1065 return stylesArr.join( '; ' );
1066 },
1067
1068 /**
1069 * Compares two objects.
1070 *
1071 * **Note:** This method performs shallow, non-strict comparison.
1072 *
1073 * @since 4.1
1074 * @param {Object} left
1075 * @param {Object} right
1076 * @param {Boolean} [onlyLeft] Check only the properties that are present in the `left` object.
1077 * @returns {Boolean} Whether objects are identical.
1078 */
1079 objectCompare: function( left, right, onlyLeft ) {
1080 var name;
1081
1082 if ( !left && !right )
1083 return true;
1084 if ( !left || !right )
1085 return false;
1086
1087 for ( name in left ) {
1088 if ( left[ name ] != right[ name ] )
1089 return false;
1090
1091 }
1092
1093 if ( !onlyLeft ) {
1094 for ( name in right ) {
1095 if ( left[ name ] != right[ name ] )
1096 return false;
1097 }
1098 }
1099
1100 return true;
1101 },
1102
1103 /**
1104 * Returns an array of passed object's keys.
1105 *
1106 * console.log( CKEDITOR.tools.objectKeys( { foo: 1, bar: false } );
1107 * // -> [ 'foo', 'bar' ]
1108 *
1109 * @since 4.1
1110 * @param {Object} obj
1111 * @returns {Array} Object's keys.
1112 */
1113 objectKeys: function( obj ) {
1114 var keys = [];
1115 for ( var i in obj )
1116 keys.push( i );
1117
1118 return keys;
1119 },
1120
1121 /**
1122 * Converts an array to an object by rewriting array items
1123 * to object properties.
1124 *
1125 * var arr = [ 'foo', 'bar', 'foo' ];
1126 * console.log( CKEDITOR.tools.convertArrayToObject( arr ) );
1127 * // -> { foo: true, bar: true }
1128 * console.log( CKEDITOR.tools.convertArrayToObject( arr, 1 ) );
1129 * // -> { foo: 1, bar: 1 }
1130 *
1131 * @since 4.1
1132 * @param {Array} arr The array to be converted to an object.
1133 * @param [fillWith=true] Set each property of an object to `fillWith` value.
1134 */
1135 convertArrayToObject: function( arr, fillWith ) {
1136 var obj = {};
1137
1138 if ( arguments.length == 1 )
1139 fillWith = true;
1140
1141 for ( var i = 0, l = arr.length; i < l; ++i )
1142 obj[ arr[ i ] ] = fillWith;
1143
1144 return obj;
1145 },
1146
1147 /**
1148 * Tries to fix the `document.domain` of the current document to match the
1149 * parent window domain, avoiding "Same Origin" policy issues.
1150 * This is an Internet Explorer only requirement.
1151 *
1152 * @since 4.1.2
1153 * @returns {Boolean} `true` if the current domain is already good or if
1154 * it has been fixed successfully.
1155 */
1156 fixDomain: function() {
1157 var domain;
1158
1159 while ( 1 ) {
1160 try {
1161 // Try to access the parent document. It throws
1162 // "access denied" if restricted by the "Same Origin" policy.
1163 domain = window.parent.document.domain;
1164 break;
1165 } catch ( e ) {
1166 // Calculate the value to set to document.domain.
1167 domain = domain ?
1168
1169 // If it is not the first pass, strip one part of the
1170 // name. E.g. "test.example.com" => "example.com"
1171 domain.replace( /.+?(?:\.|$)/, '' ) :
1172
1173 // In the first pass, we'll handle the
1174 // "document.domain = document.domain" case.
1175 document.domain;
1176
1177 // Stop here if there is no more domain parts available.
1178 if ( !domain )
1179 break;
1180
1181 document.domain = domain;
1182 }
1183 }
1184
1185 return !!domain;
1186 },
1187
1188 /**
1189 * Buffers `input` events (or any `input` calls)
1190 * and triggers `output` not more often than once per `minInterval`.
1191 *
1192 * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() {
1193 * console.log( 'foo!' );
1194 * } );
1195 *
1196 * buffer.input();
1197 * // 'foo!' logged immediately.
1198 * buffer.input();
1199 * // Nothing logged.
1200 * buffer.input();
1201 * // Nothing logged.
1202 * // ... after 200ms a single 'foo!' will be logged.
1203 *
1204 * Can be easily used with events:
1205 *
1206 * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() {
1207 * console.log( 'foo!' );
1208 * } );
1209 *
1210 * editor.on( 'key', buffer.input );
1211 * // Note: There is no need to bind buffer as a context.
1212 *
1213 * @since 4.2.1
1214 * @param {Number} minInterval Minimum interval between `output` calls in milliseconds.
1215 * @param {Function} output Function that will be executed as `output`.
1216 * @param {Object} [scopeObj] The object used to scope the listener call (the `this` object).
1217 * @returns {Object}
1218 * @returns {Function} return.input Buffer's input method.
1219 * @returns {Function} return.reset Resets buffered events &mdash; `output` will not be executed
1220 * until next `input` is triggered.
1221 */
1222 eventsBuffer: function( minInterval, output, scopeObj ) {
1223 var scheduled,
1224 lastOutput = 0;
1225
1226 function triggerOutput() {
1227 lastOutput = ( new Date() ).getTime();
1228 scheduled = false;
1229 if ( scopeObj ) {
1230 output.call( scopeObj );
1231 } else {
1232 output();
1233 }
1234 }
1235
1236 return {
1237 input: function() {
1238 if ( scheduled )
1239 return;
1240
1241 var diff = ( new Date() ).getTime() - lastOutput;
1242
1243 // If less than minInterval passed after last check,
1244 // schedule next for minInterval after previous one.
1245 if ( diff < minInterval )
1246 scheduled = setTimeout( triggerOutput, minInterval - diff );
1247 else
1248 triggerOutput();
1249 },
1250
1251 reset: function() {
1252 if ( scheduled )
1253 clearTimeout( scheduled );
1254
1255 scheduled = lastOutput = 0;
1256 }
1257 };
1258 },
1259
1260 /**
1261 * Enables HTML5 elements for older browsers (IE8) in the passed document.
1262 *
1263 * In IE8 this method can also be executed on a document fragment.
1264 *
1265 * **Note:** This method has to be used in the `<head>` section of the document.
1266 *
1267 * @since 4.3
1268 * @param {Object} doc Native `Document` or `DocumentFragment` in which the elements will be enabled.
1269 * @param {Boolean} [withAppend] Whether to append created elements to the `doc`.
1270 */
1271 enableHtml5Elements: function( doc, withAppend ) {
1272 var els = 'abbr,article,aside,audio,bdi,canvas,data,datalist,details,figcaption,figure,footer,header,hgroup,main,mark,meter,nav,output,progress,section,summary,time,video'.split( ',' ),
1273 i = els.length,
1274 el;
1275
1276 while ( i-- ) {
1277 el = doc.createElement( els[ i ] );
1278 if ( withAppend )
1279 doc.appendChild( el );
1280 }
1281 },
1282
1283 /**
1284 * Checks if any of the `arr` items match the provided regular expression.
1285 *
1286 * @param {Array} arr The array whose items will be checked.
1287 * @param {RegExp} regexp The regular expression.
1288 * @returns {Boolean} Returns `true` for the first occurrence of the search pattern.
1289 * @since 4.4
1290 */
1291 checkIfAnyArrayItemMatches: function( arr, regexp ) {
1292 for ( var i = 0, l = arr.length; i < l; ++i ) {
1293 if ( arr[ i ].match( regexp ) )
1294 return true;
1295 }
1296 return false;
1297 },
1298
1299 /**
1300 * Checks if any of the `obj` properties match the provided regular expression.
1301 *
1302 * @param obj The object whose properties will be checked.
1303 * @param {RegExp} regexp The regular expression.
1304 * @returns {Boolean} Returns `true` for the first occurrence of the search pattern.
1305 * @since 4.4
1306 */
1307 checkIfAnyObjectPropertyMatches: function( obj, regexp ) {
1308 for ( var i in obj ) {
1309 if ( i.match( regexp ) )
1310 return true;
1311 }
1312 return false;
1313 },
1314
1315 /**
1316 * Converts a keystroke to its string representation. Returns an object with two fields:
1317 *
1318 * * `display` &ndash; A string that should be used for visible labels.
1319 * For Mac devices it uses `⌥` for `ALT`, `⇧` for `SHIFT` and `⌘` for `COMMAND`.
1320 * * `aria` &ndash; A string that should be used for ARIA descriptions.
1321 * It does not use special characters such as `⌥`, `⇧` or `⌘`.
1322 *
1323 * var lang = editor.lang.common.keyboard;
1324 * var shortcut = CKEDITOR.tools.keystrokeToString( lang, CKEDITOR.CTRL + 88 );
1325 * console.log( shortcut.display ); // 'CTRL + X', on Mac '⌘ + X'.
1326 * console.log( shortcut.aria ); // 'CTRL + X', on Mac 'COMMAND + X'.
1327 *
1328 * @since 4.6.0
1329 * @param {Object} lang A language object with the key name translation.
1330 * @param {Number} keystroke The keystroke to convert.
1331 * @returns {{display: String, aria: String}}
1332 */
1333 keystrokeToString: function( lang, keystroke ) {
1334 var special = keystroke & 0xFF0000,
1335 key = keystroke & 0x00FFFF,
1336 isMac = CKEDITOR.env.mac,
1337 CTRL = 17,
1338 CMD = 224,
1339 ALT = 18,
1340 SHIFT = 16,
1341 display = [],
1342 aria = [];
1343
1344
1345 if ( special & CKEDITOR.CTRL ) {
1346 display.push( isMac ? '⌘' : lang[ CTRL ] );
1347 aria.push( isMac ? lang[ CMD ] : lang[ CTRL ] );
1348 }
1349
1350 if ( special & CKEDITOR.ALT ) {
1351 display.push( isMac ? '⌥' : lang[ ALT ] );
1352 aria.push( lang[ ALT ] );
1353 }
1354
1355 if ( special & CKEDITOR.SHIFT ) {
1356 display.push( isMac ? '⇧' : lang[ SHIFT ] );
1357 aria.push( lang[ SHIFT ] );
1358 }
1359
1360 if ( key ) {
1361 if ( lang[ key ] ) {
1362 display.push( lang[ key ] );
1363 aria.push( lang[ key ] );
1364 } else {
1365 display.push( String.fromCharCode( key ) );
1366 aria.push( String.fromCharCode( key ) );
1367 }
1368 }
1369
1370 return {
1371 display: display.join( '+' ),
1372 aria: aria.join( '+' )
1373 };
1374 },
1375
1376 /**
1377 * The data URI of a transparent image. May be used e.g. in HTML as an image source or in CSS in `url()`.
1378 *
1379 * @since 4.4
1380 * @readonly
1381 */
1382 transparentImageData: 'data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==',
1383
1384
1385 /**
1386 * Returns the value of the cookie with a given name or `null` if the cookie is not found.
1387 *
1388 * @since 4.5.6
1389 * @param {String} name
1390 * @returns {String}
1391 */
1392 getCookie: function( name ) {
1393 name = name.toLowerCase();
1394 var parts = document.cookie.split( ';' );
1395 var pair, key;
1396
1397 for ( var i = 0; i < parts.length; i++ ) {
1398 pair = parts[ i ].split( '=' );
1399 key = decodeURIComponent( CKEDITOR.tools.trim( pair[ 0 ] ).toLowerCase() );
1400
1401 if ( key === name ) {
1402 return decodeURIComponent( pair.length > 1 ? pair[ 1 ] : '' );
1403 }
1404 }
1405
1406 return null;
1407 },
1408
1409 /**
1410 * Sets the value of the cookie with a given name.
1411 *
1412 * @since 4.5.6
1413 * @param {String} name
1414 * @param {String} value
1415 */
1416 setCookie: function( name, value ) {
1417 document.cookie = encodeURIComponent( name ) + '=' + encodeURIComponent( value ) + ';path=/';
1418 },
1419
1420 /**
1421 * Returns the CSRF token value. The value is a hash stored in `document.cookie`
1422 * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication
1423 * between the web browser and the server, i.e. for the file upload feature in the editor.
1424 *
1425 * @since 4.5.6
1426 * @returns {String}
1427 */
1428 getCsrfToken: function() {
1429 var token = CKEDITOR.tools.getCookie( TOKEN_COOKIE_NAME );
1430
1431 if ( !token || token.length != TOKEN_LENGTH ) {
1432 token = generateToken( TOKEN_LENGTH );
1433 CKEDITOR.tools.setCookie( TOKEN_COOKIE_NAME, token );
1434 }
1435
1436 return token;
1437 },
1438
1439 /**
1440 * Returns an escaped CSS selector. `CSS.escape()` is used if defined, leading digit is escaped otherwise.
1441 *
1442 * @since 4.5.10
1443 * @param {String} selector A CSS selector to escape.
1444 * @returns {String} An escaped selector.
1445 */
1446 escapeCss: function( selector ) {
1447 // Invalid input.
1448 if ( !selector ) {
1449 return '';
1450 }
1451
1452 // CSS.escape() can be used.
1453 if ( window.CSS && CSS.escape ) {
1454 return CSS.escape( selector );
1455 }
1456
1457 // Simple leading digit escape.
1458 if ( !isNaN( parseInt( selector.charAt( 0 ), 10 ) ) ) {
1459 return '\\3' + selector.charAt( 0 ) + ' ' + selector.substring( 1, selector.length );
1460 }
1461
1462 return selector;
1463 },
1464
1465 /**
1466 * A set of functions for operations on styles.
1467 *
1468 * @property {CKEDITOR.tools.style}
1469 */
1470 style: {
1471 /**
1472 * Methods to parse miscellaneous CSS properties.
1473 *
1474 * @property {CKEDITOR.tools.style.parse}
1475 * @member CKEDITOR.tools.style
1476 */
1477 parse: {
1478 // Color list based on https://www.w3.org/TR/css-color-4/#named-colors.
1479 _colors: {
1480 aliceblue: '#F0F8FF',
1481 antiquewhite: '#FAEBD7',
1482 aqua: '#00FFFF',
1483 aquamarine: '#7FFFD4',
1484 azure: '#F0FFFF',
1485 beige: '#F5F5DC',
1486 bisque: '#FFE4C4',
1487 black: '#000000',
1488 blanchedalmond: '#FFEBCD',
1489 blue: '#0000FF',
1490 blueviolet: '#8A2BE2',
1491 brown: '#A52A2A',
1492 burlywood: '#DEB887',
1493 cadetblue: '#5F9EA0',
1494 chartreuse: '#7FFF00',
1495 chocolate: '#D2691E',
1496 coral: '#FF7F50',
1497 cornflowerblue: '#6495ED',
1498 cornsilk: '#FFF8DC',
1499 crimson: '#DC143C',
1500 cyan: '#00FFFF',
1501 darkblue: '#00008B',
1502 darkcyan: '#008B8B',
1503 darkgoldenrod: '#B8860B',
1504 darkgray: '#A9A9A9',
1505 darkgreen: '#006400',
1506 darkgrey: '#A9A9A9',
1507 darkkhaki: '#BDB76B',
1508 darkmagenta: '#8B008B',
1509 darkolivegreen: '#556B2F',
1510 darkorange: '#FF8C00',
1511 darkorchid: '#9932CC',
1512 darkred: '#8B0000',
1513 darksalmon: '#E9967A',
1514 darkseagreen: '#8FBC8F',
1515 darkslateblue: '#483D8B',
1516 darkslategray: '#2F4F4F',
1517 darkslategrey: '#2F4F4F',
1518 darkturquoise: '#00CED1',
1519 darkviolet: '#9400D3',
1520 deeppink: '#FF1493',
1521 deepskyblue: '#00BFFF',
1522 dimgray: '#696969',
1523 dimgrey: '#696969',
1524 dodgerblue: '#1E90FF',
1525 firebrick: '#B22222',
1526 floralwhite: '#FFFAF0',
1527 forestgreen: '#228B22',
1528 fuchsia: '#FF00FF',
1529 gainsboro: '#DCDCDC',
1530 ghostwhite: '#F8F8FF',
1531 gold: '#FFD700',
1532 goldenrod: '#DAA520',
1533 gray: '#808080',
1534 green: '#008000',
1535 greenyellow: '#ADFF2F',
1536 grey: '#808080',
1537 honeydew: '#F0FFF0',
1538 hotpink: '#FF69B4',
1539 indianred: '#CD5C5C',
1540 indigo: '#4B0082',
1541 ivory: '#FFFFF0',
1542 khaki: '#F0E68C',
1543 lavender: '#E6E6FA',
1544 lavenderblush: '#FFF0F5',
1545 lawngreen: '#7CFC00',
1546 lemonchiffon: '#FFFACD',
1547 lightblue: '#ADD8E6',
1548 lightcoral: '#F08080',
1549 lightcyan: '#E0FFFF',
1550 lightgoldenrodyellow: '#FAFAD2',
1551 lightgray: '#D3D3D3',
1552 lightgreen: '#90EE90',
1553 lightgrey: '#D3D3D3',
1554 lightpink: '#FFB6C1',
1555 lightsalmon: '#FFA07A',
1556 lightseagreen: '#20B2AA',
1557 lightskyblue: '#87CEFA',
1558 lightslategray: '#778899',
1559 lightslategrey: '#778899',
1560 lightsteelblue: '#B0C4DE',
1561 lightyellow: '#FFFFE0',
1562 lime: '#00FF00',
1563 limegreen: '#32CD32',
1564 linen: '#FAF0E6',
1565 magenta: '#FF00FF',
1566 maroon: '#800000',
1567 mediumaquamarine: '#66CDAA',
1568 mediumblue: '#0000CD',
1569 mediumorchid: '#BA55D3',
1570 mediumpurple: '#9370DB',
1571 mediumseagreen: '#3CB371',
1572 mediumslateblue: '#7B68EE',
1573 mediumspringgreen: '#00FA9A',
1574 mediumturquoise: '#48D1CC',
1575 mediumvioletred: '#C71585',
1576 midnightblue: '#191970',
1577 mintcream: '#F5FFFA',
1578 mistyrose: '#FFE4E1',
1579 moccasin: '#FFE4B5',
1580 navajowhite: '#FFDEAD',
1581 navy: '#000080',
1582 oldlace: '#FDF5E6',
1583 olive: '#808000',
1584 olivedrab: '#6B8E23',
1585 orange: '#FFA500',
1586 orangered: '#FF4500',
1587 orchid: '#DA70D6',
1588 palegoldenrod: '#EEE8AA',
1589 palegreen: '#98FB98',
1590 paleturquoise: '#AFEEEE',
1591 palevioletred: '#DB7093',
1592 papayawhip: '#FFEFD5',
1593 peachpuff: '#FFDAB9',
1594 peru: '#CD853F',
1595 pink: '#FFC0CB',
1596 plum: '#DDA0DD',
1597 powderblue: '#B0E0E6',
1598 purple: '#800080',
1599 rebeccapurple: '#663399',
1600 red: '#FF0000',
1601 rosybrown: '#BC8F8F',
1602 royalblue: '#4169E1',
1603 saddlebrown: '#8B4513',
1604 salmon: '#FA8072',
1605 sandybrown: '#F4A460',
1606 seagreen: '#2E8B57',
1607 seashell: '#FFF5EE',
1608 sienna: '#A0522D',
1609 silver: '#C0C0C0',
1610 skyblue: '#87CEEB',
1611 slateblue: '#6A5ACD',
1612 slategray: '#708090',
1613 slategrey: '#708090',
1614 snow: '#FFFAFA',
1615 springgreen: '#00FF7F',
1616 steelblue: '#4682B4',
1617 tan: '#D2B48C',
1618 teal: '#008080',
1619 thistle: '#D8BFD8',
1620 tomato: '#FF6347',
1621 turquoise: '#40E0D0',
1622 violet: '#EE82EE',
1623 wheat: '#F5DEB3',
1624 white: '#FFFFFF',
1625 whitesmoke: '#F5F5F5',
1626 yellow: '#FFFF00',
1627 yellowgreen: '#9ACD32'
1628 },
1629
1630 _rgbaRegExp: /rgba?\(\s*\d+%?\s*,\s*\d+%?\s*,\s*\d+%?\s*(?:,\s*[0-9.]+\s*)?\)/gi,
1631
1632 _hslaRegExp: /hsla?\(\s*[0-9.]+\s*,\s*\d+%\s*,\s*\d+%\s*(?:,\s*[0-9.]+\s*)?\)/gi,
1633
1634 /**
1635 * Parses the `value` used as a `background` property shorthand and returns information as an object.
1636 *
1637 * **Note:** Currently only the `color` property is extracted. Any other parts will go into the `unprocessed` property.
1638 *
1639 * var background = CKEDITOR.tools.style.parse.background( '#0C0 url(foo.png)' );
1640 * console.log( background );
1641 * // Logs: { color: '#0C0', unprocessed: 'url(foo.png)' }
1642 *
1643 * @param {String} value The value of the `background` property.
1644 * @returns {Object} An object with information extracted from the background.
1645 * @returns {String} return.color The **first** color value found. The color format remains the same as in input.
1646 * @returns {String} return.unprocessed The remaining part of the `value` that has not been processed.
1647 * @member CKEDITOR.tools.style.parse
1648 */
1649 background: function( value ) {
1650 var ret = [],
1651 colors = [];
1652
1653 colors = this._findColor( value );
1654
1655 if ( colors.length ) {
1656 ret.color = colors[ 0 ];
1657
1658 CKEDITOR.tools.array.forEach( colors, function( colorToken ) {
1659 value = value.replace( colorToken, '' );
1660 } );
1661 }
1662
1663 value = CKEDITOR.tools.trim( value );
1664
1665 if ( value ) {
1666 // If anything was left unprocessed include it as unprocessed part.
1667 ret.unprocessed = value;
1668 }
1669
1670 return ret;
1671 },
1672
1673 /**
1674 * Parses the `margin` CSS property shorthand format.
1675 *
1676 * console.log( CKEDITOR.tools.parse.margin( '3px 0 2' ) );
1677 * // Logs: { top: "3px", right: "0", bottom: "2", left: "0" }
1678 *
1679 * @param {String} value The `margin` property value.
1680 * @returns {Object}
1681 * @returns {Number} return.top Top margin.
1682 * @returns {Number} return.right Right margin.
1683 * @returns {Number} return.bottom Bottom margin.
1684 * @returns {Number} return.left Left margin.
1685 * @member CKEDITOR.tools.style.parse
1686 */
1687 margin: function( value ) {
1688 var ret = {};
1689
1690 var widths = value.match( /(?:\-?[\.\d]+(?:%|\w*)|auto|inherit|initial|unset)/g ) || [ '0px' ];
1691
1692 switch ( widths.length ) {
1693 case 1:
1694 mapStyles( [ 0, 0, 0, 0 ] );
1695 break;
1696 case 2:
1697 mapStyles( [ 0, 1, 0, 1 ] );
1698 break;
1699 case 3:
1700 mapStyles( [ 0, 1, 2, 1 ] );
1701 break;
1702 case 4:
1703 mapStyles( [ 0, 1, 2, 3 ] );
1704 break;
1705 }
1706
1707 function mapStyles( map ) {
1708 ret.top = widths[ map[ 0 ] ];
1709 ret.right = widths[ map[ 1 ] ];
1710 ret.bottom = widths[ map[ 2 ] ];
1711 ret.left = widths[ map[ 3 ] ];
1712 }
1713
1714 return ret;
1715 },
1716
1717 /**
1718 * Searches the `value` for any CSS color occurrences and returns it.
1719 *
1720 * @private
1721 * @param {String} value
1722 * @returns {String[]} An array of matched results.
1723 * @member CKEDITOR.tools.style.parse
1724 */
1725 _findColor: function( value ) {
1726 var ret = [],
1727 arrayTools = CKEDITOR.tools.array;
1728
1729
1730 // Check for rgb(a).
1731 ret = ret.concat( value.match( this._rgbaRegExp ) || [] );
1732
1733 // Check for hsl(a).
1734 ret = ret.concat( value.match( this._hslaRegExp ) || [] );
1735
1736 ret = ret.concat( arrayTools.filter( value.split( /\s+/ ), function( colorEntry ) {
1737 // Check for hex format.
1738 if ( colorEntry.match( /^\#[a-f0-9]{3}(?:[a-f0-9]{3})?$/gi ) ) {
1739 return true;
1740 }
1741
1742 // Check for preset names.
1743 return colorEntry.toLowerCase() in CKEDITOR.tools.style.parse._colors;
1744 } ) );
1745
1746 return ret;
1747 }
1748 }
1749 },
1750
1751 /**
1752 * A set of array helpers.
1753 *
1754 * @property {CKEDITOR.tools.array}
1755 * @member CKEDITOR.tools
1756 */
1757 array: {
1758 /**
1759 * Returns a copy of `array` filtered using the `fn` function. Any elements that the `fn` will return `false` for
1760 * will get removed from the returned array.
1761 *
1762 * var filtered = this.array.filter( [ 0, 1, 2, 3 ], function( value ) {
1763 * // Leave only values equal or greater than 2.
1764 * return value >= 2;
1765 * } );
1766 * console.log( filtered );
1767 * // Logs: [ 2, 3 ]
1768 *
1769 * @param {Array} array
1770 * @param {Function} fn A function that gets called with each `array` item. Any item that `fn`
1771 * returned a `false`-alike value for will be filtered out of the `array`.
1772 * @param {Mixed} fn.value The currently iterated array value.
1773 * @param {Number} fn.index The index of the currently iterated value in an array.
1774 * @param {Array} fn.array The original array passed as the `array` variable.
1775 * @param {Mixed} [thisArg=undefined] A context object for `fn`.
1776 * @returns {Array} The filtered array.
1777 * @member CKEDITOR.tools.array
1778 */
1779 filter: function( array, fn, thisArg ) {
1780 var ret = [];
1781
1782 this.forEach( array, function( val, i ) {
1783 if ( fn.call( thisArg, val, i, array ) ) {
1784 ret.push( val );
1785 }
1786 } );
1787
1788 return ret;
1789 },
1790
1791 /**
1792 * Iterates over every element in the `array`.
1793 *
1794 * @param {Array} array An array to be iterated over.
1795 * @param {Function} fn The function called for every `array` element.
1796 * @param {Mixed} fn.value The currently iterated array value.
1797 * @param {Number} fn.index The index of the currently iterated value in an array.
1798 * @param {Array} fn.array The original array passed as an `array` variable.
1799 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1800 * @member CKEDITOR.tools.array
1801 */
1802 forEach: function( array, fn, thisArg ) {
1803 var len = array.length,
1804 i;
1805
1806 for ( i = 0; i < len; i++ ) {
1807 fn.call( thisArg, array[ i ], i, array );
1808 }
1809 },
1810
1811 /**
1812 * Applies a function to each element of an array and returns the array of results in the same order.
1813 * Note the order of the parameters.
1814 *
1815 * @param {Array} array An array of elements that `fn` is applied on.
1816 * @param {Function} fn A function with the signature `a -> b`.
1817 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1818 * @returns {Array} An array of mapped elements.
1819 * @member CKEDITOR.tools.array
1820 * @since 4.6.2
1821 */
1822 map: function( array, fn, thisArg ) {
1823 var result = [];
1824 for ( var i = 0; i < array.length; i++ ) {
1825 result.push( fn.call( thisArg, array[ i ], i, array ) );
1826 }
1827 return result;
1828 },
1829
1830 /**
1831 * Applies a function against each value in an array storing the result in an accumulator passed to the next iteration.
1832 * Note the order of the parameters.
1833 *
1834 * @param {Array} array An array of elements that `fn` is applied on.
1835 * @param {Function} fn A function with the signature `(accumulator, a, index, array) -> b`.
1836 * @param {Mixed} initial Initial value of the accumulator.
1837 * @param {Mixed} [thisArg=undefined] The context object for `fn`.
1838 * @returns {Mixed} The final value of the accumulator.
1839 * @member CKEDITOR.tools.array
1840 * @since 4.6.2
1841 */
1842 reduce: function( array, fn, initial, thisArg ) {
1843 var acc = initial;
1844 for ( var i = 0; i < array.length; i++ ) {
1845 acc = fn.call( thisArg, acc, array[ i ], i, array );
1846 }
1847 return acc;
1848 }
1849 }
1850 };
1851
1852 // Generates a CSRF token with a given length.
1853 //
1854 // @since 4.5.6
1855 // @param {Number} length
1856 // @returns {string}
1857 function generateToken( length ) {
1858 var randValues = [];
1859 var result = '';
1860
1861 if ( window.crypto && window.crypto.getRandomValues ) {
1862 randValues = new Uint8Array( length );
1863 window.crypto.getRandomValues( randValues );
1864 } else {
1865 for ( var i = 0; i < length; i++ ) {
1866 randValues.push( Math.floor( Math.random() * 256 ) );
1867 }
1868 }
1869
1870 for ( var j = 0; j < randValues.length; j++ ) {
1871 var character = tokenCharset.charAt( randValues[ j ] % tokenCharset.length );
1872 result += Math.random() > 0.5 ? character.toUpperCase() : character;
1873 }
1874
1875 return result;
1876 }
1877
1878 /**
1879 * @member CKEDITOR.tools.array
1880 * @method indexOf
1881 * @inheritdoc CKEDITOR.tools#indexOf
1882 */
1883 CKEDITOR.tools.array.indexOf = CKEDITOR.tools.indexOf;
1884
1885 /**
1886 * @member CKEDITOR.tools.array
1887 * @method isArray
1888 * @inheritdoc CKEDITOR.tools#isArray
1889 */
1890 CKEDITOR.tools.array.isArray = CKEDITOR.tools.isArray;
1891
1892
1893
1894 /**
1895 * The namespace containing functions to work on CSS properties.
1896 *
1897 * @since 4.6.1
1898 * @class CKEDITOR.tools.style
1899 */
1900
1901 /**
1902 * The namespace with helper functions to parse some common CSS properties.
1903 *
1904 * @since 4.6.1
1905 * @class CKEDITOR.tools.style.parse
1906 */
1907
1908 /**
1909 * The namespace with helper functions and polyfills for arrays.
1910 *
1911 * @since 4.6.1
1912 * @class CKEDITOR.tools.array
1913 */
1914} )();
1915
1916// PACKAGER_RENAME( CKEDITOR.tools )
diff --git a/sources/core/ui.js b/sources/core/ui.js
new file mode 100644
index 0000000..ac5a285
--- /dev/null
+++ b/sources/core/ui.js
@@ -0,0 +1,185 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * Contains UI features related to an editor instance.
8 *
9 * @class
10 * @mixins CKEDITOR.event
11 * @constructor Creates a `ui` class instance.
12 * @param {CKEDITOR.editor} editor The editor instance.
13 */
14CKEDITOR.ui = function( editor ) {
15 if ( editor.ui )
16 return editor.ui;
17
18 this.items = {};
19 this.instances = {};
20 this.editor = editor;
21
22 /**
23 * Object used to store private stuff.
24 *
25 * @private
26 */
27 this._ = {
28 handlers: {}
29 };
30
31 return this;
32};
33
34// PACKAGER_RENAME( CKEDITOR.ui )
35
36CKEDITOR.ui.prototype = {
37 /**
38 * Adds a UI item to the items collection. These items can be later used in
39 * the interface.
40 *
41 * // Add a new button named 'MyBold'.
42 * editorInstance.ui.add( 'MyBold', CKEDITOR.UI_BUTTON, {
43 * label: 'My Bold',
44 * command: 'bold'
45 * } );
46 *
47 * @param {String} name The UI item name.
48 * @param {Object} type The item type.
49 * @param {Object} definition The item definition. The properties of this
50 * object depend on the item type.
51 */
52 add: function( name, type, definition ) {
53 // Compensate the unique name of this ui item to definition.
54 definition.name = name.toLowerCase();
55
56 var item = this.items[ name ] = {
57 type: type,
58 // The name of {@link CKEDITOR.command} which associate with this UI.
59 command: definition.command || null,
60 args: Array.prototype.slice.call( arguments, 2 )
61 };
62
63 CKEDITOR.tools.extend( item, definition );
64 },
65
66 /**
67 * Retrieves the created UI objects by name.
68 *
69 * @param {String} name The name of the UI definition.
70 */
71 get: function( name ) {
72 return this.instances[ name ];
73 },
74
75 /**
76 * Gets a UI object.
77 *
78 * @param {String} name The UI item name.
79 * @returns {Object} The UI element.
80 */
81 create: function( name ) {
82 var item = this.items[ name ],
83 handler = item && this._.handlers[ item.type ],
84 command = item && item.command && this.editor.getCommand( item.command );
85
86 var result = handler && handler.create.apply( this, item.args );
87
88 this.instances[ name ] = result;
89
90 // Add reference inside command object.
91 if ( command )
92 command.uiItems.push( result );
93
94 if ( result && !result.type )
95 result.type = item.type;
96
97 return result;
98 },
99
100 /**
101 * Adds a handler for a UI item type. The handler is responsible for
102 * transforming UI item definitions into UI objects.
103 *
104 * @param {Object} type The item type.
105 * @param {Object} handler The handler definition.
106 */
107 addHandler: function( type, handler ) {
108 this._.handlers[ type ] = handler;
109 },
110
111 /**
112 * Returns the unique DOM element that represents one editor's UI part, also known as "space".
113 * There are 3 main editor spaces available: `top`, `contents` and `bottom`
114 * and their availability depends on editor type.
115 *
116 * // Hide the bottom space in the UI.
117 * var bottom = editor.ui.space( 'bottom' );
118 * bottom.setStyle( 'display', 'none' );
119 *
120 * @param {String} name The name of the space.
121 * @returns {CKEDITOR.dom.element} The element that represents the space.
122 */
123 space: function( name ) {
124 return CKEDITOR.document.getById( this.spaceId( name ) );
125 },
126
127 /**
128 * Returns the HTML ID for a specific UI space name.
129 *
130 * @param {String} name The name of the space.
131 * @returns {String} The ID of an element representing this space in the DOM.
132 */
133 spaceId: function( name ) {
134 return this.editor.id + '_' + name;
135 }
136};
137
138CKEDITOR.event.implementOn( CKEDITOR.ui );
139
140/**
141 * Internal event fired when a new UI element is ready.
142 *
143 * @event ready
144 * @param {Object} data The new UI element.
145 */
146
147/**
148 * Virtual class which just illustrates the features of handler objects to be
149 * passed to the {@link CKEDITOR.ui#addHandler} function.
150 * This class is not really a part of the API, so do not call its constructor.
151 *
152 * @class CKEDITOR.ui.handlerDefinition
153 */
154
155/**
156 * Transforms an item definition into a UI item object.
157 *
158 * editorInstance.ui.addHandler( CKEDITOR.UI_BUTTON, {
159 * create: function( definition ) {
160 * return new CKEDITOR.ui.button( definition );
161 * }
162 * } );
163 *
164 * @method create
165 * @param {Object} definition The item definition.
166 * @returns {Object} The UI element.
167 * @todo We lack the "UI element" abstract super class.
168 */
169
170/**
171 * The element in the {@link CKEDITOR#document host page's document} that contains the editor content.
172 * If the [fixed editor UI](#!/guide/dev_uitypes-section-fixed-user-interface) is used, then it will be set to
173 * `editor.ui.space( 'contents' )` &mdash; i.e. the `<div>` which contains the editor `<iframe>` (in case of classic editor)
174 * or {@link CKEDITOR.editable} (in case of inline editor). Otherwise it is set to the {@link CKEDITOR.editable} itself.
175 *
176 * Use the position of this element if you need to position elements placed in the host page's document relatively to the
177 * editor content.
178 *
179 * var editor = CKEDITOR.instances.editor1;
180 * console.log( editor.ui.contentsElement.getName() ); // 'div'
181 *
182 * @since 4.5
183 * @readonly
184 * @property {CKEDITOR.dom.element} contentsElement
185 */
diff --git a/sources/lang/_translationstatus.txt b/sources/lang/_translationstatus.txt
new file mode 100644
index 0000000..233ed53
--- /dev/null
+++ b/sources/lang/_translationstatus.txt
@@ -0,0 +1,63 @@
1Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
2For licensing, see LICENSE.md or http://ckeditor.com/license
3
4af.js Found: 62 Missing: 4
5ar.js Found: 51 Missing: 15
6bg.js Found: 58 Missing: 8
7bn.js Found: 40 Missing: 26
8bs.js Found: 29 Missing: 37
9ca.js Found: 61 Missing: 5
10cs.js Found: 66 Missing: 0
11cy.js Found: 66 Missing: 0
12da.js Found: 66 Missing: 0
13de.js Found: 66 Missing: 0
14el.js Found: 59 Missing: 7
15en-au.js Found: 38 Missing: 28
16en-ca.js Found: 37 Missing: 29
17en-gb.js Found: 61 Missing: 5
18eo.js Found: 66 Missing: 0
19es.js Found: 66 Missing: 0
20et.js Found: 66 Missing: 0
21eu.js Found: 48 Missing: 18
22fa.js Found: 66 Missing: 0
23fi.js Found: 66 Missing: 0
24fo.js Found: 66 Missing: 0
25fr-ca.js Found: 42 Missing: 24
26fr.js Found: 66 Missing: 0
27gl.js Found: 40 Missing: 26
28gu.js Found: 66 Missing: 0
29he.js Found: 66 Missing: 0
30hi.js Found: 43 Missing: 23
31hr.js Found: 66 Missing: 0
32hu.js Found: 63 Missing: 3
33is.js Found: 41 Missing: 25
34it.js Found: 66 Missing: 0
35ja.js Found: 62 Missing: 4
36ka.js Found: 62 Missing: 4
37km.js Found: 40 Missing: 26
38ko.js Found: 40 Missing: 26
39lt.js Found: 66 Missing: 0
40lv.js Found: 40 Missing: 26
41mk.js Found: 0 Missing: 66
42mn.js Found: 40 Missing: 26
43ms.js Found: 39 Missing: 27
44nb.js Found: 66 Missing: 0
45nl.js Found: 65 Missing: 1
46no.js Found: 66 Missing: 0
47pl.js Found: 66 Missing: 0
48pt-br.js Found: 66 Missing: 0
49pt.js Found: 52 Missing: 14
50ro.js Found: 61 Missing: 5
51ru.js Found: 66 Missing: 0
52sk.js Found: 49 Missing: 17
53sl.js Found: 48 Missing: 18
54sr-latn.js Found: 40 Missing: 26
55sr.js Found: 40 Missing: 26
56sv.js Found: 62 Missing: 4
57th.js Found: 40 Missing: 26
58tr.js Found: 66 Missing: 0
59ug.js Found: 66 Missing: 0
60uk.js Found: 66 Missing: 0
61vi.js Found: 66 Missing: 0
62zh-cn.js Found: 66 Missing: 0
63zh.js Found: 58 Missing: 8
diff --git a/sources/lang/af.js b/sources/lang/af.js
new file mode 100644
index 0000000..925dc4a
--- /dev/null
+++ b/sources/lang/af.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Afrikaans language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'af' ] = {
21 // ARIA description.
22 editor: 'Woordverwerker',
23 editorPanel: 'Woordverwerkerpaneel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Druk op ALT 0 vir hulp',
30
31 browseServer: 'Blaai op bediener',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Oplaai',
35 uploadSubmit: 'Stuur aan die bediener',
36 image: 'Beeld',
37 flash: 'Flash',
38 form: 'Vorm',
39 checkbox: 'Merkhokkie',
40 radio: 'Radioknoppie',
41 textField: 'Teksveld',
42 textarea: 'Teksarea',
43 hiddenField: 'Versteekteveld',
44 button: 'Knop',
45 select: 'Keuseveld',
46 imageButton: 'Beeldknop',
47 notSet: '<geen instelling>',
48 id: 'Id',
49 name: 'Naam',
50 langDir: 'Skryfrigting',
51 langDirLtr: 'Links na regs (LTR)',
52 langDirRtl: 'Regs na links (RTL)',
53 langCode: 'Taalkode',
54 longDescr: 'Lang beskrywing URL',
55 cssClass: 'CSS klasse',
56 advisoryTitle: 'Aanbevole titel',
57 cssStyle: 'Styl',
58 ok: 'OK',
59 cancel: 'Kanselleer',
60 close: 'Sluit',
61 preview: 'Voorbeeld',
62 resize: 'Skalierung',
63 generalTab: 'Algemeen',
64 advancedTab: 'Gevorderd',
65 validateNumberFailed: 'Hierdie waarde is nie \'n nommer nie.',
66 confirmNewPage: 'Alle wysiginge sal verlore gaan. Is jy seker dat jy \'n nuwe bladsy wil laai?',
67 confirmCancel: 'Sommige opsies is gewysig. Is jy seker dat jy hierdie dialoogvenster wil sluit?',
68 options: 'Opsies',
69 target: 'Teiken',
70 targetNew: 'Nuwe venster (_blank)',
71 targetTop: 'Boonste venster (_top)',
72 targetSelf: 'Selfde venster (_self)',
73 targetParent: 'Oorspronklike venster (_parent)',
74 langDirLTR: 'Links na Regs (LTR)',
75 langDirRTL: 'Regs na Links (RTL)',
76 styles: 'Styl',
77 cssClasses: 'CSS klasse',
78 width: 'Breedte',
79 height: 'Hoogte',
80 align: 'Orienteerung',
81 alignLeft: 'Links',
82 alignRight: 'Regs',
83 alignCenter: 'Middel',
84 alignJustify: 'Eweredig',
85 alignTop: 'Bo',
86 alignMiddle: 'Middel',
87 alignBottom: 'Onder',
88 alignNone: 'Geen',
89 invalidValue: 'Ongeldige waarde',
90 invalidHeight: 'Hoogte moet \'n getal wees',
91 invalidWidth: 'Breedte moet \'n getal wees.',
92 invalidCssLength: 'Die waarde vir die "%1" veld moet \'n posetiewe getal wees met of sonder \'n geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).',
93 invalidHtmlLength: 'Die waarde vir die "%1" veld moet \'n posetiewe getal wees met of sonder \'n geldige HTML eenheid (px of %).',
94 invalidInlineStyle: 'Ongeldige CSS. Formaat is een of meer sleutel-wert paare, "naam : wert" met kommapunte gesky.',
95 cssLengthTooltip: 'Voeg \'n getal wert in pixel in, of \'n waarde met geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nie beskikbaar nie</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Einde',
109 36: 'Tuis',
110 46: 'Verwyder',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ar.js b/sources/lang/ar.js
new file mode 100644
index 0000000..1412f22
--- /dev/null
+++ b/sources/lang/ar.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Arabic language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ar' ] = {
21 // ARIA description.
22 editor: 'محرر النص الغني',
23 editorPanel: 'لائحة محرر النص المنسق',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'إضغط على ALT + 0 للحصول على المساعدة.',
30
31 browseServer: 'تصفح',
32 url: 'الرابط',
33 protocol: 'البروتوكول',
34 upload: 'رفع',
35 uploadSubmit: 'أرسل',
36 image: 'صورة',
37 flash: 'فلاش',
38 form: 'نموذج',
39 checkbox: 'خانة إختيار',
40 radio: 'زر اختيار',
41 textField: 'مربع نص',
42 textarea: 'مساحة نصية',
43 hiddenField: 'إدراج حقل خفي',
44 button: 'زر ضغط',
45 select: 'اختار',
46 imageButton: 'زر صورة',
47 notSet: '<بدون تحديد>',
48 id: 'الرقم',
49 name: 'إسم',
50 langDir: 'إتجاه النص',
51 langDirLtr: 'اليسار لليمين (LTR)',
52 langDirRtl: 'اليمين لليسار (RTL)',
53 langCode: 'رمز اللغة',
54 longDescr: 'الوصف التفصيلى',
55 cssClass: 'فئات التنسيق',
56 advisoryTitle: 'عنوان التقرير',
57 cssStyle: 'نمط',
58 ok: 'موافق',
59 cancel: 'إلغاء الأمر',
60 close: 'أغلق',
61 preview: 'استعراض',
62 resize: 'تغيير الحجم',
63 generalTab: 'عام',
64 advancedTab: 'متقدم',
65 validateNumberFailed: 'لايوجد نتيجة',
66 confirmNewPage: 'ستفقد أي متغييرات اذا لم تقم بحفظها اولا. هل أنت متأكد أنك تريد صفحة جديدة؟',
67 confirmCancel: 'بعض الخيارات قد تغيرت. هل أنت متأكد من إغلاق مربع النص؟',
68 options: 'خيارات',
69 target: 'هدف الرابط',
70 targetNew: 'نافذة جديدة',
71 targetTop: 'النافذة الأعلى',
72 targetSelf: 'داخل النافذة',
73 targetParent: 'النافذة الأم',
74 langDirLTR: 'اليسار لليمين (LTR)',
75 langDirRTL: 'اليمين لليسار (RTL)',
76 styles: 'نمط',
77 cssClasses: 'فئات التنسيق',
78 width: 'العرض',
79 height: 'الإرتفاع',
80 align: 'محاذاة',
81 alignLeft: 'يسار',
82 alignRight: 'يمين',
83 alignCenter: 'وسط',
84 alignJustify: 'ضبط',
85 alignTop: 'أعلى',
86 alignMiddle: 'وسط',
87 alignBottom: 'أسفل',
88 alignNone: 'None', // MISSING
89 invalidValue: 'قيمة غير مفبولة.',
90 invalidHeight: 'الارتفاع يجب أن يكون عدداً.',
91 invalidWidth: 'العرض يجب أن يكون عدداً.',
92 invalidCssLength: 'قيمة الخانة المخصصة لـ "%1" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة CSS قياس مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).',
93 invalidHtmlLength: 'قيمة الخانة المخصصة لـ "%1" يجب أن تكون رقما موجبا، باستخدام أو من غير استخدام وحدة HTML قياس مقبولة (px or %).',
94 invalidInlineStyle: 'قيمة الخانة المخصصة لـ Inline Style يجب أن تختوي على مجموع واحد أو أكثر بالشكل التالي: "name : value", مفصولة بفاصلة منقزطة.',
95 cssLengthTooltip: 'أدخل رقما للقيمة بالبكسل أو رقما بوحدة CSS مقبولة (px, %, in, cm, mm, em, ex, pt, or pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, غير متاح</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/az.js b/sources/lang/az.js
new file mode 100644
index 0000000..796fec7
--- /dev/null
+++ b/sources/lang/az.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Azerbaijani language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'az' ] = {
21 // ARIA description.
22 editor: 'Mətn Redaktoru',
23 editorPanel: 'Mətn Redaktorun Paneli',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Yardım üçün ALT 0 düymələrini basın',
30
31 browseServer: 'Fayların siyahı',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Serverə yüklə',
35 uploadSubmit: 'Göndər',
36 image: 'Şəkil',
37 flash: 'Flash',
38 form: 'Forma',
39 checkbox: 'Çekboks',
40 radio: 'Radio düyməsi',
41 textField: 'Mətn xanası',
42 textarea: 'Mətn',
43 hiddenField: 'Gizli xana',
44 button: 'Düymə',
45 select: 'Opsiyaların seçilməsi',
46 imageButton: 'Şəkil tipli düymə',
47 notSet: '<seçilməmiş>',
48 id: 'Id',
49 name: 'Ad',
50 langDir: 'Yaziların istiqaməti',
51 langDirLtr: 'Soldan sağa (LTR)',
52 langDirRtl: 'Sağdan sola (RTL)',
53 langCode: 'Dilin kodu',
54 longDescr: 'URL-ın ətraflı izahı',
55 cssClass: 'CSS klassları',
56 advisoryTitle: 'Başlıq',
57 cssStyle: 'CSS',
58 ok: 'Tədbiq et',
59 cancel: 'İmtina et',
60 close: 'Bağla',
61 preview: 'Baxış',
62 resize: 'Eni dəyiş',
63 generalTab: 'Əsas',
64 advancedTab: 'Əlavə',
65 validateNumberFailed: 'Rəqəm deyil.',
66 confirmNewPage: 'Yadda saxlanılmamış dəyişikliklər itiriləcək. Davam etmək istədiyinizə əminsinizmi?',
67 confirmCancel: 'Dəyişikliklər edilib. Pəncərəni bağlamaq istəyirsizə əminsinizmi?',
68 options: 'Seçimlər',
69 target: 'Hədəf çərçivə',
70 targetNew: 'Yeni pəncərə (_blank)',
71 targetTop: 'Əsas pəncərə (_top)',
72 targetSelf: 'Carı pəncərə (_self)',
73 targetParent: 'Ana pəncərə (_parent)',
74 langDirLTR: 'Soldan sağa (LTR)',
75 langDirRTL: 'Sağdan sola (RTL)',
76 styles: 'Üslub',
77 cssClasses: 'Üslub klası',
78 width: 'En',
79 height: 'Uzunluq',
80 align: 'Yerləşmə',
81 alignLeft: 'Sol',
82 alignRight: 'Sağ',
83 alignCenter: 'Mərkəz',
84 alignJustify: 'Eninə görə',
85 alignTop: 'Yuxarı',
86 alignMiddle: 'Orta',
87 alignBottom: 'Aşağı',
88 alignNone: 'Yoxdur',
89 invalidValue: 'Yanlışdır.',
90 invalidHeight: 'Hündürlük rəqəm olmalıdır.',
91 invalidWidth: 'En rəqəm olmalıdır.',
92 invalidCssLength: '"%1" xanasında göstərilən məzmun tam və müsbət olmalıdır, CSS-də olan ölçü vahidlərin (px, %, in, cm, mm, em, ex, pt, or pc) istifadısinə icazə verilir.',
93 invalidHtmlLength: '"%1" xanasında göstərilən məzmun tam və müsbət olmalıdır HTML-də olan ölçü vahidlərin (px və ya %) istifadısinə icazə verilir.',
94 invalidInlineStyle: 'Teq içində olan üslub "ad : məzmun" şəklidə, nöqtə-verqül işarəsi ilə bitməlidir',
95 cssLengthTooltip: 'Piksel sayı və ya digər CSS ölçü vahidləri (px, %, in, cm, mm, em, ex, pt, or pc) daxil edin.',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, mövcud deyil</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Boşluq',
108 35: 'Son',
109 36: 'Evə',
110 46: 'Sil',
111 224: 'Əmr'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Qısayol düymələri'
116 }
117};
diff --git a/sources/lang/bg.js b/sources/lang/bg.js
new file mode 100644
index 0000000..84a1d55
--- /dev/null
+++ b/sources/lang/bg.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Bulgarian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'bg' ] = {
21 // ARIA description.
22 editor: 'Текстов редактор за форматиран текст',
23 editorPanel: 'Панел на текстовия редактор',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'натиснете ALT 0 за помощ',
30
31 browseServer: 'Избор от сървъра',
32 url: 'URL',
33 protocol: 'Протокол',
34 upload: 'Качване',
35 uploadSubmit: 'Изпращане към сървъра',
36 image: 'Снимка',
37 flash: 'Флаш',
38 form: 'Форма',
39 checkbox: 'Поле за избор',
40 radio: 'Радио бутон',
41 textField: 'Текстово поле',
42 textarea: 'Текстова зона',
43 hiddenField: 'Скрито поле',
44 button: 'Бутон',
45 select: 'Поле за избор',
46 imageButton: 'Бутон за снимка',
47 notSet: '<не е избрано>',
48 id: 'ID',
49 name: 'Име',
50 langDir: 'Посока на езика',
51 langDirLtr: 'Ляво на дясно (ЛнД)',
52 langDirRtl: 'Дясно на ляво (ДнЛ)',
53 langCode: 'Код на езика',
54 longDescr: 'Уеб адрес за дълго описание',
55 cssClass: 'Класове за CSS',
56 advisoryTitle: 'Препоръчително заглавие',
57 cssStyle: 'Стил',
58 ok: 'ОК',
59 cancel: 'Отказ',
60 close: 'Затвори',
61 preview: 'Преглед',
62 resize: 'Влачете за да оразмерите',
63 generalTab: 'Общи',
64 advancedTab: 'Разширено',
65 validateNumberFailed: 'Тази стойност не е число',
66 confirmNewPage: 'Всички незапазени промени ще бъдат изгубени. Сигурни ли сте, че желаете да заредите нова страница?',
67 confirmCancel: 'Някои от опциите са променени. Сигурни ли сте, че желаете да затворите прозореца?',
68 options: 'Опции',
69 target: 'Цел',
70 targetNew: 'Нов прозорец (_blank)',
71 targetTop: 'Горна позиция (_top)',
72 targetSelf: 'Текущия прозорец (_self)',
73 targetParent: 'Основен прозорец (_parent)',
74 langDirLTR: 'Ляво на дясно (ЛнД)',
75 langDirRTL: 'Дясно на ляво (ДнЛ)',
76 styles: 'Стил',
77 cssClasses: 'Класове за CSS',
78 width: 'Ширина',
79 height: 'Височина',
80 align: 'Подравняване',
81 alignLeft: 'Ляво',
82 alignRight: 'Дясно',
83 alignCenter: 'Център',
84 alignJustify: 'Двустранно подравняване',
85 alignTop: 'Горе',
86 alignMiddle: 'По средата',
87 alignBottom: 'Долу',
88 alignNone: 'Без подравняване',
89 invalidValue: 'Невалидна стойност.',
90 invalidHeight: 'Височината трябва да е число.',
91 invalidWidth: 'Ширина требе да е число.',
92 invalidCssLength: 'Стойността на полето "%1" трябва да бъде положително число с или без валидна CSS измервателна единица (px, %, in, cm, mm, em, ex, pt, или pc).',
93 invalidHtmlLength: 'Стойността на полето "%1" трябва да бъде положително число с или без валидна HTML измервателна единица (px или %).',
94 invalidInlineStyle: 'Стойността на стилa трябва да съдържат една или повече двойки във формат "name : value", разделени с двоеточие.',
95 cssLengthTooltip: 'Въведете числена стойност в пиксели или друга валидна CSS единица (px, %, in, cm, mm, em, ex, pt, или pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, недостъпно</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/bn.js b/sources/lang/bn.js
new file mode 100644
index 0000000..9c6e69b
--- /dev/null
+++ b/sources/lang/bn.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Bengali/Bangla language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'bn' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'ব্রাউজ সার্ভার',
32 url: 'URL',
33 protocol: 'প্রোটোকল',
34 upload: 'আপলোড',
35 uploadSubmit: 'ইহাকে সার্ভারে প্রেরন কর',
36 image: 'ছবির লেবেল যুক্ত কর',
37 flash: 'ফ্লাশ লেবেল যুক্ত কর',
38 form: 'ফর্ম',
39 checkbox: 'চেক বাক্স',
40 radio: 'রেডিও বাটন',
41 textField: 'টেক্সট ফীল্ড',
42 textarea: 'টেক্সট এরিয়া',
43 hiddenField: 'গুপ্ত ফীল্ড',
44 button: 'বাটন',
45 select: 'বাছাই ফীল্ড',
46 imageButton: 'ছবির বাটন',
47 notSet: '<সেট নেই>',
48 id: 'আইডি',
49 name: 'নাম',
50 langDir: 'ভাষা লেখার দিক',
51 langDirLtr: 'বাম থেকে ডান (LTR)',
52 langDirRtl: 'ডান থেকে বাম (RTL)',
53 langCode: 'ভাষা কোড',
54 longDescr: 'URL এর লম্বা বর্ণনা',
55 cssClass: 'স্টাইল-শীট ক্লাস',
56 advisoryTitle: 'পরামর্শ শীর্ষক',
57 cssStyle: 'স্টাইল',
58 ok: 'ওকে',
59 cancel: 'বাতিল',
60 close: 'Close', // MISSING
61 preview: 'প্রিভিউ',
62 resize: 'Resize', // MISSING
63 generalTab: 'General', // MISSING
64 advancedTab: 'এডভান্সড',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Options', // MISSING
69 target: 'টার্গেট',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'বাম থেকে ডান (LTR)',
75 langDirRTL: 'ডান থেকে বাম (RTL)',
76 styles: 'স্টাইল',
77 cssClasses: 'স্টাইল-শীট ক্লাস',
78 width: 'প্রস্থ',
79 height: 'দৈর্ঘ্য',
80 align: 'এলাইন',
81 alignLeft: 'বামে',
82 alignRight: 'ডানে',
83 alignCenter: 'মাঝখানে',
84 alignJustify: 'ব্লক জাস্টিফাই',
85 alignTop: 'উপর',
86 alignMiddle: 'মধ্য',
87 alignBottom: 'নীচে',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/bs.js b/sources/lang/bs.js
new file mode 100644
index 0000000..f214df8
--- /dev/null
+++ b/sources/lang/bs.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Bosnian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'bs' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Browse Server', // MISSING
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Šalji',
35 uploadSubmit: 'Šalji na server',
36 image: 'Slika',
37 flash: 'Flash', // MISSING
38 form: 'Form', // MISSING
39 checkbox: 'Checkbox', // MISSING
40 radio: 'Radio Button', // MISSING
41 textField: 'Text Field', // MISSING
42 textarea: 'Textarea', // MISSING
43 hiddenField: 'Hidden Field', // MISSING
44 button: 'Button',
45 select: 'Selection Field', // MISSING
46 imageButton: 'Image Button', // MISSING
47 notSet: '<nije podešeno>',
48 id: 'Id',
49 name: 'Naziv',
50 langDir: 'Smjer pisanja',
51 langDirLtr: 'S lijeva na desno (LTR)',
52 langDirRtl: 'S desna na lijevo (RTL)',
53 langCode: 'Jezièni kôd',
54 longDescr: 'Dugaèki opis URL-a',
55 cssClass: 'Klase CSS stilova',
56 advisoryTitle: 'Advisory title',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Odustani',
60 close: 'Close', // MISSING
61 preview: 'Prikaži',
62 resize: 'Resize', // MISSING
63 generalTab: 'General', // MISSING
64 advancedTab: 'Naprednije',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Options', // MISSING
69 target: 'Prozor',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'S lijeva na desno (LTR)',
75 langDirRTL: 'S desna na lijevo (RTL)',
76 styles: 'Stil',
77 cssClasses: 'Klase CSS stilova',
78 width: 'Širina',
79 height: 'Visina',
80 align: 'Poravnanje',
81 alignLeft: 'Lijevo',
82 alignRight: 'Desno',
83 alignCenter: 'Centar',
84 alignJustify: 'Puno poravnanje',
85 alignTop: 'Vrh',
86 alignMiddle: 'Sredina',
87 alignBottom: 'Dno',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ca.js b/sources/lang/ca.js
new file mode 100644
index 0000000..5ca9450
--- /dev/null
+++ b/sources/lang/ca.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Catalan language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ca' ] = {
21 // ARIA description.
22 editor: 'Editor de text enriquit',
23 editorPanel: 'Panell de l\'editor de text enriquit',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Premeu ALT 0 per ajuda',
30
31 browseServer: 'Veure servidor',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Puja',
35 uploadSubmit: 'Envia-la al servidor',
36 image: 'Imatge',
37 flash: 'Flash',
38 form: 'Formulari',
39 checkbox: 'Casella de verificació',
40 radio: 'Botó d\'opció',
41 textField: 'Camp de text',
42 textarea: 'Àrea de text',
43 hiddenField: 'Camp ocult',
44 button: 'Botó',
45 select: 'Camp de selecció',
46 imageButton: 'Botó d\'imatge',
47 notSet: '<no definit>',
48 id: 'Id',
49 name: 'Nom',
50 langDir: 'Direcció de l\'idioma',
51 langDirLtr: 'D\'esquerra a dreta (LTR)',
52 langDirRtl: 'De dreta a esquerra (RTL)',
53 langCode: 'Codi d\'idioma',
54 longDescr: 'Descripció llarga de la URL',
55 cssClass: 'Classes del full d\'estil',
56 advisoryTitle: 'Títol consultiu',
57 cssStyle: 'Estil',
58 ok: 'D\'acord',
59 cancel: 'Cancel·la',
60 close: 'Tanca',
61 preview: 'Previsualitza',
62 resize: 'Arrossegueu per redimensionar',
63 generalTab: 'General',
64 advancedTab: 'Avançat',
65 validateNumberFailed: 'Aquest valor no és un número.',
66 confirmNewPage: 'Els canvis en aquest contingut que no es desin es perdran. Esteu segur que voleu carregar una pàgina nova?',
67 confirmCancel: 'Algunes opcions s\'han canviat. Esteu segur que voleu tancar el quadre de diàleg?',
68 options: 'Opcions',
69 target: 'Destí',
70 targetNew: 'Nova finestra (_blank)',
71 targetTop: 'Finestra superior (_top)',
72 targetSelf: 'Mateixa finestra (_self)',
73 targetParent: 'Finestra pare (_parent)',
74 langDirLTR: 'D\'esquerra a dreta (LTR)',
75 langDirRTL: 'De dreta a esquerra (RTL)',
76 styles: 'Estil',
77 cssClasses: 'Classes del full d\'estil',
78 width: 'Amplada',
79 height: 'Alçada',
80 align: 'Alineació',
81 alignLeft: 'Ajusta a l\'esquerra',
82 alignRight: 'Ajusta a la dreta',
83 alignCenter: 'Centre',
84 alignJustify: 'Justificat',
85 alignTop: 'Superior',
86 alignMiddle: 'Centre',
87 alignBottom: 'Inferior',
88 alignNone: 'Cap',
89 invalidValue: 'Valor no vàlid.',
90 invalidHeight: 'L\'alçada ha de ser un número.',
91 invalidWidth: 'L\'amplada ha de ser un número.',
92 invalidCssLength: 'El valor especificat per als "%1" camps ha de ser un número positiu amb o sense unitat de mesura vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).',
93 invalidHtmlLength: 'El valor especificat per als "%1" camps ha de ser un número positiu amb o sense unitat de mesura vàlida d\'HTML (px o %).',
94 invalidInlineStyle: 'El valor especificat per l\'estil en línia ha de constar d\'una o més tuples amb el format "name: value", separats per punt i coma.',
95 cssLengthTooltip: 'Introduïu un número per un valor en píxels o un número amb una unitat vàlida de CSS (px, %, in, cm, mm, em, ex, pt o pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, no disponible</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Retrocés',
103 13: 'Intro',
104 16: 'Majúscules',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Fi',
109 36: 'Inici',
110 46: 'Eliminar',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/cs.js b/sources/lang/cs.js
new file mode 100644
index 0000000..b76bee7
--- /dev/null
+++ b/sources/lang/cs.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Czech language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'cs' ] = {
21 // ARIA description.
22 editor: 'Textový editor',
23 editorPanel: 'Panel textového editoru',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Stiskněte ALT 0 pro nápovědu',
30
31 browseServer: 'Vybrat na serveru',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Odeslat',
35 uploadSubmit: 'Odeslat na server',
36 image: 'Obrázek',
37 flash: 'Flash',
38 form: 'Formulář',
39 checkbox: 'Zaškrtávací políčko',
40 radio: 'Přepínač',
41 textField: 'Textové pole',
42 textarea: 'Textová oblast',
43 hiddenField: 'Skryté pole',
44 button: 'Tlačítko',
45 select: 'Seznam',
46 imageButton: 'Obrázkové tlačítko',
47 notSet: '<nenastaveno>',
48 id: 'Id',
49 name: 'Jméno',
50 langDir: 'Směr jazyka',
51 langDirLtr: 'Zleva doprava (LTR)',
52 langDirRtl: 'Zprava doleva (RTL)',
53 langCode: 'Kód jazyka',
54 longDescr: 'Dlouhý popis URL',
55 cssClass: 'Třída stylu',
56 advisoryTitle: 'Pomocný titulek',
57 cssStyle: 'Styl',
58 ok: 'OK',
59 cancel: 'Zrušit',
60 close: 'Zavřít',
61 preview: 'Náhled',
62 resize: 'Uchopit pro změnu velikosti',
63 generalTab: 'Obecné',
64 advancedTab: 'Rozšířené',
65 validateNumberFailed: 'Zadaná hodnota není číselná.',
66 confirmNewPage: 'Jakékoliv neuložené změny obsahu budou ztraceny. Skutečně chcete otevřít novou stránku?',
67 confirmCancel: 'Některá z nastavení byla změněna. Skutečně chcete zavřít dialogové okno?',
68 options: 'Nastavení',
69 target: 'Cíl',
70 targetNew: 'Nové okno (_blank)',
71 targetTop: 'Okno nejvyšší úrovně (_top)',
72 targetSelf: 'Stejné okno (_self)',
73 targetParent: 'Rodičovské okno (_parent)',
74 langDirLTR: 'Zleva doprava (LTR)',
75 langDirRTL: 'Zprava doleva (RTL)',
76 styles: 'Styly',
77 cssClasses: 'Třídy stylů',
78 width: 'Šířka',
79 height: 'Výška',
80 align: 'Zarovnání',
81 alignLeft: 'Vlevo',
82 alignRight: 'Vpravo',
83 alignCenter: 'Na střed',
84 alignJustify: 'Zarovnat do bloku',
85 alignTop: 'Nahoru',
86 alignMiddle: 'Na střed',
87 alignBottom: 'Dolů',
88 alignNone: 'Žádné',
89 invalidValue: 'Neplatná hodnota.',
90 invalidHeight: 'Zadaná výška musí být číslo.',
91 invalidWidth: 'Šířka musí být číslo.',
92 invalidCssLength: 'Hodnota určená pro pole "%1" musí být kladné číslo bez nebo s platnou jednotkou míry CSS (px, %, in, cm, mm, em, ex, pt, nebo pc).',
93 invalidHtmlLength: 'Hodnota určená pro pole "%1" musí být kladné číslo bez nebo s platnou jednotkou míry HTML (px nebo %).',
94 invalidInlineStyle: 'Hodnota určená pro řádkový styl se musí skládat z jedné nebo více n-tic ve formátu "název : hodnota", oddělené středníky',
95 cssLengthTooltip: 'Zadejte číslo jako hodnotu v pixelech nebo číslo s platnou jednotkou CSS (px, %, v cm, mm, em, ex, pt, nebo pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nedostupné</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Konec',
109 36: 'Domů',
110 46: 'Smazat',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/cy.js b/sources/lang/cy.js
new file mode 100644
index 0000000..3f075aa
--- /dev/null
+++ b/sources/lang/cy.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Welsh language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'cy' ] = {
21 // ARIA description.
22 editor: 'Golygydd Testun Cyfoethog',
23 editorPanel: 'Panel Golygydd Testun Cyfoethog',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Gwasgwch ALT 0 am gymorth',
30
31 browseServer: 'Pori\'r Gweinydd',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Lanlwytho',
35 uploadSubmit: 'Anfon i\'r Gweinydd',
36 image: 'Delwedd',
37 flash: 'Flash',
38 form: 'Ffurflen',
39 checkbox: 'Blwch ticio',
40 radio: 'Botwm Radio',
41 textField: 'Maes Testun',
42 textarea: 'Ardal Testun',
43 hiddenField: 'Maes Cudd',
44 button: 'Botwm',
45 select: 'Maes Dewis',
46 imageButton: 'Botwm Delwedd',
47 notSet: '<heb osod>',
48 id: 'Id',
49 name: 'Name',
50 langDir: 'Cyfeiriad Iaith',
51 langDirLtr: 'Chwith i\'r Dde (LTR)',
52 langDirRtl: 'Dde i\'r Chwith (RTL)',
53 langCode: 'Cod Iaith',
54 longDescr: 'URL Disgrifiad Hir',
55 cssClass: 'Dosbarthiadau Dalen Arddull',
56 advisoryTitle: 'Teitl Cynghorol',
57 cssStyle: 'Arddull',
58 ok: 'Iawn',
59 cancel: 'Diddymu',
60 close: 'Cau',
61 preview: 'Rhagolwg',
62 resize: 'Ailfeintio',
63 generalTab: 'Cyffredinol',
64 advancedTab: 'Uwch',
65 validateNumberFailed: '\'Dyw\'r gwerth hwn ddim yn rhif.',
66 confirmNewPage: 'Byddwch chi\'n colli unrhyw newidiadau i\'r cynnwys sydd heb eu cadw. Ydych am barhau i lwytho tudalen newydd?',
67 confirmCancel: 'Cafodd rhai o\'r opsiynau eu newid. Ydych chi wir am gau\'r deialog?',
68 options: 'Opsiynau',
69 target: 'Targed',
70 targetNew: 'Ffenest Newydd (_blank)',
71 targetTop: 'Ffenest ar y Brig (_top)',
72 targetSelf: 'Yr un Ffenest (_self)',
73 targetParent: 'Ffenest y Rhiant (_parent)',
74 langDirLTR: 'Chwith i\'r Dde (LTR)',
75 langDirRTL: 'Dde i\'r Chwith (RTL)',
76 styles: 'Arddull',
77 cssClasses: 'Dosbarthiadau Dalen Arddull',
78 width: 'Lled',
79 height: 'Uchder',
80 align: 'Alinio',
81 alignLeft: 'Chwith',
82 alignRight: 'Dde',
83 alignCenter: 'Canol',
84 alignJustify: 'Unioni',
85 alignTop: 'Brig',
86 alignMiddle: 'Canol',
87 alignBottom: 'Gwaelod',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Gwerth annilys.',
90 invalidHeight: 'Mae\'n rhaid i\'r uchder fod yn rhif.',
91 invalidWidth: 'Mae\'n rhaid i\'r lled fod yn rhif.',
92 invalidCssLength: 'Mae\'n rhaid i\'r gwerth ar gyfer maes "%1" fod yn rhif positif gyda neu heb uned fesuriad CSS dilys (px, %, in, cm, mm, em, ex, pt, neu pc).',
93 invalidHtmlLength: 'Mae\'n rhaid i\'r gwerth ar gyfer maes "%1" fod yn rhif positif gyda neu heb uned fesuriad HTML dilys (px neu %).',
94 invalidInlineStyle: 'Mae\'n rhaid i\'r gwerth ar gyfer arddull mewn-llinell gynnwys un set neu fwy ar y fformat "enw : gwerth", wedi\'u gwahanu gyda hanner colon.',
95 cssLengthTooltip: 'Rhowch rif am werth mewn picsel neu rhif gydag uned CSS dilys (px, %, in, cm, mm, em, pt neu pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, ddim ar gael</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/da.js b/sources/lang/da.js
new file mode 100644
index 0000000..9b0a63d
--- /dev/null
+++ b/sources/lang/da.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Danish language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'da' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Tryk ALT 0 for hjælp',
30
31 browseServer: 'Gennemse...',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Upload',
35 uploadSubmit: 'Upload',
36 image: 'Indsæt billede',
37 flash: 'Indsæt Flash',
38 form: 'Indsæt formular',
39 checkbox: 'Indsæt afkrydsningsfelt',
40 radio: 'Indsæt alternativknap',
41 textField: 'Indsæt tekstfelt',
42 textarea: 'Indsæt tekstboks',
43 hiddenField: 'Indsæt skjult felt',
44 button: 'Indsæt knap',
45 select: 'Indsæt liste',
46 imageButton: 'Indsæt billedknap',
47 notSet: '<intet valgt>',
48 id: 'Id',
49 name: 'Navn',
50 langDir: 'Tekstretning',
51 langDirLtr: 'Fra venstre mod højre (LTR)',
52 langDirRtl: 'Fra højre mod venstre (RTL)',
53 langCode: 'Sprogkode',
54 longDescr: 'Udvidet beskrivelse',
55 cssClass: 'Typografiark (CSS)',
56 advisoryTitle: 'Titel',
57 cssStyle: 'Typografi (CSS)',
58 ok: 'OK',
59 cancel: 'Annullér',
60 close: 'Luk',
61 preview: 'Forhåndsvisning',
62 resize: 'Træk for at skalere',
63 generalTab: 'Generelt',
64 advancedTab: 'Avanceret',
65 validateNumberFailed: 'Værdien er ikke et tal.',
66 confirmNewPage: 'Alt indhold, der ikke er blevet gemt, vil gå tabt. Er du sikker på, at du vil indlæse en ny side?',
67 confirmCancel: 'Nogle af indstillingerne er blevet ændret. Er du sikker på, at du vil lukke vinduet?',
68 options: 'Vis muligheder',
69 target: 'Mål',
70 targetNew: 'Nyt vindue (_blank)',
71 targetTop: 'Øverste vindue (_top)',
72 targetSelf: 'Samme vindue (_self)',
73 targetParent: 'Samme vindue (_parent)',
74 langDirLTR: 'Venstre til højre (LTR)',
75 langDirRTL: 'Højre til venstre (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheetklasser',
78 width: 'Bredde',
79 height: 'Højde',
80 align: 'Justering',
81 alignLeft: 'Venstre',
82 alignRight: 'Højre',
83 alignCenter: 'Centreret',
84 alignJustify: 'Lige margener',
85 alignTop: 'Øverst',
86 alignMiddle: 'Centreret',
87 alignBottom: 'Nederst',
88 alignNone: 'Ingen',
89 invalidValue: 'Ugyldig værdi.',
90 invalidHeight: 'Højde skal være et tal.',
91 invalidWidth: 'Bredde skal være et tal.',
92 invalidCssLength: 'Værdien specificeret for "%1" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px, %, in, cm, mm, em, ex, pt, eller pc).',
93 invalidHtmlLength: 'Værdien specificeret for "%1" feltet skal være et positivt nummer med eller uden en CSS måleenhed (px eller %).',
94 invalidInlineStyle: 'Værdien specificeret for inline style skal indeholde en eller flere elementer med et format som "name:value", separeret af semikoloner',
95 cssLengthTooltip: 'Indsæt en numerisk værdi i pixel eller nummer med en gyldig CSS værdi (px, %, in, cm, mm, em, ex, pt, eller pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, ikke tilgængelig</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Retur',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Mellemrum',
108 35: 'End',
109 36: 'Home',
110 46: 'Slet',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Tastatur genvej'
116 }
117};
diff --git a/sources/lang/de-ch.js b/sources/lang/de-ch.js
new file mode 100644
index 0000000..8f9c196
--- /dev/null
+++ b/sources/lang/de-ch.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7* @fileOverview
8*/
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'de-ch' ] = {
20 // ARIA description.
21 editor: 'WYSIWYG-Editor',
22 editorPanel: 'WYSIWYG-Editor-Leiste',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Drücken Sie ALT 0 für Hilfe',
29
30 browseServer: 'Server durchsuchen',
31 url: 'URL',
32 protocol: 'Protokoll',
33 upload: 'Hochladen',
34 uploadSubmit: 'Zum Server senden',
35 image: 'Bild',
36 flash: 'Flash',
37 form: 'Formular',
38 checkbox: 'Kontrollbox',
39 radio: 'Optionsfeld',
40 textField: 'Textfeld',
41 textarea: 'Textfeld',
42 hiddenField: 'Verstecktes Feld',
43 button: 'Schaltfläche',
44 select: 'Auswahlfeld',
45 imageButton: 'Bildschaltfläche',
46 notSet: '<nicht festgelegt>',
47 id: 'Kennung',
48 name: 'Name',
49 langDir: 'Schreibrichtung',
50 langDirLtr: 'Links nach Rechts (LTR)',
51 langDirRtl: 'Rechts nach Links (RTL)',
52 langCode: 'Sprachcode',
53 longDescr: 'Langbeschreibungs-URL',
54 cssClass: 'Formatvorlagenklassen',
55 advisoryTitle: 'Titel Beschreibung',
56 cssStyle: 'Stil',
57 ok: 'OK',
58 cancel: 'Abbrechen',
59 close: 'Schliessen',
60 preview: 'Vorschau',
61 resize: 'Grösse ändern',
62 generalTab: 'Allgemein',
63 advancedTab: 'Erweitert',
64 validateNumberFailed: 'Dieser Wert ist keine Nummer.',
65 confirmNewPage: 'Alle nicht gespeicherten Änderungen gehen verlohren. Sind Sie sicher die neue Seite zu laden?',
66 confirmCancel: 'Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schliessen?',
67 options: 'Optionen',
68 target: 'Zielseite',
69 targetNew: 'Neues Fenster (_blank)',
70 targetTop: 'Oberstes Fenster (_top)',
71 targetSelf: 'Gleiches Fenster (_self)',
72 targetParent: 'Oberes Fenster (_parent)',
73 langDirLTR: 'Links nach Rechts (LNR)',
74 langDirRTL: 'Rechts nach Links (RNL)',
75 styles: 'Style',
76 cssClasses: 'Stylesheet Klasse',
77 width: 'Breite',
78 height: 'Höhe',
79 align: 'Ausrichtung',
80 alignLeft: 'Links',
81 alignRight: 'Rechts',
82 alignCenter: 'Zentriert',
83 alignJustify: 'Blocksatz',
84 alignTop: 'Oben',
85 alignMiddle: 'Mitte',
86 alignBottom: 'Unten',
87 alignNone: 'Keine',
88 invalidValue: 'Ungültiger Wert.',
89 invalidHeight: 'Höhe muss eine Zahl sein.',
90 invalidWidth: 'Breite muss eine Zahl sein.',
91 invalidCssLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
92 invalidHtmlLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).',
93 invalidInlineStyle: 'Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format "Name : Wert" getrennt mit Semikolons.',
94 cssLengthTooltip: 'Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, nicht verfügbar</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Rücktaste',
102 13: 'Eingabe',
103 16: 'Umschalt',
104 17: 'Strg',
105 18: 'Alt',
106 32: 'Space', // MISSING
107 35: 'Ende',
108 36: 'Pos1',
109 46: 'Entfernen',
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/de.js b/sources/lang/de.js
new file mode 100644
index 0000000..cf1bc09
--- /dev/null
+++ b/sources/lang/de.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * German language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'de' ] = {
21 // ARIA description.
22 editor: 'WYSIWYG-Editor',
23 editorPanel: 'WYSIWYG-Editor-Leiste',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Drücken Sie ALT 0 für Hilfe',
30
31 browseServer: 'Server durchsuchen',
32 url: 'URL',
33 protocol: 'Protokoll',
34 upload: 'Hochladen',
35 uploadSubmit: 'Zum Server senden',
36 image: 'Bild',
37 flash: 'Flash',
38 form: 'Formular',
39 checkbox: 'Kontrollbox',
40 radio: 'Optionsfeld',
41 textField: 'Textfeld',
42 textarea: 'Textfeld',
43 hiddenField: 'Verstecktes Feld',
44 button: 'Schaltfläche',
45 select: 'Auswahlfeld',
46 imageButton: 'Bildschaltfläche',
47 notSet: '<nicht festgelegt>',
48 id: 'Kennung',
49 name: 'Name',
50 langDir: 'Schreibrichtung',
51 langDirLtr: 'Links nach Rechts (LTR)',
52 langDirRtl: 'Rechts nach Links (RTL)',
53 langCode: 'Sprachcode',
54 longDescr: 'Langbeschreibungs-URL',
55 cssClass: 'Formatvorlagenklassen',
56 advisoryTitle: 'Titel Beschreibung',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Abbrechen',
60 close: 'Schließen',
61 preview: 'Vorschau',
62 resize: 'Größe ändern',
63 generalTab: 'Allgemein',
64 advancedTab: 'Erweitert',
65 validateNumberFailed: 'Dieser Wert ist keine Nummer.',
66 confirmNewPage: 'Alle nicht gespeicherten Änderungen gehen verlohren. Sind Sie sicher die neue Seite zu laden?',
67 confirmCancel: 'Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schließen?',
68 options: 'Optionen',
69 target: 'Zielseite',
70 targetNew: 'Neues Fenster (_blank)',
71 targetTop: 'Oberstes Fenster (_top)',
72 targetSelf: 'Gleiches Fenster (_self)',
73 targetParent: 'Oberes Fenster (_parent)',
74 langDirLTR: 'Links nach Rechts (LNR)',
75 langDirRTL: 'Rechts nach Links (RNL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Klasse',
78 width: 'Breite',
79 height: 'Höhe',
80 align: 'Ausrichtung',
81 alignLeft: 'Links',
82 alignRight: 'Rechts',
83 alignCenter: 'Zentriert',
84 alignJustify: 'Blocksatz',
85 alignTop: 'Oben',
86 alignMiddle: 'Mitte',
87 alignBottom: 'Unten',
88 alignNone: 'Keine',
89 invalidValue: 'Ungültiger Wert.',
90 invalidHeight: 'Höhe muss eine Zahl sein.',
91 invalidWidth: 'Breite muss eine Zahl sein.',
92 invalidCssLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
93 invalidHtmlLength: 'Wert spezifiziert für "%1" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).',
94 invalidInlineStyle: 'Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format "Name : Wert" getrennt mit Semikolons.',
95 cssLengthTooltip: 'Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nicht verfügbar</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Rücktaste',
103 13: 'Eingabe',
104 16: 'Umschalt',
105 17: 'Strg',
106 18: 'Alt',
107 32: 'Leer',
108 35: 'Ende',
109 36: 'Pos1',
110 46: 'Entfernen',
111 224: 'Befehl'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Tastaturkürzel'
116 }
117};
diff --git a/sources/lang/el.js b/sources/lang/el.js
new file mode 100644
index 0000000..445c43d
--- /dev/null
+++ b/sources/lang/el.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Greek language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'el' ] = {
21 // ARIA description.
22 editor: 'Επεξεργαστής Πλούσιου Κειμένου',
23 editorPanel: 'Πίνακας Επεξεργαστή Πλούσιου Κειμένου',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Πατήστε το ALT 0 για βοήθεια',
30
31 browseServer: 'Εξερεύνηση Διακομιστή',
32 url: 'URL',
33 protocol: 'Πρωτόκολλο',
34 upload: 'Αποστολή',
35 uploadSubmit: 'Αποστολή στον Διακομιστή',
36 image: 'Εικόνα',
37 flash: 'Flash',
38 form: 'Φόρμα',
39 checkbox: 'Κουτί Επιλογής',
40 radio: 'Κουμπί Επιλογής',
41 textField: 'Πεδίο Κειμένου',
42 textarea: 'Περιοχή Κειμένου',
43 hiddenField: 'Κρυφό Πεδίο',
44 button: 'Κουμπί',
45 select: 'Πεδίο Επιλογής',
46 imageButton: 'Κουμπί Εικόνας',
47 notSet: '<δεν έχει ρυθμιστεί>',
48 id: 'Id',
49 name: 'Όνομα',
50 langDir: 'Κατεύθυνση Κειμένου',
51 langDirLtr: 'Αριστερά προς Δεξιά (LTR)',
52 langDirRtl: 'Δεξιά προς Αριστερά (RTL)',
53 langCode: 'Κωδικός Γλώσσας',
54 longDescr: 'Αναλυτική Περιγραφή URL',
55 cssClass: 'Κλάσεις Φύλλων Στυλ',
56 advisoryTitle: 'Ενδεικτικός Τίτλος',
57 cssStyle: 'Μορφή Κειμένου',
58 ok: 'OK',
59 cancel: 'Ακύρωση',
60 close: 'Κλείσιμο',
61 preview: 'Προεπισκόπηση',
62 resize: 'Αλλαγή Μεγέθους',
63 generalTab: 'Γενικά',
64 advancedTab: 'Για Προχωρημένους',
65 validateNumberFailed: 'Αυτή η τιμή δεν είναι αριθμός.',
66 confirmNewPage: 'Οι όποιες αλλαγές στο περιεχόμενο θα χαθούν. Είσαστε σίγουροι ότι θέλετε να φορτώσετε μια νέα σελίδα;',
67 confirmCancel: 'Μερικές επιλογές έχουν αλλάξει. Είσαστε σίγουροι ότι θέλετε να κλείσετε το παράθυρο διαλόγου;',
68 options: 'Επιλογές',
69 target: 'Προορισμός',
70 targetNew: 'Νέο Παράθυρο (_blank)',
71 targetTop: 'Αρχική Περιοχή (_top)',
72 targetSelf: 'Ίδιο Παράθυρο (_self)',
73 targetParent: 'Γονεϊκό Παράθυρο (_parent)',
74 langDirLTR: 'Αριστερά προς Δεξιά (LTR)',
75 langDirRTL: 'Δεξιά προς Αριστερά (RTL)',
76 styles: 'Μορφή',
77 cssClasses: 'Κλάσεις Φύλλων Στυλ',
78 width: 'Πλάτος',
79 height: 'Ύψος',
80 align: 'Στοίχιση',
81 alignLeft: 'Αριστερά',
82 alignRight: 'Δεξιά',
83 alignCenter: 'Κέντρο',
84 alignJustify: 'Πλήρης Στοίχιση',
85 alignTop: 'Πάνω',
86 alignMiddle: 'Μέση',
87 alignBottom: 'Κάτω',
88 alignNone: 'Χωρίς',
89 invalidValue: 'Μη έγκυρη τιμή.',
90 invalidHeight: 'Το ύψος πρέπει να είναι ένας αριθμός.',
91 invalidWidth: 'Το πλάτος πρέπει να είναι ένας αριθμός.',
92 invalidCssLength: 'Η τιμή που ορίζεται για το πεδίο "%1" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).',
93 invalidHtmlLength: 'Η τιμή που ορίζεται για το πεδίο "%1" πρέπει να είναι ένας θετικός αριθμός με ή χωρίς μια έγκυρη μονάδα μέτρησης HTML (px ή %).',
94 invalidInlineStyle: 'Η τιμή για το εν σειρά στυλ πρέπει να περιέχει ένα ή περισσότερα ζεύγη με την μορφή "όνομα: τιμή" διαχωρισμένα με Ελληνικό ερωτηματικό.',
95 cssLengthTooltip: 'Εισάγεται μια τιμή σε pixel ή έναν αριθμό μαζί με μια έγκυρη μονάδα μέτρησης CSS (px, %, in, cm, mm, em, ex, pt, ή pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, δεν είναι διαθέσιμο</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/en-au.js b/sources/lang/en-au.js
new file mode 100644
index 0000000..4fc57f0
--- /dev/null
+++ b/sources/lang/en-au.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * English (Australia) language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'en-au' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Browse Server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Upload',
35 uploadSubmit: 'Send it to the Server',
36 image: 'Image',
37 flash: 'Flash',
38 form: 'Form',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Hidden Field',
44 button: 'Button',
45 select: 'Selection Field',
46 imageButton: 'Image Button',
47 notSet: '<not set>',
48 id: 'Id',
49 name: 'Name',
50 langDir: 'Language Direction',
51 langDirLtr: 'Left to Right (LTR)',
52 langDirRtl: 'Right to Left (RTL)',
53 langCode: 'Language Code',
54 longDescr: 'Long Description URL',
55 cssClass: 'Stylesheet Classes',
56 advisoryTitle: 'Advisory Title',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Cancel',
60 close: 'Close', // MISSING
61 preview: 'Preview',
62 resize: 'Resize', // MISSING
63 generalTab: 'General',
64 advancedTab: 'Advanced',
65 validateNumberFailed: 'This value is not a number.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
68 options: 'Options', // MISSING
69 target: 'Target',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'Left to Right (LTR)',
75 langDirRTL: 'Right to Left (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Width', // MISSING
79 height: 'Height', // MISSING
80 align: 'Align',
81 alignLeft: 'Left', // MISSING
82 alignRight: 'Right', // MISSING
83 alignCenter: 'Centre',
84 alignJustify: 'Justify',
85 alignTop: 'Top', // MISSING
86 alignMiddle: 'Middle', // MISSING
87 alignBottom: 'Bottom', // MISSING
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/en-ca.js b/sources/lang/en-ca.js
new file mode 100644
index 0000000..42d1aff
--- /dev/null
+++ b/sources/lang/en-ca.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * English (Canadian) language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'en-ca' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Browse Server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Upload',
35 uploadSubmit: 'Send it to the Server',
36 image: 'Image',
37 flash: 'Flash',
38 form: 'Form',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Hidden Field',
44 button: 'Button',
45 select: 'Selection Field',
46 imageButton: 'Image Button',
47 notSet: '<not set>',
48 id: 'Id',
49 name: 'Name',
50 langDir: 'Language Direction',
51 langDirLtr: 'Left to Right (LTR)',
52 langDirRtl: 'Right to Left (RTL)',
53 langCode: 'Language Code',
54 longDescr: 'Long Description URL',
55 cssClass: 'Stylesheet Classes',
56 advisoryTitle: 'Advisory Title',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Cancel',
60 close: 'Close', // MISSING
61 preview: 'Preview',
62 resize: 'Resize', // MISSING
63 generalTab: 'General',
64 advancedTab: 'Advanced',
65 validateNumberFailed: 'This value is not a number.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
68 options: 'Options', // MISSING
69 target: 'Target',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'Left to Right (LTR)',
75 langDirRTL: 'Right to Left (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Width', // MISSING
79 height: 'Height', // MISSING
80 align: 'Align',
81 alignLeft: 'Left', // MISSING
82 alignRight: 'Right', // MISSING
83 alignCenter: 'Centre',
84 alignJustify: 'Justify',
85 alignTop: 'Top', // MISSING
86 alignMiddle: 'Middle', // MISSING
87 alignBottom: 'Bottom', // MISSING
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/en-gb.js b/sources/lang/en-gb.js
new file mode 100644
index 0000000..04cc61d
--- /dev/null
+++ b/sources/lang/en-gb.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * English (United Kingdom) language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'en-gb' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help',
30
31 browseServer: 'Browse Server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Upload',
35 uploadSubmit: 'Send it to the Server',
36 image: 'Image',
37 flash: 'Flash',
38 form: 'Form',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Hidden Field',
44 button: 'Button',
45 select: 'Selection Field',
46 imageButton: 'Image Button',
47 notSet: '<not set>',
48 id: 'Id',
49 name: 'Name',
50 langDir: 'Language Direction',
51 langDirLtr: 'Left to Right (LTR)',
52 langDirRtl: 'Right to Left (RTL)',
53 langCode: 'Language Code',
54 longDescr: 'Long Description URL',
55 cssClass: 'Stylesheet Classes',
56 advisoryTitle: 'Advisory Title',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Cancel',
60 close: 'Close',
61 preview: 'Preview',
62 resize: 'Drag to resize',
63 generalTab: 'General',
64 advancedTab: 'Advanced',
65 validateNumberFailed: 'This value is not a number.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialogue window?',
68 options: 'Options',
69 target: 'Target',
70 targetNew: 'New Window (_blank)',
71 targetTop: 'Topmost Window (_top)',
72 targetSelf: 'Same Window (_self)',
73 targetParent: 'Parent Window (_parent)',
74 langDirLTR: 'Left to Right (LTR)',
75 langDirRTL: 'Right to Left (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Width',
79 height: 'Height',
80 align: 'Align',
81 alignLeft: 'Left',
82 alignRight: 'Right',
83 alignCenter: 'Centre',
84 alignJustify: 'Justify',
85 alignTop: 'Top',
86 alignMiddle: 'Middle',
87 alignBottom: 'Bottom',
88 alignNone: 'None',
89 invalidValue: 'Invalid value.',
90 invalidHeight: 'Height must be a number.',
91 invalidWidth: 'Width must be a number.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).',
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).',
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.',
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/en.js b/sources/lang/en.js
new file mode 100644
index 0000000..aa509fe
--- /dev/null
+++ b/sources/lang/en.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the English
8 * language. This is the base file for all translations.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'en' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help',
30
31 browseServer: 'Browse Server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Upload',
35 uploadSubmit: 'Send it to the Server',
36 image: 'Image',
37 flash: 'Flash',
38 form: 'Form',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Hidden Field',
44 button: 'Button',
45 select: 'Selection Field',
46 imageButton: 'Image Button',
47 notSet: '<not set>',
48 id: 'Id',
49 name: 'Name',
50 langDir: 'Language Direction',
51 langDirLtr: 'Left to Right (LTR)',
52 langDirRtl: 'Right to Left (RTL)',
53 langCode: 'Language Code',
54 longDescr: 'Long Description URL',
55 cssClass: 'Stylesheet Classes',
56 advisoryTitle: 'Advisory Title',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Cancel',
60 close: 'Close',
61 preview: 'Preview',
62 resize: 'Resize',
63 generalTab: 'General',
64 advancedTab: 'Advanced',
65 validateNumberFailed: 'This value is not a number.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?',
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?',
68 options: 'Options',
69 target: 'Target',
70 targetNew: 'New Window (_blank)',
71 targetTop: 'Topmost Window (_top)',
72 targetSelf: 'Same Window (_self)',
73 targetParent: 'Parent Window (_parent)',
74 langDirLTR: 'Left to Right (LTR)',
75 langDirRTL: 'Right to Left (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Width',
79 height: 'Height',
80 align: 'Alignment',
81 alignLeft: 'Left',
82 alignRight: 'Right',
83 alignCenter: 'Center',
84 alignJustify: 'Justify',
85 alignTop: 'Top',
86 alignMiddle: 'Middle',
87 alignBottom: 'Bottom',
88 alignNone: 'None',
89 invalidValue: 'Invalid value.',
90 invalidHeight: 'Height must be a number.',
91 invalidWidth: 'Width must be a number.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).',
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).',
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.',
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space',
108 35: 'End',
109 36: 'Home',
110 46: 'Delete',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut'
116 }
117};
diff --git a/sources/lang/eo.js b/sources/lang/eo.js
new file mode 100644
index 0000000..f270dfc
--- /dev/null
+++ b/sources/lang/eo.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Esperanto language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'eo' ] = {
21 // ARIA description.
22 editor: 'RiĉTeksta Redaktilo',
23 editorPanel: 'Panelo de la RiĉTeksta Redaktilo',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Premu ALT 0 por helpilo',
30
31 browseServer: 'Foliumi en la Servilo',
32 url: 'URL',
33 protocol: 'Protokolo',
34 upload: 'Alŝuti',
35 uploadSubmit: 'Sendu al Servilo',
36 image: 'Bildo',
37 flash: 'Flaŝo',
38 form: 'Formularo',
39 checkbox: 'Markobutono',
40 radio: 'Radiobutono',
41 textField: 'Teksta kampo',
42 textarea: 'Teksta Areo',
43 hiddenField: 'Kaŝita Kampo',
44 button: 'Butono',
45 select: 'Elekta Kampo',
46 imageButton: 'Bildbutono',
47 notSet: '<Defaŭlta>',
48 id: 'Id',
49 name: 'Nomo',
50 langDir: 'Skribdirekto',
51 langDirLtr: 'De maldekstro dekstren (LTR)',
52 langDirRtl: 'De dekstro maldekstren (RTL)',
53 langCode: 'Lingva Kodo',
54 longDescr: 'URL de Longa Priskribo',
55 cssClass: 'Klasoj de Stilfolioj',
56 advisoryTitle: 'Priskriba Titolo',
57 cssStyle: 'Stilo',
58 ok: 'Akcepti',
59 cancel: 'Rezigni',
60 close: 'Fermi',
61 preview: 'Vidigi Aspekton',
62 resize: 'Movigi por ŝanĝi la grandon',
63 generalTab: 'Ĝenerala',
64 advancedTab: 'Speciala',
65 validateNumberFailed: 'Tiu valoro ne estas nombro.',
66 confirmNewPage: 'La neregistritaj ŝanĝoj estas perdotaj. Ĉu vi certas, ke vi volas ŝargi novan paĝon?',
67 confirmCancel: 'Iuj opcioj esta ŝanĝitaj. Ĉu vi certas, ke vi volas fermi la dialogon?',
68 options: 'Opcioj',
69 target: 'Celo',
70 targetNew: 'Nova Fenestro (_blank)',
71 targetTop: 'Supra Fenestro (_top)',
72 targetSelf: 'Sama Fenestro (_self)',
73 targetParent: 'Patra Fenestro (_parent)',
74 langDirLTR: 'De maldekstro dekstren (LTR)',
75 langDirRTL: 'De dekstro maldekstren (RTL)',
76 styles: 'Stilo',
77 cssClasses: 'Stilfoliaj Klasoj',
78 width: 'Larĝo',
79 height: 'Alto',
80 align: 'Ĝisrandigo',
81 alignLeft: 'Maldekstre',
82 alignRight: 'Dekstre',
83 alignCenter: 'Centre',
84 alignJustify: 'Ĝisrandigi Ambaŭflanke',
85 alignTop: 'Supre',
86 alignMiddle: 'Centre',
87 alignBottom: 'Malsupre',
88 alignNone: 'Neniu',
89 invalidValue: 'Nevalida Valoro',
90 invalidHeight: 'Alto devas esti nombro.',
91 invalidWidth: 'Larĝo devas esti nombro.',
92 invalidCssLength: 'La valoro indikita por la "%1" kampo devas esti pozitiva nombro kun aŭ sen valida CSSmezurunuo (px, %, in, cm, mm, em, ex, pt, or pc).',
93 invalidHtmlLength: 'La valoro indikita por la "%1" kampo devas esti pozitiva nombro kun aŭ sen valida HTMLmezurunuo (px or %).',
94 invalidInlineStyle: 'La valoro indikita por la enlinia stilo devas konsisti el unu aŭ pluraj elementoj kun la formato de "nomo : valoro", apartigitaj per punktokomoj.',
95 cssLengthTooltip: 'Entajpu nombron por rastrumera valoro aŭ nombron kun valida CSSunuo (px, %, in, cm, mm, em, ex, pt, or pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nehavebla</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Retropaŝo',
103 13: 'Enigi',
104 16: 'Registrumo',
105 17: 'Stirklavo',
106 18: 'Alt-klavo',
107 32: 'Space', // MISSING
108 35: 'Fino',
109 36: 'Hejmo',
110 46: 'Forigi',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/es.js b/sources/lang/es.js
new file mode 100644
index 0000000..40d9ae0
--- /dev/null
+++ b/sources/lang/es.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Spanish language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'es' ] = {
21 // ARIA description.
22 editor: 'Editor de texto enriquecido',
23 editorPanel: 'Panel del Editor de Texto Enriquecido',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Pulse ALT 0 para ayuda',
30
31 browseServer: 'Ver Servidor',
32 url: 'URL',
33 protocol: 'Protocolo',
34 upload: 'Cargar',
35 uploadSubmit: 'Enviar al Servidor',
36 image: 'Imagen',
37 flash: 'Flash',
38 form: 'Formulario',
39 checkbox: 'Casilla de Verificación',
40 radio: 'Botones de Radio',
41 textField: 'Campo de Texto',
42 textarea: 'Area de Texto',
43 hiddenField: 'Campo Oculto',
44 button: 'Botón',
45 select: 'Campo de Selección',
46 imageButton: 'Botón Imagen',
47 notSet: '<No definido>',
48 id: 'Id',
49 name: 'Nombre',
50 langDir: 'Orientación',
51 langDirLtr: 'Izquierda a Derecha (LTR)',
52 langDirRtl: 'Derecha a Izquierda (RTL)',
53 langCode: 'Cód. de idioma',
54 longDescr: 'Descripción larga URL',
55 cssClass: 'Clases de hojas de estilo',
56 advisoryTitle: 'Título',
57 cssStyle: 'Estilo',
58 ok: 'Aceptar',
59 cancel: 'Cancelar',
60 close: 'Cerrar',
61 preview: 'Previsualización',
62 resize: 'Arrastre para redimensionar',
63 generalTab: 'General',
64 advancedTab: 'Avanzado',
65 validateNumberFailed: 'El valor no es un número.',
66 confirmNewPage: 'Cualquier cambio que no se haya guardado se perderá.\r\n¿Está seguro de querer crear una nueva página?',
67 confirmCancel: 'Algunas de las opciones se han cambiado.\r\n¿Está seguro de querer cerrar el diálogo?',
68 options: 'Opciones',
69 target: 'Destino',
70 targetNew: 'Nueva ventana (_blank)',
71 targetTop: 'Ventana principal (_top)',
72 targetSelf: 'Misma ventana (_self)',
73 targetParent: 'Ventana padre (_parent)',
74 langDirLTR: 'Izquierda a derecha (LTR)',
75 langDirRTL: 'Derecha a izquierda (RTL)',
76 styles: 'Estilos',
77 cssClasses: 'Clase de la hoja de estilos',
78 width: 'Anchura',
79 height: 'Altura',
80 align: 'Alineación',
81 alignLeft: 'Izquierda',
82 alignRight: 'Derecha',
83 alignCenter: 'Centrado',
84 alignJustify: 'Justificado',
85 alignTop: 'Tope',
86 alignMiddle: 'Centro',
87 alignBottom: 'Pie',
88 alignNone: 'Ninguno',
89 invalidValue: 'Valor no válido',
90 invalidHeight: 'Altura debe ser un número.',
91 invalidWidth: 'Anchura debe ser un número.',
92 invalidCssLength: 'El valor especificado para el campo "%1" debe ser un número positivo, incluyendo optionalmente una unidad de medida CSS válida (px, %, in, cm, mm, em, ex, pt, o pc).',
93 invalidHtmlLength: 'El valor especificado para el campo "%1" debe ser un número positivo, incluyendo optionalmente una unidad de medida HTML válida (px o %).',
94 invalidInlineStyle: 'El valor especificado para el estilo debe consistir en uno o más pares con el formato "nombre: valor", separados por punto y coma.',
95 cssLengthTooltip: 'Introduca un número para el valor en pixels o un número con una unidad de medida CSS válida (px, %, in, cm, mm, em, ex, pt, o pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, no disponible</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Retroceso',
103 13: 'Ingresar',
104 16: 'Mayús.',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Fin',
109 36: 'Inicio',
110 46: 'Suprimir',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/et.js b/sources/lang/et.js
new file mode 100644
index 0000000..c98ea81
--- /dev/null
+++ b/sources/lang/et.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Estonian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'et' ] = {
21 // ARIA description.
22 editor: 'Rikkalik tekstiredaktor',
23 editorPanel: 'Rikkaliku tekstiredaktori paneel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Abi saamiseks vajuta ALT 0',
30
31 browseServer: 'Serveri sirvimine',
32 url: 'URL',
33 protocol: 'Protokoll',
34 upload: 'Laadi üles',
35 uploadSubmit: 'Saada serverisse',
36 image: 'Pilt',
37 flash: 'Flash',
38 form: 'Vorm',
39 checkbox: 'Märkeruut',
40 radio: 'Raadionupp',
41 textField: 'Tekstilahter',
42 textarea: 'Tekstiala',
43 hiddenField: 'Varjatud lahter',
44 button: 'Nupp',
45 select: 'Valiklahter',
46 imageButton: 'Piltnupp',
47 notSet: '<määramata>',
48 id: 'ID',
49 name: 'Nimi',
50 langDir: 'Keele suund',
51 langDirLtr: 'Vasakult paremale (LTR)',
52 langDirRtl: 'Paremalt vasakule (RTL)',
53 langCode: 'Keele kood',
54 longDescr: 'Pikk kirjeldus URL',
55 cssClass: 'Stiilistiku klassid',
56 advisoryTitle: 'Soovituslik pealkiri',
57 cssStyle: 'Laad',
58 ok: 'Olgu',
59 cancel: 'Loobu',
60 close: 'Sulge',
61 preview: 'Eelvaade',
62 resize: 'Suuruse muutmiseks lohista',
63 generalTab: 'Üldine',
64 advancedTab: 'Täpsemalt',
65 validateNumberFailed: 'See väärtus pole number.',
66 confirmNewPage: 'Kõik salvestamata muudatused lähevad kaotsi. Kas oled kindel, et tahad laadida uue lehe?',
67 confirmCancel: 'Mõned valikud on muudetud. Kas oled kindel, et tahad dialoogi sulgeda?',
68 options: 'Valikud',
69 target: 'Sihtkoht',
70 targetNew: 'Uus aken (_blank)',
71 targetTop: 'Kõige ülemine aken (_top)',
72 targetSelf: 'Sama aken (_self)',
73 targetParent: 'Vanemaken (_parent)',
74 langDirLTR: 'Vasakult paremale (LTR)',
75 langDirRTL: 'Paremalt vasakule (RTL)',
76 styles: 'Stiili',
77 cssClasses: 'Stiililehe klassid',
78 width: 'Laius',
79 height: 'Kõrgus',
80 align: 'Joondus',
81 alignLeft: 'Vasak',
82 alignRight: 'Paremale',
83 alignCenter: 'Kesk',
84 alignJustify: 'Rööpjoondus',
85 alignTop: 'Üles',
86 alignMiddle: 'Keskele',
87 alignBottom: 'Alla',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Vigane väärtus.',
90 invalidHeight: 'Kõrgus peab olema number.',
91 invalidWidth: 'Laius peab olema number.',
92 invalidCssLength: '"%1" välja jaoks määratud väärtus peab olema positiivne täisarv CSS ühikuga (px, %, in, cm, mm, em, ex, pt või pc) või ilma.',
93 invalidHtmlLength: '"%1" välja jaoks määratud väärtus peab olema positiivne täisarv HTML ühikuga (px või %) või ilma.',
94 invalidInlineStyle: 'Reasisese stiili määrangud peavad koosnema paarisväärtustest (tuples), mis on semikoolonitega eraldatult järgnevas vormingus: "nimi : väärtus".',
95 cssLengthTooltip: 'Sisesta väärtus pikslites või number koos sobiva CSS-i ühikuga (px, %, in, cm, mm, em, ex, pt või pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, pole saadaval</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/eu.js b/sources/lang/eu.js
new file mode 100644
index 0000000..98b92ef
--- /dev/null
+++ b/sources/lang/eu.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Basque language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'eu' ] = {
21 // ARIA description.
22 editor: 'Testu aberastuaren editorea',
23 editorPanel: 'Testu aberastuaren editorearen panela',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Sakatu ALT 0 laguntza jasotzeko',
30
31 browseServer: 'Arakatu zerbitzaria',
32 url: 'URLa',
33 protocol: 'Protokoloa',
34 upload: 'Kargatu',
35 uploadSubmit: 'Bidali zerbitzarira',
36 image: 'Irudia',
37 flash: 'Flash',
38 form: 'Formularioa',
39 checkbox: 'Kontrol-laukia',
40 radio: 'Aukera-botoia',
41 textField: 'Testu-eremua',
42 textarea: 'Testu-area',
43 hiddenField: 'Ezkutuko eremua',
44 button: 'Botoia',
45 select: 'Hautespen-eremua',
46 imageButton: 'Irudi-botoia',
47 notSet: '<ezarri gabe>',
48 id: 'Id',
49 name: 'Izena',
50 langDir: 'Hizkuntzaren norabidea',
51 langDirLtr: 'Ezkerretik eskuinera (LTR)',
52 langDirRtl: 'Eskuinetik ezkerrera (RTL)',
53 langCode: 'Hizkuntzaren kodea',
54 longDescr: 'URLaren deskribapen luzea',
55 cssClass: 'Estilo-orriko klaseak',
56 advisoryTitle: 'Aholkatutako izenburua',
57 cssStyle: 'Estiloa',
58 ok: 'Ados',
59 cancel: 'Utzi',
60 close: 'Itxi',
61 preview: 'Aurrebista',
62 resize: 'Aldatu tamainaz',
63 generalTab: 'Orokorra',
64 advancedTab: 'Aurreratua',
65 validateNumberFailed: 'Balio hau ez da zenbaki bat.',
66 confirmNewPage: 'Eduki honetan gorde gabe dauden aldaketak galduko dira. Ziur zaude orri berri bat kargatu nahi duzula?',
67 confirmCancel: 'Aukera batzuk aldatu dituzu. Ziur zaude elkarrizketa-koadroa itxi nahi duzula?',
68 options: 'Aukerak',
69 target: 'Helburua',
70 targetNew: 'Leiho berria (_blank)',
71 targetTop: 'Goieneko leihoan (_top)',
72 targetSelf: 'Leiho berean (_self)',
73 targetParent: 'Leiho gurasoan (_parent)',
74 langDirLTR: 'Ezkerretik eskuinera (LTR)',
75 langDirRTL: 'Eskuinetik ezkerrera (RTL)',
76 styles: 'Estiloa',
77 cssClasses: 'Estilo-orriko klaseak',
78 width: 'Zabalera',
79 height: 'Altuera',
80 align: 'Lerrokatzea',
81 alignLeft: 'Ezkerrean',
82 alignRight: 'Eskuinean',
83 alignCenter: 'Erdian',
84 alignJustify: 'Justifikatu',
85 alignTop: 'Goian',
86 alignMiddle: 'Erdian',
87 alignBottom: 'Behean',
88 alignNone: 'Bat ere ez',
89 invalidValue: 'Balio desegokia.',
90 invalidHeight: 'Altuera zenbaki bat izan behar da.',
91 invalidWidth: 'Zabalera zenbaki bat izan behar da.',
92 invalidCssLength: '"%1" eremurako zehaztutako balioak zenbaki positibo bat izan behar du, CSS neurri unitate batekin edo gabe (px, %, in, cm, mm, em, ex, pt edo pc).',
93 invalidHtmlLength: '"%1" eremurako zehaztutako balioak zenbaki positibo bat izan behar du, HTML neurri unitate batekin edo gabe (px edo %).',
94 invalidInlineStyle: 'Lineako estiloan zehaztutako balioak "izen : balio" formatuko tupla bat edo gehiago izan behar dira, komaz bereiztuak.',
95 cssLengthTooltip: 'Sartu zenbaki bat edo zenbaki bat baliozko CSS unitate batekin (px, %, in, cm, mm, em, ex, pt, edo pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, erabilezina</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Sartu',
104 16: 'Maius',
105 17: 'Ktrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Buka',
109 36: 'Etxea',
110 46: 'Ezabatu',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/fa.js b/sources/lang/fa.js
new file mode 100644
index 0000000..3540510
--- /dev/null
+++ b/sources/lang/fa.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Persian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'fa' ] = {
21 // ARIA description.
22 editor: 'ویرایش‌گر متن غنی',
23 editorPanel: 'پنل ویرایشگر متن غنی',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'کلید Alt+0 را برای راهنمایی بفشارید',
30
31 browseServer: 'فهرست​نمایی سرور',
32 url: 'URL',
33 protocol: 'قرارداد',
34 upload: 'بالاگذاری',
35 uploadSubmit: 'به سرور بفرست',
36 image: 'تصویر',
37 flash: 'فلش',
38 form: 'فرم',
39 checkbox: 'چک‌باکس',
40 radio: 'دکمه‌ی رادیویی',
41 textField: 'فیلد متنی',
42 textarea: 'ناحیهٴ متنی',
43 hiddenField: 'فیلد پنهان',
44 button: 'دکمه',
45 select: 'فیلد انتخاب چند گزینه​ای',
46 imageButton: 'دکمه‌ی تصویری',
47 notSet: '<تعیین‌نشده>',
48 id: 'شناسه',
49 name: 'نام',
50 langDir: 'جهت زبان',
51 langDirLtr: 'چپ به راست',
52 langDirRtl: 'راست به چپ',
53 langCode: 'کد زبان',
54 longDescr: 'URL توصیف طولانی',
55 cssClass: 'کلاس​های شیوه​نامه (Stylesheet)',
56 advisoryTitle: 'عنوان کمکی',
57 cssStyle: 'سبک',
58 ok: 'پذیرش',
59 cancel: 'انصراف',
60 close: 'بستن',
61 preview: 'پیش‌نمایش',
62 resize: 'تغییر اندازه',
63 generalTab: 'عمومی',
64 advancedTab: 'پیش‌رفته',
65 validateNumberFailed: 'این مقدار یک عدد نیست.',
66 confirmNewPage: 'هر تغییر ایجاد شده​ی ذخیره نشده از بین خواهد رفت. آیا اطمینان دارید که قصد بارگیری صفحه جدیدی را دارید؟',
67 confirmCancel: 'برخی از گزینه‌ها تغییر کرده‌اند. آیا واقعا قصد بستن این پنجره را دارید؟',
68 options: 'گزینه​ها',
69 target: 'مقصد',
70 targetNew: 'پنجره جدید',
71 targetTop: 'بالاترین پنجره',
72 targetSelf: 'همان پنجره',
73 targetParent: 'پنجره والد',
74 langDirLTR: 'چپ به راست',
75 langDirRTL: 'راست به چپ',
76 styles: 'سبک',
77 cssClasses: 'کلاس‌های سبک‌نامه',
78 width: 'عرض',
79 height: 'طول',
80 align: 'چینش',
81 alignLeft: 'چپ',
82 alignRight: 'راست',
83 alignCenter: 'وسط',
84 alignJustify: 'بلوک چین',
85 alignTop: 'بالا',
86 alignMiddle: 'میانه',
87 alignBottom: 'پائین',
88 alignNone: 'هیچ',
89 invalidValue: 'مقدار نامعتبر.',
90 invalidHeight: 'ارتفاع باید یک عدد باشد.',
91 invalidWidth: 'عرض باید یک عدد باشد.',
92 invalidCssLength: 'عدد تعیین شده برای فیلد "%1" باید یک عدد مثبت با یا بدون یک واحد اندازه گیری CSS معتبر باشد (px, %, in, cm, mm, em, ex, pt, or pc).',
93 invalidHtmlLength: 'عدد تعیین شده برای فیلد "%1" باید یک عدد مثبت با یا بدون یک واحد اندازه گیری HTML معتبر باشد (px or %).',
94 invalidInlineStyle: 'عدد تعیین شده برای سبک درون​خطی -Inline Style- باید دارای یک یا چند چندتایی با شکلی شبیه "name : value" که باید با یک ";" از هم جدا شوند.',
95 cssLengthTooltip: 'یک عدد برای یک مقدار بر حسب پیکسل و یا یک عدد با یک واحد CSS معتبر وارد کنید (px, %, in, cm, mm, em, ex, pt, or pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">، غیر قابل دسترس</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'عقبگرد',
103 13: 'ورود',
104 16: 'تعویض',
105 17: 'کنترل',
106 18: 'دگرساز',
107 32: 'Space', // MISSING
108 35: 'پایان',
109 36: 'خانه',
110 46: 'حذف',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/fi.js b/sources/lang/fi.js
new file mode 100644
index 0000000..d10adab
--- /dev/null
+++ b/sources/lang/fi.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Finnish language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'fi' ] = {
21 // ARIA description.
22 editor: 'Rikastekstieditori',
23 editorPanel: 'Rikastekstieditoripaneeli',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Paina ALT 0 nähdäksesi ohjeen',
30
31 browseServer: 'Selaa palvelinta',
32 url: 'Osoite',
33 protocol: 'Protokolla',
34 upload: 'Lisää tiedosto',
35 uploadSubmit: 'Lähetä palvelimelle',
36 image: 'Kuva',
37 flash: 'Flash-animaatio',
38 form: 'Lomake',
39 checkbox: 'Valintaruutu',
40 radio: 'Radiopainike',
41 textField: 'Tekstikenttä',
42 textarea: 'Tekstilaatikko',
43 hiddenField: 'Piilokenttä',
44 button: 'Painike',
45 select: 'Valintakenttä',
46 imageButton: 'Kuvapainike',
47 notSet: '<ei asetettu>',
48 id: 'Tunniste',
49 name: 'Nimi',
50 langDir: 'Kielen suunta',
51 langDirLtr: 'Vasemmalta oikealle (LTR)',
52 langDirRtl: 'Oikealta vasemmalle (RTL)',
53 langCode: 'Kielikoodi',
54 longDescr: 'Pitkän kuvauksen URL',
55 cssClass: 'Tyyliluokat',
56 advisoryTitle: 'Avustava otsikko',
57 cssStyle: 'Tyyli',
58 ok: 'OK',
59 cancel: 'Peruuta',
60 close: 'Sulje',
61 preview: 'Esikatselu',
62 resize: 'Raahaa muuttaaksesi kokoa',
63 generalTab: 'Yleinen',
64 advancedTab: 'Lisäominaisuudet',
65 validateNumberFailed: 'Arvon pitää olla numero.',
66 confirmNewPage: 'Kaikki tallentamattomat muutokset tähän sisältöön menetetään. Oletko varma, että haluat ladata uuden sivun?',
67 confirmCancel: 'Jotkut asetuksista on muuttuneet. Oletko varma, että haluat sulkea valintaikkunan?',
68 options: 'Asetukset',
69 target: 'Kohde',
70 targetNew: 'Uusi ikkuna (_blank)',
71 targetTop: 'Päällimmäinen ikkuna (_top)',
72 targetSelf: 'Sama ikkuna (_self)',
73 targetParent: 'Ylemmän tason ikkuna (_parent)',
74 langDirLTR: 'Vasemmalta oikealle (LTR)',
75 langDirRTL: 'Oikealta vasemmalle (RTL)',
76 styles: 'Tyyli',
77 cssClasses: 'Tyylitiedoston luokat',
78 width: 'Leveys',
79 height: 'Korkeus',
80 align: 'Kohdistus',
81 alignLeft: 'Vasemmalle',
82 alignRight: 'Oikealle',
83 alignCenter: 'Keskelle',
84 alignJustify: 'Tasaa molemmat reunat',
85 alignTop: 'Ylös',
86 alignMiddle: 'Keskelle',
87 alignBottom: 'Alas',
88 alignNone: 'Ei asetettu',
89 invalidValue: 'Virheellinen arvo.',
90 invalidHeight: 'Korkeuden täytyy olla numero.',
91 invalidWidth: 'Leveyden täytyy olla numero.',
92 invalidCssLength: 'Kentän "%1" arvon täytyy olla positiivinen luku CSS mittayksikön (px, %, in, cm, mm, em, ex, pt tai pc) kanssa tai ilman.',
93 invalidHtmlLength: 'Kentän "%1" arvon täytyy olla positiivinen luku HTML mittayksikön (px tai %) kanssa tai ilman.',
94 invalidInlineStyle: 'Tyylille annetun arvon täytyy koostua yhdestä tai useammasta "nimi : arvo" parista, jotka ovat eroteltuna toisistaan puolipisteillä.',
95 cssLengthTooltip: 'Anna numeroarvo pikseleinä tai numeroarvo CSS mittayksikön kanssa (px, %, in, cm, mm, em, ex, pt, tai pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, ei saatavissa</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/fo.js b/sources/lang/fo.js
new file mode 100644
index 0000000..205b20f
--- /dev/null
+++ b/sources/lang/fo.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Faroese language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'fo' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Trýst ALT og 0 fyri vegleiðing',
30
31 browseServer: 'Ambætarakagi',
32 url: 'URL',
33 protocol: 'Protokoll',
34 upload: 'Send til ambætaran',
35 uploadSubmit: 'Send til ambætaran',
36 image: 'Myndir',
37 flash: 'Flash',
38 form: 'Formur',
39 checkbox: 'Flugubein',
40 radio: 'Radioknøttur',
41 textField: 'Tekstteigur',
42 textarea: 'Tekstumráði',
43 hiddenField: 'Fjaldur teigur',
44 button: 'Knøttur',
45 select: 'Valskrá',
46 imageButton: 'Myndaknøttur',
47 notSet: '<ikki sett>',
48 id: 'Id',
49 name: 'Navn',
50 langDir: 'Tekstkós',
51 langDirLtr: 'Frá vinstru til høgru (LTR)',
52 langDirRtl: 'Frá høgru til vinstru (RTL)',
53 langCode: 'Málkoda',
54 longDescr: 'Víðkað URL frágreiðing',
55 cssClass: 'Typografi klassar',
56 advisoryTitle: 'Vegleiðandi heiti',
57 cssStyle: 'Typografi',
58 ok: 'Góðkent',
59 cancel: 'Avlýs',
60 close: 'Lat aftur',
61 preview: 'Frumsýn',
62 resize: 'Drag fyri at broyta stødd',
63 generalTab: 'Generelt',
64 advancedTab: 'Fjølbroytt',
65 validateNumberFailed: 'Hetta er ikki eitt tal.',
66 confirmNewPage: 'Allar ikki goymdar broytingar í hesum innihaldið hvørva. Skal nýggj síða lesast kortini?',
67 confirmCancel: 'Nakrir valmøguleikar eru broyttir. Ert tú vísur í, at dialogurin skal latast aftur?',
68 options: 'Options',
69 target: 'Target',
70 targetNew: 'Nýtt vindeyga (_blank)',
71 targetTop: 'Vindeyga ovast (_top)',
72 targetSelf: 'Sama vindeyga (_self)',
73 targetParent: 'Upphavligt vindeyga (_parent)',
74 langDirLTR: 'Frá vinstru til høgru (LTR)',
75 langDirRTL: 'Frá høgru til vinstru (RTL)',
76 styles: 'Style',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Breidd',
79 height: 'Hædd',
80 align: 'Justering',
81 alignLeft: 'Vinstra',
82 alignRight: 'Høgra',
83 alignCenter: 'Miðsett',
84 alignJustify: 'Javnir tekstkantar',
85 alignTop: 'Ovast',
86 alignMiddle: 'Miðja',
87 alignBottom: 'Botnur',
88 alignNone: 'Eingin',
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Hædd má vera eitt tal.',
91 invalidWidth: 'Breidd má vera eitt tal.',
92 invalidCssLength: 'Virðið sett í "%1" feltið má vera eitt positivt tal, við ella uttan gyldugum CSS mátieind (px, %, in, cm, mm, em, ex, pt, ella pc).',
93 invalidHtmlLength: 'Virðið sett í "%1" feltiðield má vera eitt positivt tal, við ella uttan gyldugum CSS mátieind (px ella %).',
94 invalidInlineStyle: 'Virði specifiserað fyri inline style má hava eitt ella fleiri pør (tuples) skrivað sum "name : value", hvørt parið sundurskilt við semi-colon.',
95 cssLengthTooltip: 'Skriva eitt tal fyri eitt virði í pixels ella eitt tal við gyldigum CSS eind (px, %, in, cm, mm, em, ex, pt, ella pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, ikki tøkt</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/fr-ca.js b/sources/lang/fr-ca.js
new file mode 100644
index 0000000..2702f0c
--- /dev/null
+++ b/sources/lang/fr-ca.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Canadian French language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'fr-ca' ] = {
21 // ARIA description.
22 editor: 'Éditeur de texte enrichi',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Appuyez sur 0 pour de l\'aide',
30
31 browseServer: 'Parcourir le serveur',
32 url: 'URL',
33 protocol: 'Protocole',
34 upload: 'Envoyer',
35 uploadSubmit: 'Envoyer au serveur',
36 image: 'Image',
37 flash: 'Animation Flash',
38 form: 'Formulaire',
39 checkbox: 'Case à cocher',
40 radio: 'Bouton radio',
41 textField: 'Champ texte',
42 textarea: 'Zone de texte',
43 hiddenField: 'Champ caché',
44 button: 'Bouton',
45 select: 'Liste déroulante',
46 imageButton: 'Bouton image',
47 notSet: '<Par défaut>',
48 id: 'Id',
49 name: 'Nom',
50 langDir: 'Sens d\'écriture',
51 langDirLtr: 'De gauche à droite (LTR)',
52 langDirRtl: 'De droite à gauche (RTL)',
53 langCode: 'Code langue',
54 longDescr: 'URL de description longue',
55 cssClass: 'Classes CSS',
56 advisoryTitle: 'Titre',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Annuler',
60 close: 'Fermer',
61 preview: 'Aperçu',
62 resize: 'Redimensionner',
63 generalTab: 'Général',
64 advancedTab: 'Avancé',
65 validateNumberFailed: 'Cette valeur n\'est pas un nombre.',
66 confirmNewPage: 'Les changements non sauvegardés seront perdus. Êtes-vous certain de vouloir charger une nouvelle page?',
67 confirmCancel: 'Certaines options ont été modifiées. Êtes-vous certain de vouloir fermer?',
68 options: 'Options',
69 target: 'Cible',
70 targetNew: 'Nouvelle fenêtre (_blank)',
71 targetTop: 'Fenêtre supérieur (_top)',
72 targetSelf: 'Cette fenêtre (_self)',
73 targetParent: 'Fenêtre parent (_parent)',
74 langDirLTR: 'De gauche à droite (LTR)',
75 langDirRTL: 'De droite à gauche (RTL)',
76 styles: 'Style',
77 cssClasses: 'Classe CSS',
78 width: 'Largeur',
79 height: 'Hauteur',
80 align: 'Alignement',
81 alignLeft: 'Gauche',
82 alignRight: 'Droite',
83 alignCenter: 'Centré',
84 alignJustify: 'Justifié',
85 alignTop: 'Haut',
86 alignMiddle: 'Milieu',
87 alignBottom: 'Bas',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Valeur invalide.',
90 invalidHeight: 'La hauteur doit être un nombre.',
91 invalidWidth: 'La largeur doit être un nombre.',
92 invalidCssLength: 'La valeur spécifiée pour le champ "%1" doit être un nombre positif avec ou sans unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).',
93 invalidHtmlLength: 'La valeur spécifiée pour le champ "%1" doit être un nombre positif avec ou sans unité de mesure HTML valide (px ou %).',
94 invalidInlineStyle: 'La valeur spécifiée pour le style intégré doit être composée d\'un ou plusieurs couples de valeur au format "nom : valeur", separés par des points-virgules.',
95 cssLengthTooltip: 'Entrer un nombre pour la valeur en pixel ou un nombre avec une unité CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, indisponible</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/fr.js b/sources/lang/fr.js
new file mode 100644
index 0000000..95b2d41
--- /dev/null
+++ b/sources/lang/fr.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * French language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'fr' ] = {
21 // ARIA description.
22 editor: 'Éditeur de texte enrichi',
23 editorPanel: 'Tableau de bord de l\'éditeur de texte enrichi',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Utilisez le raccourci Alt-0 pour obtenir de l\'aide',
30
31 browseServer: 'Parcourir le serveur',
32 url: 'URL',
33 protocol: 'Protocole',
34 upload: 'Téléverser',
35 uploadSubmit: 'Envoyer sur le serveur',
36 image: 'Image',
37 flash: 'Flash',
38 form: 'Formulaire',
39 checkbox: 'Case à cocher',
40 radio: 'Bouton radio',
41 textField: 'Champ texte',
42 textarea: 'Zone de texte',
43 hiddenField: 'Champ invisible',
44 button: 'Bouton',
45 select: 'Liste déroulante',
46 imageButton: 'Bouton avec image',
47 notSet: '<indéfini>',
48 id: 'ID',
49 name: 'Nom',
50 langDir: 'Sens d\'écriture',
51 langDirLtr: 'Gauche à droite (LTR)',
52 langDirRtl: 'Droite à gauche (RTL)',
53 langCode: 'Code de langue',
54 longDescr: 'URL de description longue',
55 cssClass: 'Classes de style',
56 advisoryTitle: 'Infobulle',
57 cssStyle: 'Style',
58 ok: 'OK',
59 cancel: 'Annuler',
60 close: 'Fermer',
61 preview: 'Aperçu',
62 resize: 'Redimensionner',
63 generalTab: 'Général',
64 advancedTab: 'Avancé',
65 validateNumberFailed: 'Cette valeur n\'est pas un nombre.',
66 confirmNewPage: 'Les changements non sauvegardés seront perdus. Êtes-vous sûr de vouloir charger une nouvelle page ?',
67 confirmCancel: 'Certaines options ont été modifiées. Êtes-vous sûr de vouloir fermer ?',
68 options: 'Options',
69 target: 'Cible',
70 targetNew: 'Nouvelle fenêtre (_blank)',
71 targetTop: 'Fenêtre supérieure (_top)',
72 targetSelf: 'Même fenêtre (_self)',
73 targetParent: 'Fenêtre parent (_parent)',
74 langDirLTR: 'Gauche à droite (LTR)',
75 langDirRTL: 'Droite à gauche (RTL)',
76 styles: 'Style',
77 cssClasses: 'Classes de style',
78 width: 'Largeur',
79 height: 'Hauteur',
80 align: 'Alignement',
81 alignLeft: 'Gauche',
82 alignRight: 'Droite',
83 alignCenter: 'Centrer',
84 alignJustify: 'Justifier',
85 alignTop: 'Haut',
86 alignMiddle: 'Milieu',
87 alignBottom: 'Bas',
88 alignNone: 'Aucun',
89 invalidValue: 'Valeur invalide.',
90 invalidHeight: 'La hauteur doit être un nombre.',
91 invalidWidth: 'La largeur doit être un nombre.',
92 invalidCssLength: 'La valeur spécifiée pour le champ « %1 » doit être un nombre positif avec ou sans unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).',
93 invalidHtmlLength: 'La valeur spécifiée pour le champ « %1 » doit être un nombre positif avec ou sans unité de mesure HTML valide (px ou %).',
94 invalidInlineStyle: 'La valeur spécifiée pour le style en ligne doit être composée d\'un ou plusieurs couples au format « nom : valeur », séparés par des points-virgules.',
95 cssLengthTooltip: 'Entrer un nombre pour une valeur en pixels ou un nombre avec une unité de mesure CSS valide (px, %, in, cm, mm, em, ex, pt, ou pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, indisponible</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Entrée',
104 16: 'Majuscule',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Fin',
109 36: 'Origine',
110 46: 'Supprimer',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/gl.js b/sources/lang/gl.js
new file mode 100644
index 0000000..331a21b
--- /dev/null
+++ b/sources/lang/gl.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Galician language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'gl' ] = {
21 // ARIA description.
22 editor: 'Editor de texto mellorado',
23 editorPanel: 'Panel do editor de texto mellorado',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Prema ALT 0 para obter axuda',
30
31 browseServer: 'Examinar o servidor',
32 url: 'URL',
33 protocol: 'Protocolo',
34 upload: 'Enviar',
35 uploadSubmit: 'Enviar ao servidor',
36 image: 'Imaxe',
37 flash: 'Flash',
38 form: 'Formulario',
39 checkbox: 'Caixa de selección',
40 radio: 'Botón de opción',
41 textField: 'Campo de texto',
42 textarea: 'Área de texto',
43 hiddenField: 'Campo agochado',
44 button: 'Botón',
45 select: 'Campo de selección',
46 imageButton: 'Botón de imaxe',
47 notSet: '<sen estabelecer>',
48 id: 'ID',
49 name: 'Nome',
50 langDir: 'Dirección de escritura do idioma',
51 langDirLtr: 'Esquerda a dereita (LTR)',
52 langDirRtl: 'Dereita a esquerda (RTL)',
53 langCode: 'Código do idioma',
54 longDescr: 'Descrición completa do URL',
55 cssClass: 'Clases da folla de estilos',
56 advisoryTitle: 'Título',
57 cssStyle: 'Estilo',
58 ok: 'Aceptar',
59 cancel: 'Cancelar',
60 close: 'Pechar',
61 preview: 'Vista previa',
62 resize: 'Redimensionar',
63 generalTab: 'Xeral',
64 advancedTab: 'Avanzado',
65 validateNumberFailed: 'Este valor non é un número.',
66 confirmNewPage: 'Calquera cambio que non gardara neste contido perderase.\r\nConfirma que quere cargar unha páxina nova?',
67 confirmCancel: 'Algunhas das opcións foron cambiadas.\r\nConfirma que quere pechar o diálogo?',
68 options: 'Opcións',
69 target: 'Destino',
70 targetNew: 'Nova xanela (_blank)',
71 targetTop: 'Xanela principal (_top)',
72 targetSelf: 'Mesma xanela (_self)',
73 targetParent: 'Xanela superior (_parent)',
74 langDirLTR: 'Esquerda a dereita (LTR)',
75 langDirRTL: 'Dereita a esquerda (RTL)',
76 styles: 'Estilo',
77 cssClasses: 'Clases da folla de estilos',
78 width: 'Largo',
79 height: 'Alto',
80 align: 'Aliñamento',
81 alignLeft: 'Esquerda',
82 alignRight: 'Dereita',
83 alignCenter: 'Centro',
84 alignJustify: 'Xustificado',
85 alignTop: 'Arriba',
86 alignMiddle: 'Centro',
87 alignBottom: 'Abaixo',
88 alignNone: 'Ningún',
89 invalidValue: 'Valor incorrecto.',
90 invalidHeight: 'O alto debe ser un número.',
91 invalidWidth: 'O largo debe ser un número.',
92 invalidCssLength: 'O valor especificado para o campo «%1» debe ser un número positivo con ou sen unha unidade de medida CSS correcta (px, %, in, cm, mm, em, ex, pt, ou pc).',
93 invalidHtmlLength: 'O valor especificado para o campo «%1» debe ser un número positivo con ou sen unha unidade de medida HTML correcta (px ou %).',
94 invalidInlineStyle: 'O valor especificado no estilo en liña debe consistir nunha ou máis tuplas co formato «nome : valor», separadas por punto e coma.',
95 cssLengthTooltip: 'Escriba un número para o valor en píxeles ou un número cunha unidade CSS correcta (px, %, in, cm, mm, em, ex, pt, ou pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, non dispoñíbel</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Intro',
104 16: 'Maiús',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Fin',
109 36: 'Inicio',
110 46: 'Supr',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/gu.js b/sources/lang/gu.js
new file mode 100644
index 0000000..17862d0
--- /dev/null
+++ b/sources/lang/gu.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Gujarati language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'gu' ] = {
21 // ARIA description.
22 editor: 'રીચ ટેક્ષ્ત્ એડીટર',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'પ્રેસ ALT 0 મદદ માટ',
30
31 browseServer: 'સર્વર બ્રાઉઝ કરો',
32 url: 'URL',
33 protocol: 'પ્રોટોકૉલ',
34 upload: 'અપલોડ',
35 uploadSubmit: 'આ સર્વરને મોકલવું',
36 image: 'ચિત્ર',
37 flash: 'ફ્લૅશ',
38 form: 'ફૉર્મ/પત્રક',
39 checkbox: 'ચેક બોક્સ',
40 radio: 'રેડિઓ બટન',
41 textField: 'ટેક્સ્ટ ફીલ્ડ, શબ્દ ક્ષેત્ર',
42 textarea: 'ટેક્સ્ટ એરિઆ, શબ્દ વિસ્તાર',
43 hiddenField: 'ગુપ્ત ક્ષેત્ર',
44 button: 'બટન',
45 select: 'પસંદગી ક્ષેત્ર',
46 imageButton: 'ચિત્ર બટન',
47 notSet: '<સેટ નથી>',
48 id: 'Id',
49 name: 'નામ',
50 langDir: 'ભાષા લેખવાની પદ્ધતિ',
51 langDirLtr: 'ડાબે થી જમણે (LTR)',
52 langDirRtl: 'જમણે થી ડાબે (RTL)',
53 langCode: 'ભાષા કોડ',
54 longDescr: 'વધારે માહિતી માટે URL',
55 cssClass: 'સ્ટાઇલ-શીટ ક્લાસ',
56 advisoryTitle: 'મુખ્ય મથાળું',
57 cssStyle: 'સ્ટાઇલ',
58 ok: 'ઠીક છે',
59 cancel: 'રદ કરવું',
60 close: 'બંધ કરવું',
61 preview: 'જોવું',
62 resize: 'ખેંચી ને યોગ્ય કરવું',
63 generalTab: 'જનરલ',
64 advancedTab: 'અડ્વાન્સડ',
65 validateNumberFailed: 'આ રકમ આકડો નથી.',
66 confirmNewPage: 'સવે કાર્ય વગરનું ફકરો ખોવાઈ જશે. તમને ખાતરી છે કે તમને નવું પાનું ખોલવું છે?',
67 confirmCancel: 'ઘણા વિકલ્પો બદલાયા છે. તમારે આ બોક્ષ્ બંધ કરવું છે?',
68 options: 'વિકલ્પો',
69 target: 'લક્ષ્ય',
70 targetNew: 'નવી વિન્ડો (_blank)',
71 targetTop: 'ઉપરની વિન્ડો (_top)',
72 targetSelf: 'એજ વિન્ડો (_self)',
73 targetParent: 'પેરનટ વિન્ડો (_parent)',
74 langDirLTR: 'ડાબે થી જમણે (LTR)',
75 langDirRTL: 'જમણે થી ડાબે (RTL)',
76 styles: 'શૈલી',
77 cssClasses: 'શૈલી કલાસીસ',
78 width: 'પહોળાઈ',
79 height: 'ઊંચાઈ',
80 align: 'લાઇનદોરીમાં ગોઠવવું',
81 alignLeft: 'ડાબી બાજુ ગોઠવવું',
82 alignRight: 'જમણી',
83 alignCenter: 'મધ્ય સેન્ટર',
84 alignJustify: 'બ્લૉક, અંતરાય જસ્ટિફાઇ',
85 alignTop: 'ઉપર',
86 alignMiddle: 'વચ્ચે',
87 alignBottom: 'નીચે',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'ઉંચાઈ એક આંકડો હોવો જોઈએ.',
91 invalidWidth: 'પોહળ ઈ એક આંકડો હોવો જોઈએ.',
92 invalidCssLength: '"%1" ની વેલ્યુ એક પોસીટીવ આંકડો હોવો જોઈએ અથવા CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc) વગર.',
93 invalidHtmlLength: '"%1" ની વેલ્યુ એક પોસીટીવ આંકડો હોવો જોઈએ અથવા HTML measurement unit (px or %) વગર.',
94 invalidInlineStyle: 'ઈનલાઈન સ્ટાઈલ ની વેલ્યુ "name : value" ના ફોર્મેટ માં હોવી જોઈએ, વચ્ચે સેમી-કોલોન જોઈએ.',
95 cssLengthTooltip: 'પિક્ષ્લ્ નો આંકડો CSS unit (px, %, in, cm, mm, em, ex, pt, or pc) માં નાખો.',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, નથી મળતું</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/he.js b/sources/lang/he.js
new file mode 100644
index 0000000..27b57bd
--- /dev/null
+++ b/sources/lang/he.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Hebrew language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'he' ] = {
21 // ARIA description.
22 editor: 'עורך טקסט עשיר',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'לחץ אלט ALT + 0 לעזרה',
30
31 browseServer: 'סייר השרת',
32 url: 'כתובת (URL)',
33 protocol: 'פרוטוקול',
34 upload: 'העלאה',
35 uploadSubmit: 'שליחה לשרת',
36 image: 'תמונה',
37 flash: 'פלאש',
38 form: 'טופס',
39 checkbox: 'תיבת סימון',
40 radio: 'לחצן אפשרויות',
41 textField: 'שדה טקסט',
42 textarea: 'איזור טקסט',
43 hiddenField: 'שדה חבוי',
44 button: 'כפתור',
45 select: 'שדה בחירה',
46 imageButton: 'כפתור תמונה',
47 notSet: '<לא נקבע>',
48 id: 'זיהוי (ID)',
49 name: 'שם',
50 langDir: 'כיוון שפה',
51 langDirLtr: 'שמאל לימין (LTR)',
52 langDirRtl: 'ימין לשמאל (RTL)',
53 langCode: 'קוד שפה',
54 longDescr: 'קישור לתיאור מפורט',
55 cssClass: 'מחלקת עיצוב (CSS Class)',
56 advisoryTitle: 'כותרת מוצעת',
57 cssStyle: 'סגנון',
58 ok: 'אישור',
59 cancel: 'ביטול',
60 close: 'סגירה',
61 preview: 'תצוגה מקדימה',
62 resize: 'יש לגרור בכדי לשנות את הגודל',
63 generalTab: 'כללי',
64 advancedTab: 'אפשרויות מתקדמות',
65 validateNumberFailed: 'הערך חייב להיות מספרי.',
66 confirmNewPage: 'כל השינויים שלא נשמרו יאבדו. האם להעלות דף חדש?',
67 confirmCancel: 'חלק מהאפשרויות שונו, האם לסגור את הדיאלוג?',
68 options: 'אפשרויות',
69 target: 'מטרה',
70 targetNew: 'חלון חדש (_blank)',
71 targetTop: 'החלון העליון ביותר (_top)',
72 targetSelf: 'אותו חלון (_self)',
73 targetParent: 'חלון האב (_parent)',
74 langDirLTR: 'שמאל לימין (LTR)',
75 langDirRTL: 'ימין לשמאל (RTL)',
76 styles: 'סגנון',
77 cssClasses: 'מחלקות גליונות סגנון',
78 width: 'רוחב',
79 height: 'גובה',
80 align: 'יישור',
81 alignLeft: 'לשמאל',
82 alignRight: 'לימין',
83 alignCenter: 'מרכז',
84 alignJustify: 'יישור לשוליים',
85 alignTop: 'למעלה',
86 alignMiddle: 'לאמצע',
87 alignBottom: 'לתחתית',
88 alignNone: 'None', // MISSING
89 invalidValue: 'ערך לא חוקי.',
90 invalidHeight: 'הגובה חייב להיות מספר.',
91 invalidWidth: 'הרוחב חייב להיות מספר.',
92 invalidCssLength: 'הערך שצוין לשדה "%1" חייב להיות מספר חיובי עם או ללא יחידת מידה חוקית של CSS (px, %, in, cm, mm, em, ex, pt, או pc).',
93 invalidHtmlLength: 'הערך שצוין לשדה "%1" חייב להיות מספר חיובי עם או ללא יחידת מידה חוקית של HTML (px או %).',
94 invalidInlineStyle: 'הערך שצויין לשדה הסגנון חייב להכיל זוג ערכים אחד או יותר בפורמט "שם : ערך", מופרדים על ידי נקודה-פסיק.',
95 cssLengthTooltip: 'יש להכניס מספר המייצג פיקסלים או מספר עם יחידת גליונות סגנון תקינה (px, %, in, cm, mm, em, ex, pt, או pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, לא זמין</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'End',
109 36: 'Home',
110 46: 'מחק',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/hi.js b/sources/lang/hi.js
new file mode 100644
index 0000000..e0b29a3
--- /dev/null
+++ b/sources/lang/hi.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Hindi language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'hi' ] = {
21 // ARIA description.
22 editor: 'रिच टेक्स्ट एडिटर',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'मदद के लिये ALT 0 दबाए',
30
31 browseServer: 'सर्वर ब्राउज़ करें',
32 url: 'URL',
33 protocol: 'प्रोटोकॉल',
34 upload: 'अपलोड',
35 uploadSubmit: 'इसे सर्वर को भेजें',
36 image: 'तस्वीर',
37 flash: 'फ़्लैश',
38 form: 'फ़ॉर्म',
39 checkbox: 'चॅक बॉक्स',
40 radio: 'रेडिओ बटन',
41 textField: 'टेक्स्ट फ़ील्ड',
42 textarea: 'टेक्स्ट एरिया',
43 hiddenField: 'गुप्त फ़ील्ड',
44 button: 'बटन',
45 select: 'चुनाव फ़ील्ड',
46 imageButton: 'तस्वीर बटन',
47 notSet: '<सॅट नहीं>',
48 id: 'Id',
49 name: 'नाम',
50 langDir: 'भाषा लिखने की दिशा',
51 langDirLtr: 'बायें से दायें (LTR)',
52 langDirRtl: 'दायें से बायें (RTL)',
53 langCode: 'भाषा कोड',
54 longDescr: 'अधिक विवरण के लिए URL',
55 cssClass: 'स्टाइल-शीट क्लास',
56 advisoryTitle: 'परामर्श शीर्शक',
57 cssStyle: 'स्टाइल',
58 ok: 'ठीक है',
59 cancel: 'रद्द करें',
60 close: 'Close', // MISSING
61 preview: 'प्रीव्यू',
62 resize: 'Resize', // MISSING
63 generalTab: 'सामान्य',
64 advancedTab: 'ऍड्वान्स्ड',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Options', // MISSING
69 target: 'टार्गेट',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'बायें से दायें (LTR)',
75 langDirRTL: 'दायें से बायें (RTL)',
76 styles: 'स्टाइल',
77 cssClasses: 'स्टाइल-शीट क्लास',
78 width: 'चौड़ाई',
79 height: 'ऊँचाई',
80 align: 'ऍलाइन',
81 alignLeft: 'दायें',
82 alignRight: 'दायें',
83 alignCenter: 'बीच में',
84 alignJustify: 'ब्लॉक जस्टीफ़ाई',
85 alignTop: 'ऊपर',
86 alignMiddle: 'मध्य',
87 alignBottom: 'नीचे',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/hr.js b/sources/lang/hr.js
new file mode 100644
index 0000000..d12a338
--- /dev/null
+++ b/sources/lang/hr.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Croatian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'hr' ] = {
21 // ARIA description.
22 editor: 'Bogati uređivač teksta, %1',
23 editorPanel: 'Ploča Bogatog Uređivača Teksta',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Pritisni ALT 0 za pomoć',
30
31 browseServer: 'Pretraži server',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Pošalji',
35 uploadSubmit: 'Pošalji na server',
36 image: 'Slika',
37 flash: 'Flash',
38 form: 'Forma',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Hidden Field',
44 button: 'Button',
45 select: 'Selection Field',
46 imageButton: 'Image Button',
47 notSet: '<nije postavljeno>',
48 id: 'Id',
49 name: 'Naziv',
50 langDir: 'Smjer jezika',
51 langDirLtr: 'S lijeva na desno (LTR)',
52 langDirRtl: 'S desna na lijevo (RTL)',
53 langCode: 'Kôd jezika',
54 longDescr: 'Dugački opis URL',
55 cssClass: 'Klase stilova',
56 advisoryTitle: 'Advisory naslov',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Poništi',
60 close: 'Zatvori',
61 preview: 'Pregledaj',
62 resize: 'Povuci za promjenu veličine',
63 generalTab: 'Općenito',
64 advancedTab: 'Napredno',
65 validateNumberFailed: 'Ova vrijednost nije broj.',
66 confirmNewPage: 'Sve napravljene promjene će biti izgubljene ukoliko ih niste snimili. Sigurno želite učitati novu stranicu?',
67 confirmCancel: 'Neke od opcija su promjenjene. Sigurno želite zatvoriti ovaj prozor?',
68 options: 'Opcije',
69 target: 'Odredište',
70 targetNew: 'Novi prozor (_blank)',
71 targetTop: 'Vršni prozor (_top)',
72 targetSelf: 'Isti prozor (_self)',
73 targetParent: 'Roditeljski prozor (_parent)',
74 langDirLTR: 'S lijeva na desno (LTR)',
75 langDirRTL: 'S desna na lijevo (RTL)',
76 styles: 'Stil',
77 cssClasses: 'Klase stilova',
78 width: 'Širina',
79 height: 'Visina',
80 align: 'Poravnanje',
81 alignLeft: 'Lijevo',
82 alignRight: 'Desno',
83 alignCenter: 'Središnje',
84 alignJustify: 'Blok poravnanje',
85 alignTop: 'Vrh',
86 alignMiddle: 'Sredina',
87 alignBottom: 'Dolje',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Neispravna vrijednost.',
90 invalidHeight: 'Visina mora biti broj.',
91 invalidWidth: 'Širina mora biti broj.',
92 invalidCssLength: 'Vrijednost određena za "%1" polje mora biti pozitivni broj sa ili bez važećih CSS mjernih jedinica (px, %, in, cm, mm, em, ex, pt ili pc).',
93 invalidHtmlLength: 'Vrijednost određena za "%1" polje mora biti pozitivni broj sa ili bez važećih HTML mjernih jedinica (px ili %).',
94 invalidInlineStyle: 'Vrijednost za linijski stil mora sadržavati jednu ili više definicija s formatom "naziv:vrijednost", odvojenih točka-zarezom.',
95 cssLengthTooltip: 'Unesite broj za vrijednost u pikselima ili broj s važećim CSS mjernim jedinicama (px, %, in, cm, mm, em, ex, pt ili pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nedostupno</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/hu.js b/sources/lang/hu.js
new file mode 100644
index 0000000..0cd0d96
--- /dev/null
+++ b/sources/lang/hu.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Hungarian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'hu' ] = {
21 // ARIA description.
22 editor: 'HTML szerkesztő',
23 editorPanel: 'Rich Text szerkesztő panel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Segítségért nyomjon ALT 0',
30
31 browseServer: 'Böngészés a szerveren',
32 url: 'Hivatkozás',
33 protocol: 'Protokoll',
34 upload: 'Feltöltés',
35 uploadSubmit: 'Küldés a szerverre',
36 image: 'Kép',
37 flash: 'Flash',
38 form: 'Űrlap',
39 checkbox: 'Jelölőnégyzet',
40 radio: 'Választógomb',
41 textField: 'Szövegmező',
42 textarea: 'Szövegterület',
43 hiddenField: 'Rejtettmező',
44 button: 'Gomb',
45 select: 'Legördülő lista',
46 imageButton: 'Képgomb',
47 notSet: '<nincs beállítva>',
48 id: 'Azonosító',
49 name: 'Név',
50 langDir: 'Írás iránya',
51 langDirLtr: 'Balról jobbra',
52 langDirRtl: 'Jobbról balra',
53 langCode: 'Nyelv kódja',
54 longDescr: 'Részletes leírás webcíme',
55 cssClass: 'Stíluskészlet',
56 advisoryTitle: 'Súgócimke',
57 cssStyle: 'Stílus',
58 ok: 'Rendben',
59 cancel: 'Mégsem',
60 close: 'Bezárás',
61 preview: 'Előnézet',
62 resize: 'Húzza az átméretezéshez',
63 generalTab: 'Általános',
64 advancedTab: 'További opciók',
65 validateNumberFailed: 'A mezőbe csak számokat írhat.',
66 confirmNewPage: 'Minden nem mentett változás el fog veszni! Biztosan be szeretné tölteni az oldalt?',
67 confirmCancel: 'Az űrlap tartalma megváltozott, ám a változásokat nem rögzítette. Biztosan be szeretné zárni az űrlapot?',
68 options: 'Beállítások',
69 target: 'Cél',
70 targetNew: 'Új ablak (_blank)',
71 targetTop: 'Legfelső ablak (_top)',
72 targetSelf: 'Aktuális ablakban (_self)',
73 targetParent: 'Szülő ablak (_parent)',
74 langDirLTR: 'Balról jobbra (LTR)',
75 langDirRTL: 'Jobbról balra (RTL)',
76 styles: 'Stílus',
77 cssClasses: 'Stíluslap osztály',
78 width: 'Szélesség',
79 height: 'Magasság',
80 align: 'Igazítás',
81 alignLeft: 'Bal',
82 alignRight: 'Jobbra',
83 alignCenter: 'Középre',
84 alignJustify: 'Sorkizárt',
85 alignTop: 'Tetejére',
86 alignMiddle: 'Középre',
87 alignBottom: 'Aljára',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Érvénytelen érték.',
90 invalidHeight: 'A magasság mezőbe csak számokat írhat.',
91 invalidWidth: 'A szélesség mezőbe csak számokat írhat.',
92 invalidCssLength: '"%1"-hez megadott érték csakis egy pozitív szám lehet, esetleg egy érvényes CSS egységgel megjelölve(px, %, in, cm, mm, em, ex, pt vagy pc).',
93 invalidHtmlLength: '"%1"-hez megadott érték csakis egy pozitív szám lehet, esetleg egy érvényes HTML egységgel megjelölve(px vagy %).',
94 invalidInlineStyle: 'Az inline stílusnak megadott értéknek tartalmaznia kell egy vagy több rekordot a "name : value" formátumban, pontosvesszővel elválasztva.',
95 cssLengthTooltip: 'Adjon meg egy számot értéknek pixelekben vagy egy számot érvényes CSS mértékegységben (px, %, in, cm, mm, em, ex, pt, vagy pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nem elérhető</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/id.js b/sources/lang/id.js
new file mode 100644
index 0000000..86e7076
--- /dev/null
+++ b/sources/lang/id.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'id' ] = {
20 // ARIA description.
21 editor: 'Rich Text Editor',
22 editorPanel: 'Panel Rich Text Editor',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Tekan ALT 0 untuk bantuan.',
29
30 browseServer: 'Jelajah Server',
31 url: 'URL',
32 protocol: 'Protokol',
33 upload: 'Unggah',
34 uploadSubmit: 'Kirim ke Server',
35 image: 'Gambar',
36 flash: 'Flash',
37 form: 'Formulir',
38 checkbox: 'Kotak Cek',
39 radio: 'Tombol Radio',
40 textField: 'Kolom Teks',
41 textarea: 'Area Teks',
42 hiddenField: 'Kolom Tersembunyi',
43 button: 'Tombol',
44 select: 'Kolom Seleksi',
45 imageButton: 'Tombol Gambar',
46 notSet: '<tidak diatur>',
47 id: 'Id',
48 name: 'Nama',
49 langDir: 'Arah Bahasa',
50 langDirLtr: 'Kiri ke Kanan (LTR)',
51 langDirRtl: 'Kanan ke Kiri',
52 langCode: 'Kode Bahasa',
53 longDescr: 'Deskripsi URL Panjang',
54 cssClass: 'Kelas Stylesheet',
55 advisoryTitle: 'Penasehat Judul',
56 cssStyle: 'Gaya',
57 ok: 'OK',
58 cancel: 'Batal',
59 close: 'Tutup',
60 preview: 'Pratinjau',
61 resize: 'Ubah ukuran',
62 generalTab: 'Umum',
63 advancedTab: 'Lebih Lanjut',
64 validateNumberFailed: 'Nilai ini tidak sebuah angka',
65 confirmNewPage: 'Semua perubahan yang tidak disimpan di konten ini akan hilang. Apakah anda yakin ingin memuat halaman baru?',
66 confirmCancel: 'Beberapa opsi telah berubah. Apakah anda yakin ingin menutup dialog?',
67 options: 'Opsi',
68 target: 'Sasaran',
69 targetNew: 'Jendela Baru (_blank)',
70 targetTop: 'Laman Atas (_top)',
71 targetSelf: 'Jendela yang Sama (_self)',
72 targetParent: 'Jendela Induk (_parent)',
73 langDirLTR: 'Kiri ke Kanan (LTR)',
74 langDirRTL: 'Kanan ke Kiri (RTL)',
75 styles: 'Gaya',
76 cssClasses: 'Kelas Stylesheet',
77 width: 'Lebar',
78 height: 'Tinggi',
79 align: 'Penjajaran',
80 alignLeft: 'Kiri',
81 alignRight: 'Kanan',
82 alignCenter: 'Tengah',
83 alignJustify: 'Rata kiri-kanan',
84 alignTop: 'Atas',
85 alignMiddle: 'Tengah',
86 alignBottom: 'Bawah',
87 alignNone: 'Tidak ada',
88 invalidValue: 'Nilai tidak sah.',
89 invalidHeight: 'Tinggi harus sebuah angka.',
90 invalidWidth: 'Lebar harus sebuah angka.',
91 invalidCssLength: 'Nilai untuk "%1" harus sebuah angkat positif dengan atau tanpa pengukuran unit CSS yang sah (px, %, in, cm, mm, em, ex, pt, or pc).',
92 invalidHtmlLength: 'Nilai yang dispesifikasian untuk kolom "%1" harus sebuah angka positif dengan atau tanpa sebuah unit pengukuran HTML (px atau %) yang valid.',
93 invalidInlineStyle: 'Nilai pada inline style merupakan pasangan nama dan nilai dengan format "nama : nilai", yang dipisahkan dengan titik dua.',
94 cssLengthTooltip: 'Masukkan sebuah angka untuk sebuah nilai dalam pixel atau sebuah angka dengan unit CSS yang sah (px, %, in, cm, mm, em, ex, pt, or pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, tidak tersedia</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backspace',
102 13: 'Enter',
103 16: 'Shift',
104 17: 'Ctrl',
105 18: 'Alt',
106 32: 'Spasi',
107 35: 'End',
108 36: 'Home',
109 46: 'Hapus',
110 224: 'Command'
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Pintasan Keyboard'
115 }
116};
diff --git a/sources/lang/is.js b/sources/lang/is.js
new file mode 100644
index 0000000..256b667
--- /dev/null
+++ b/sources/lang/is.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Icelandic language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'is' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Fletta í skjalasafni',
32 url: 'Vefslóð',
33 protocol: 'Samskiptastaðall',
34 upload: 'Senda upp',
35 uploadSubmit: 'Hlaða upp',
36 image: 'Setja inn mynd',
37 flash: 'Flash',
38 form: 'Setja inn innsláttarform',
39 checkbox: 'Setja inn hökunarreit',
40 radio: 'Setja inn valhnapp',
41 textField: 'Setja inn textareit',
42 textarea: 'Setja inn textasvæði',
43 hiddenField: 'Setja inn falið svæði',
44 button: 'Setja inn hnapp',
45 select: 'Setja inn lista',
46 imageButton: 'Setja inn myndahnapp',
47 notSet: '<ekkert valið>',
48 id: 'Auðkenni',
49 name: 'Nafn',
50 langDir: 'Lesstefna',
51 langDirLtr: 'Frá vinstri til hægri (LTR)',
52 langDirRtl: 'Frá hægri til vinstri (RTL)',
53 langCode: 'Tungumálakóði',
54 longDescr: 'Nánari lýsing',
55 cssClass: 'Stílsniðsflokkur',
56 advisoryTitle: 'Titill',
57 cssStyle: 'Stíll',
58 ok: 'Í lagi',
59 cancel: 'Hætta við',
60 close: 'Close', // MISSING
61 preview: 'Forskoða',
62 resize: 'Resize', // MISSING
63 generalTab: 'Almennt',
64 advancedTab: 'Tæknilegt',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Options', // MISSING
69 target: 'Mark',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'Frá vinstri til hægri (LTR)',
75 langDirRTL: 'Frá hægri til vinstri (RTL)',
76 styles: 'Stíll',
77 cssClasses: 'Stílsniðsflokkur',
78 width: 'Breidd',
79 height: 'Hæð',
80 align: 'Jöfnun',
81 alignLeft: 'Vinstri',
82 alignRight: 'Hægri',
83 alignCenter: 'Miðjað',
84 alignJustify: 'Jafna báðum megin',
85 alignTop: 'Efst',
86 alignMiddle: 'Miðjuð',
87 alignBottom: 'Neðst',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/it.js b/sources/lang/it.js
new file mode 100644
index 0000000..8229aad
--- /dev/null
+++ b/sources/lang/it.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Italian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'it' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Pannello Rich Text Editor',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Premi ALT 0 per aiuto',
30
31 browseServer: 'Cerca sul server',
32 url: 'URL',
33 protocol: 'Protocollo',
34 upload: 'Carica',
35 uploadSubmit: 'Invia al server',
36 image: 'Immagine',
37 flash: 'Oggetto Flash',
38 form: 'Modulo',
39 checkbox: 'Checkbox',
40 radio: 'Radio Button',
41 textField: 'Campo di testo',
42 textarea: 'Area di testo',
43 hiddenField: 'Campo nascosto',
44 button: 'Bottone',
45 select: 'Menu di selezione',
46 imageButton: 'Bottone immagine',
47 notSet: '<non impostato>',
48 id: 'Id',
49 name: 'Nome',
50 langDir: 'Direzione scrittura',
51 langDirLtr: 'Da Sinistra a Destra (LTR)',
52 langDirRtl: 'Da Destra a Sinistra (RTL)',
53 langCode: 'Codice Lingua',
54 longDescr: 'URL descrizione estesa',
55 cssClass: 'Nome classe CSS',
56 advisoryTitle: 'Titolo',
57 cssStyle: 'Stile',
58 ok: 'OK',
59 cancel: 'Annulla',
60 close: 'Chiudi',
61 preview: 'Anteprima',
62 resize: 'Trascina per ridimensionare',
63 generalTab: 'Generale',
64 advancedTab: 'Avanzate',
65 validateNumberFailed: 'Il valore inserito non è un numero.',
66 confirmNewPage: 'Ogni modifica non salvata sarà persa. Sei sicuro di voler caricare una nuova pagina?',
67 confirmCancel: 'Alcune delle opzioni sono state cambiate. Sei sicuro di voler chiudere la finestra di dialogo?',
68 options: 'Opzioni',
69 target: 'Destinazione',
70 targetNew: 'Nuova finestra (_blank)',
71 targetTop: 'Finestra in primo piano (_top)',
72 targetSelf: 'Stessa finestra (_self)',
73 targetParent: 'Finestra Padre (_parent)',
74 langDirLTR: 'Da sinistra a destra (LTR)',
75 langDirRTL: 'Da destra a sinistra (RTL)',
76 styles: 'Stile',
77 cssClasses: 'Classi di stile',
78 width: 'Larghezza',
79 height: 'Altezza',
80 align: 'Allineamento',
81 alignLeft: 'Sinistra',
82 alignRight: 'Destra',
83 alignCenter: 'Centrato',
84 alignJustify: 'Giustifica',
85 alignTop: 'In Alto',
86 alignMiddle: 'Centrato',
87 alignBottom: 'In Basso',
88 alignNone: 'Nessuno',
89 invalidValue: 'Valore non valido.',
90 invalidHeight: 'L\'altezza dev\'essere un numero',
91 invalidWidth: 'La Larghezza dev\'essere un numero',
92 invalidCssLength: 'Il valore indicato per il campo "%1" deve essere un numero positivo con o senza indicazione di una valida unità di misura per le classi CSS (px, %, in, cm, mm, em, ex, pt, o pc).',
93 invalidHtmlLength: 'Il valore indicato per il campo "%1" deve essere un numero positivo con o senza indicazione di una valida unità di misura per le pagine HTML (px o %).',
94 invalidInlineStyle: 'Il valore specificato per lo stile inline deve consistere in una o più tuple con il formato di "name : value", separati da semicolonne.',
95 cssLengthTooltip: 'Inserisci un numero per il valore in pixel oppure un numero con una valida unità CSS (px, %, in, cm, mm, ex, pt, o pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, non disponibile</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Invio',
104 16: 'Maiusc',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Spazio',
108 35: 'Fine',
109 36: 'Inizio',
110 46: 'Canc',
111 224: 'Comando'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Scorciatoia da tastiera'
116 }
117};
diff --git a/sources/lang/ja.js b/sources/lang/ja.js
new file mode 100644
index 0000000..56b69f7
--- /dev/null
+++ b/sources/lang/ja.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Japanese language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ja' ] = {
21 // ARIA description.
22 editor: 'リッチテキストエディタ',
23 editorPanel: 'リッチテキストエディタパネル',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'ヘルプは ALT 0 を押してください',
30
31 browseServer: 'サーバブラウザ',
32 url: 'URL',
33 protocol: 'プロトコル',
34 upload: 'アップロード',
35 uploadSubmit: 'サーバーに送信',
36 image: 'イメージ',
37 flash: 'Flash',
38 form: 'フォーム',
39 checkbox: 'チェックボックス',
40 radio: 'ラジオボタン',
41 textField: '1行テキスト',
42 textarea: 'テキストエリア',
43 hiddenField: '不可視フィールド',
44 button: 'ボタン',
45 select: '選択フィールド',
46 imageButton: '画像ボタン',
47 notSet: '<なし>',
48 id: 'Id',
49 name: 'Name属性',
50 langDir: '文字表記の方向',
51 langDirLtr: '左から右 (LTR)',
52 langDirRtl: '右から左 (RTL)',
53 langCode: '言語コード',
54 longDescr: 'longdesc属性(長文説明)',
55 cssClass: 'スタイルシートクラス',
56 advisoryTitle: 'Title属性',
57 cssStyle: 'スタイルシート',
58 ok: 'OK',
59 cancel: 'キャンセル',
60 close: '閉じる',
61 preview: 'プレビュー',
62 resize: 'ドラッグしてリサイズ',
63 generalTab: '全般',
64 advancedTab: '高度な設定',
65 validateNumberFailed: '値が数ではありません',
66 confirmNewPage: '変更内容を保存せず、 新しいページを開いてもよろしいでしょうか?',
67 confirmCancel: 'オプション設定を変更しました。ダイアログを閉じてもよろしいでしょうか?',
68 options: 'オプション',
69 target: 'ターゲット',
70 targetNew: '新しいウインドウ (_blank)',
71 targetTop: '最上部ウィンドウ (_top)',
72 targetSelf: '同じウィンドウ (_self)',
73 targetParent: '親ウィンドウ (_parent)',
74 langDirLTR: '左から右 (LTR)',
75 langDirRTL: '右から左 (RTL)',
76 styles: 'スタイル',
77 cssClasses: 'スタイルシートクラス',
78 width: '幅',
79 height: '高さ',
80 align: '行揃え',
81 alignLeft: '左',
82 alignRight: '右',
83 alignCenter: '中央',
84 alignJustify: '両端揃え',
85 alignTop: '上',
86 alignMiddle: '中央',
87 alignBottom: '下',
88 alignNone: 'なし',
89 invalidValue: '不正な値です。',
90 invalidHeight: '高さは数値で入力してください。',
91 invalidWidth: '幅は数値で入力してください。',
92 invalidCssLength: '入力された "%1" 項目の値は、CSSの大きさ(px, %, in, cm, mm, em, ex, pt, または pc)が正しいものである/ないに関わらず、正の値である必要があります。',
93 invalidHtmlLength: '入力された "%1" 項目の値は、HTMLの大きさ(px または %)が正しいものである/ないに関わらず、正の値である必要があります。',
94 invalidInlineStyle: '入力されたインラインスタイルの値は、"名前 : 値" のフォーマットのセットで、複数の場合はセミコロンで区切られている形式である必要があります。',
95 cssLengthTooltip: 'ピクセル数もしくはCSSにセットできる数値を入力してください。(px,%,in,cm,mm,em,ex,pt,or pc)',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, 利用不可能</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space',
108 35: 'End',
109 36: 'Home',
110 46: 'Delete',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'キーボードショートカット'
116 }
117};
diff --git a/sources/lang/ka.js b/sources/lang/ka.js
new file mode 100644
index 0000000..999132e
--- /dev/null
+++ b/sources/lang/ka.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the Georgian
8 * language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ka' ] = {
21 // ARIA description.
22 editor: 'ტექსტის რედაქტორი',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'დააჭირეთ ALT 0-ს დახმარების მისაღებად',
30
31 browseServer: 'სერვერზე დათვალიერება',
32 url: 'URL',
33 protocol: 'პროტოკოლი',
34 upload: 'ატვირთვა',
35 uploadSubmit: 'სერვერზე გაგზავნა',
36 image: 'სურათი',
37 flash: 'Flash',
38 form: 'ფორმა',
39 checkbox: 'მონიშვნის ღილაკი',
40 radio: 'ამორჩევის ღილაკი',
41 textField: 'ტექსტური ველი',
42 textarea: 'ტექსტური არე',
43 hiddenField: 'მალული ველი',
44 button: 'ღილაკი',
45 select: 'არჩევის ველი',
46 imageButton: 'სურათიანი ღილაკი',
47 notSet: '<არაფერი>',
48 id: 'Id',
49 name: 'სახელი',
50 langDir: 'ენის მიმართულება',
51 langDirLtr: 'მარცხნიდან მარჯვნივ (LTR)',
52 langDirRtl: 'მარჯვნიდან მარცხნივ (RTL)',
53 langCode: 'ენის კოდი',
54 longDescr: 'დიდი აღწერის URL',
55 cssClass: 'CSS კლასი',
56 advisoryTitle: 'სათაური',
57 cssStyle: 'CSS სტილი',
58 ok: 'დიახ',
59 cancel: 'გაუქმება',
60 close: 'დახურვა',
61 preview: 'გადახედვა',
62 resize: 'გაწიე ზომის შესაცვლელად',
63 generalTab: 'ინფორმაცია',
64 advancedTab: 'გაფართოებული',
65 validateNumberFailed: 'ეს მნიშვნელობა არაა რიცხვი.',
66 confirmNewPage: 'ამ დოკუმენტში ყველა ჩაუწერელი ცვლილება დაიკარგება. დარწმუნებული ხართ რომ ახალი გვერდის ჩატვირთვა გინდათ?',
67 confirmCancel: 'ზოგიერთი პარამეტრი შეცვლილია, დარწმუნებულილ ხართ რომ ფანჯრის დახურვა გსურთ?',
68 options: 'პარამეტრები',
69 target: 'გახსნის ადგილი',
70 targetNew: 'ახალი ფანჯარა (_blank)',
71 targetTop: 'ზედა ფანჯარა (_top)',
72 targetSelf: 'იგივე ფანჯარა (_self)',
73 targetParent: 'მშობელი ფანჯარა (_parent)',
74 langDirLTR: 'მარცხნიდან მარჯვნივ (LTR)',
75 langDirRTL: 'მარჯვნიდან მარცხნივ (RTL)',
76 styles: 'სტილი',
77 cssClasses: 'CSS კლასი',
78 width: 'სიგანე',
79 height: 'სიმაღლე',
80 align: 'სწორება',
81 alignLeft: 'მარცხენა',
82 alignRight: 'მარჯვენა',
83 alignCenter: 'შუა',
84 alignJustify: '両端揃え',
85 alignTop: 'ზემოთა',
86 alignMiddle: 'შუა',
87 alignBottom: 'ქვემოთა',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'სიმაღლე რიცხვით უნდა იყოს წარმოდგენილი.',
91 invalidWidth: 'სიგანე რიცხვით უნდა იყოს წარმოდგენილი.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, მიუწვდომელია</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/km.js b/sources/lang/km.js
new file mode 100644
index 0000000..b9908d9
--- /dev/null
+++ b/sources/lang/km.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Khmer language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'km' ] = {
21 // ARIA description.
22 editor: 'ឧបករណ៍​សរសេរ​អត្ថបទ​សម្បូរ​បែប',
23 editorPanel: 'ផ្ទាំង​ឧបករណ៍​សរសេរ​អត្ថបទ​សម្បូរ​បែប',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'ចុច ALT 0 សម្រាប់​ជំនួយ',
30
31 browseServer: 'រក​មើល​ក្នុង​ម៉ាស៊ីន​បម្រើ',
32 url: 'URL',
33 protocol: 'ពិធីការ',
34 upload: 'ផ្ទុក​ឡើង',
35 uploadSubmit: 'បញ្ជូនទៅកាន់ម៉ាស៊ីន​បម្រើ',
36 image: 'រូបភាព',
37 flash: 'Flash',
38 form: 'បែបបទ',
39 checkbox: 'ប្រអប់​ធីក',
40 radio: 'ប៊ូតុង​មូល',
41 textField: 'វាល​អត្ថបទ',
42 textarea: 'Textarea',
43 hiddenField: 'វាល​កំបាំង',
44 button: 'ប៊ូតុង',
45 select: 'វាល​ជម្រើស',
46 imageButton: 'ប៊ូតុង​រូបភាព',
47 notSet: '<មិនកំណត់>',
48 id: 'Id',
49 name: 'ឈ្មោះ',
50 langDir: 'ទិសដៅភាសា',
51 langDirLtr: 'ពីឆ្វេងទៅស្តាំ (LTR)',
52 langDirRtl: 'ពីស្តាំទៅឆ្វេង (RTL)',
53 langCode: 'លេខ​កូដ​ភាសា',
54 longDescr: 'URL អធិប្បាយ​វែង',
55 cssClass: 'Stylesheet Classes',
56 advisoryTitle: 'ចំណង​ជើង​ណែនាំ',
57 cssStyle: 'រចនាបថ',
58 ok: 'ព្រម',
59 cancel: 'បោះបង់',
60 close: 'បិទ',
61 preview: 'មើល​ជា​មុន',
62 resize: 'ប្ដូរ​ទំហំ',
63 generalTab: 'ទូទៅ',
64 advancedTab: 'កម្រិត​ខ្ពស់',
65 validateNumberFailed: 'តម្លៃ​នេះ​ពុំ​មែន​ជា​លេខ​ទេ។',
66 confirmNewPage: 'រាល់​បន្លាស់​ប្ដូរ​នានា​ដែល​មិន​ទាន់​រក្សា​ទុក​ក្នុង​មាតិកា​នេះ នឹង​ត្រូវ​បាត់​បង់។ តើ​អ្នក​ពិត​ជា​ចង់​ផ្ទុក​ទំព័រ​ថ្មី​មែនទេ?',
67 confirmCancel: 'ការ​កំណត់​មួយ​ចំនួន​ត្រូ​វ​បាន​ផ្លាស់​ប្ដូរ។ តើ​អ្នក​ពិត​ជា​ចង់​បិទ​ប្រអប់​នេះ​មែនទេ?',
68 options: 'ការ​កំណត់',
69 target: 'គោលដៅ',
70 targetNew: 'វីនដូ​ថ្មី (_blank)',
71 targetTop: 'វីនដូ​លើ​គេ (_top)',
72 targetSelf: 'វីនដូ​ដូច​គ្នា (_self)',
73 targetParent: 'វីនដូ​មេ (_parent)',
74 langDirLTR: 'ពីឆ្វេងទៅស្តាំ(LTR)',
75 langDirRTL: 'ពីស្តាំទៅឆ្វេង(RTL)',
76 styles: 'រចនាបថ',
77 cssClasses: 'Stylesheet Classes',
78 width: 'ទទឹង',
79 height: 'កំពស់',
80 align: 'កំណត់​ទីតាំង',
81 alignLeft: 'ខាងឆ្វង',
82 alignRight: 'ខាងស្តាំ',
83 alignCenter: 'កណ្តាល',
84 alignJustify: 'តំរឹមសងខាង',
85 alignTop: 'ខាងលើ',
86 alignMiddle: 'កណ្តាល',
87 alignBottom: 'ខាងក្រោម',
88 alignNone: 'គ្មាន',
89 invalidValue: 'តម្លៃ​មិន​ត្រឹម​ត្រូវ។',
90 invalidHeight: 'តម្លៃ​កំពស់​ត្រូវ​តែ​ជា​លេខ។',
91 invalidWidth: 'តម្លៃ​ទទឹង​ត្រូវ​តែ​ជា​លេខ។',
92 invalidCssLength: 'តម្លៃ​កំណត់​សម្រាប់​វាល "%1" ត្រូវ​តែ​ជា​លេខ​វិជ្ជមាន​ ដោយ​ភ្ជាប់ឬ​មិន​ភ្ជាប់​ជាមួយ​នឹង​ឯកតា​រង្វាស់​របស់ CSS (px, %, in, cm, mm, em, ex, pt ឬ pc) ។',
93 invalidHtmlLength: 'តម្លៃ​កំណត់​សម្រាប់​វាល "%1" ត្រូវ​តែ​ជា​លេខ​វិជ្ជមាន ដោយ​ភ្ជាប់​ឬ​មិន​ភ្ជាប់​ជាមួយ​នឹង​ឯកតា​រង្វាស់​របស់ HTML (px ឬ %) ។',
94 invalidInlineStyle: 'តម្លៃ​កំណត់​សម្រាប់​រចនាបថ​ក្នុង​តួ ត្រូវ​តែ​មាន​មួយ​ឬ​ធាតុ​ច្រើន​ដោយ​មាន​ទ្រង់ទ្រាយ​ជា "ឈ្មោះ : តម្លៃ" ហើយ​ញែក​ចេញ​ពី​គ្នា​ដោយ​ចុច​ក្បៀស។',
95 cssLengthTooltip: 'បញ្ចូល​លេខ​សម្រាប់​តម្លៃ​ជា​ភិចសែល ឬ​លេខ​ដែល​មាន​ឯកតា​ត្រឹមត្រូវ​របស់ CSS (px, %, in, cm, mm, em, ex, pt ឬ pc) ។',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, មិន​មាន</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'លុបថយក្រោយ',
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'ចុង',
109 36: 'ផ្ទះ',
110 46: 'លុប',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ko.js b/sources/lang/ko.js
new file mode 100644
index 0000000..d08261d
--- /dev/null
+++ b/sources/lang/ko.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Korean language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ko' ] = {
21 // ARIA description.
22 editor: '리치 텍스트 편집기',
23 editorPanel: '리치 텍스트 편집기 패널',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: '도움이 필요하면 ALT 0 을 누르세요',
30
31 browseServer: '서버 보기',
32 url: 'URL',
33 protocol: '프로토콜',
34 upload: '업로드',
35 uploadSubmit: '서버로 전송',
36 image: '이미지',
37 flash: '플래시',
38 form: '폼',
39 checkbox: '체크 박스',
40 radio: '라디오 버튼',
41 textField: '한 줄 입력 칸',
42 textarea: '여러 줄 입력 칸',
43 hiddenField: '숨은 입력 칸',
44 button: '버튼',
45 select: '선택 목록',
46 imageButton: '이미지 버튼',
47 notSet: '<설정 안 됨>',
48 id: 'ID',
49 name: '이름',
50 langDir: '언어 방향',
51 langDirLtr: '왼쪽에서 오른쪽 (LTR)',
52 langDirRtl: '오른쪽에서 왼쪽 (RTL)',
53 langCode: '언어 코드',
54 longDescr: '웹 주소 설명',
55 cssClass: '스타일 시트 클래스',
56 advisoryTitle: '보조 제목',
57 cssStyle: '스타일',
58 ok: '확인',
59 cancel: '취소',
60 close: '닫기',
61 preview: '미리보기',
62 resize: '크기 조절',
63 generalTab: '일반',
64 advancedTab: '자세히',
65 validateNumberFailed: '이 값은 숫자가 아닙니다.',
66 confirmNewPage: '저장하지 않은 모든 변경사항은 유실됩니다. 정말로 새로운 페이지를 부르겠습니까?',
67 confirmCancel: '일부 옵션이 변경 되었습니다. 정말로 창을 닫겠습니까?',
68 options: '옵션',
69 target: '타겟',
70 targetNew: '새 창 (_blank)',
71 targetTop: '최상위 창 (_top)',
72 targetSelf: '같은 창 (_self)',
73 targetParent: '부모 창 (_parent)',
74 langDirLTR: '왼쪽에서 오른쪽 (LTR)',
75 langDirRTL: '오른쪽에서 왼쪽 (RTL)',
76 styles: '스타일',
77 cssClasses: '스타일 시트 클래스',
78 width: '너비',
79 height: '높이',
80 align: '정렬',
81 alignLeft: '왼쪽',
82 alignRight: '오른쪽',
83 alignCenter: '가운데',
84 alignJustify: '양쪽 맞춤',
85 alignTop: '위',
86 alignMiddle: '중간',
87 alignBottom: '아래',
88 alignNone: '기본',
89 invalidValue: '잘못된 값.',
90 invalidHeight: '높이는 숫자여야 합니다.',
91 invalidWidth: '넓이는 숫자여야 합니다.',
92 invalidCssLength: '"%1" 값은 유효한 CSS 측정 단위(px, %, in, cm, mm, em, ex, pt, or pc)를 포함하거나 포함하지 않은 양수 여야 합니다.',
93 invalidHtmlLength: '"%1" 값은 유효한 HTML 측정 단위(px or %)를 포함하거나 포함하지 않은 양수여야 합니다.',
94 invalidInlineStyle: '인라인 스타일에 설정된 값은 "name : value" 형식을 가진 하나 이상의 투플(tuples)이 세미콜론(;)으로 구분되어 구성되어야 합니다.',
95 cssLengthTooltip: '픽셀 단위의 숫자만 입력하시거나 유효한 CSS 단위(px, %, in, cm, mm, em, ex, pt, or pc)와 함께 숫자를 입력해주세요.',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, 사용불가</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ku.js b/sources/lang/ku.js
new file mode 100644
index 0000000..ec53e49
--- /dev/null
+++ b/sources/lang/ku.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'ku' ] = {
20 // ARIA description.
21 editor: 'سەرنووسەی دەقی تەواو',
22 editorPanel: 'بڕگەی سەرنووسەی دەقی تەواو',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'کلیکی ALT لەگەڵ 0 بکه‌ بۆ یارمەتی',
29
30 browseServer: 'هێنانی ڕاژە',
31 url: 'ناونیشانی بەستەر',
32 protocol: 'پڕۆتۆکۆڵ',
33 upload: 'بارکردن',
34 uploadSubmit: 'ناردنی بۆ ڕاژە',
35 image: 'وێنە',
36 flash: 'فلاش',
37 form: 'داڕشتە',
38 checkbox: 'خانەی نیشانکردن',
39 radio: 'جێگرەوەی دوگمە',
40 textField: 'خانەی دەق',
41 textarea: 'ڕووبەری دەق',
42 hiddenField: 'شاردنەوی خانە',
43 button: 'دوگمە',
44 select: 'هەڵبژاردەی خانە',
45 imageButton: 'دوگمەی وێنە',
46 notSet: '<هیچ دانەدراوە>',
47 id: 'ناسنامە',
48 name: 'ناو',
49 langDir: 'ئاراستەی زمان',
50 langDirLtr: 'چەپ بۆ ڕاست (LTR)',
51 langDirRtl: 'ڕاست بۆ چەپ (RTL)',
52 langCode: 'هێمای زمان',
53 longDescr: 'پێناسەی درێژی بەستەر',
54 cssClass: 'شێوازی چینی په‌ڕە',
55 advisoryTitle: 'ڕاوێژکاری سەردێڕ',
56 cssStyle: 'شێواز',
57 ok: 'باشە',
58 cancel: 'پاشگەزبوونەوە',
59 close: 'داخستن',
60 preview: 'پێشبینین',
61 resize: 'گۆڕینی ئەندازە',
62 generalTab: 'گشتی',
63 advancedTab: 'پەرەسەندوو',
64 validateNumberFailed: 'ئەم نرخە ژمارە نیە، تکایە نرخێکی ژمارە بنووسە.',
65 confirmNewPage: 'سەرجەم گۆڕانکاریەکان و پێکهاتەکانی ناووەوە لەدەست دەدەی گەر بێتوو پاشکەوتی نەکەی یەکەم جار، تۆ هەر دڵنیایی لەکردنەوەی پەنجەرەکی نوێ؟',
66 confirmCancel: 'هەندێك هەڵبژاردە گۆڕدراوە. تۆ دڵنیایی لە داخستنی ئەم دیالۆگە؟',
67 options: 'هەڵبژاردەکان',
68 target: 'ئامانج',
69 targetNew: 'پەنجەرەیەکی نوێ (_blank)',
70 targetTop: 'لووتکەی پەنجەرە (_top)',
71 targetSelf: 'لەهەمان پەنجەرە (_self)',
72 targetParent: 'پەنجەرەی باوان (_parent)',
73 langDirLTR: 'چەپ بۆ ڕاست (LTR)',
74 langDirRTL: 'ڕاست بۆ چەپ (RTL)',
75 styles: 'شێواز',
76 cssClasses: 'شێوازی چینی پەڕە',
77 width: 'پانی',
78 height: 'درێژی',
79 align: 'ڕێککەرەوە',
80 alignLeft: 'چەپ',
81 alignRight: 'ڕاست',
82 alignCenter: 'ناوەڕاست',
83 alignJustify: 'هاوستوونی',
84 alignTop: 'سەرەوە',
85 alignMiddle: 'ناوەند',
86 alignBottom: 'ژێرەوە',
87 alignNone: 'هیچ',
88 invalidValue: 'نرخێکی نادرووست.',
89 invalidHeight: 'درێژی دەبێت ژمارە بێت.',
90 invalidWidth: 'پانی دەبێت ژمارە بێت.',
91 invalidCssLength: 'ئەم نرخەی دراوە بۆ خانەی "%1" دەبێت ژمارەکی درووست بێت یان بێ ناونیشانی ئامرازی (px, %, in, cm, mm, em, ex, pt, یان pc).',
92 invalidHtmlLength: 'ئەم نرخەی دراوە بۆ خانەی "%1" دەبێت ژمارەکی درووست بێت یان بێ ناونیشانی ئامرازی HTML (px یان %).',
93 invalidInlineStyle: 'دانەی نرخی شێوازی ناوهێڵ دەبێت پێکهاتبێت لەیەك یان زیاتری داڕشتە "ناو : نرخ", جیاکردنەوەی بە فاریزە و خاڵ',
94 cssLengthTooltip: 'ژمارەیەك بنووسه‌ بۆ نرخی piksel یان ئامرازێکی درووستی CSS (px, %, in, cm, mm, em, ex, pt, یان pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, ئامادە نیە</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backspace', // MISSING
102 13: 'Enter', // MISSING
103 16: 'Shift', // MISSING
104 17: 'Ctrl', // MISSING
105 18: 'Alt', // MISSING
106 32: 'Space', // MISSING
107 35: 'End', // MISSING
108 36: 'Home', // MISSING
109 46: 'Delete', // MISSING
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/lt.js b/sources/lang/lt.js
new file mode 100644
index 0000000..e6d9d7f
--- /dev/null
+++ b/sources/lang/lt.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Lithuanian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'lt' ] = {
21 // ARIA description.
22 editor: 'Pilnas redaktorius',
23 editorPanel: 'Pilno redagtoriaus skydelis',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Spauskite ALT 0 dėl pagalbos',
30
31 browseServer: 'Naršyti po serverį',
32 url: 'URL',
33 protocol: 'Protokolas',
34 upload: 'Siųsti',
35 uploadSubmit: 'Siųsti į serverį',
36 image: 'Vaizdas',
37 flash: 'Flash',
38 form: 'Forma',
39 checkbox: 'Žymimasis langelis',
40 radio: 'Žymimoji akutė',
41 textField: 'Teksto laukas',
42 textarea: 'Teksto sritis',
43 hiddenField: 'Nerodomas laukas',
44 button: 'Mygtukas',
45 select: 'Atrankos laukas',
46 imageButton: 'Vaizdinis mygtukas',
47 notSet: '<nėra nustatyta>',
48 id: 'Id',
49 name: 'Vardas',
50 langDir: 'Teksto kryptis',
51 langDirLtr: 'Iš kairės į dešinę (LTR)',
52 langDirRtl: 'Iš dešinės į kairę (RTL)',
53 langCode: 'Kalbos kodas',
54 longDescr: 'Ilgas aprašymas URL',
55 cssClass: 'Stilių lentelės klasės',
56 advisoryTitle: 'Konsultacinė antraštė',
57 cssStyle: 'Stilius',
58 ok: 'OK',
59 cancel: 'Nutraukti',
60 close: 'Uždaryti',
61 preview: 'Peržiūrėti',
62 resize: 'Pavilkite, kad pakeistumėte dydį',
63 generalTab: 'Bendros savybės',
64 advancedTab: 'Papildomas',
65 validateNumberFailed: 'Ši reikšmė nėra skaičius.',
66 confirmNewPage: 'Visas neišsaugotas turinys bus prarastas. Ar tikrai norite įkrauti naują puslapį?',
67 confirmCancel: 'Kai kurie parametrai pasikeitė. Ar tikrai norite užverti langą?',
68 options: 'Parametrai',
69 target: 'Tikslinė nuoroda',
70 targetNew: 'Naujas langas (_blank)',
71 targetTop: 'Viršutinis langas (_top)',
72 targetSelf: 'Esamas langas (_self)',
73 targetParent: 'Paskutinis langas (_parent)',
74 langDirLTR: 'Iš kairės į dešinę (LTR)',
75 langDirRTL: 'Iš dešinės į kairę (RTL)',
76 styles: 'Stilius',
77 cssClasses: 'Stilių klasės',
78 width: 'Plotis',
79 height: 'Aukštis',
80 align: 'Lygiuoti',
81 alignLeft: 'Kairę',
82 alignRight: 'Dešinę',
83 alignCenter: 'Centrą',
84 alignJustify: 'Lygiuoti abi puses',
85 alignTop: 'Viršūnę',
86 alignMiddle: 'Vidurį',
87 alignBottom: 'Apačią',
88 alignNone: 'Niekas',
89 invalidValue: 'Neteisinga reikšmė.',
90 invalidHeight: 'Aukštis turi būti nurodytas skaičiais.',
91 invalidWidth: 'Plotis turi būti nurodytas skaičiais.',
92 invalidCssLength: 'Reikšmė nurodyta "%1" laukui, turi būti teigiamas skaičius su arba be tinkamo CSS matavimo vieneto (px, %, in, cm, mm, em, ex, pt arba pc).',
93 invalidHtmlLength: 'Reikšmė nurodyta "%1" laukui, turi būti teigiamas skaičius su arba be tinkamo HTML matavimo vieneto (px arba %).',
94 invalidInlineStyle: 'Reikšmė nurodyta vidiniame stiliuje turi būti sudaryta iš vieno šių reikšmių "vardas : reikšmė", atskirta kabliataškiais.',
95 cssLengthTooltip: 'Įveskite reikšmę pikseliais arba skaičiais su tinkamu CSS vienetu (px, %, in, cm, mm, em, ex, pt arba pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, netinkamas</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/lv.js b/sources/lang/lv.js
new file mode 100644
index 0000000..1759e6c
--- /dev/null
+++ b/sources/lang/lv.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Latvian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'lv' ] = {
21 // ARIA description.
22 editor: 'Bagātinātā teksta redaktors',
23 editorPanel: 'Bagātinātā teksta redaktora panelis',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Palīdzībai, nospiediet ALT 0 ',
30
31 browseServer: 'Skatīt servera saturu',
32 url: 'URL',
33 protocol: 'Protokols',
34 upload: 'Augšupielādēt',
35 uploadSubmit: 'Nosūtīt serverim',
36 image: 'Attēls',
37 flash: 'Flash',
38 form: 'Forma',
39 checkbox: 'Atzīmēšanas kastīte',
40 radio: 'Izvēles poga',
41 textField: 'Teksta rinda',
42 textarea: 'Teksta laukums',
43 hiddenField: 'Paslēpta teksta rinda',
44 button: 'Poga',
45 select: 'Iezīmēšanas lauks',
46 imageButton: 'Attēlpoga',
47 notSet: '<nav iestatīts>',
48 id: 'Id',
49 name: 'Nosaukums',
50 langDir: 'Valodas lasīšanas virziens',
51 langDirLtr: 'No kreisās uz labo (LTR)',
52 langDirRtl: 'No labās uz kreiso (RTL)',
53 langCode: 'Valodas kods',
54 longDescr: 'Gara apraksta Hipersaite',
55 cssClass: 'Stilu saraksta klases',
56 advisoryTitle: 'Konsultatīvs virsraksts',
57 cssStyle: 'Stils',
58 ok: 'Darīts!',
59 cancel: 'Atcelt',
60 close: 'Aizvērt',
61 preview: 'Priekšskatījums',
62 resize: 'Mērogot',
63 generalTab: 'Vispārīgi',
64 advancedTab: 'Izvērstais',
65 validateNumberFailed: 'Šī vērtība nav skaitlis',
66 confirmNewPage: 'Jebkuras nesaglabātās izmaiņas tiks zaudētas. Vai tiešām vēlaties atvērt jaunu lapu?',
67 confirmCancel: 'Daži no uzstādījumiem ir mainīti. Vai tiešām vēlaties aizvērt šo dialogu?',
68 options: 'Uzstādījumi',
69 target: 'Mērķis',
70 targetNew: 'Jauns logs (_blank)',
71 targetTop: 'Virsējais logs (_top)',
72 targetSelf: 'Tas pats logs (_self)',
73 targetParent: 'Avota logs (_parent)',
74 langDirLTR: 'Kreisais uz Labo (LTR)',
75 langDirRTL: 'Labais uz Kreiso (RTL)',
76 styles: 'Stils',
77 cssClasses: 'Stilu klases',
78 width: 'Platums',
79 height: 'Augstums',
80 align: 'Nolīdzināt',
81 alignLeft: 'Pa kreisi',
82 alignRight: 'Pa labi',
83 alignCenter: 'Centrēti',
84 alignJustify: 'Izlīdzināt malas',
85 alignTop: 'Augšā',
86 alignMiddle: 'Vertikāli centrēts',
87 alignBottom: 'Apakšā',
88 alignNone: 'Nekas',
89 invalidValue: 'Nekorekta vērtība',
90 invalidHeight: 'Augstumam jābūt skaitlim.',
91 invalidWidth: 'Platumam jābūt skaitlim',
92 invalidCssLength: 'Laukam "%1" norādītajai vērtībai jābūt pozitīvam skaitlim ar vai bez korektām CSS mērvienībām (px, %, in, cm, mm, em, ex, pt, vai pc).',
93 invalidHtmlLength: 'Laukam "%1" norādītajai vērtībai jābūt pozitīvam skaitlim ar vai bez korektām HTML mērvienībām (px vai %).',
94 invalidInlineStyle: 'Iekļautajā stilā norādītajai vērtībai jāsastāv no viena vai vairākiem pāriem pēc forma\'ta "nosaukums: vērtība", atdalītiem ar semikolu.',
95 cssLengthTooltip: 'Ievadiet vērtību pikseļos vai skaitli ar derīgu CSS mērvienību (px, %, in, cm, mm, em, ex, pt, vai pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nav pieejams</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/mk.js b/sources/lang/mk.js
new file mode 100644
index 0000000..750da11
--- /dev/null
+++ b/sources/lang/mk.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'mk' ] = {
20 // ARIA description.
21 editor: 'Rich Text Editor', // MISSING
22 editorPanel: 'Rich Text Editor panel', // MISSING
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Притисни ALT 0 за помош',
29
30 browseServer: 'Пребарај низ серверот',
31 url: 'URL',
32 protocol: 'Протокол',
33 upload: 'Прикачи',
34 uploadSubmit: 'Прикачи на сервер',
35 image: 'Слика',
36 flash: 'Flash', // MISSING
37 form: 'Form', // MISSING
38 checkbox: 'Checkbox', // MISSING
39 radio: 'Radio Button', // MISSING
40 textField: 'Поле за текст',
41 textarea: 'Големо поле за текст',
42 hiddenField: 'Скриено поле',
43 button: 'Button',
44 select: 'Selection Field', // MISSING
45 imageButton: 'Копче-слика',
46 notSet: '<not set>',
47 id: 'Id',
48 name: 'Name',
49 langDir: 'Насока на јазик',
50 langDirLtr: 'Лево кон десно',
51 langDirRtl: 'Десно кон лево',
52 langCode: 'Код на јазик',
53 longDescr: 'Long Description URL', // MISSING
54 cssClass: 'Stylesheet Classes', // MISSING
55 advisoryTitle: 'Advisory Title', // MISSING
56 cssStyle: 'Стил',
57 ok: 'OK',
58 cancel: 'Cancel', // MISSING
59 close: 'Close', // MISSING
60 preview: 'Preview', // MISSING
61 resize: 'Resize', // MISSING
62 generalTab: 'Општо',
63 advancedTab: 'Advanced', // MISSING
64 validateNumberFailed: 'This value is not a number.', // MISSING
65 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
66 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
67 options: 'Опции',
68 target: 'Target', // MISSING
69 targetNew: 'Нов прозорец (_blank)',
70 targetTop: 'Најгорниот прозорец (_top)',
71 targetSelf: 'Истиот прозорец (_self)',
72 targetParent: 'Прозорец-родител (_parent)',
73 langDirLTR: 'Лево кон десно',
74 langDirRTL: 'Десно кон лево',
75 styles: 'Стил',
76 cssClasses: 'Stylesheet Classes', // MISSING
77 width: 'Широчина',
78 height: 'Височина',
79 align: 'Alignment', // MISSING
80 alignLeft: 'Лево',
81 alignRight: 'Десно',
82 alignCenter: 'Во средина',
83 alignJustify: 'Justify', // MISSING
84 alignTop: 'Горе',
85 alignMiddle: 'Средина',
86 alignBottom: 'Доле',
87 alignNone: 'Никое',
88 invalidValue: 'Невалидна вредност',
89 invalidHeight: 'Височината мора да биде број.',
90 invalidWidth: 'Широчината мора да биде број.',
91 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
92 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
93 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
94 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backspace', // MISSING
102 13: 'Enter', // MISSING
103 16: 'Shift', // MISSING
104 17: 'Ctrl', // MISSING
105 18: 'Alt', // MISSING
106 32: 'Space', // MISSING
107 35: 'End', // MISSING
108 36: 'Home', // MISSING
109 46: 'Delete', // MISSING
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/mn.js b/sources/lang/mn.js
new file mode 100644
index 0000000..c5854a1
--- /dev/null
+++ b/sources/lang/mn.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Mongolian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'mn' ] = {
21 // ARIA description.
22 editor: 'Хэлбэрт бичвэр боловсруулагч',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Үйлчлэгч тооцоолуур (сервэр)-ийг үзэх',
32 url: 'цахим хуудасны хаяг (URL)',
33 protocol: 'Протокол',
34 upload: 'Илгээж ачаалах',
35 uploadSubmit: 'Үүнийг үйлчлэгч тооцоолуур (сервер) лүү илгээх',
36 image: 'Зураг',
37 flash: 'Флаш хөдөлгөөнтэй зураг',
38 form: 'Маягт',
39 checkbox: 'Тэмдэглээний нүд',
40 radio: 'Радио товчлуур',
41 textField: 'Бичвэрийн талбар',
42 textarea: 'Бичвэрийн зай',
43 hiddenField: 'Далд талбар',
44 button: 'Товчлуур',
45 select: 'Сонголтын талбар',
46 imageButton: 'Зургий товчуур',
47 notSet: '<тохируулаагүй>',
48 id: 'Id (техникийн нэр)',
49 name: 'Нэр',
50 langDir: 'Хэлний чиглэл',
51 langDirLtr: 'Зүүнээс баруун (LTR)',
52 langDirRtl: 'Баруунаас зүүн (RTL)',
53 langCode: 'Хэлний код',
54 longDescr: 'Урт тайлбарын вэб хаяг',
55 cssClass: 'Хэлбэрийн хуудасны ангиуд',
56 advisoryTitle: 'Зөвлөх гарчиг',
57 cssStyle: 'Загвар',
58 ok: 'За',
59 cancel: 'Болих',
60 close: 'Хаах',
61 preview: 'Урьдчилан харах',
62 resize: 'Resize', // MISSING
63 generalTab: 'Ерөнхий',
64 advancedTab: 'Гүнзгий',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Сонголт',
69 target: 'Бай',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'Зүүн талаас баруун тийшээ (LTR)',
75 langDirRTL: 'Баруун талаас зүүн тийшээ (RTL)',
76 styles: 'Загвар',
77 cssClasses: 'Хэлбэрийн хуудасны ангиуд',
78 width: 'Өргөн',
79 height: 'Өндөр',
80 align: 'Эгнээ',
81 alignLeft: 'Зүүн',
82 alignRight: 'Баруун',
83 alignCenter: 'Төвд',
84 alignJustify: 'Тэгшлэх',
85 alignTop: 'Дээд талд',
86 alignMiddle: 'Дунд',
87 alignBottom: 'Доод талд',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Өндөр нь тоо байх ёстой.',
91 invalidWidth: 'Өргөн нь тоо байх ёстой.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ms.js b/sources/lang/ms.js
new file mode 100644
index 0000000..764e92f
--- /dev/null
+++ b/sources/lang/ms.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Malay language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ms' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Browse Server',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Muat Naik',
35 uploadSubmit: 'Hantar ke Server',
36 image: 'Gambar',
37 flash: 'Flash', // MISSING
38 form: 'Borang',
39 checkbox: 'Checkbox',
40 radio: 'Butang Radio',
41 textField: 'Text Field',
42 textarea: 'Textarea',
43 hiddenField: 'Field Tersembunyi',
44 button: 'Butang',
45 select: 'Field Pilihan',
46 imageButton: 'Butang Bergambar',
47 notSet: '<tidak di set>',
48 id: 'Id',
49 name: 'Nama',
50 langDir: 'Arah Tulisan',
51 langDirLtr: 'Kiri ke Kanan (LTR)',
52 langDirRtl: 'Kanan ke Kiri (RTL)',
53 langCode: 'Kod Bahasa',
54 longDescr: 'Butiran Panjang URL',
55 cssClass: 'Kelas-kelas Stylesheet',
56 advisoryTitle: 'Tajuk Makluman',
57 cssStyle: 'Stail',
58 ok: 'OK',
59 cancel: 'Batal',
60 close: 'Tutup',
61 preview: 'Prebiu',
62 resize: 'Resize', // MISSING
63 generalTab: 'Umum',
64 advancedTab: 'Advanced',
65 validateNumberFailed: 'This value is not a number.', // MISSING
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Options', // MISSING
69 target: 'Sasaran',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'Kiri ke Kanan (LTR)',
75 langDirRTL: 'Kanan ke Kiri (RTL)',
76 styles: 'Stail',
77 cssClasses: 'Kelas-kelas Stylesheet',
78 width: 'Lebar',
79 height: 'Tinggi',
80 align: 'Jajaran',
81 alignLeft: 'Kiri',
82 alignRight: 'Kanan',
83 alignCenter: 'Tengah',
84 alignJustify: 'Jajaran Blok',
85 alignTop: 'Atas',
86 alignMiddle: 'Pertengahan',
87 alignBottom: 'Bawah',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Nilai tidak sah.',
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/nb.js b/sources/lang/nb.js
new file mode 100644
index 0000000..e27c582
--- /dev/null
+++ b/sources/lang/nb.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Norwegian Bokmål language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'nb' ] = {
21 // ARIA description.
22 editor: 'Rikteksteditor',
23 editorPanel: 'Panel for rikteksteditor',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Trykk ALT 0 for hjelp',
30
31 browseServer: 'Bla gjennom tjener',
32 url: 'URL',
33 protocol: 'Protokoll',
34 upload: 'Last opp',
35 uploadSubmit: 'Send det til serveren',
36 image: 'Bilde',
37 flash: 'Flash',
38 form: 'Skjema',
39 checkbox: 'Avmerkingsboks',
40 radio: 'Alternativknapp',
41 textField: 'Tekstboks',
42 textarea: 'Tekstområde',
43 hiddenField: 'Skjult felt',
44 button: 'Knapp',
45 select: 'Rullegardinliste',
46 imageButton: 'Bildeknapp',
47 notSet: '<ikke satt>',
48 id: 'Id',
49 name: 'Navn',
50 langDir: 'Språkretning',
51 langDirLtr: 'Venstre til høyre (LTR)',
52 langDirRtl: 'Høyre til venstre (RTL)',
53 langCode: 'Språkkode',
54 longDescr: 'Utvidet beskrivelse',
55 cssClass: 'Stilarkklasser',
56 advisoryTitle: 'Tittel',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Avbryt',
60 close: 'Lukk',
61 preview: 'Forhåndsvis',
62 resize: 'Dra for å skalere',
63 generalTab: 'Generelt',
64 advancedTab: 'Avansert',
65 validateNumberFailed: 'Denne verdien er ikke et tall.',
66 confirmNewPage: 'Alle ulagrede endringer som er gjort i dette innholdet vil gå tapt. Er du sikker på at du vil laste en ny side?',
67 confirmCancel: 'Du har endret noen alternativer. Er du sikker på at du vil lukke dialogvinduet?',
68 options: 'Valg',
69 target: 'Mål',
70 targetNew: 'Nytt vindu (_blank)',
71 targetTop: 'Hele vinduet (_top)',
72 targetSelf: 'Samme vindu (_self)',
73 targetParent: 'Foreldrevindu (_parent)',
74 langDirLTR: 'Venstre til høyre (VTH)',
75 langDirRTL: 'Høyre til venstre (HTV)',
76 styles: 'Stil',
77 cssClasses: 'Stilarkklasser',
78 width: 'Bredde',
79 height: 'Høyde',
80 align: 'Juster',
81 alignLeft: 'Venstre',
82 alignRight: 'Høyre',
83 alignCenter: 'Midtjuster',
84 alignJustify: 'Blokkjuster',
85 alignTop: 'Topp',
86 alignMiddle: 'Midten',
87 alignBottom: 'Bunn',
88 alignNone: 'Ingen',
89 invalidValue: 'Ugyldig verdi.',
90 invalidHeight: 'Høyde må være et tall.',
91 invalidWidth: 'Bredde må være et tall.',
92 invalidCssLength: 'Den angitte verdien for feltet "%1" må være et positivt tall med eller uten en gyldig CSS-målingsenhet (px, %, in, cm, mm, em, ex, pt, eller pc).',
93 invalidHtmlLength: 'Den angitte verdien for feltet "%1" må være et positivt tall med eller uten en gyldig HTML-målingsenhet (px eller %).',
94 invalidInlineStyle: 'Verdi angitt for inline stil må bestå av en eller flere sett med formatet "navn : verdi", separert med semikolon',
95 cssLengthTooltip: 'Skriv inn et tall for en piksel-verdi eller et tall med en gyldig CSS-enhet (px, %, in, cm, mm, em, ex, pt, eller pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, utilgjenglig</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Mellomrom',
108 35: 'End',
109 36: 'Home',
110 46: 'Delete',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Tastatursnarvei'
116 }
117};
diff --git a/sources/lang/nl.js b/sources/lang/nl.js
new file mode 100644
index 0000000..5f1f251
--- /dev/null
+++ b/sources/lang/nl.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Dutch language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'nl' ] = {
21 // ARIA description.
22 editor: 'Tekstverwerker',
23 editorPanel: 'Tekstverwerker beheerpaneel',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Druk ALT 0 voor hulp',
30
31 browseServer: 'Bladeren op server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Upload',
35 uploadSubmit: 'Naar server verzenden',
36 image: 'Afbeelding',
37 flash: 'Flash',
38 form: 'Formulier',
39 checkbox: 'Selectievinkje',
40 radio: 'Keuzerondje',
41 textField: 'Tekstveld',
42 textarea: 'Tekstvak',
43 hiddenField: 'Verborgen veld',
44 button: 'Knop',
45 select: 'Selectieveld',
46 imageButton: 'Afbeeldingsknop',
47 notSet: '<niet ingevuld>',
48 id: 'Id',
49 name: 'Naam',
50 langDir: 'Schrijfrichting',
51 langDirLtr: 'Links naar rechts (LTR)',
52 langDirRtl: 'Rechts naar links (RTL)',
53 langCode: 'Taalcode',
54 longDescr: 'Lange URL-omschrijving',
55 cssClass: 'Stylesheet-klassen',
56 advisoryTitle: 'Adviserende titel',
57 cssStyle: 'Stijl',
58 ok: 'OK',
59 cancel: 'Annuleren',
60 close: 'Sluiten',
61 preview: 'Voorbeeld',
62 resize: 'Sleep om te herschalen',
63 generalTab: 'Algemeen',
64 advancedTab: 'Geavanceerd',
65 validateNumberFailed: 'Deze waarde is geen geldig getal.',
66 confirmNewPage: 'Alle aangebrachte wijzigingen gaan verloren. Weet u zeker dat u een nieuwe pagina wilt openen?',
67 confirmCancel: 'Enkele opties zijn gewijzigd. Weet u zeker dat u dit dialoogvenster wilt sluiten?',
68 options: 'Opties',
69 target: 'Doelvenster',
70 targetNew: 'Nieuw venster (_blank)',
71 targetTop: 'Hele venster (_top)',
72 targetSelf: 'Zelfde venster (_self)',
73 targetParent: 'Origineel venster (_parent)',
74 langDirLTR: 'Links naar rechts (LTR)',
75 langDirRTL: 'Rechts naar links (RTL)',
76 styles: 'Stijl',
77 cssClasses: 'Stylesheet-klassen',
78 width: 'Breedte',
79 height: 'Hoogte',
80 align: 'Uitlijning',
81 alignLeft: 'Links',
82 alignRight: 'Rechts',
83 alignCenter: 'Centreren',
84 alignJustify: 'Uitvullen',
85 alignTop: 'Boven',
86 alignMiddle: 'Midden',
87 alignBottom: 'Onder',
88 alignNone: 'Geen',
89 invalidValue: 'Ongeldige waarde.',
90 invalidHeight: 'De hoogte moet een getal zijn.',
91 invalidWidth: 'De breedte moet een getal zijn.',
92 invalidCssLength: 'Waarde in veld "%1" moet een positief nummer zijn, met of zonder een geldige CSS meeteenheid (px, %, in, cm, mm, em, ex, pt of pc).',
93 invalidHtmlLength: 'Waarde in veld "%1" moet een positief nummer zijn, met of zonder een geldige HTML meeteenheid (px of %).',
94 invalidInlineStyle: 'Waarde voor de online stijl moet bestaan uit een of meerdere tupels met het formaat "naam : waarde", gescheiden door puntkomma\'s.',
95 cssLengthTooltip: 'Geef een nummer in voor een waarde in pixels of geef een nummer in met een geldige CSS eenheid (px, %, in, cm, mm, em, ex, pt, of pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, niet beschikbaar</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Spatie',
108 35: 'End',
109 36: 'Home',
110 46: 'Verwijderen',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Sneltoets'
116 }
117};
diff --git a/sources/lang/no.js b/sources/lang/no.js
new file mode 100644
index 0000000..87691f9
--- /dev/null
+++ b/sources/lang/no.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Norwegian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'no' ] = {
21 // ARIA description.
22 editor: 'Rikteksteditor',
23 editorPanel: 'Panel for rikteksteditor',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Trykk ALT 0 for hjelp',
30
31 browseServer: 'Bla igjennom server',
32 url: 'URL',
33 protocol: 'Protokoll',
34 upload: 'Last opp',
35 uploadSubmit: 'Send det til serveren',
36 image: 'Bilde',
37 flash: 'Flash',
38 form: 'Skjema',
39 checkbox: 'Avmerkingsboks',
40 radio: 'Alternativknapp',
41 textField: 'Tekstboks',
42 textarea: 'Tekstområde',
43 hiddenField: 'Skjult felt',
44 button: 'Knapp',
45 select: 'Rullegardinliste',
46 imageButton: 'Bildeknapp',
47 notSet: '<ikke satt>',
48 id: 'Id',
49 name: 'Navn',
50 langDir: 'Språkretning',
51 langDirLtr: 'Venstre til høyre (VTH)',
52 langDirRtl: 'Høyre til venstre (HTV)',
53 langCode: 'Språkkode',
54 longDescr: 'Utvidet beskrivelse',
55 cssClass: 'Stilarkklasser',
56 advisoryTitle: 'Tittel',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Avbryt',
60 close: 'Lukk',
61 preview: 'Forhåndsvis',
62 resize: 'Dra for å skalere',
63 generalTab: 'Generelt',
64 advancedTab: 'Avansert',
65 validateNumberFailed: 'Denne verdien er ikke et tall.',
66 confirmNewPage: 'Alle ulagrede endringer som er gjort i dette innholdet vil bli tapt. Er du sikker på at du vil laste en ny side?',
67 confirmCancel: 'Noen av valgene har blitt endret. Er du sikker på at du vil lukke dialogen?',
68 options: 'Valg',
69 target: 'Mål',
70 targetNew: 'Nytt vindu (_blank)',
71 targetTop: 'Hele vindu (_top)',
72 targetSelf: 'Samme vindu (_self)',
73 targetParent: 'Foreldrevindu (_parent)',
74 langDirLTR: 'Venstre til høyre (VTH)',
75 langDirRTL: 'Høyre til venstre (HTV)',
76 styles: 'Stil',
77 cssClasses: 'Stilarkklasser',
78 width: 'Bredde',
79 height: 'Høyde',
80 align: 'Juster',
81 alignLeft: 'Venstre',
82 alignRight: 'Høyre',
83 alignCenter: 'Midtjuster',
84 alignJustify: 'Blokkjuster',
85 alignTop: 'Topp',
86 alignMiddle: 'Midten',
87 alignBottom: 'Bunn',
88 alignNone: 'Ingen',
89 invalidValue: 'Ugyldig verdi.',
90 invalidHeight: 'Høyde må være et tall.',
91 invalidWidth: 'Bredde må være et tall.',
92 invalidCssLength: 'Den angitte verdien for feltet "%1" må være et positivt tall med eller uten en gyldig CSS-målingsenhet (px, %, in, cm, mm, em, ex, pt, eller pc).',
93 invalidHtmlLength: 'Den angitte verdien for feltet "%1" må være et positivt tall med eller uten en gyldig HTML-målingsenhet (px eller %).',
94 invalidInlineStyle: 'Verdi angitt for inline stil må bestå av en eller flere sett med formatet "navn : verdi", separert med semikolon',
95 cssLengthTooltip: 'Skriv inn et tall for en piksel-verdi eller et tall med en gyldig CSS-enhet (px, %, in, cm, mm, em, ex, pt, eller pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, utilgjenglig</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/oc.js b/sources/lang/oc.js
new file mode 100644
index 0000000..a78420f
--- /dev/null
+++ b/sources/lang/oc.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the Occitan
8 * language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'oc' ] = {
21 // ARIA description.
22 editor: 'Editor de tèxte enriquit',
23 editorPanel: 'Tablèu de bòrd de l\'editor de tèxte enriquit',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Utilisatz l\'acorchi Alt-0 per obténer d\'ajuda',
30
31 browseServer: 'Percórrer lo servidor',
32 url: 'URL',
33 protocol: 'Protocòl',
34 upload: 'Mandar',
35 uploadSubmit: 'Mandar sul servidor',
36 image: 'Imatge',
37 flash: 'Flash',
38 form: 'Formulari',
39 checkbox: 'Casa de marcar',
40 radio: 'Boton ràdio',
41 textField: 'Camp tèxte',
42 textarea: 'Zòna de tèxte',
43 hiddenField: 'Camp invisible',
44 button: 'Boton',
45 select: 'Lista desenrotlanta',
46 imageButton: 'Boton amb imatge',
47 notSet: '<indefinit>',
48 id: 'Id',
49 name: 'Nom',
50 langDir: 'Sens d\'escritura',
51 langDirLtr: 'Esquèrra a dreita (LTR)',
52 langDirRtl: 'Dreita a esquèrra (RTL)',
53 langCode: 'Còdi de lenga',
54 longDescr: 'URL de descripcion longa',
55 cssClass: 'Classas d\'estil',
56 advisoryTitle: 'Infobulla',
57 cssStyle: 'Estil',
58 ok: 'D\'acòrdi',
59 cancel: 'Anullar',
60 close: 'Tampar',
61 preview: 'Previsualizar',
62 resize: 'Redimensionar',
63 generalTab: 'General',
64 advancedTab: 'Avançat',
65 validateNumberFailed: 'Aquesta valor es pas un nombre.',
66 confirmNewPage: 'Los cambiaments pas salvats seràn perduts. Sètz segur que volètz cargar una novèla pagina ?',
67 confirmCancel: 'Certanas opcions son estadas modificadas. Sètz segur que volètz tampar ?',
68 options: 'Opcions',
69 target: 'Cibla',
70 targetNew: 'Novèla fenèstra (_blank)',
71 targetTop: 'Fenèstra superiora (_top)',
72 targetSelf: 'Meteissa fenèstra (_self)',
73 targetParent: 'Fenèstra parent (_parent)',
74 langDirLTR: 'Esquèrra a dreita (LTR)',
75 langDirRTL: 'Dreita a esquèrra (RTL)',
76 styles: 'Estil',
77 cssClasses: 'Classas d\'estil',
78 width: 'Largor',
79 height: 'Nautor',
80 align: 'Alinhament',
81 alignLeft: 'Esquèrra',
82 alignRight: 'Dreita',
83 alignCenter: 'Centrar',
84 alignJustify: 'Justificar',
85 alignTop: 'Naut',
86 alignMiddle: 'Mitan',
87 alignBottom: 'Bas',
88 alignNone: 'Pas cap',
89 invalidValue: 'Valor invalida.',
90 invalidHeight: 'La nautor deu èsser un nombre.',
91 invalidWidth: 'La largor deu èsser un nombre.',
92 invalidCssLength: 'La valor especificada pel camp « %1 » deu èsser un nombre positiu amb o sens unitat de mesura CSS valid (px, %, in, cm, mm, em, ex, pt, o pc).',
93 invalidHtmlLength: 'La valor especificada pel camp « %1 » deu èsser un nombre positiu amb o sens unitat de mesura HTML valid (px o %).',
94 invalidInlineStyle: 'La valor especificada per l\'estil en linha deu èsser compausada d\'un o mantun parelh al format « nom : valor », separats per de punts-virgulas.',
95 cssLengthTooltip: 'Entrar un nombre per una valor en pixèls o un nombre amb una unitat de mesura CSS valida (px, %, in, cm, mm, em, ex, pt, o pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, indisponible</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Retorn',
103 13: 'Entrada',
104 16: 'Majuscula',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Espaci',
108 35: 'Fin',
109 36: 'Origina',
110 46: 'Suprimir',
111 224: 'Comanda'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Acorchi de clavièr'
116 }
117};
diff --git a/sources/lang/pl.js b/sources/lang/pl.js
new file mode 100644
index 0000000..3290a6b
--- /dev/null
+++ b/sources/lang/pl.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Polish language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'pl' ] = {
21 // ARIA description.
22 editor: 'Edytor tekstu sformatowanego',
23 editorPanel: 'Panel edytora tekstu sformatowanego',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'W celu uzyskania pomocy naciśnij ALT 0',
30
31 browseServer: 'Przeglądaj',
32 url: 'Adres URL',
33 protocol: 'Protokół',
34 upload: 'Wyślij',
35 uploadSubmit: 'Wyślij',
36 image: 'Obrazek',
37 flash: 'Flash',
38 form: 'Formularz',
39 checkbox: 'Pole wyboru (checkbox)',
40 radio: 'Przycisk opcji (radio)',
41 textField: 'Pole tekstowe',
42 textarea: 'Obszar tekstowy',
43 hiddenField: 'Pole ukryte',
44 button: 'Przycisk',
45 select: 'Lista wyboru',
46 imageButton: 'Przycisk graficzny',
47 notSet: '<nie ustawiono>',
48 id: 'Id',
49 name: 'Nazwa',
50 langDir: 'Kierunek tekstu',
51 langDirLtr: 'Od lewej do prawej (LTR)',
52 langDirRtl: 'Od prawej do lewej (RTL)',
53 langCode: 'Kod języka',
54 longDescr: 'Adres URL długiego opisu',
55 cssClass: 'Nazwa klasy CSS',
56 advisoryTitle: 'Opis obiektu docelowego',
57 cssStyle: 'Styl',
58 ok: 'OK',
59 cancel: 'Anuluj',
60 close: 'Zamknij',
61 preview: 'Podgląd',
62 resize: 'Przeciągnij, aby zmienić rozmiar',
63 generalTab: 'Ogólne',
64 advancedTab: 'Zaawansowane',
65 validateNumberFailed: 'Ta wartość nie jest liczbą.',
66 confirmNewPage: 'Wszystkie niezapisane zmiany zostaną utracone. Czy na pewno wczytać nową stronę?',
67 confirmCancel: 'Pewne opcje zostały zmienione. Czy na pewno zamknąć okno dialogowe?',
68 options: 'Opcje',
69 target: 'Obiekt docelowy',
70 targetNew: 'Nowe okno (_blank)',
71 targetTop: 'Okno najwyżej w hierarchii (_top)',
72 targetSelf: 'To samo okno (_self)',
73 targetParent: 'Okno nadrzędne (_parent)',
74 langDirLTR: 'Od lewej do prawej (LTR)',
75 langDirRTL: 'Od prawej do lewej (RTL)',
76 styles: 'Style',
77 cssClasses: 'Klasy arkusza stylów',
78 width: 'Szerokość',
79 height: 'Wysokość',
80 align: 'Wyrównaj',
81 alignLeft: 'Do lewej',
82 alignRight: 'Do prawej',
83 alignCenter: 'Do środka',
84 alignJustify: 'Wyjustuj',
85 alignTop: 'Do góry',
86 alignMiddle: 'Do środka',
87 alignBottom: 'Do dołu',
88 alignNone: 'Brak',
89 invalidValue: 'Nieprawidłowa wartość.',
90 invalidHeight: 'Wysokość musi być liczbą.',
91 invalidWidth: 'Szerokość musi być liczbą.',
92 invalidCssLength: 'Wartość podana dla pola "%1" musi być liczbą dodatnią bez jednostki lub z poprawną jednostką długości zgodną z CSS (px, %, in, cm, mm, em, ex, pt lub pc).',
93 invalidHtmlLength: 'Wartość podana dla pola "%1" musi być liczbą dodatnią bez jednostki lub z poprawną jednostką długości zgodną z HTML (px lub %).',
94 invalidInlineStyle: 'Wartość podana dla stylu musi składać się z jednej lub większej liczby krotek w formacie "nazwa : wartość", rozdzielonych średnikami.',
95 cssLengthTooltip: 'Wpisz liczbę dla wartości w pikselach lub liczbę wraz z jednostką długości zgodną z CSS (px, %, in, cm, mm, em, ex, pt lub pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, niedostępne</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'spacja',
108 35: 'End',
109 36: 'Home',
110 46: 'Delete',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Skrót klawiszowy'
116 }
117};
diff --git a/sources/lang/pt-br.js b/sources/lang/pt-br.js
new file mode 100644
index 0000000..a6bc34f
--- /dev/null
+++ b/sources/lang/pt-br.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7* @fileOverview
8*/
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'pt-br' ] = {
20 // ARIA description.
21 editor: 'Editor de Rich Text',
22 editorPanel: 'Painel do editor de Rich Text',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Pressione ALT+0 para ajuda',
29
30 browseServer: 'Localizar no Servidor',
31 url: 'URL',
32 protocol: 'Protocolo',
33 upload: 'Enviar ao Servidor',
34 uploadSubmit: 'Enviar para o Servidor',
35 image: 'Imagem',
36 flash: 'Flash',
37 form: 'Formulário',
38 checkbox: 'Caixa de Seleção',
39 radio: 'Botão de Opção',
40 textField: 'Caixa de Texto',
41 textarea: 'Área de Texto',
42 hiddenField: 'Campo Oculto',
43 button: 'Botão',
44 select: 'Caixa de Listagem',
45 imageButton: 'Botão de Imagem',
46 notSet: '<não ajustado>',
47 id: 'Id',
48 name: 'Nome',
49 langDir: 'Direção do idioma',
50 langDirLtr: 'Esquerda para Direita (LTR)',
51 langDirRtl: 'Direita para Esquerda (RTL)',
52 langCode: 'Idioma',
53 longDescr: 'Descrição da URL',
54 cssClass: 'Classe de CSS',
55 advisoryTitle: 'Título',
56 cssStyle: 'Estilos',
57 ok: 'OK',
58 cancel: 'Cancelar',
59 close: 'Fechar',
60 preview: 'Visualizar',
61 resize: 'Arraste para redimensionar',
62 generalTab: 'Geral',
63 advancedTab: 'Avançado',
64 validateNumberFailed: 'Este valor não é um número.',
65 confirmNewPage: 'Todas as mudanças não salvas serão perdidas. Tem certeza de que quer abrir uma nova página?',
66 confirmCancel: 'Algumas opções foram alteradas. Tem certeza de que quer fechar a caixa de diálogo?',
67 options: 'Opções',
68 target: 'Destino',
69 targetNew: 'Nova Janela (_blank)',
70 targetTop: 'Janela de Cima (_top)',
71 targetSelf: 'Mesma Janela (_self)',
72 targetParent: 'Janela Pai (_parent)',
73 langDirLTR: 'Esquerda para Direita (LTR)',
74 langDirRTL: 'Direita para Esquerda (RTL)',
75 styles: 'Estilo',
76 cssClasses: 'Classes',
77 width: 'Largura',
78 height: 'Altura',
79 align: 'Alinhamento',
80 alignLeft: 'Esquerda',
81 alignRight: 'Direita',
82 alignCenter: 'Centralizado',
83 alignJustify: 'Justificar',
84 alignTop: 'Superior',
85 alignMiddle: 'Centralizado',
86 alignBottom: 'Inferior',
87 alignNone: 'Nenhum',
88 invalidValue: 'Valor inválido.',
89 invalidHeight: 'A altura tem que ser um número',
90 invalidWidth: 'A largura tem que ser um número.',
91 invalidCssLength: 'O valor do campo "%1" deve ser um número positivo opcionalmente seguido por uma válida unidade de medida de CSS (px, %, in, cm, mm, em, ex, pt ou pc).',
92 invalidHtmlLength: 'O valor do campo "%1" deve ser um número positivo opcionalmente seguido por uma válida unidade de medida de HTML (px ou %).',
93 invalidInlineStyle: 'O valor válido para estilo deve conter uma ou mais tuplas no formato "nome : valor", separados por ponto e vírgula.',
94 cssLengthTooltip: 'Insira um número para valor em pixels ou um número seguido de uma válida unidade de medida de CSS (px, %, in, cm, mm, em, ex, pt ou pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, indisponível</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Tecla Retroceder',
102 13: 'Enter',
103 16: 'Shift',
104 17: 'Ctrl',
105 18: 'Alt',
106 32: 'Tecla Espaço',
107 35: 'End',
108 36: 'Home',
109 46: 'Delete',
110 224: 'Comando'
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Atalho do teclado'
115 }
116};
diff --git a/sources/lang/pt.js b/sources/lang/pt.js
new file mode 100644
index 0000000..d5ae35e
--- /dev/null
+++ b/sources/lang/pt.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Portuguese language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'pt' ] = {
21 // ARIA description.
22 editor: 'Editor de texto enriquecido',
23 editorPanel: 'Painel do editor de texto enriquecido',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Pressione ALT+0 para ajuda',
30
31 browseServer: 'Navegar no servidor',
32 url: 'URL',
33 protocol: 'Protocolo',
34 upload: 'Carregar',
35 uploadSubmit: 'Enviar para o servidor',
36 image: 'Imagem',
37 flash: 'Flash',
38 form: 'Formulário',
39 checkbox: 'Caixa de verificação',
40 radio: 'Botão',
41 textField: 'Campo de texto',
42 textarea: 'Área de texto',
43 hiddenField: 'Campo oculto',
44 button: 'Botão',
45 select: 'Campo de seleção',
46 imageButton: 'Botão da imagem',
47 notSet: '<Não definido>',
48 id: 'ID',
49 name: 'Nome',
50 langDir: 'Direção do idioma',
51 langDirLtr: 'Esquerda para a Direita (EPD)',
52 langDirRtl: 'Direita para a Esquerda (DPE)',
53 langCode: 'Código do idioma',
54 longDescr: 'Descrição completa do URL',
55 cssClass: 'Classes de estilo das folhas',
56 advisoryTitle: 'Título consultivo',
57 cssStyle: 'Estilo',
58 ok: 'CONFIRMAR',
59 cancel: 'Cancelar',
60 close: 'Fechar',
61 preview: 'Pré-visualização',
62 resize: 'Redimensionar',
63 generalTab: 'Geral',
64 advancedTab: 'Avançado',
65 validateNumberFailed: 'Este valor não é um numero.',
66 confirmNewPage: 'Irão ser perdidas quaisquer alterações não guardadas. Tem a certeza que deseja carregar a nova página?',
67 confirmCancel: 'Foram alteradas algumas das opções. Tem a certeza que deseja fechar a janela?',
68 options: 'Opções',
69 target: 'Destino',
70 targetNew: 'Nova janela (_blank)',
71 targetTop: 'Janela superior (_top)',
72 targetSelf: 'Mesma janela (_self)',
73 targetParent: 'Janela dependente (_parent)',
74 langDirLTR: 'Esquerda para a Direita (EPD)',
75 langDirRTL: 'Direita para a Esquerda (DPE)',
76 styles: 'Estilo',
77 cssClasses: 'Classes de folhas de estilo',
78 width: 'Largura',
79 height: 'Altura',
80 align: 'Alinhamento',
81 alignLeft: 'Esquerda',
82 alignRight: 'Direita',
83 alignCenter: 'Centrado',
84 alignJustify: 'Justificado',
85 alignTop: 'Topo',
86 alignMiddle: 'Centro',
87 alignBottom: 'Base',
88 alignNone: 'Nenhum',
89 invalidValue: 'Valor inválido.',
90 invalidHeight: 'A altura deve ser um número.',
91 invalidWidth: 'A largura deve ser um número. ',
92 invalidCssLength: 'O valor especificado para o campo "1%" deve ser um número positivo, com ou sem uma unidade de medida CSS válida (px, %, in, cm, mm, em, ex, pt, ou pc).',
93 invalidHtmlLength: 'O valor especificado para o campo "1%" deve ser um número positivo, com ou sem uma unidade de medida HTML válida (px ou %).',
94 invalidInlineStyle: 'O valor especificado para o estilo em linha deve constituir um ou mais conjuntos de valores com o formato de "nome : valor", separados por ponto e vírgula.',
95 cssLengthTooltip: 'Insira um número para um valor em pontos ou um número com uma unidade CSS válida (px, %, in, cm, mm, em, ex, pt, ou pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, indisponível</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'Fim',
109 36: 'Entrada',
110 46: 'Eliminar',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ro.js b/sources/lang/ro.js
new file mode 100644
index 0000000..d118aba
--- /dev/null
+++ b/sources/lang/ro.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Romanian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ro' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Apasă ALT 0 pentru ajutor',
30
31 browseServer: 'Răsfoieşte server',
32 url: 'URL',
33 protocol: 'Protocol',
34 upload: 'Încarcă',
35 uploadSubmit: 'Trimite la server',
36 image: 'Imagine',
37 flash: 'Flash',
38 form: 'Formular (Form)',
39 checkbox: 'Bifă (Checkbox)',
40 radio: 'Buton radio (RadioButton)',
41 textField: 'Câmp text (TextField)',
42 textarea: 'Suprafaţă text (Textarea)',
43 hiddenField: 'Câmp ascuns (HiddenField)',
44 button: 'Buton',
45 select: 'Câmp selecţie (SelectionField)',
46 imageButton: 'Buton imagine (ImageButton)',
47 notSet: '<nesetat>',
48 id: 'Id',
49 name: 'Nume',
50 langDir: 'Direcţia cuvintelor',
51 langDirLtr: 'stânga-dreapta (LTR)',
52 langDirRtl: 'dreapta-stânga (RTL)',
53 langCode: 'Codul limbii',
54 longDescr: 'Descrierea lungă URL',
55 cssClass: 'Clasele cu stilul paginii (CSS)',
56 advisoryTitle: 'Titlul consultativ',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Anulare',
60 close: 'Închide',
61 preview: 'Previzualizare',
62 resize: 'Trage pentru a redimensiona',
63 generalTab: 'General',
64 advancedTab: 'Avansat',
65 validateNumberFailed: 'Această valoare nu este un număr.',
66 confirmNewPage: 'Orice modificări nesalvate ale acestui conținut, vor fi pierdute. Sigur doriți încărcarea unei noi pagini?',
67 confirmCancel: 'Câteva opțiuni au fost schimbate. Sigur doriți să închideți dialogul?',
68 options: 'Opțiuni',
69 target: 'Țintă',
70 targetNew: 'Fereastră nouă (_blank)',
71 targetTop: 'Topmost Window (_top)',
72 targetSelf: 'În aceeași fereastră (_self)',
73 targetParent: 'Parent Window (_parent)',
74 langDirLTR: 'Stânga spre Dreapta (LTR)',
75 langDirRTL: 'Dreapta spre Stânga (RTL)',
76 styles: 'Stil',
77 cssClasses: 'Stylesheet Classes',
78 width: 'Lăţime',
79 height: 'Înălţime',
80 align: 'Aliniere',
81 alignLeft: 'Mărește Bara',
82 alignRight: 'Dreapta',
83 alignCenter: 'Centru',
84 alignJustify: 'Aliniere în bloc (Block Justify)',
85 alignTop: 'Sus',
86 alignMiddle: 'Mijloc',
87 alignBottom: 'Jos',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Valoare invalidă',
90 invalidHeight: 'Înălțimea trebuie să fie un număr.',
91 invalidWidth: 'Lățimea trebuie să fie un număr.',
92 invalidCssLength: 'Valoarea specificată pentru câmpul "%1" trebuie să fie un număr pozitiv cu sau fără o unitate de măsură CSS (px, %, in, cm, mm, em, ex, pt, sau pc).',
93 invalidHtmlLength: 'Valoarea specificată pentru câmpul "%1" trebuie să fie un număr pozitiv cu sau fără o unitate de măsură HTML (px sau %).',
94 invalidInlineStyle: 'Valoarea specificată pentru stil trebuie să conțină una sau mai multe construcții de tipul "name : value", separate prin punct și virgulă.',
95 cssLengthTooltip: 'Introduceți un număr în pixeli sau un număr cu o unitate de măsură CSS (px, %, in, cm, mm, em, ex, pt, sau pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nu este disponibil</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ru.js b/sources/lang/ru.js
new file mode 100644
index 0000000..1ccc052
--- /dev/null
+++ b/sources/lang/ru.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object for the
8 * Russian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'ru' ] = {
21 // ARIA description.
22 editor: 'Визуальный текстовый редактор',
23 editorPanel: 'Визуальный редактор текста',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Нажмите ALT-0 для открытия справки',
30
31 browseServer: 'Выбор на сервере',
32 url: 'Ссылка',
33 protocol: 'Протокол',
34 upload: 'Загрузка файла',
35 uploadSubmit: 'Загрузить на сервер',
36 image: 'Изображение',
37 flash: 'Flash',
38 form: 'Форма',
39 checkbox: 'Чекбокс',
40 radio: 'Радиокнопка',
41 textField: 'Текстовое поле',
42 textarea: 'Многострочное текстовое поле',
43 hiddenField: 'Скрытое поле',
44 button: 'Кнопка',
45 select: 'Выпадающий список',
46 imageButton: 'Кнопка-изображение',
47 notSet: '<не указано>',
48 id: 'Идентификатор',
49 name: 'Имя',
50 langDir: 'Направление текста',
51 langDirLtr: 'Слева направо (LTR)',
52 langDirRtl: 'Справа налево (RTL)',
53 langCode: 'Код языка',
54 longDescr: 'Длинное описание ссылки',
55 cssClass: 'Класс CSS',
56 advisoryTitle: 'Заголовок',
57 cssStyle: 'Стиль',
58 ok: 'ОК',
59 cancel: 'Отмена',
60 close: 'Закрыть',
61 preview: 'Предпросмотр',
62 resize: 'Перетащите для изменения размера',
63 generalTab: 'Основное',
64 advancedTab: 'Дополнительно',
65 validateNumberFailed: 'Это значение не является числом.',
66 confirmNewPage: 'Несохранённые изменения будут потеряны! Вы действительно желаете перейти на другую страницу?',
67 confirmCancel: 'Некоторые параметры были изменены. Вы уверены, что желаете закрыть без сохранения?',
68 options: 'Параметры',
69 target: 'Цель',
70 targetNew: 'Новое окно (_blank)',
71 targetTop: 'Главное окно (_top)',
72 targetSelf: 'Текущее окно (_self)',
73 targetParent: 'Родительское окно (_parent)',
74 langDirLTR: 'Слева направо (LTR)',
75 langDirRTL: 'Справа налево (RTL)',
76 styles: 'Стиль',
77 cssClasses: 'CSS классы',
78 width: 'Ширина',
79 height: 'Высота',
80 align: 'Выравнивание',
81 alignLeft: 'По левому краю',
82 alignRight: 'По правому краю',
83 alignCenter: 'По центру',
84 alignJustify: 'По ширине',
85 alignTop: 'Поверху',
86 alignMiddle: 'Посередине',
87 alignBottom: 'Понизу',
88 alignNone: 'Нет',
89 invalidValue: 'Недопустимое значение.',
90 invalidHeight: 'Высота задается числом.',
91 invalidWidth: 'Ширина задается числом.',
92 invalidCssLength: 'Значение, указанное в поле "%1", должно быть положительным целым числом. Допускается указание единиц меры CSS (px, %, in, cm, mm, em, ex, pt или pc).',
93 invalidHtmlLength: 'Значение, указанное в поле "%1", должно быть положительным целым числом. Допускается указание единиц меры HTML (px или %).',
94 invalidInlineStyle: 'Значение, указанное для стиля элемента, должно состоять из одной или нескольких пар данных в формате "параметр : значение", разделённых точкой с запятой.',
95 cssLengthTooltip: 'Введите значение в пикселях, либо число с корректной единицей меры CSS (px, %, in, cm, mm, em, ex, pt или pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, недоступно</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Пробел',
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Комбинация клавиш'
116 }
117};
diff --git a/sources/lang/si.js b/sources/lang/si.js
new file mode 100644
index 0000000..df0d734
--- /dev/null
+++ b/sources/lang/si.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'si' ] = {
20 // ARIA description.
21 editor: 'පොහොසත් වචන සංස්කරණ',
22 editorPanel: 'Rich Text Editor panel', // MISSING
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'උදව් ලබා ගැනීමට ALT බොත්තම ඔබන්න',
29
30 browseServer: 'සෙවුම් සේවාදායකය',
31 url: 'URL',
32 protocol: 'මුලාපත්‍රය',
33 upload: 'උඩුගතකිරීම',
34 uploadSubmit: 'සේවාදායකය වෙත යොමුකිරිම',
35 image: 'රුපය',
36 flash: 'දීප්තිය',
37 form: 'පෝරමය',
38 checkbox: 'ලකුණුකිරීමේ කොටුව',
39 radio: 'තේරීම් ',
40 textField: 'ලියන ප්‍රදේශය',
41 textarea: 'අකුරු ',
42 hiddenField: 'සැඟවුණු ප්‍රදේශය',
43 button: 'බොත්තම',
44 select: 'තෝරන්න ',
45 imageButton: 'රුප ',
46 notSet: '<යොදා >',
47 id: 'අංකය',
48 name: 'නම',
49 langDir: 'භාෂා දිශාව',
50 langDirLtr: 'වමේසිට දකුණුට',
51 langDirRtl: 'දකුණේ සිට වමට',
52 langCode: 'භාෂා කේතය',
53 longDescr: 'සම්පුර්න පැහැදිලි කිරීම',
54 cssClass: 'විලාශ පත්‍ර පන්තිය',
55 advisoryTitle: 'උපදෙස් ',
56 cssStyle: 'විලාසය',
57 ok: 'නිරදි',
58 cancel: 'අවලංගු කිරීම',
59 close: 'වැසීම',
60 preview: 'නැවත ',
61 resize: 'විශාලත්වය නැවත වෙනස් කිරීම',
62 generalTab: 'පොදු කරුණු.',
63 advancedTab: 'දීය',
64 validateNumberFailed: 'මෙම වටිනාකම අංකයක් නොවේ',
65 confirmNewPage: 'ආරක්ෂා නොකළ සියලුම දත්තයන් මැකියනුලැබේ. ඔබට නව පිටුවක් ලබා ගැනීමට අවශ්‍යද?',
66 confirmCancel: 'ඇතම් විකල්පයන් වෙනස් කර ඇත. ඔබට මින් නික්මීමට අවශ්‍යද?',
67 options: ' විකල්ප',
68 target: 'අරමුණ',
69 targetNew: 'නව කව්ළුව',
70 targetTop: 'වැදගත් කව්ළුව',
71 targetSelf: 'එම කව්ළුව(_තම\\\\)',
72 targetParent: 'මව් කව්ළුව(_)',
73 langDirLTR: 'වමේසිට දකුණුට',
74 langDirRTL: 'දකුණේ සිට වමට',
75 styles: 'විලාසය',
76 cssClasses: 'විලාසපත්‍ර පන්තිය',
77 width: 'පළල',
78 height: 'උස',
79 align: 'ගැලපුම',
80 alignLeft: 'වම',
81 alignRight: 'දකුණ',
82 alignCenter: 'මධ්‍ය',
83 alignJustify: 'Justify', // MISSING
84 alignTop: 'ඉ',
85 alignMiddle: 'මැද',
86 alignBottom: 'පහල',
87 alignNone: 'None', // MISSING
88 invalidValue: 'වැරදී වටිනාකමකි',
89 invalidHeight: 'උස අංකයක් විය යුතුය',
90 invalidWidth: 'පළල අංකයක් විය යුතුය',
91 invalidCssLength: 'වටිනාකමක් නිරූපණය කිරීම "%1" ප්‍රදේශය ධන සංක්‍යාත්මක වටිනාකමක් හෝ නිවරදි නොවන CSS මිනුම් එකක(px, %, in, cm, mm, em, ex, pt, pc)',
92 invalidHtmlLength: 'වටිනාකමක් නිරූපණය කිරීම "%1" ප්‍රදේශය ධන සංක්‍යාත්මක වටිනාකමක් හෝ නිවරදි නොවන HTML මිනුම් එකක (px හෝ %).',
93 invalidInlineStyle: 'වටිනාකමක් නිරූපණය කිරීම පේළි විලාසයයට ආකෘතිය අනතර්ග විය යුතය "නම : වටිනාකම", තිත් කොමාවකින් වෙන් වෙන ලද.',
94 cssLengthTooltip: 'සංක්‍යා ඇතුලත් කිරීමේදී වටිනාකම තිත් ප්‍රමාණය නිවරදි CSS ඒකක(තිත්, %, අඟල්,සෙමි, mm, em, ex, pt, pc)',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span පන්තිය="ළඟා වියහැකි ද බලන්න">, නොමැතිනම්</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backspace', // MISSING
102 13: 'Enter', // MISSING
103 16: 'Shift', // MISSING
104 17: 'Ctrl', // MISSING
105 18: 'Alt', // MISSING
106 32: 'Space', // MISSING
107 35: 'End', // MISSING
108 36: 'Home', // MISSING
109 46: 'Delete', // MISSING
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/sk.js b/sources/lang/sk.js
new file mode 100644
index 0000000..e473cc6
--- /dev/null
+++ b/sources/lang/sk.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Slovak language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'sk' ] = {
21 // ARIA description.
22 editor: 'Editor formátovaného textu',
23 editorPanel: 'Panel editora formátovaného textu',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Stlačením ALT 0 spustiť pomocníka',
30
31 browseServer: 'Prehliadať server',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Odoslať',
35 uploadSubmit: 'Odoslať na server',
36 image: 'Obrázok',
37 flash: 'Flash',
38 form: 'Formulár',
39 checkbox: 'Zaškrtávacie pole',
40 radio: 'Prepínač',
41 textField: 'Textové pole',
42 textarea: 'Textová oblasť',
43 hiddenField: 'Skryté pole',
44 button: 'Tlačidlo',
45 select: 'Rozbaľovací zoznam',
46 imageButton: 'Obrázkové tlačidlo',
47 notSet: '<nenastavené>',
48 id: 'Id',
49 name: 'Meno',
50 langDir: 'Orientácia jazyka',
51 langDirLtr: 'Zľava doprava (LTR)',
52 langDirRtl: 'Sprava doľava (RTL)',
53 langCode: 'Kód jazyka',
54 longDescr: 'Dlhý popis URL',
55 cssClass: 'Trieda štýlu',
56 advisoryTitle: 'Pomocný titulok',
57 cssStyle: 'Štýl',
58 ok: 'OK',
59 cancel: 'Zrušiť',
60 close: 'Zatvorit',
61 preview: 'Náhľad',
62 resize: 'Zmeniť veľkosť',
63 generalTab: 'Hlavné',
64 advancedTab: 'Rozšírené',
65 validateNumberFailed: 'Hodnota nie je číslo.',
66 confirmNewPage: 'Prajete si načítat novú stránku? Všetky neuložené zmeny budú stratené. ',
67 confirmCancel: 'Niektore možnosti boli zmenené. Naozaj chcete zavrieť okno?',
68 options: 'Možnosti',
69 target: 'Cieľ',
70 targetNew: 'Nové okno (_blank)',
71 targetTop: 'Najvrchnejšie okno (_top)',
72 targetSelf: 'To isté okno (_self)',
73 targetParent: 'Rodičovské okno (_parent)',
74 langDirLTR: 'Zľava doprava (LTR)',
75 langDirRTL: 'Sprava doľava (RTL)',
76 styles: 'Štýl',
77 cssClasses: 'Triedy štýlu',
78 width: 'Šírka',
79 height: 'Výška',
80 align: 'Zarovnanie',
81 alignLeft: 'Vľavo',
82 alignRight: 'Vpravo',
83 alignCenter: 'Na stred',
84 alignJustify: 'Zarovnať do bloku',
85 alignTop: 'Nahor',
86 alignMiddle: 'Na stred',
87 alignBottom: 'Dole',
88 alignNone: 'Žiadne',
89 invalidValue: 'Neplatná hodnota.',
90 invalidHeight: 'Výška musí byť číslo.',
91 invalidWidth: 'Šírka musí byť číslo.',
92 invalidCssLength: 'Špecifikovaná hodnota pre pole "%1" musí byť kladné číslo s alebo bez platnej CSS mernej jednotky (px, %, in, cm, mm, em, ex, pt alebo pc).',
93 invalidHtmlLength: 'Špecifikovaná hodnota pre pole "%1" musí byť kladné číslo s alebo bez platnej HTML mernej jednotky (px alebo %).',
94 invalidInlineStyle: 'Zadaná hodnota pre inline štýl musí pozostávať s jedného, alebo viac dvojíc formátu "názov: hodnota", oddelených bodkočiarkou.',
95 cssLengthTooltip: 'Vložte číslo pre hodnotu v pixeloch alebo číslo so správnou CSS jednotou (px, %, in, cm, mm, em, ex, pt alebo pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nedostupný</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Medzerník',
108 35: 'End',
109 36: 'Home',
110 46: 'Delete',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Klávesová skratka'
116 }
117};
diff --git a/sources/lang/sl.js b/sources/lang/sl.js
new file mode 100644
index 0000000..bbaa5ea
--- /dev/null
+++ b/sources/lang/sl.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Slovenian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'sl' ] = {
21 // ARIA description.
22 editor: 'Urejevalnik obogatenega besedila',
23 editorPanel: 'Plošča urejevalnika obogatenega besedila',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Pritisnite ALT 0 za pomoč',
30
31 browseServer: 'Prebrskaj na strežniku',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Naloži',
35 uploadSubmit: 'Pošlji na strežnik',
36 image: 'Slika',
37 flash: 'Flash',
38 form: 'Obrazec',
39 checkbox: 'Potrditveno polje',
40 radio: 'Izbirno polje',
41 textField: 'Besedilno polje',
42 textarea: 'Besedilno območje',
43 hiddenField: 'Skrito polje',
44 button: 'Gumb',
45 select: 'Spustno polje',
46 imageButton: 'Slikovni gumb',
47 notSet: '<ni določen>',
48 id: 'Id',
49 name: 'Ime',
50 langDir: 'Smer jezika',
51 langDirLtr: 'Od leve proti desni (LTR)',
52 langDirRtl: 'Od desne proti levi (RTL)',
53 langCode: 'Koda jezika',
54 longDescr: 'Dolg opis URL-ja',
55 cssClass: 'Razredi slogovne predloge',
56 advisoryTitle: 'Predlagani naslov',
57 cssStyle: 'Slog',
58 ok: 'V redu',
59 cancel: 'Prekliči',
60 close: 'Zapri',
61 preview: 'Predogled',
62 resize: 'Potegni za spremembo velikosti',
63 generalTab: 'Splošno',
64 advancedTab: 'Napredno',
65 validateNumberFailed: 'Vrednost ni število.',
66 confirmNewPage: 'Vse neshranjene spremembe vsebine bodo izgubljene. Ali res želite naložiti novo stran?',
67 confirmCancel: 'Spremenili ste nekaj možnosti. Ali res želite zapreti okno?',
68 options: 'Možnosti',
69 target: 'Cilj',
70 targetNew: 'Novo okno (_blank)',
71 targetTop: 'Vrhovno okno (_top)',
72 targetSelf: 'Isto okno (_self)',
73 targetParent: 'Starševsko okno (_parent)',
74 langDirLTR: 'Od leve proti desni (LTR)',
75 langDirRTL: 'Od desne proti levi (RTL)',
76 styles: 'Slog',
77 cssClasses: 'Razredi slogovne predloge',
78 width: 'Širina',
79 height: 'Višina',
80 align: 'Poravnava',
81 alignLeft: 'Levo',
82 alignRight: 'Desno',
83 alignCenter: 'Sredinsko',
84 alignJustify: 'Obojestranska poravnava',
85 alignTop: 'Na vrh',
86 alignMiddle: 'V sredino',
87 alignBottom: 'Na dno',
88 alignNone: 'Brez poravnave',
89 invalidValue: 'Neveljavna vrednost.',
90 invalidHeight: 'Višina mora biti število.',
91 invalidWidth: 'Širina mora biti število.',
92 invalidCssLength: 'Vrednost, določena za polje »%1«, mora biti pozitivno število z ali brez veljavne CSS-enote za merjenje (px, %, in, cm, mm, em, ex, pt ali pc).',
93 invalidHtmlLength: 'Vrednost, določena za polje »%1«, mora biti pozitivno število z ali brez veljavne HTML-enote za merjenje (px ali %).',
94 invalidInlineStyle: 'Vrednost, določena za slog v vrstici, mora biti sestavljena iz ene ali več dvojic oblike »ime : vrednost«, ločenih s podpičji.',
95 cssLengthTooltip: 'Vnesite število za vrednost v slikovnih pikah ali število z veljavno CSS-enoto (px, %, in, cm, mm, em, ex, pt ali pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, nedosegljiv</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/sq.js b/sources/lang/sq.js
new file mode 100644
index 0000000..d5812ea
--- /dev/null
+++ b/sources/lang/sq.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'sq' ] = {
20 // ARIA description.
21 editor: 'Redaktues i Pasur Teksti',
22 editorPanel: 'Paneli i redaktuesit të tekstit të plotë',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Shtyp ALT 0 për ndihmë',
29
30 browseServer: 'Shfleto në Server',
31 url: 'URL',
32 protocol: 'Protokolli',
33 upload: 'Ngarko',
34 uploadSubmit: 'Dërgo në server',
35 image: 'Imazh',
36 flash: 'Objekt flash',
37 form: 'Formular',
38 checkbox: 'Checkbox',
39 radio: 'Buton radio',
40 textField: 'Fushë tekst',
41 textarea: 'Hapësirë tekst',
42 hiddenField: 'Fushë e fshehur',
43 button: 'Buton',
44 select: 'Menu zgjedhjeje',
45 imageButton: 'Buton imazhi',
46 notSet: '<e pazgjedhur>',
47 id: 'Id',
48 name: 'Emër',
49 langDir: 'Kod gjuhe',
50 langDirLtr: 'Nga e majta në të djathtë (LTR)',
51 langDirRtl: 'Nga e djathta në të majtë (RTL)',
52 langCode: 'Kod gjuhe',
53 longDescr: 'Përshkrim i hollësishëm',
54 cssClass: 'Klasa stili CSS',
55 advisoryTitle: 'Titull',
56 cssStyle: 'Stil',
57 ok: 'OK',
58 cancel: 'Anulo',
59 close: 'Mbyll',
60 preview: 'Parashiko',
61 resize: 'Ripërmaso',
62 generalTab: 'Të përgjithshme',
63 advancedTab: 'Të përparuara',
64 validateNumberFailed: 'Vlera e futur nuk është një numër',
65 confirmNewPage: 'Çdo ndryshim që nuk është ruajtur do humbasë. Je i sigurtë që dëshiron të krijosh një faqe të re?',
66 confirmCancel: 'Disa opsione kanë ndryshuar. Je i sigurtë që dëshiron ta mbyllësh dritaren?',
67 options: 'Opsione',
68 target: 'Objektivi',
69 targetNew: 'Dritare e re (_blank)',
70 targetTop: 'Dritare në plan të parë (_top)',
71 targetSelf: 'E njëjta dritare (_self)',
72 targetParent: 'Dritarja prind (_parent)',
73 langDirLTR: 'Nga e majta në të djathë (LTR)',
74 langDirRTL: 'Nga e djathta në të majtë (RTL)',
75 styles: 'Stil',
76 cssClasses: 'Klasa Stili CSS',
77 width: 'Gjerësi',
78 height: 'Lartësi',
79 align: 'Rreshtim',
80 alignLeft: 'Majtas',
81 alignRight: 'Djathtas',
82 alignCenter: 'Qendër',
83 alignJustify: 'Zgjero',
84 alignTop: 'Lart',
85 alignMiddle: 'Në mes',
86 alignBottom: 'Poshtë',
87 alignNone: 'Asnjë',
88 invalidValue: 'Vlerë e pavlefshme',
89 invalidHeight: 'Lartësia duhet të jetë një numër',
90 invalidWidth: 'Gjerësia duhet të jetë një numër',
91 invalidCssLength: 'Vlera e fushës "%1" duhet të jetë një numër pozitiv me apo pa njësi matëse të vlefshme CSS (px, %, in, cm, mm, em, ex, pt ose pc).',
92 invalidHtmlLength: 'Vlera e fushës "%1" duhet të jetë një numër pozitiv me apo pa njësi matëse të vlefshme HTML (px ose %)',
93 invalidInlineStyle: 'Stili inline duhet të jetë një apo disa vlera të formatit "emër: vlerë", ndarë nga pikëpresje.',
94 cssLengthTooltip: 'Fut një numër për vlerën në pixel apo një numër me një njësi të vlefshme CSS (px, %, in, cm, mm, ex, pt, ose pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, i padisponueshëm</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Prapa',
102 13: 'Enter',
103 16: 'Shift',
104 17: 'Ctrl',
105 18: 'Alt',
106 32: 'Space', // MISSING
107 35: 'End',
108 36: 'Home',
109 46: 'Grise',
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/sr-latn.js b/sources/lang/sr-latn.js
new file mode 100644
index 0000000..9994a0a
--- /dev/null
+++ b/sources/lang/sr-latn.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Serbian (Latin) language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'sr-latn' ] = {
21 // ARIA description.
22 editor: 'Bogati uređivač teksta',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Pretraži server',
32 url: 'URL',
33 protocol: 'Protokol',
34 upload: 'Pošalji',
35 uploadSubmit: 'Pošalji na server',
36 image: 'Slika',
37 flash: 'Fleš',
38 form: 'Forma',
39 checkbox: 'Polje za potvrdu',
40 radio: 'Radio-dugme',
41 textField: 'Tekstualno polje',
42 textarea: 'Zona teksta',
43 hiddenField: 'Skriveno polje',
44 button: 'Dugme',
45 select: 'Izborno polje',
46 imageButton: 'Dugme sa slikom',
47 notSet: '<nije postavljeno>',
48 id: 'Id',
49 name: 'Naziv',
50 langDir: 'Smer jezika',
51 langDirLtr: 'S leva na desno (LTR)',
52 langDirRtl: 'S desna na levo (RTL)',
53 langCode: 'Kôd jezika',
54 longDescr: 'Pun opis URL',
55 cssClass: 'Stylesheet klase',
56 advisoryTitle: 'Advisory naslov',
57 cssStyle: 'Stil',
58 ok: 'OK',
59 cancel: 'Otkaži',
60 close: 'Zatvori',
61 preview: 'Izgled stranice',
62 resize: 'Resize', // MISSING
63 generalTab: 'Opšte',
64 advancedTab: 'Napredni tagovi',
65 validateNumberFailed: 'Ova vrednost nije broj.',
66 confirmNewPage: 'Nesačuvane promene ovog sadržaja će biti izgubljene. Jeste li sigurni da želita da učitate novu stranu?',
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Opcije',
69 target: 'Meta',
70 targetNew: 'Novi prozor (_blank)',
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Isti prozor (_self)',
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'S leva na desno (LTR)',
75 langDirRTL: 'S desna na levo (RTL)',
76 styles: 'Stil',
77 cssClasses: 'Stylesheet klase',
78 width: 'Širina',
79 height: 'Visina',
80 align: 'Ravnanje',
81 alignLeft: 'Levo',
82 alignRight: 'Desno',
83 alignCenter: 'Sredina',
84 alignJustify: 'Obostrano ravnanje',
85 alignTop: 'Vrh',
86 alignMiddle: 'Sredina',
87 alignBottom: 'Dole',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Visina mora biti broj.',
91 invalidWidth: 'Širina mora biti broj.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/sr.js b/sources/lang/sr.js
new file mode 100644
index 0000000..341bf7a
--- /dev/null
+++ b/sources/lang/sr.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Serbian (Cyrillic) language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'sr' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Press ALT 0 for help', // MISSING
30
31 browseServer: 'Претражи сервер',
32 url: 'УРЛ',
33 protocol: 'Протокол',
34 upload: 'Пошаљи',
35 uploadSubmit: 'Пошаљи на сервер',
36 image: 'Слика',
37 flash: 'Флеш елемент',
38 form: 'Форма',
39 checkbox: 'Поље за потврду',
40 radio: 'Радио-дугме',
41 textField: 'Текстуално поље',
42 textarea: 'Зона текста',
43 hiddenField: 'Скривено поље',
44 button: 'Дугме',
45 select: 'Изборно поље',
46 imageButton: 'Дугме са сликом',
47 notSet: '<није постављено>',
48 id: 'Ид',
49 name: 'Назив',
50 langDir: 'Смер језика',
51 langDirLtr: 'С лева на десно (LTR)',
52 langDirRtl: 'С десна на лево (RTL)',
53 langCode: 'Kôд језика',
54 longDescr: 'Пун опис УРЛ',
55 cssClass: 'Stylesheet класе',
56 advisoryTitle: 'Advisory наслов',
57 cssStyle: 'Стил',
58 ok: 'OK',
59 cancel: 'Oткажи',
60 close: 'Затвори',
61 preview: 'Изглед странице',
62 resize: 'Resize', // MISSING
63 generalTab: 'Опште',
64 advancedTab: 'Напредни тагови',
65 validateNumberFailed: 'Ова вредност није цигра.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Опције',
69 target: 'Meтa',
70 targetNew: 'New Window (_blank)', // MISSING
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'Same Window (_self)', // MISSING
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'С лева на десно (LTR)',
75 langDirRTL: 'С десна на лево (RTL)',
76 styles: 'Стил',
77 cssClasses: 'Stylesheet класе',
78 width: 'Ширина',
79 height: 'Висина',
80 align: 'Равнање',
81 alignLeft: 'Лево',
82 alignRight: 'Десно',
83 alignCenter: 'Средина',
84 alignJustify: 'Обострано равнање',
85 alignTop: 'Врх',
86 alignMiddle: 'Средина',
87 alignBottom: 'Доле',
88 alignNone: 'None', // MISSING
89 invalidValue: 'Invalid value.', // MISSING
90 invalidHeight: 'Height must be a number.', // MISSING
91 invalidWidth: 'Width must be a number.', // MISSING
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/sv.js b/sources/lang/sv.js
new file mode 100644
index 0000000..3074d46
--- /dev/null
+++ b/sources/lang/sv.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7* @fileOverview
8*/
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'sv' ] = {
20 // ARIA description.
21 editor: 'Rich Text-editor',
22 editorPanel: 'Panel till Rich Text-editor',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Tryck ALT 0 för hjälp',
29
30 browseServer: 'Bläddra på server',
31 url: 'URL',
32 protocol: 'Protokoll',
33 upload: 'Ladda upp',
34 uploadSubmit: 'Skicka till server',
35 image: 'Bild',
36 flash: 'Flash',
37 form: 'Formulär',
38 checkbox: 'Kryssruta',
39 radio: 'Alternativknapp',
40 textField: 'Textfält',
41 textarea: 'Textruta',
42 hiddenField: 'Dolt fält',
43 button: 'Knapp',
44 select: 'Flervalslista',
45 imageButton: 'Bildknapp',
46 notSet: '<ej angivet>',
47 id: 'Id',
48 name: 'Namn',
49 langDir: 'Språkriktning',
50 langDirLtr: 'Vänster till Höger (VTH)',
51 langDirRtl: 'Höger till Vänster (HTV)',
52 langCode: 'Språkkod',
53 longDescr: 'URL-beskrivning',
54 cssClass: 'Stilmall',
55 advisoryTitle: 'Titel',
56 cssStyle: 'Stilmall',
57 ok: 'OK',
58 cancel: 'Avbryt',
59 close: 'Stäng',
60 preview: 'Förhandsgranska',
61 resize: 'Dra för att ändra storlek',
62 generalTab: 'Allmänt',
63 advancedTab: 'Avancerad',
64 validateNumberFailed: 'Värdet är inte ett nummer.',
65 confirmNewPage: 'Alla ändringar i innehållet kommer att förloras. Är du säker på att du vill ladda en ny sida?',
66 confirmCancel: 'Några av alternativen har ändrats. Är du säker på att du vill stänga dialogrutan?',
67 options: 'Alternativ',
68 target: 'Mål',
69 targetNew: 'Nytt fönster (_blank)',
70 targetTop: 'Översta fönstret (_top)',
71 targetSelf: 'Samma fönster (_self)',
72 targetParent: 'Föregående fönster (_parent)',
73 langDirLTR: 'Vänster till höger (LTR)',
74 langDirRTL: 'Höger till vänster (RTL)',
75 styles: 'Stil',
76 cssClasses: 'Stilmallar',
77 width: 'Bredd',
78 height: 'Höjd',
79 align: 'Justering',
80 alignLeft: 'Vänster',
81 alignRight: 'Höger',
82 alignCenter: 'Centrerad',
83 alignJustify: 'Justera till marginaler',
84 alignTop: 'Överkant',
85 alignMiddle: 'Mitten',
86 alignBottom: 'Nederkant',
87 alignNone: 'Ingen',
88 invalidValue: 'Felaktigt värde.',
89 invalidHeight: 'Höjd måste vara ett nummer.',
90 invalidWidth: 'Bredd måste vara ett nummer.',
91 invalidCssLength: 'Värdet för fältet "%1" måste vara ett positivt nummer med eller utan CSS-mätenheter (px, %, in, cm, mm, em, ex, pt, eller pc).',
92 invalidHtmlLength: 'Värdet för fältet "%1" måste vara ett positivt nummer med eller utan godkända HTML-mätenheter (px eller %).',
93 invalidInlineStyle: 'Det angivna värdet för style måste innehålla en eller flera tupler separerade med semikolon i följande format: "name : value"',
94 cssLengthTooltip: 'Ange ett nummer i pixlar eller ett nummer men godkänd CSS-mätenhet (px, %, in, cm, mm, em, ex, pt, eller pc).',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, Ej tillgänglig</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backsteg',
102 13: 'Retur',
103 16: 'Skift',
104 17: 'Ctrl',
105 18: 'Alt',
106 32: 'Mellanslag',
107 35: 'Slut',
108 36: 'Hem',
109 46: 'Radera',
110 224: 'Kommando'
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Kortkommando'
115 }
116};
diff --git a/sources/lang/th.js b/sources/lang/th.js
new file mode 100644
index 0000000..6dc918e
--- /dev/null
+++ b/sources/lang/th.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Thai language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'th' ] = {
21 // ARIA description.
22 editor: 'Rich Text Editor', // MISSING
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'กด ALT 0 หากต้องการความช่วยเหลือ',
30
31 browseServer: 'เปิดหน้าต่างจัดการไฟล์อัพโหลด',
32 url: 'ที่อยู่อ้างอิง URL',
33 protocol: 'โปรโตคอล',
34 upload: 'อัพโหลดไฟล์',
35 uploadSubmit: 'อัพโหลดไฟล์ไปเก็บไว้ที่เครื่องแม่ข่าย (เซิร์ฟเวอร์)',
36 image: 'รูปภาพ',
37 flash: 'ไฟล์ Flash',
38 form: 'แบบฟอร์ม',
39 checkbox: 'เช็คบ๊อก',
40 radio: 'เรดิโอบัตตอน',
41 textField: 'เท็กซ์ฟิลด์',
42 textarea: 'เท็กซ์แอเรีย',
43 hiddenField: 'ฮิดเดนฟิลด์',
44 button: 'ปุ่ม',
45 select: 'แถบตัวเลือก',
46 imageButton: 'ปุ่มแบบรูปภาพ',
47 notSet: '<ไม่ระบุ>',
48 id: 'ไอดี',
49 name: 'ชื่อ',
50 langDir: 'การเขียน-อ่านภาษา',
51 langDirLtr: 'จากซ้ายไปขวา (LTR)',
52 langDirRtl: 'จากขวามาซ้าย (RTL)',
53 langCode: 'รหัสภาษา',
54 longDescr: 'คำอธิบายประกอบ URL',
55 cssClass: 'คลาสของไฟล์กำหนดลักษณะการแสดงผล',
56 advisoryTitle: 'คำเกริ่นนำ',
57 cssStyle: 'ลักษณะการแสดงผล',
58 ok: 'ตกลง',
59 cancel: 'ยกเลิก',
60 close: 'ปิด',
61 preview: 'ดูหน้าเอกสารตัวอย่าง',
62 resize: 'ปรับขนาด',
63 generalTab: 'ทั่วไป',
64 advancedTab: 'ขั้นสูง',
65 validateNumberFailed: 'ค่านี้ไม่ใช่ตัวเลข',
66 confirmNewPage: 'การเปลี่ยนแปลงใดๆ ในเนื้อหานี้ ที่ไม่ได้ถูกบันทึกไว้ จะสูญหายทั้งหมด คุณแน่ใจว่าจะเรียกหน้าใหม่?',
67 confirmCancel: 'ตัวเลือกบางตัวมีการเปลี่ยนแปลง คุณแน่ใจว่าจะปิดกล่องโต้ตอบนี้?',
68 options: 'ตัวเลือก',
69 target: 'การเปิดหน้าลิงค์',
70 targetNew: 'หน้าต่างใหม่ (_blank)',
71 targetTop: 'Topmost Window (_top)', // MISSING
72 targetSelf: 'หน้าต่างเดียวกัน (_self)',
73 targetParent: 'Parent Window (_parent)', // MISSING
74 langDirLTR: 'จากซ้ายไปขวา (LTR)',
75 langDirRTL: 'จากขวามาซ้าย (RTL)',
76 styles: 'ลักษณะการแสดงผล',
77 cssClasses: 'คลาสของไฟล์กำหนดลักษณะการแสดงผล',
78 width: 'ความกว้าง',
79 height: 'ความสูง',
80 align: 'การจัดวาง',
81 alignLeft: 'ชิดซ้าย',
82 alignRight: 'ชิดขวา',
83 alignCenter: 'กึ่งกลาง',
84 alignJustify: 'நியாயப்படுத்தவும்',
85 alignTop: 'บนสุด',
86 alignMiddle: 'กึ่งกลางแนวตั้ง',
87 alignBottom: 'ชิดด้านล่าง',
88 alignNone: 'None', // MISSING
89 invalidValue: 'ค่าไม่ถูกต้อง',
90 invalidHeight: 'ความสูงต้องเป็นตัวเลข',
91 invalidWidth: 'ความกว้างต้องเป็นตัวเลข',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace', // MISSING
103 13: 'Enter', // MISSING
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Delete', // MISSING
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/tr.js b/sources/lang/tr.js
new file mode 100644
index 0000000..0cbd57c
--- /dev/null
+++ b/sources/lang/tr.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7* @fileOverview
8*/
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'tr' ] = {
20 // ARIA description.
21 editor: 'Zengin Metin Editörü',
22 editorPanel: 'Zengin Metin Editör Paneli',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'Yardım için ALT 0 tuşlarına basın',
29
30 browseServer: 'Sunucuya Gözat',
31 url: 'URL',
32 protocol: 'Protokol',
33 upload: 'Karşıya Yükle',
34 uploadSubmit: 'Sunucuya Gönder',
35 image: 'Resim',
36 flash: 'Flash',
37 form: 'Form',
38 checkbox: 'Onay Kutusu',
39 radio: 'Seçenek Düğmesi',
40 textField: 'Metin Kutusu',
41 textarea: 'Metin Alanı',
42 hiddenField: 'Gizli Alan',
43 button: 'Düğme',
44 select: 'Seçme Alanı',
45 imageButton: 'Resim Düğmesi',
46 notSet: '<tanımlanmamış>',
47 id: 'Kimlik',
48 name: 'İsim',
49 langDir: 'Dil Yönü',
50 langDirLtr: 'Soldan Sağa (LTR)',
51 langDirRtl: 'Sağdan Sola (RTL)',
52 langCode: 'Dil Kodlaması',
53 longDescr: 'Uzun Tanımlı URL',
54 cssClass: 'Biçem Sayfası Sınıfları',
55 advisoryTitle: 'Öneri Başlığı',
56 cssStyle: 'Biçem',
57 ok: 'Tamam',
58 cancel: 'İptal',
59 close: 'Kapat',
60 preview: 'Önizleme',
61 resize: 'Yeniden Boyutlandır',
62 generalTab: 'Genel',
63 advancedTab: 'Gelişmiş',
64 validateNumberFailed: 'Bu değer bir sayı değildir.',
65 confirmNewPage: 'Bu içerikle ilgili kaydedilmemiş tüm bilgiler kaybolacaktır. Yeni bir sayfa yüklemek istediğinizden emin misiniz?',
66 confirmCancel: 'Bazı seçenekleri değiştirdiniz. İletişim penceresini kapatmak istediğinizden emin misiniz?',
67 options: 'Seçenekler',
68 target: 'Hedef',
69 targetNew: 'Yeni Pencere (_blank)',
70 targetTop: 'En Üstteki Pencere (_top)',
71 targetSelf: 'Aynı Pencere (_self)',
72 targetParent: 'Üst Pencere (_parent)',
73 langDirLTR: 'Soldan Sağa (LTR)',
74 langDirRTL: 'Sağdan Sola (RTL)',
75 styles: 'Biçem',
76 cssClasses: 'Biçem Sayfası Sınıfları',
77 width: 'Genişlik',
78 height: 'Yükseklik',
79 align: 'Hizalama',
80 alignLeft: 'Sol',
81 alignRight: 'Sağ',
82 alignCenter: 'Ortala',
83 alignJustify: 'İki Kenara Yaslanmış',
84 alignTop: 'Üst',
85 alignMiddle: 'Orta',
86 alignBottom: 'Alt',
87 alignNone: 'Hiçbiri',
88 invalidValue: 'Geçersiz değer.',
89 invalidHeight: 'Yükseklik değeri bir sayı olmalıdır.',
90 invalidWidth: 'Genişlik değeri bir sayı olmalıdır.',
91 invalidCssLength: '"%1" alanı için verilen değer, geçerli bir CSS ölçü birimi (px, %, in, cm, mm, em, ex, pt, veya pc) içeren veya içermeyen pozitif bir sayı olmalıdır.',
92 invalidHtmlLength: 'Belirttiğiniz sayı "%1" alanı için pozitif bir sayı HTML birim değeri olmalıdır (px veya %).',
93 invalidInlineStyle: 'Satıriçi biçem için verilen değer, "isim : değer" biçiminde birbirinden noktalı virgüllerle ayrılan bir veya daha fazla değişkenler grubundan oluşmalıdır.',
94 cssLengthTooltip: 'Piksel türünde bir sayı veya geçerli bir CSS ölçü birimi (px, %, in, cm, mm, em, ex, pt veya pc) içeren bir sayı girin.',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class="cke_accessibility">, kullanılamaz</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Silme Tuşu',
102 13: 'Giriş Tuşu',
103 16: 'Üst Karater Tuşu',
104 17: 'Kontrol Tuşu',
105 18: 'Alt Tuşu',
106 32: 'Boşluk Tuşu',
107 35: 'En Sona Tuşu',
108 36: 'En Başa Tuşu',
109 46: 'Silme Tuşu',
110 224: 'Komut Tuşu'
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Klavye Kısayolu'
115 }
116};
diff --git a/sources/lang/tt.js b/sources/lang/tt.js
new file mode 100644
index 0000000..c63170b
--- /dev/null
+++ b/sources/lang/tt.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Tatar language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'tt' ] = {
21 // ARIA description.
22 editor: 'Форматлаулы текст өлкәсе',
23 editorPanel: 'Rich Text Editor panel', // MISSING
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Ярдәм өчен ALT 0 басыгыз',
30
31 browseServer: 'Сервер карап чыгу',
32 url: 'Сылталама',
33 protocol: 'Протокол',
34 upload: 'Йөкләү',
35 uploadSubmit: 'Серверга җибәрү',
36 image: 'Рәсем',
37 flash: 'Флеш',
38 form: 'Форма',
39 checkbox: 'Чекбокс',
40 radio: 'Радио төймә',
41 textField: 'Текст кыры',
42 textarea: 'Текст мәйданы',
43 hiddenField: 'Яшерен кыр',
44 button: 'Төймə',
45 select: 'Сайлау кыры',
46 imageButton: 'Рәсемле төймə',
47 notSet: '<билгеләнмәгән>',
48 id: 'Id',
49 name: 'Исем',
50 langDir: 'Язылыш юнəлеше',
51 langDirLtr: 'Сулдан уңга язылыш (LTR)',
52 langDirRtl: 'Уңнан сулга язылыш (RTL)',
53 langCode: 'Тел коды',
54 longDescr: 'Җентекле тасвирламага сылталама',
55 cssClass: 'Стильләр класслары',
56 advisoryTitle: 'Киңәш исем',
57 cssStyle: 'Стиль',
58 ok: 'Тәмам',
59 cancel: 'Баш тарту',
60 close: 'Чыгу',
61 preview: 'Карап алу',
62 resize: 'Зурлыкны үзгәртү',
63 generalTab: 'Төп',
64 advancedTab: 'Киңәйтелгән көйләүләр',
65 validateNumberFailed: 'Әлеге кыйммәт сан түгел.',
66 confirmNewPage: 'Any unsaved changes to this content will be lost. Are you sure you want to load new page?', // MISSING
67 confirmCancel: 'You have changed some options. Are you sure you want to close the dialog window?', // MISSING
68 options: 'Үзлекләр',
69 target: 'Максат',
70 targetNew: 'Яңа тәрәзә (_blank)',
71 targetTop: 'Өске тәрәзә (_top)',
72 targetSelf: 'Шул үк тәрәзә (_self)',
73 targetParent: 'Ана тәрәзә (_parent)',
74 langDirLTR: 'Сулдан уңга язылыш (LTR)',
75 langDirRTL: 'Уңнан сулга язылыш (RTL)',
76 styles: 'Стиль',
77 cssClasses: 'Стильләр класслары',
78 width: 'Киңлек',
79 height: 'Биеклек',
80 align: 'Тигезләү',
81 alignLeft: 'Сул якка',
82 alignRight: 'Уң якка',
83 alignCenter: 'Үзәккә',
84 alignJustify: 'Киңлеккә карап тигезләү',
85 alignTop: 'Өскә',
86 alignMiddle: 'Уртага',
87 alignBottom: 'Аска',
88 alignNone: 'Һичбер',
89 invalidValue: 'Дөрес булмаган кыйммәт.',
90 invalidHeight: 'Биеклек сан булырга тиеш.',
91 invalidWidth: 'Киңлек сан булырга тиеш.',
92 invalidCssLength: 'Value specified for the "%1" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
93 invalidHtmlLength: 'Value specified for the "%1" field must be a positive number with or without a valid HTML measurement unit (px or %).', // MISSING
94 invalidInlineStyle: 'Value specified for the inline style must consist of one or more tuples with the format of "name : value", separated by semi-colons.', // MISSING
95 cssLengthTooltip: 'Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).', // MISSING
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, unavailable</span>', // MISSING
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Кайтару',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'End',
109 36: 'Home',
110 46: 'Бетерү',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/ug.js b/sources/lang/ug.js
new file mode 100644
index 0000000..13a256d
--- /dev/null
+++ b/sources/lang/ug.js
@@ -0,0 +1,116 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview
8 */
9
10/**#@+
11 @type String
12 @example
13*/
14
15/**
16 * Contains the dictionary of language entries.
17 * @namespace
18 */
19CKEDITOR.lang[ 'ug' ] = {
20 // ARIA description.
21 editor: 'تەھرىرلىگۈچ',
22 editorPanel: 'مول تېكست تەھرىرلىگۈچ تاختىسى',
23
24 // Common messages and labels.
25 common: {
26 // Screenreader titles. Please note that screenreaders are not always capable
27 // of reading non-English words. So be careful while translating it.
28 editorHelp: 'ALT+0 نى بېسىپ ياردەمنى كۆرۈڭ',
29
30 browseServer: 'كۆرسىتىش مۇلازىمېتىر',
31 url: 'ئەسلى ھۆججەت',
32 protocol: 'كېلىشىم',
33 upload: 'يۈكلە',
34 uploadSubmit: 'مۇلازىمېتىرغا يۈكلە',
35 image: 'سۈرەت',
36 flash: 'Flash',
37 form: 'جەدۋەل',
38 checkbox: 'كۆپ تاللاش رامكىسى',
39 radio: 'يەككە تاللاش توپچىسى',
40 textField: 'يەككە قۇر تېكىست',
41 textarea: 'كۆپ قۇر تېكىست',
42 hiddenField: 'يوشۇرۇن دائىرە',
43 button: 'توپچا',
44 select: 'تىزىم/تىزىملىك',
45 imageButton: 'سۈرەت دائىرە',
46 notSet: '‹تەڭشەلمىگەن›',
47 id: 'ID',
48 name: 'ئات',
49 langDir: 'تىل يۆنىلىشى',
50 langDirLtr: 'سولدىن ئوڭغا (LTR)',
51 langDirRtl: 'ئوڭدىن سولغا (RTL)',
52 langCode: 'تىل كودى',
53 longDescr: 'تەپسىلىي چۈشەندۈرۈش ئادرېسى',
54 cssClass: 'ئۇسلۇب خىلىنىڭ ئاتى',
55 advisoryTitle: 'ماۋزۇ',
56 cssStyle: 'قۇر ئىچىدىكى ئۇسلۇبى',
57 ok: 'جەزملە',
58 cancel: 'ۋاز كەچ',
59 close: 'تاقا',
60 preview: 'ئالدىن كۆزەت',
61 resize: 'چوڭلۇقىنى ئۆزگەرت',
62 generalTab: 'ئادەتتىكى',
63 advancedTab: 'ئالىي',
64 validateNumberFailed: 'سان پىچىمىدا كىرگۈزۈش زۆرۈر',
65 confirmNewPage: 'نۆۋەتتىكى پۈتۈك مەزمۇنى ساقلانمىدى، يېڭى پۈتۈك قۇرامسىز؟',
66 confirmCancel: 'قىسمەن ئۆزگەرتىش ساقلانمىدى، بۇ سۆزلەشكۈنى تاقامسىز؟',
67 options: 'تاللانما',
68 target: 'نىشان كۆزنەك',
69 targetNew: 'يېڭى كۆزنەك (_blank)',
70 targetTop: 'پۈتۈن بەت (_top)',
71 targetSelf: 'مەزكۇر كۆزنەك (_self)',
72 targetParent: 'ئاتا كۆزنەك (_parent)',
73 langDirLTR: 'سولدىن ئوڭغا (LTR)',
74 langDirRTL: 'ئوڭدىن سولغا (RTL)',
75 styles: 'ئۇسلۇبلار',
76 cssClasses: 'ئۇسلۇب خىللىرى',
77 width: 'كەڭلىك',
78 height: 'ئېگىزلىك',
79 align: 'توغرىلىنىشى',
80 alignLeft: 'سول',
81 alignRight: 'ئوڭ',
82 alignCenter: 'ئوتتۇرا',
83 alignJustify: 'ئىككى تەرەپتىن توغرىلا',
84 alignTop: 'ئۈستى',
85 alignMiddle: 'ئوتتۇرا',
86 alignBottom: 'ئاستى',
87 alignNone: 'يوق',
88 invalidValue: 'ئىناۋەتسىز قىممەت.',
89 invalidHeight: 'ئېگىزلىك چوقۇم رەقەم پىچىمىدا بولۇشى زۆرۈر',
90 invalidWidth: 'كەڭلىك چوقۇم رەقەم پىچىمىدا بولۇشى زۆرۈر',
91 invalidCssLength: 'بۇ سۆز بۆلىكى چوقۇم مۇۋاپىق بولغان CSS ئۇزۇنلۇق قىممىتى بولۇشى زۆرۈر، بىرلىكى (px, %, in, cm, mm, em, ex, pt ياكى pc)',
92 invalidHtmlLength: 'بۇ سۆز بۆلىكى چوقۇم بىرىكمە HTML ئۇزۇنلۇق قىممىتى بولۇشى كېرەك. ئۆز ئىچىگە ئالىدىغان بىرلىك (px ياكى %)',
93 invalidInlineStyle: 'ئىچكى باغلانما ئۇسلۇبى چوقۇم چېكىتلىك پەش بىلەن ئايرىلغان بىر ياكى كۆپ «خاسلىق ئاتى:خاسلىق قىممىتى» پىچىمىدا بولۇشى لازىم',
94 cssLengthTooltip: 'بۇ سۆز بۆلىكى بىرىكمە CSS ئۇزۇنلۇق قىممىتى بولۇشى كېرەك. ئۆز ئىچىگە ئالىدىغان بىرلىك (px, %, in, cm, mm, em, ex, pt ياكى pc)',
95
96 // Put the voice-only part of the label in the span.
97 unavailable: '%1<span class=\\\\"cke_accessibility\\\\">، ئىشلەتكىلى بولمايدۇ</span>',
98
99 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
100 keyboard: {
101 8: 'Backspace',
102 13: 'Enter',
103 16: 'Shift',
104 17: 'Ctrl',
105 18: 'Alt',
106 32: 'Space', // MISSING
107 35: 'End',
108 36: 'Home',
109 46: 'ئۆچۈر',
110 224: 'Command' // MISSING
111 },
112
113 // Prepended to ARIA labels with shortcuts.
114 keyboardShortcut: 'Keyboard shortcut' // MISSING
115 }
116};
diff --git a/sources/lang/uk.js b/sources/lang/uk.js
new file mode 100644
index 0000000..baa78e6
--- /dev/null
+++ b/sources/lang/uk.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Ukrainian language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'uk' ] = {
21 // ARIA description.
22 editor: 'Текстовий редактор',
23 editorPanel: 'Панель текстового редактора',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'натисніть ALT 0 для довідки',
30
31 browseServer: 'Огляд Сервера',
32 url: 'URL',
33 protocol: 'Протокол',
34 upload: 'Надіслати',
35 uploadSubmit: 'Надіслати на сервер',
36 image: 'Зображення',
37 flash: 'Flash',
38 form: 'Форма',
39 checkbox: 'Галочка',
40 radio: 'Кнопка вибору',
41 textField: 'Текстове поле',
42 textarea: 'Текстова область',
43 hiddenField: 'Приховане поле',
44 button: 'Кнопка',
45 select: 'Список',
46 imageButton: 'Кнопка із зображенням',
47 notSet: '<не визначено>',
48 id: 'Ідентифікатор',
49 name: 'Ім\'я',
50 langDir: 'Напрямок мови',
51 langDirLtr: 'Зліва направо (LTR)',
52 langDirRtl: 'Справа наліво (RTL)',
53 langCode: 'Код мови',
54 longDescr: 'Довгий опис URL',
55 cssClass: 'Клас CSS',
56 advisoryTitle: 'Заголовок',
57 cssStyle: 'Стиль CSS',
58 ok: 'ОК',
59 cancel: 'Скасувати',
60 close: 'Закрити',
61 preview: 'Попередній перегляд',
62 resize: 'Потягніть для зміни розмірів',
63 generalTab: 'Основне',
64 advancedTab: 'Додаткове',
65 validateNumberFailed: 'Значення не є цілим числом.',
66 confirmNewPage: 'Всі незбережені зміни будуть втрачені. Ви впевнені, що хочете завантажити нову сторінку?',
67 confirmCancel: 'Деякі опції змінено. Закрити вікно без збереження змін?',
68 options: 'Опції',
69 target: 'Ціль',
70 targetNew: 'Нове вікно (_blank)',
71 targetTop: 'Поточне вікно (_top)',
72 targetSelf: 'Поточний фрейм/вікно (_self)',
73 targetParent: 'Батьківський фрейм/вікно (_parent)',
74 langDirLTR: 'Зліва направо (LTR)',
75 langDirRTL: 'Справа наліво (RTL)',
76 styles: 'Стиль CSS',
77 cssClasses: 'Клас CSS',
78 width: 'Ширина',
79 height: 'Висота',
80 align: 'Вирівнювання',
81 alignLeft: 'По лівому краю',
82 alignRight: 'По правому краю',
83 alignCenter: 'По центру',
84 alignJustify: 'По ширині',
85 alignTop: 'По верхньому краю',
86 alignMiddle: 'По середині',
87 alignBottom: 'По нижньому краю',
88 alignNone: 'Нема',
89 invalidValue: 'Невірне значення.',
90 invalidHeight: 'Висота повинна бути цілим числом.',
91 invalidWidth: 'Ширина повинна бути цілим числом.',
92 invalidCssLength: 'Значення, вказане для "%1" в полі повинно бути позитивним числом або без дійсного виміру CSS блоку (px, %, in, cm, mm, em, ex, pt або pc).',
93 invalidHtmlLength: 'Значення, вказане для "%1" в полі повинно бути позитивним числом або без дійсного виміру HTML блоку (px або %).',
94 invalidInlineStyle: 'Значення, вказане для вбудованого стилю повинне складатися з одного чи кількох кортежів у форматі "ім\'я : значення", розділених крапкою з комою.',
95 cssLengthTooltip: 'Введіть номер значення в пікселях або число з дійсною одиниці CSS (px, %, in, cm, mm, em, ex, pt або pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, не доступне</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Backspace',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: 'Space', // MISSING
108 35: 'End',
109 36: 'Home',
110 46: 'Видалити',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/vi.js b/sources/lang/vi.js
new file mode 100644
index 0000000..45d3d30
--- /dev/null
+++ b/sources/lang/vi.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Vietnamese language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'vi' ] = {
21 // ARIA description.
22 editor: 'Bộ soạn thảo văn bản có định dạng',
23 editorPanel: 'Bảng điều khiển Rich Text Editor',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: 'Nhấn ALT + 0 để được giúp đỡ',
30
31 browseServer: 'Duyệt máy chủ',
32 url: 'URL',
33 protocol: 'Giao thức',
34 upload: 'Tải lên',
35 uploadSubmit: 'Tải lên máy chủ',
36 image: 'Hình ảnh',
37 flash: 'Flash',
38 form: 'Biểu mẫu',
39 checkbox: 'Nút kiểm',
40 radio: 'Nút chọn',
41 textField: 'Trường văn bản',
42 textarea: 'Vùng văn bản',
43 hiddenField: 'Trường ẩn',
44 button: 'Nút',
45 select: 'Ô chọn',
46 imageButton: 'Nút hình ảnh',
47 notSet: '<không thiết lập>',
48 id: 'Định danh',
49 name: 'Tên',
50 langDir: 'Hướng ngôn ngữ',
51 langDirLtr: 'Trái sang phải (LTR)',
52 langDirRtl: 'Phải sang trái (RTL)',
53 langCode: 'Mã ngôn ngữ',
54 longDescr: 'Mô tả URL',
55 cssClass: 'Lớp Stylesheet',
56 advisoryTitle: 'Nhan đề hướng dẫn',
57 cssStyle: 'Kiểu ',
58 ok: 'Đồng ý',
59 cancel: 'Bỏ qua',
60 close: 'Đóng',
61 preview: 'Xem trước',
62 resize: 'Kéo rê để thay đổi kích cỡ',
63 generalTab: 'Tab chung',
64 advancedTab: 'Tab mở rộng',
65 validateNumberFailed: 'Giá trị này không phải là số.',
66 confirmNewPage: 'Mọi thay đổi không được lưu lại, nội dung này sẽ bị mất. Bạn có chắc chắn muốn tải một trang mới?',
67 confirmCancel: 'Một vài tùy chọn đã bị thay đổi. Bạn có chắc chắn muốn đóng hộp thoại?',
68 options: 'Tùy chọn',
69 target: 'Đích đến',
70 targetNew: 'Cửa sổ mới (_blank)',
71 targetTop: 'Cửa sổ trên cùng (_top)',
72 targetSelf: 'Tại trang (_self)',
73 targetParent: 'Cửa sổ cha (_parent)',
74 langDirLTR: 'Trái sang phải (LTR)',
75 langDirRTL: 'Phải sang trái (RTL)',
76 styles: 'Kiểu',
77 cssClasses: 'Lớp CSS',
78 width: 'Chiều rộng',
79 height: 'Chiều cao',
80 align: 'Vị trí',
81 alignLeft: 'Trái',
82 alignRight: 'Phải',
83 alignCenter: 'Giữa',
84 alignJustify: 'Sắp chữ',
85 alignTop: 'Trên',
86 alignMiddle: 'Giữa',
87 alignBottom: 'Dưới',
88 alignNone: 'Không',
89 invalidValue: 'Giá trị không hợp lệ.',
90 invalidHeight: 'Chiều cao phải là số nguyên.',
91 invalidWidth: 'Chiều rộng phải là số nguyên.',
92 invalidCssLength: 'Giá trị quy định cho trường "%1" phải là một số dương có hoặc không có một đơn vị đo CSS hợp lệ (px, %, in, cm, mm, em, ex, pt, hoặc pc).',
93 invalidHtmlLength: 'Giá trị quy định cho trường "%1" phải là một số dương có hoặc không có một đơn vị đo HTML hợp lệ (px hoặc %).',
94 invalidInlineStyle: 'Giá trị quy định cho kiểu nội tuyến phải bao gồm một hoặc nhiều dữ liệu với định dạng "tên:giá trị", cách nhau bằng dấu chấm phẩy.',
95 cssLengthTooltip: 'Nhập một giá trị theo pixel hoặc một số với một đơn vị CSS hợp lệ (px, %, in, cm, mm, em, ex, pt, hoặc pc).',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">, không có</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: 'Phím Backspace',
103 13: 'Enter',
104 16: 'Shift', // MISSING
105 17: 'Ctrl', // MISSING
106 18: 'Alt', // MISSING
107 32: 'Space', // MISSING
108 35: 'End', // MISSING
109 36: 'Home', // MISSING
110 46: 'Xóa',
111 224: 'Command' // MISSING
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: 'Keyboard shortcut' // MISSING
116 }
117};
diff --git a/sources/lang/zh-cn.js b/sources/lang/zh-cn.js
new file mode 100644
index 0000000..b89c0c9
--- /dev/null
+++ b/sources/lang/zh-cn.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Chinese Simplified language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'zh-cn' ] = {
21 // ARIA description.
22 editor: '所见即所得编辑器',
23 editorPanel: '所见即所得编辑器面板',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: '按 ALT+0 获得帮助',
30
31 browseServer: '浏览服务器',
32 url: 'URL',
33 protocol: '协议',
34 upload: '上传',
35 uploadSubmit: '上传到服务器',
36 image: '图像',
37 flash: 'Flash',
38 form: '表单',
39 checkbox: '复选框',
40 radio: '单选按钮',
41 textField: '单行文本',
42 textarea: '多行文本',
43 hiddenField: '隐藏域',
44 button: '按钮',
45 select: '列表/菜单',
46 imageButton: '图像按钮',
47 notSet: '<没有设置>',
48 id: 'ID',
49 name: '名称',
50 langDir: '语言方向',
51 langDirLtr: '从左到右 (LTR)',
52 langDirRtl: '从右到左 (RTL)',
53 langCode: '语言代码',
54 longDescr: '详细说明 URL',
55 cssClass: '样式类名称',
56 advisoryTitle: '标题',
57 cssStyle: '行内样式',
58 ok: '确定',
59 cancel: '取消',
60 close: '关闭',
61 preview: '预览',
62 resize: '拖拽以改变大小',
63 generalTab: '常规',
64 advancedTab: '高级',
65 validateNumberFailed: '需要输入数字格式',
66 confirmNewPage: '当前文档内容未保存,是否确认新建文档?',
67 confirmCancel: '部分修改尚未保存,是否确认关闭对话框?',
68 options: '选项',
69 target: '目标窗口',
70 targetNew: '新窗口 (_blank)',
71 targetTop: '整页 (_top)',
72 targetSelf: '本窗口 (_self)',
73 targetParent: '父窗口 (_parent)',
74 langDirLTR: '从左到右 (LTR)',
75 langDirRTL: '从右到左 (RTL)',
76 styles: '样式',
77 cssClasses: '样式类',
78 width: '宽度',
79 height: '高度',
80 align: '对齐方式',
81 alignLeft: '左对齐',
82 alignRight: '右对齐',
83 alignCenter: '居中',
84 alignJustify: '两端对齐',
85 alignTop: '顶端',
86 alignMiddle: '居中',
87 alignBottom: '底部',
88 alignNone: '无',
89 invalidValue: '无效的值。',
90 invalidHeight: '高度必须为数字格式',
91 invalidWidth: '宽度必须为数字格式',
92 invalidCssLength: '此“%1”字段的值必须为正数,可以包含或不包含一个有效的 CSS 长度单位(px, %, in, cm, mm, em, ex, pt 或 pc)',
93 invalidHtmlLength: '此“%1”字段的值必须为正数,可以包含或不包含一个有效的 HTML 长度单位(px 或 %)',
94 invalidInlineStyle: '内联样式必须为格式是以分号分隔的一个或多个“属性名 : 属性值”。',
95 cssLengthTooltip: '输入一个表示像素值的数字,或加上一个有效的 CSS 长度单位(px, %, in, cm, mm, em, ex, pt 或 pc)。',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">,不可用</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: '退格键',
103 13: '回车键',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: '空格键',
108 35: '行尾键',
109 36: '行首键',
110 46: '删除键',
111 224: 'Command'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: '快捷键'
116 }
117};
diff --git a/sources/lang/zh.js b/sources/lang/zh.js
new file mode 100644
index 0000000..c8a0548
--- /dev/null
+++ b/sources/lang/zh.js
@@ -0,0 +1,117 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Defines the {@link CKEDITOR.lang} object, for the
8 * Chinese Traditional language.
9 */
10
11/**#@+
12 @type String
13 @example
14*/
15
16/**
17 * Contains the dictionary of language entries.
18 * @namespace
19 */
20CKEDITOR.lang[ 'zh' ] = {
21 // ARIA description.
22 editor: 'RTF 編輯器',
23 editorPanel: 'RTF 編輯器面板',
24
25 // Common messages and labels.
26 common: {
27 // Screenreader titles. Please note that screenreaders are not always capable
28 // of reading non-English words. So be careful while translating it.
29 editorHelp: '按下 ALT 0 取得說明。',
30
31 browseServer: '瀏覽伺服器',
32 url: 'URL',
33 protocol: '通訊協定',
34 upload: '上傳',
35 uploadSubmit: '傳送至伺服器',
36 image: '圖像',
37 flash: 'Flash',
38 form: '表格',
39 checkbox: '核取方塊',
40 radio: '選項按鈕',
41 textField: '文字欄位',
42 textarea: '文字區域',
43 hiddenField: '隱藏欄位',
44 button: '按鈕',
45 select: '選取欄位',
46 imageButton: '影像按鈕',
47 notSet: '<未設定>',
48 id: 'ID',
49 name: '名稱',
50 langDir: '語言方向',
51 langDirLtr: '由左至右 (LTR)',
52 langDirRtl: '由右至左 (RTL)',
53 langCode: '語言代碼',
54 longDescr: '完整描述 URL',
55 cssClass: '樣式表類別',
56 advisoryTitle: '標題',
57 cssStyle: '樣式',
58 ok: '確定',
59 cancel: '取消',
60 close: '關閉',
61 preview: '預覽',
62 resize: '調整大小',
63 generalTab: '一般',
64 advancedTab: '進階',
65 validateNumberFailed: '此值不是數值。',
66 confirmNewPage: '現存的修改尚未儲存,要開新檔案?',
67 confirmCancel: '部份選項尚未儲存,要關閉對話框?',
68 options: '選項',
69 target: '目標',
70 targetNew: '開新視窗 (_blank)',
71 targetTop: '最上層視窗 (_top)',
72 targetSelf: '相同視窗 (_self)',
73 targetParent: '父視窗 (_parent)',
74 langDirLTR: '由左至右 (LTR)',
75 langDirRTL: '由右至左 (RTL)',
76 styles: '樣式',
77 cssClasses: '樣式表類別',
78 width: '寬度',
79 height: '高度',
80 align: '對齊方式',
81 alignLeft: '靠左對齊',
82 alignRight: '靠右對齊',
83 alignCenter: '置中對齊',
84 alignJustify: '左右對齊',
85 alignTop: '頂端',
86 alignMiddle: '中間對齊',
87 alignBottom: '底端',
88 alignNone: '無',
89 invalidValue: '無效值。',
90 invalidHeight: '高度必須為數字。',
91 invalidWidth: '寬度必須為數字。',
92 invalidCssLength: '「%1」的值應為正數,並可包含有效的 CSS 單位 (px, %, in, cm, mm, em, ex, pt, 或 pc)。',
93 invalidHtmlLength: '「%1」的值應為正數,並可包含有效的 HTML 單位 (px 或 %)。',
94 invalidInlineStyle: '行內樣式的值應包含一個以上的變數值組,其格式如「名稱:值」,並以分號區隔之。',
95 cssLengthTooltip: '請輸入數值,單位是像素或有效的 CSS 單位 (px, %, in, cm, mm, em, ex, pt, 或 pc)。',
96
97 // Put the voice-only part of the label in the span.
98 unavailable: '%1<span class="cke_accessibility">,無法使用</span>',
99
100 // Keyboard keys translations used for creating shortcuts descriptions in tooltips, context menus and ARIA labels.
101 keyboard: {
102 8: '退格鍵',
103 13: 'Enter',
104 16: 'Shift',
105 17: 'Ctrl',
106 18: 'Alt',
107 32: '空白鍵',
108 35: 'End',
109 36: 'Home',
110 46: '刪除',
111 224: 'Command 鍵'
112 },
113
114 // Prepended to ARIA labels with shortcuts.
115 keyboardShortcut: '鍵盤快捷鍵'
116 }
117};
diff --git a/sources/plugins/a11yhelp/dialogs/a11yhelp.js b/sources/plugins/a11yhelp/dialogs/a11yhelp.js
new file mode 100644
index 0000000..73b930c
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/a11yhelp.js
@@ -0,0 +1,217 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.dialog.add( 'a11yHelp', function( editor ) {
7 var lang = editor.lang.a11yhelp,
8 coreLang = editor.lang.common.keyboard,
9 id = CKEDITOR.tools.getNextId();
10
11 // CharCode <-> KeyChar.
12 var keyMap = {
13 8: coreLang[ 8 ],
14 9: lang.tab,
15 13: coreLang[ 13 ],
16 16: coreLang[ 16 ],
17 17: coreLang[ 17 ],
18 18: coreLang[ 18 ],
19 19: lang.pause,
20 20: lang.capslock,
21 27: lang.escape,
22 33: lang.pageUp,
23 34: lang.pageDown,
24 35: coreLang[ 35 ],
25 36: coreLang[ 36 ],
26 37: lang.leftArrow,
27 38: lang.upArrow,
28 39: lang.rightArrow,
29 40: lang.downArrow,
30 45: lang.insert,
31 46: coreLang[ 46 ],
32 91: lang.leftWindowKey,
33 92: lang.rightWindowKey,
34 93: lang.selectKey,
35 96: lang.numpad0,
36 97: lang.numpad1,
37 98: lang.numpad2,
38 99: lang.numpad3,
39 100: lang.numpad4,
40 101: lang.numpad5,
41 102: lang.numpad6,
42 103: lang.numpad7,
43 104: lang.numpad8,
44 105: lang.numpad9,
45 106: lang.multiply,
46 107: lang.add,
47 109: lang.subtract,
48 110: lang.decimalPoint,
49 111: lang.divide,
50 112: lang.f1,
51 113: lang.f2,
52 114: lang.f3,
53 115: lang.f4,
54 116: lang.f5,
55 117: lang.f6,
56 118: lang.f7,
57 119: lang.f8,
58 120: lang.f9,
59 121: lang.f10,
60 122: lang.f11,
61 123: lang.f12,
62 144: lang.numLock,
63 145: lang.scrollLock,
64 186: lang.semiColon,
65 187: lang.equalSign,
66 188: lang.comma,
67 189: lang.dash,
68 190: lang.period,
69 191: lang.forwardSlash,
70 192: lang.graveAccent,
71 219: lang.openBracket,
72 220: lang.backSlash,
73 221: lang.closeBracket,
74 222: lang.singleQuote
75 };
76
77 // Modifier keys override.
78 keyMap[ CKEDITOR.ALT ] = coreLang[ 18 ];
79 keyMap[ CKEDITOR.SHIFT ] = coreLang[ 16 ];
80 keyMap[ CKEDITOR.CTRL ] = coreLang[ 17 ];
81
82 // Sort in desc.
83 var modifiers = [ CKEDITOR.ALT, CKEDITOR.SHIFT, CKEDITOR.CTRL ];
84
85 function representKeyStroke( keystroke ) {
86 var quotient, modifier,
87 presentation = [];
88
89 for ( var i = 0; i < modifiers.length; i++ ) {
90 modifier = modifiers[ i ];
91 quotient = keystroke / modifiers[ i ];
92 if ( quotient > 1 && quotient <= 2 ) {
93 keystroke -= modifier;
94 presentation.push( keyMap[ modifier ] );
95 }
96 }
97
98 presentation.push( keyMap[ keystroke ] || String.fromCharCode( keystroke ) );
99
100 return presentation.join( '+' );
101 }
102
103 var variablesPattern = /\$\{(.*?)\}/g;
104
105 var replaceVariables = ( function() {
106 // Swaps keystrokes with their commands in object literal.
107 // This makes searching keystrokes by command much easier.
108 var keystrokesByCode = editor.keystrokeHandler.keystrokes,
109 keystrokesByName = {};
110
111 for ( var i in keystrokesByCode )
112 keystrokesByName[ keystrokesByCode[ i ] ] = i;
113
114 return function( match, name ) {
115 // Return the keystroke representation or leave match untouched
116 // if there's no keystroke for such command.
117 return keystrokesByName[ name ] ? representKeyStroke( keystrokesByName[ name ] ) : match;
118 };
119 } )();
120
121 // Create the help list directly from lang file entries.
122 function buildHelpContents() {
123 var pageTpl = '<div class="cke_accessibility_legend" role="document" aria-labelledby="' + id + '_arialbl" tabIndex="-1">%1</div>' +
124 '<span id="' + id + '_arialbl" class="cke_voice_label">' + lang.contents + ' </span>',
125 sectionTpl = '<h1>%1</h1><dl>%2</dl>',
126 itemTpl = '<dt>%1</dt><dd>%2</dd>';
127
128 var pageHtml = [],
129 sections = lang.legend,
130 sectionLength = sections.length;
131
132 for ( var i = 0; i < sectionLength; i++ ) {
133 var section = sections[ i ],
134 sectionHtml = [],
135 items = section.items,
136 itemsLength = items.length;
137
138 for ( var j = 0; j < itemsLength; j++ ) {
139 var item = items[ j ],
140 itemLegend = item.legend.replace( variablesPattern, replaceVariables );
141
142 // (#9765) If some commands haven't been replaced in the legend,
143 // most likely their keystrokes are unavailable and we shouldn't include
144 // them in our help list.
145 if ( itemLegend.match( variablesPattern ) )
146 continue;
147
148 sectionHtml.push( itemTpl.replace( '%1', item.name ).replace( '%2', itemLegend ) );
149 }
150
151 pageHtml.push( sectionTpl.replace( '%1', section.name ).replace( '%2', sectionHtml.join( '' ) ) );
152 }
153
154 return pageTpl.replace( '%1', pageHtml.join( '' ) );
155 }
156
157 return {
158 title: lang.title,
159 minWidth: 600,
160 minHeight: 400,
161 contents: [ {
162 id: 'info',
163 label: editor.lang.common.generalTab,
164 expand: true,
165 elements: [
166 {
167 type: 'html',
168 id: 'legends',
169 style: 'white-space:normal;',
170 focus: function() {
171 this.getElement().focus();
172 },
173 html: buildHelpContents() + '<style type="text/css">' +
174 '.cke_accessibility_legend' +
175 '{' +
176 'width:600px;' +
177 'height:400px;' +
178 'padding-right:5px;' +
179 'overflow-y:auto;' +
180 'overflow-x:hidden;' +
181 '}' +
182 // Some adjustments are to be done for Quirks to work "properly" (#5757)
183 '.cke_browser_quirks .cke_accessibility_legend,' +
184 '{' +
185 'height:390px' +
186 '}' +
187 // Override non-wrapping white-space rule in reset css.
188 '.cke_accessibility_legend *' +
189 '{' +
190 'white-space:normal;' +
191 '}' +
192 '.cke_accessibility_legend h1' +
193 '{' +
194 'font-size: 20px;' +
195 'border-bottom: 1px solid #AAA;' +
196 'margin: 5px 0px 15px;' +
197 '}' +
198 '.cke_accessibility_legend dl' +
199 '{' +
200 'margin-left: 5px;' +
201 '}' +
202 '.cke_accessibility_legend dt' +
203 '{' +
204 'font-size: 13px;' +
205 'font-weight: bold;' +
206 '}' +
207 '.cke_accessibility_legend dd' +
208 '{' +
209 'margin:10px' +
210 '}' +
211 '</style>'
212 }
213 ]
214 } ],
215 buttons: [ CKEDITOR.dialog.cancelButton ]
216 };
217} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/_translationstatus.txt b/sources/plugins/a11yhelp/dialogs/lang/_translationstatus.txt
new file mode 100644
index 0000000..28e8dae
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/_translationstatus.txt
@@ -0,0 +1,25 @@
1Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
2For licensing, see LICENSE.md or http://ckeditor.com/license
3
4cs.js Found: 30 Missing: 0
5cy.js Found: 30 Missing: 0
6da.js Found: 12 Missing: 18
7de.js Found: 30 Missing: 0
8el.js Found: 25 Missing: 5
9eo.js Found: 30 Missing: 0
10fa.js Found: 30 Missing: 0
11fi.js Found: 30 Missing: 0
12fr.js Found: 30 Missing: 0
13gu.js Found: 12 Missing: 18
14he.js Found: 30 Missing: 0
15it.js Found: 30 Missing: 0
16mk.js Found: 5 Missing: 25
17nb.js Found: 30 Missing: 0
18nl.js Found: 30 Missing: 0
19no.js Found: 30 Missing: 0
20pt-br.js Found: 30 Missing: 0
21ro.js Found: 6 Missing: 24
22tr.js Found: 30 Missing: 0
23ug.js Found: 27 Missing: 3
24vi.js Found: 6 Missing: 24
25zh-cn.js Found: 30 Missing: 0
diff --git a/sources/plugins/a11yhelp/dialogs/lang/af.js b/sources/plugins/a11yhelp/dialogs/lang/af.js
new file mode 100644
index 0000000..7469bc1
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/af.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'af', {
7 title: 'Toeganglikheid instruksies',
8 contents: 'Hulp inhoud. Druk ESC om toe te maak.',
9 legend: [
10 {
11 name: 'Algemeen',
12 items: [
13 {
14 name: 'Bewerker balk',
15 legend: 'Druk ${toolbarFocus} om op die werkbalk te land. Beweeg na die volgende en voorige wekrbalkgroep met TAB and SHIFT+TAB. Beweeg na die volgende en voorige werkbalkknop met die regter of linker pyl. Druk SPASIE of ENTER om die knop te bevestig.'
16 },
17
18 {
19 name: 'Bewerker dialoog',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Bewerkerinhoudmenu',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pouse',
88 capslock: 'Hoofletterslot',
89 escape: 'Ontsnap',
90 pageUp: 'Blaaiop',
91 pageDown: 'Blaaiaf',
92 leftArrow: 'Linkspyl',
93 upArrow: 'Oppyl',
94 rightArrow: 'Regterpyl',
95 downArrow: 'Afpyl',
96 insert: 'Toevoeg',
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Nommerblok 0',
101 numpad1: 'Nommerblok 1',
102 numpad2: 'Nommerblok 2',
103 numpad3: 'Nommerblok 3',
104 numpad4: 'Nommerblok 4',
105 numpad5: 'Nommerblok 5',
106 numpad6: 'Nommerblok 6',
107 numpad7: 'Nommerblok 7',
108 numpad8: 'Nommerblok 8',
109 numpad9: 'Nommerblok 9',
110 multiply: 'Maal',
111 add: 'Plus',
112 subtract: 'Minus',
113 decimalPoint: 'Desimaalepunt',
114 divide: 'Gedeeldeur',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Nommervergrendel',
128 scrollLock: 'Rolvergrendel',
129 semiColon: 'Kommapunt',
130 equalSign: 'Isgelykaan',
131 comma: 'Komma',
132 dash: 'Koppelteken',
133 period: 'Punt',
134 forwardSlash: 'Skuinsstreep',
135 graveAccent: 'Aksentteken',
136 openBracket: 'Oopblokhakkie',
137 backSlash: 'Trustreep',
138 closeBracket: 'Toeblokhakkie',
139 singleQuote: 'Enkelaanhaalingsteken'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ar.js b/sources/plugins/a11yhelp/dialogs/lang/ar.js
new file mode 100644
index 0000000..5c316c7
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ar.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ar', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'عام',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'إضافة',
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'تقسيم',
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'فاصلة',
132 dash: 'Dash', // MISSING
133 period: 'نقطة',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/az.js b/sources/plugins/a11yhelp/dialogs/lang/az.js
new file mode 100644
index 0000000..9c04b65
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/az.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'az', {
7 title: 'Əlillərə dəstək üzrə təlimat',
8 contents: 'Kömək. Pəncərəni bağlamaq üçün ESC basın.',
9 legend: [
10 {
11 name: 'Əsas',
12 items: [
13 {
14 name: 'Düzəliş edənin alətlər çubuğu',
15 legend: 'Panelə keçmək üçün ${toolbarFocus} basın. Növbəti panelə TAB, əvvəlki panelə isə SHIFT+TAB düyməsi vasitəsi ilə keçə bilərsiz. Paneldəki düymələr arasında sol və sağ ox düyməsi ilə keçid edə bilərsiz. Seçilmiş düyməsi SPACE və ya ENTER ilə işlədə bilərsiniz.'
16 },
17
18 {
19 name: 'Redaktorun pəncərəsi',
20 legend:
21 'Pəncərə içində növbəti element seçmək üçün TAB düyməni basın, əvvəlki isə - SHIFT+TAB. Təsdiq edilməsi üçün ENTER, imtina edilməsi isə ESC diymələri istifadə edin. Pəncərədə bir neçə vərəq olanda olnarın siyahı ALT+F10 ilə aça bilərsiz. Vərəqlərin siyahı fokus altında olanda ox düymələr vasitəsi ilə onların arasında keçid edə bilərsiz.'
22 },
23
24 {
25 name: 'Redaktorun seçimlərin menyusu',
26 legend: 'Seçimləri redaktə etmək üçün ${contextMenu} ya da APPLICATION KEY basın. Növbəti seçimə keçmək üçün TAB ya AŞAĞI OX düyməsini basın, əvvəlki isə - SHIFT+TAB ya YUXARI OX. Seçimi arımaq SPACE ya ENTER düymələri istifadə edin. Alt menyunu açmaq üçün SPACE, ENTER ya SAĞA OX basın. ESC ya SOLA OX ilə geriyə qayıda bilərsiz. Bütün menyunu ESC ilə bağlıyın.'
27 },
28
29 {
30 name: 'Düzəliş edənin siyahı qutusu',
31 legend: 'Siyahı qutusu içində növbəti bənd seçmək üçün TAB ya AŞAĞI OX, əvvəlki isə SHIFT+TAB ya YUXARI OX basın. Seçimi arımaq SPACE ya ENTER düymələri istifadə edin. Siyahı qutusu ESC ilə bağlıyın.'
32 },
33
34 {
35 name: 'Redaktor elementin cığır paneli',
36 legend: 'Elementin cığır paneli seçmək üçün ${elementsPathFocus} basın. Növbəti element seçmək üçün TAB ya SAĞA OX, əvvəlki isə SHIFT+TAB ya SOLA OX istifadə edin. Elementi arımaq SPACE ya ENTER düymələri mövcuddur.'
37 }
38 ]
39 },
40 {
41 name: 'Əmrlər',
42 items: [
43 {
44 name: 'Əmri geri qaytar',
45 legend: '${undo} basın'
46 },
47 {
48 name: 'Geri əmri',
49 legend: '${redo} basın'
50 },
51 {
52 name: 'Qalın əmri',
53 legend: '${bold} basın'
54 },
55 {
56 name: 'Kursiv əmri',
57 legend: '${italic} basın'
58 },
59 {
60 name: 'Altdan xətt əmri',
61 legend: '${underline} basın'
62 },
63 {
64 name: 'Link əmri',
65 legend: '${link} basın'
66 },
67 {
68 name: 'Paneli gizlət əmri',
69 legend: '${toolbarCollapse} basın'
70 },
71 {
72 name: 'Əvvəlki fokus sahəsi seç əmrı',
73 legend: 'Kursordan əvvəl ən yaxın əlçatmaz yerə dəymək üçün ${accessPreviousSpace} basın, misal üçün: iki dal-badal HR teg. Uzaq yerlərə dəymək üçün bir neçə dəfə basın.'
74 },
75 {
76 name: 'Növbəti fokus sahəsi seç əmrı',
77 legend: 'Kursordan sonra ən yaxın əlçatmaz yerə dəymək üçün ${accessNextSpace} basın, misal üçün: iki dal-badal HR teg. Uzaq yerlərə dəymək üçün bir neçə dəfə basın.'
78 },
79 {
80 name: 'Hərtərəfli Kömək',
81 legend: '${a11yHelp} basın'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Sola ox işarəsi',
93 upArrow: 'Yuxarı ox işarəsi',
94 rightArrow: 'Sağa ox işarəsi',
95 downArrow: 'Aşağı ox işarəsi',
96 insert: 'Insert',
97 leftWindowKey: 'Soldaki Windows düyməsi',
98 rightWindowKey: 'Sağdaki Windows düyməsi',
99 selectKey: 'Düyməni seçin',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Vurma',
111 add: 'Əlavə et',
112 subtract: 'Çıxma',
113 decimalPoint: 'Onluq kəsri tam ədəddən ayıran nöqtə',
114 divide: 'Bölüşdürmə',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Nöqtəli verqül',
130 equalSign: 'Barəbərlik işarəsi',
131 comma: 'Vergül',
132 dash: 'Defis',
133 period: 'Nöqtə',
134 forwardSlash: 'Çəp xətt',
135 graveAccent: 'Vurğu işarəsi',
136 openBracket: 'Açılan mötərizə',
137 backSlash: 'Tərs çəpəki xətt',
138 closeBracket: 'Bağlanan mötərizə',
139 singleQuote: 'Tək dırnaq'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/bg.js b/sources/plugins/a11yhelp/dialogs/lang/bg.js
new file mode 100644
index 0000000..ce9cdd8
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/bg.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'bg', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Общо',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ca.js b/sources/plugins/a11yhelp/dialogs/lang/ca.js
new file mode 100644
index 0000000..f415b90
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ca.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ca', {
7 title: 'Instruccions d\'Accessibilitat',
8 contents: 'Continguts de l\'Ajuda. Per tancar aquest quadre de diàleg premi ESC.',
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Editor de barra d\'eines',
15 legend: 'Premi ${toolbarFocus} per desplaçar-se per la barra d\'eines. Vagi en el següent i anterior grup de barra d\'eines amb TAB i SHIFT+TAB. Vagi en el següent i anterior botó de la barra d\'eines amb RIGHT ARROW i LEFT ARROW. Premi SPACE o ENTER per activar el botó de la barra d\'eines.'
16 },
17
18 {
19 name: 'Editor de quadre de diàleg',
20 legend:
21 'Dins d\'un quadre de diàleg, premi la tecla TAB per desplaçar-se fins al següent element del quadre de diàleg, premi la tecla Shift + TAB per desplaçar-se a l\'anterior element del quadre de diàleg, premi la tecla ENTER per confirmar el quadre de diàleg, premi la tecla ESC per cancel·lar el quadre de diàleg. Quan un quadre de diàleg té diverses pestanyes, la llista de pestanyes pot ser assolit ja sigui amb ALT + F10 o TAB, com a part de l\'ordre de tabulació del quadre de diàleg. Amb la llista de pestanyes seleccionada, pot anar a la fitxa següent i anterior amb la tecla FLETXA DRETA i ESQUERRA, respectivament.'
22 },
23
24 {
25 name: 'Editor de menú contextual',
26 legend: 'Premi ${contextMenu} o APPLICATION KEY per obrir el menú contextual. Després desplacis a la següent opció del menú amb TAB o DOWN ARROW. Desplacis a l\'anterior opció amb SHIFT+TAB o UP ARROW. Premi SPACE o ENTER per seleccionar l\'opció del menú. Obri el submenú de l\'actual opció utilitzant SPACE o ENTER o RIGHT ARROW. Pot tornar a l\'opció del menú pare amb ESC o LEFT ARROW. Tanqui el menú contextual amb ESC.'
27 },
28
29 {
30 name: 'Editor de caixa de llista',
31 legend: 'Dins d\'un quadre de llista, desplacis al següent element de la llista amb TAB o DOWN ARROW. Desplacis a l\'anterior element de la llista amb SHIFT+TAB o UP ARROW. Premi SPACE o ENTER per seleccionar l\'opció de la llista. Premi ESC per tancar el quadre de llista.'
32 },
33
34 {
35 name: 'Editor de barra de ruta de l\'element',
36 legend: 'Premi ${elementsPathFocus} per anar als elements de la barra de ruta. Desplacis al botó de l\'element següent amb TAB o RIGHT ARROW. Desplacis a l\'anterior botó amb SHIFT+TAB o LEFT ARROW. Premi SPACE o ENTER per seleccionar l\'element a l\'editor.'
37 }
38 ]
39 },
40 {
41 name: 'Ordres',
42 items: [
43 {
44 name: 'Desfer ordre',
45 legend: 'Premi ${undo}'
46 },
47 {
48 name: 'Refer ordre',
49 legend: 'Premi ${redo}'
50 },
51 {
52 name: 'Ordre negreta',
53 legend: 'Premi ${bold}'
54 },
55 {
56 name: 'Ordre cursiva',
57 legend: 'Premi ${italic}'
58 },
59 {
60 name: 'Ordre subratllat',
61 legend: 'Premi ${underline}'
62 },
63 {
64 name: 'Ordre enllaç',
65 legend: 'Premi ${link}'
66 },
67 {
68 name: 'Ordre amagar barra d\'eines',
69 legend: 'Premi ${toolbarCollapse}'
70 },
71 {
72 name: 'Ordre per accedir a l\'anterior espai enfocat',
73 legend: 'Premi ${accessPreviousSpace} per accedir a l\'enfocament d\'espai més proper inabastable abans del símbol d\'intercalació, per exemple: dos elements HR adjacents. Repetiu la combinació de tecles per arribar a enfocaments d\'espais distants.'
74 },
75 {
76 name: 'Ordre per accedir al següent espai enfocat',
77 legend: 'Premi ${accessNextSpace} per accedir a l\'enfocament d\'espai més proper inabastable després del símbol d\'intercalació, per exemple: dos elements HR adjacents. Repetiu la combinació de tecles per arribar a enfocaments d\'espais distants.'
78 },
79 {
80 name: 'Ajuda d\'accessibilitat',
81 legend: 'Premi ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulació',
87 pause: 'Pausa',
88 capslock: 'Bloqueig de majúscules',
89 escape: 'Escape',
90 pageUp: 'Pàgina Amunt',
91 pageDown: 'Pàgina Avall',
92 leftArrow: 'Fletxa Esquerra',
93 upArrow: 'Fletxa Amunt',
94 rightArrow: 'Fletxa Dreta',
95 downArrow: 'Fletxa Avall',
96 insert: 'Inserir',
97 leftWindowKey: 'Tecla Windows Esquerra',
98 rightWindowKey: 'Tecla Windows Dreta',
99 selectKey: 'Tecla Seleccionar',
100 numpad0: 'Teclat Numèric 0',
101 numpad1: 'Teclat Numèric 1',
102 numpad2: 'Teclat Numèric 2',
103 numpad3: 'Teclat Numèric 3',
104 numpad4: 'Teclat Numèric 4',
105 numpad5: 'Teclat Numèric 5',
106 numpad6: 'Teclat Numèric 6',
107 numpad7: 'Teclat Numèric 7',
108 numpad8: 'Teclat Numèric 8',
109 numpad9: 'Teclat Numèric 9',
110 multiply: 'Multiplicació',
111 add: 'Suma',
112 subtract: 'Resta',
113 decimalPoint: 'Punt Decimal',
114 divide: 'Divisió',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Bloqueig Teclat Numèric',
128 scrollLock: 'Bloqueig de Desplaçament',
129 semiColon: 'Punt i Coma',
130 equalSign: 'Símbol Igual',
131 comma: 'Coma',
132 dash: 'Guió',
133 period: 'Punt',
134 forwardSlash: 'Barra Diagonal',
135 graveAccent: 'Accent Obert',
136 openBracket: 'Claudàtor Obert',
137 backSlash: 'Barra Invertida',
138 closeBracket: 'Claudàtor Tancat',
139 singleQuote: 'Cometa Simple'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/cs.js b/sources/plugins/a11yhelp/dialogs/lang/cs.js
new file mode 100644
index 0000000..39e4d64
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/cs.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'cs', {
7 title: 'Instrukce pro přístupnost',
8 contents: 'Obsah nápovědy. Pro uzavření tohoto dialogu stiskněte klávesu ESC.',
9 legend: [
10 {
11 name: 'Obecné',
12 items: [
13 {
14 name: 'Panel nástrojů editoru',
15 legend: 'Stiskněte${toolbarFocus} k procházení panelu nástrojů. Přejděte na další a předchozí skupiny pomocí TAB a SHIFT+TAB. Přechod na další a předchozí tlačítko panelu nástrojů je pomocí ŠIPKA VPRAVO nebo ŠIPKA VLEVO. Stisknutím mezerníku nebo klávesy ENTER tlačítko aktivujete.'
16 },
17
18 {
19 name: 'Dialogové okno editoru',
20 legend:
21 'Uvnitř dialogového okna stiskněte TAB pro přesunutí na další prvek okna, stiskněte SHIFT+TAB pro přesun na předchozí prvek okna, stiskněte ENTER pro odeslání dialogu, stiskněte ESC pro jeho zrušení. Pro dialogová okna, která mají mnoho karet stiskněte ALT+F10 pro zaměření seznamu karet, nebo TAB, pro posun podle pořadí karet.Při zaměření seznamu karet se můžete jimi posouvat pomocí ŠIPKY VPRAVO a VLEVO.'
22 },
23
24 {
25 name: 'Kontextové menu editoru',
26 legend: 'Stiskněte ${contextMenu} nebo klávesu APPLICATION k otevření kontextového menu. Pak se přesuňte na další možnost menu pomocí TAB nebo ŠIPKY DOLŮ. Přesuňte se na předchozí možnost pomocí SHIFT+TAB nebo ŠIPKY NAHORU. Stiskněte MEZERNÍK nebo ENTER pro zvolení možnosti menu. Podmenu současné možnosti otevřete pomocí MEZERNÍKU nebo ENTER či ŠIPKY DOLEVA. Kontextové menu uzavřete stiskem ESC.'
27 },
28
29 {
30 name: 'Rámeček seznamu editoru',
31 legend: 'Uvnitř rámečku seznamu se přesunete na další položku menu pomocí TAB nebo ŠIPKA DOLŮ. Na předchozí položku se přesunete SHIFT+TAB nebo ŠIPKA NAHORU. Stiskněte MEZERNÍK nebo ENTER pro zvolení možnosti seznamu. Stiskněte ESC pro uzavření seznamu.'
32 },
33
34 {
35 name: 'Lišta cesty prvku v editoru',
36 legend: 'Stiskněte ${elementsPathFocus} pro procházení lišty cesty prvku. Na další tlačítko prvku se přesunete pomocí TAB nebo ŠIPKA VPRAVO. Na předchozí tlačítko se přesunete pomocí SHIFT+TAB nebo ŠIPKA VLEVO. Stiskněte MEZERNÍK nebo ENTER pro vybrání prvku v editoru.'
37 }
38 ]
39 },
40 {
41 name: 'Příkazy',
42 items: [
43 {
44 name: ' Příkaz Zpět',
45 legend: 'Stiskněte ${undo}'
46 },
47 {
48 name: ' Příkaz Znovu',
49 legend: 'Stiskněte ${redo}'
50 },
51 {
52 name: ' Příkaz Tučné',
53 legend: 'Stiskněte ${bold}'
54 },
55 {
56 name: ' Příkaz Kurzíva',
57 legend: 'Stiskněte ${italic}'
58 },
59 {
60 name: ' Příkaz Podtržení',
61 legend: 'Stiskněte ${underline}'
62 },
63 {
64 name: ' Příkaz Odkaz',
65 legend: 'Stiskněte ${link}'
66 },
67 {
68 name: ' Příkaz Skrýt panel nástrojů',
69 legend: 'Stiskněte ${toolbarCollapse}'
70 },
71 {
72 name: 'Příkaz pro přístup k předchozímu prostoru zaměření',
73 legend: 'Stiskněte ${accessPreviousSpace} pro přístup k nejbližšímu nedosažitelnému prostoru zaměření před stříškou, například: dva přilehlé prvky HR. Pro dosažení vzdálených prostorů zaměření tuto kombinaci kláves opakujte.'
74 },
75 {
76 name: 'Příkaz pro přístup k dalšímu prostoru zaměření',
77 legend: 'Stiskněte ${accessNextSpace} pro přístup k nejbližšímu nedosažitelnému prostoru zaměření po stříšce, například: dva přilehlé prvky HR. Pro dosažení vzdálených prostorů zaměření tuto kombinaci kláves opakujte.'
78 },
79 {
80 name: ' Nápověda přístupnosti',
81 legend: 'Stiskněte ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulátor',
87 pause: 'Pauza',
88 capslock: 'Caps lock',
89 escape: 'Escape',
90 pageUp: 'Stránka nahoru',
91 pageDown: 'Stránka dolů',
92 leftArrow: 'Šipka vlevo',
93 upArrow: 'Šipka nahoru',
94 rightArrow: 'Šipka vpravo',
95 downArrow: 'Šipka dolů',
96 insert: 'Vložit',
97 leftWindowKey: 'Levá klávesa Windows',
98 rightWindowKey: 'Pravá klávesa Windows',
99 selectKey: 'Vyberte klávesu',
100 numpad0: 'Numerická klávesa 0',
101 numpad1: 'Numerická klávesa 1',
102 numpad2: 'Numerická klávesa 2',
103 numpad3: 'Numerická klávesa 3',
104 numpad4: 'Numerická klávesa 4',
105 numpad5: 'Numerická klávesa 5',
106 numpad6: 'Numerická klávesa 6',
107 numpad7: 'Numerická klávesa 7',
108 numpad8: 'Numerická klávesa 8',
109 numpad9: 'Numerická klávesa 9',
110 multiply: 'Numerická klávesa násobení',
111 add: 'Přidat',
112 subtract: 'Numerická klávesa odečítání',
113 decimalPoint: 'Desetinná tečka',
114 divide: 'Numerická klávesa dělení',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num lock',
128 scrollLock: 'Scroll lock',
129 semiColon: 'Středník',
130 equalSign: 'Rovnítko',
131 comma: 'Čárka',
132 dash: 'Pomlčka',
133 period: 'Tečka',
134 forwardSlash: 'Lomítko',
135 graveAccent: 'Přízvuk',
136 openBracket: 'Otevřená hranatá závorka',
137 backSlash: 'Obrácené lomítko',
138 closeBracket: 'Uzavřená hranatá závorka',
139 singleQuote: 'Jednoduchá uvozovka'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/cy.js b/sources/plugins/a11yhelp/dialogs/lang/cy.js
new file mode 100644
index 0000000..3ac77cf
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/cy.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'cy', {
7 title: 'Canllawiau Hygyrchedd',
8 contents: 'Cynnwys Cymorth. I gau y deialog hwn, pwyswch ESC.',
9 legend: [
10 {
11 name: 'Cyffredinol',
12 items: [
13 {
14 name: 'Bar Offer y Golygydd',
15 legend: 'Pwyswch $ {toolbarFocus} i fynd at y bar offer. Symudwch i\'r grŵp bar offer nesaf a blaenorol gyda TAB a SHIFT+TAB. Symudwch i\'r botwm bar offer nesaf a blaenorol gyda SAETH DDE neu SAETH CHWITH. Pwyswch SPACE neu ENTER i wneud botwm y bar offer yn weithredol.'
16 },
17
18 {
19 name: 'Deialog y Golygydd',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Dewislen Cyd-destun y Golygydd',
26 legend: 'Pwyswch $ {contextMenu} neu\'r ALLWEDD \'APPLICATION\' i agor y ddewislen cyd-destun. Yna symudwch i\'r opsiwn ddewislen nesaf gyda\'r TAB neu\'r SAETH I LAWR. Symudwch i\'r opsiwn blaenorol gyda SHIFT+TAB neu\'r SAETH I FYNY. Pwyswch SPACE neu ENTER i ddewis yr opsiwn ddewislen. Agorwch is-dewislen yr opsiwn cyfredol gyda SPACE neu ENTER neu SAETH DDE. Ewch yn ôl i\'r eitem ar y ddewislen uwch gydag ESC neu SAETH CHWITH. Ceuwch y ddewislen cyd-destun gydag ESC.'
27 },
28
29 {
30 name: 'Blwch Rhestr y Golygydd',
31 legend: 'Tu mewn y blwch rhestr, ewch i\'r eitem rhestr nesaf gyda TAB neu\'r SAETH I LAWR. Symudwch i restr eitem flaenorol gyda SHIFT+TAB neu SAETH I FYNY. Pwyswch SPACE neu ENTER i ddewis yr opsiwn o\'r rhestr. Pwyswch ESC i gau\'r rhestr.'
32 },
33
34 {
35 name: 'Bar Llwybr Elfen y Golygydd',
36 legend: 'Pwyswch ${elementsPathFocus} i fynd i\'r bar llwybr elfennau. Symudwch i fotwm yr elfen nesaf gyda TAB neu SAETH DDE. Symudwch i fotwm blaenorol gyda SHIFT+TAB neu SAETH CHWITH. Pwyswch SPACE neu ENTER i ddewis yr elfen yn y golygydd.'
37 }
38 ]
39 },
40 {
41 name: 'Gorchmynion',
42 items: [
43 {
44 name: 'Gorchymyn dadwneud',
45 legend: 'Pwyswch ${undo}'
46 },
47 {
48 name: 'Gorchymyn ailadrodd',
49 legend: 'Pwyswch ${redo}'
50 },
51 {
52 name: 'Gorchymyn Bras',
53 legend: 'Pwyswch ${bold}'
54 },
55 {
56 name: 'Gorchymyn italig',
57 legend: 'Pwyswch ${italig}'
58 },
59 {
60 name: 'Gorchymyn tanlinellu',
61 legend: 'Pwyso ${underline}'
62 },
63 {
64 name: 'Gorchymyn dolen',
65 legend: 'Pwyswch ${link}'
66 },
67 {
68 name: 'Gorchymyn Cwympo\'r Dewislen',
69 legend: 'Pwyswch ${toolbarCollapse}'
70 },
71 {
72 name: 'Myned i orchymyn bwlch ffocws blaenorol',
73 legend: 'Pwyswch ${accessPreviousSpace} i fyned i\'r "blwch ffocws sydd methu ei gyrraedd" cyn y caret, er enghraifft: dwy elfen HR drws nesaf i\'w gilydd. AIladroddwch y cyfuniad allwedd i gyrraedd bylchau ffocws pell.'
74 },
75 {
76 name: 'Ewch i\'r gorchymyn blwch ffocws nesaf',
77 legend: 'Pwyswch ${accessNextSpace} i fyned i\'r blwch ffocws agosaf nad oes modd ei gyrraedd ar ôl y caret, er enghraifft: dwy elfen HR drws nesaf i\'w gilydd. Ailadroddwch y cyfuniad allwedd i gyrraedd blychau ffocws pell.'
78 },
79 {
80 name: 'Cymorth Hygyrchedd',
81 legend: 'Pwyswch ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape',
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/da.js b/sources/plugins/a11yhelp/dialogs/lang/da.js
new file mode 100644
index 0000000..f507bf0
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/da.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'da', {
7 title: 'Tilgængelighedsinstrukser',
8 contents: 'Onlinehjælp. For at lukke dette vindue klik ESC',
9 legend: [
10 {
11 name: 'Generelt',
12 items: [
13 {
14 name: 'Editor værktøjslinje',
15 legend: 'Tryk ${toolbarFocus} for at navigere til værktøjslinjen. Flyt til næste eller forrige værktøjsline gruppe ved hjælp af TAB eller SHIFT+TAB. Flyt til næste eller forrige værktøjslinje knap med venstre- eller højre piltast. Tryk på SPACE eller ENTER for at aktivere værktøjslinje knappen.'
16 },
17
18 {
19 name: 'Editor dialogboks',
20 legend:
21 'Inde i en dialogboks kan du, trykke på TAB for at navigere til næste element, trykke på SHIFT+TAB for at navigere til forrige element, trykke på ENTER for at afsende eller trykke på ESC for at lukke dialogboksen.\r\nNår en dialogboks har flere faner, fanelisten kan tilgås med ALT+F10 eller med TAB. Hvis fanelisten er i fokus kan du skifte til næste eller forrige tab, med højre- og venstre piltast.'
22 },
23
24 {
25 name: 'Redaktør kontekstmenu',
26 legend: 'Tryk ${contextMenu} eller APPLICATION KEY for at åbne kontekstmenuen. Flyt derefter til næste menuvalg med TAB eller PIL NED. Flyt til forrige valg med SHIFT+TAB eller PIL OP. Tryk MELLEMRUM eller RETUR for at vælge menu-muligheder. Åben under-menu af aktuelle valg med MELLEMRUM eller RETUR eller HØJRE PIL. Gå tilbage til overliggende menu-emne med ESC eller VENSTRE PIL. Luk kontekstmenu med ESC.'
27 },
28
29 {
30 name: 'Redaktør listeboks',
31 legend: 'Flyt til næste emne med TAB eller PIL NED inde i en listeboks. Flyt til forrige listeemne med SHIFT+TAB eller PIL OP. Tryk MELLEMRUM eller RETUR for at vælge liste-muligheder. Tryk ESC for at lukke liste-boksen.'
32 },
33
34 {
35 name: 'Redaktør elementsti-bar',
36 legend: 'Tryk ${elementsPathFocus} for at navigere til elementernes sti-bar. Flyt til næste element-knap med TAB eller HØJRE PIL. Flyt til forrige knap med SHIFT+TAB eller VENSTRE PIL. Klik MELLEMRUM eller RETUR for at vælge element i editoren.'
37 }
38 ]
39 },
40 {
41 name: 'Kommandoer',
42 items: [
43 {
44 name: 'Fortryd kommando',
45 legend: 'Klik på ${undo}'
46 },
47 {
48 name: 'Gentag kommando',
49 legend: 'Klik ${redo}'
50 },
51 {
52 name: 'Fed kommando',
53 legend: 'Klik ${bold}'
54 },
55 {
56 name: 'Kursiv kommando',
57 legend: 'Klik ${italic}'
58 },
59 {
60 name: 'Understregnings kommando',
61 legend: 'Klik ${underline}'
62 },
63 {
64 name: 'Link kommando',
65 legend: 'Klik ${link}'
66 },
67 {
68 name: 'Klap værktøjslinje sammen kommando ',
69 legend: 'Klik ${toolbarCollapse}'
70 },
71 {
72 name: 'Adgang til forrige fokusområde kommando',
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: 'Tilgængelighedshjælp',
81 legend: 'Kilk ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Venstre pil',
93 upArrow: 'Pil op',
94 rightArrow: 'Højre pil',
95 downArrow: 'Pil ned',
96 insert: 'Insert',
97 leftWindowKey: 'Venstre Windows tast',
98 rightWindowKey: 'Højre Windows tast',
99 selectKey: 'Select-knap',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Gange',
111 add: 'Plus',
112 subtract: 'Minus',
113 decimalPoint: 'Komma',
114 divide: 'Divider',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semikolon',
130 equalSign: 'Lighedstegn',
131 comma: 'Komma',
132 dash: 'Bindestreg',
133 period: 'Punktum',
134 forwardSlash: 'Skråstreg',
135 graveAccent: 'Accent grave',
136 openBracket: 'Start klamme',
137 backSlash: 'Omvendt skråstreg',
138 closeBracket: 'Slut klamme',
139 singleQuote: 'Enkelt citationstegn'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/de-ch.js b/sources/plugins/a11yhelp/dialogs/lang/de-ch.js
new file mode 100644
index 0000000..8d26d73
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/de-ch.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'de-ch', {
7 title: 'Barrierefreiheitinformationen',
8 contents: 'Hilfeinhalt. Um den Dialog zu schliessen die Taste ESC drücken.',
9 legend: [
10 {
11 name: 'Allgemein',
12 items: [
13 {
14 name: 'Editorwerkzeugleiste',
15 legend: 'Drücken Sie ${toolbarFocus} auf der Symbolleiste. Gehen Sie zur nächsten oder vorherigen Symbolleistengruppe mit TAB und SHIFT+TAB. Gehen Sie zur nächsten oder vorherigen Symbolleiste auf die Schaltfläche mit dem RECHTS- oder LINKS-Pfeil. Drücken Sie die Leertaste oder Eingabetaste, um die Schaltfläche in der Symbolleiste aktivieren.'
16 },
17
18 {
19 name: 'Editordialog',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor-Kontextmenü',
26 legend: 'Dürcken Sie ${contextMenu} oder die Anwendungstaste um das Kontextmenü zu öffnen. Man kann die Pfeiltasten zum Wechsel benutzen. Mit der Leertaste oder der Enter-Taste kann man den Menüpunkt aufrufen. Schliessen Sie das Kontextmenü mit der ESC-Taste.'
27 },
28
29 {
30 name: 'Editor-Listenbox',
31 legend: 'Innerhalb einer Listenbox kann man mit der TAB-Taste oder den Pfeilrunter-Taste den nächsten Menüeintrag wählen. Mit der SHIFT+TAB Tastenkombination oder der Pfeilhoch-Taste gelangt man zum vorherigen Menüpunkt. Mit der Leertaste oder Enter kann man den Menüpunkt auswählen. Drücken Sie ESC zum Verlassen des Menüs.'
32 },
33
34 {
35 name: 'Editor-Elementpfadleiste',
36 legend: 'Drücken Sie ${elementsPathFocus} um sich durch die Pfadleiste zu bewegen. Um zum nächsten Element zu gelangen drücken Sie TAB oder die Pfeilrechts-Taste. Zum vorherigen Element gelangen Sie mit der SHIFT+TAB oder der Pfeillinks-Taste. Drücken Sie die Leertaste oder Enter um das Element auszuwählen.'
37 }
38 ]
39 },
40 {
41 name: 'Befehle',
42 items: [
43 {
44 name: 'Rückgängig-Befehl',
45 legend: 'Drücken Sie ${undo}'
46 },
47 {
48 name: 'Wiederherstellen-Befehl',
49 legend: 'Drücken Sie ${redo}'
50 },
51 {
52 name: 'Fettschrift-Befehl',
53 legend: 'Drücken Sie ${bold}'
54 },
55 {
56 name: 'Kursiv-Befehl',
57 legend: 'Drücken Sie ${italic}'
58 },
59 {
60 name: 'Unterstreichen-Befehl',
61 legend: 'Drücken Sie ${underline}'
62 },
63 {
64 name: 'Link-Befehl',
65 legend: 'Drücken Sie ${link}'
66 },
67 {
68 name: 'Werkzeugleiste einklappen-Befehl',
69 legend: 'Drücken Sie ${toolbarCollapse}'
70 },
71 {
72 name: 'Zugang bisheriger Fokussierung Raumbefehl ',
73 legend: 'Drücken Sie ${accessPreviousSpace} auf den am nächsten nicht erreichbar Fokus-Abstand vor die Einfügemarke zugreifen: zwei benachbarte HR-Elemente. Wiederholen Sie die Tastenkombination um entfernte Fokusräume zu erreichen. '
74 },
75 {
76 name: 'Zugang nächster Schwerpunkt Raumbefehl ',
77 legend: 'Drücken Sie $ { accessNextSpace }, um den nächsten unerreichbar Fokus Leerzeichen nach dem Cursor zum Beispiel auf: zwei benachbarten HR Elemente. Wiederholen Sie die Tastenkombination zum fernen Fokus Bereiche zu erreichen. '
78 },
79 {
80 name: 'Eingabehilfen',
81 legend: 'Drücken Sie ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Feststell',
89 escape: 'Escape',
90 pageUp: 'Bild auf',
91 pageDown: 'Bild ab',
92 leftArrow: 'Linke Pfeiltaste',
93 upArrow: 'Obere Pfeiltaste',
94 rightArrow: 'Rechte Pfeiltaste',
95 downArrow: 'Untere Pfeiltaste',
96 insert: 'Einfügen',
97 leftWindowKey: 'Linke Windowstaste',
98 rightWindowKey: 'Rechte Windowstaste',
99 selectKey: 'Taste auswählen',
100 numpad0: 'Ziffernblock 0',
101 numpad1: 'Ziffernblock 1',
102 numpad2: 'Ziffernblock 2',
103 numpad3: 'Ziffernblock 3',
104 numpad4: 'Ziffernblock 4',
105 numpad5: 'Ziffernblock 5',
106 numpad6: 'Ziffernblock 6',
107 numpad7: 'Ziffernblock 7',
108 numpad8: 'Ziffernblock 8',
109 numpad9: 'Ziffernblock 9',
110 multiply: 'Multiplizieren',
111 add: 'Addieren',
112 subtract: 'Subtrahieren',
113 decimalPoint: 'Punkt',
114 divide: 'Dividieren',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Ziffernblock feststellen',
128 scrollLock: 'Rollen',
129 semiColon: 'Semikolon',
130 equalSign: 'Gleichheitszeichen',
131 comma: 'Komma',
132 dash: 'Bindestrich',
133 period: 'Punkt',
134 forwardSlash: 'Schrägstrich',
135 graveAccent: 'Gravis',
136 openBracket: 'Öffnende eckige Klammer',
137 backSlash: 'Rückwärtsgewandter Schrägstrich',
138 closeBracket: 'Schliessende eckige Klammer',
139 singleQuote: 'Einfaches Anführungszeichen'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/de.js b/sources/plugins/a11yhelp/dialogs/lang/de.js
new file mode 100644
index 0000000..c74be37
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/de.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'de', {
7 title: 'Barrierefreiheitinformationen',
8 contents: 'Hilfeinhalt. Um den Dialog zu schliessen die Taste ESC drücken.',
9 legend: [
10 {
11 name: 'Allgemein',
12 items: [
13 {
14 name: 'Editorwerkzeugleiste',
15 legend: 'Drücken Sie ${toolbarFocus} auf der Symbolleiste. Gehen Sie zur nächsten oder vorherigen Symbolleistengruppe mit TAB und SHIFT+TAB. Gehen Sie zur nächsten oder vorherigen Symbolleiste auf die Schaltfläche mit dem RECHTS- oder LINKS-Pfeil. Drücken Sie die Leertaste oder Eingabetaste, um die Schaltfläche in der Symbolleiste aktivieren.'
16 },
17
18 {
19 name: 'Editordialog',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor-Kontextmenü',
26 legend: 'Dürcken Sie ${contextMenu} oder die Anwendungstaste um das Kontextmenü zu öffnen. Man kann die Pfeiltasten zum Wechsel benutzen. Mit der Leertaste oder der Enter-Taste kann man den Menüpunkt aufrufen. Schliessen Sie das Kontextmenü mit der ESC-Taste.'
27 },
28
29 {
30 name: 'Editor-Listenbox',
31 legend: 'Innerhalb einer Listenbox kann man mit der TAB-Taste oder den Pfeilrunter-Taste den nächsten Menüeintrag wählen. Mit der SHIFT+TAB Tastenkombination oder der Pfeilhoch-Taste gelangt man zum vorherigen Menüpunkt. Mit der Leertaste oder Enter kann man den Menüpunkt auswählen. Drücken Sie ESC zum Verlassen des Menüs.'
32 },
33
34 {
35 name: 'Editor-Elementpfadleiste',
36 legend: 'Drücken Sie ${elementsPathFocus} um sich durch die Pfadleiste zu bewegen. Um zum nächsten Element zu gelangen drücken Sie TAB oder die Pfeilrechts-Taste. Zum vorherigen Element gelangen Sie mit der SHIFT+TAB oder der Pfeillinks-Taste. Drücken Sie die Leertaste oder Enter um das Element auszuwählen.'
37 }
38 ]
39 },
40 {
41 name: 'Befehle',
42 items: [
43 {
44 name: 'Rückgängig-Befehl',
45 legend: 'Drücken Sie ${undo}'
46 },
47 {
48 name: 'Wiederherstellen-Befehl',
49 legend: 'Drücken Sie ${redo}'
50 },
51 {
52 name: 'Fettschrift-Befehl',
53 legend: 'Drücken Sie ${bold}'
54 },
55 {
56 name: 'Kursiv-Befehl',
57 legend: 'Drücken Sie ${italic}'
58 },
59 {
60 name: 'Unterstreichen-Befehl',
61 legend: 'Drücken Sie ${underline}'
62 },
63 {
64 name: 'Link-Befehl',
65 legend: 'Drücken Sie ${link}'
66 },
67 {
68 name: 'Werkzeugleiste einklappen-Befehl',
69 legend: 'Drücken Sie ${toolbarCollapse}'
70 },
71 {
72 name: 'Zugang bisheriger Fokussierung Raumbefehl ',
73 legend: 'Drücken Sie ${accessPreviousSpace} auf den am nächsten nicht erreichbar Fokus-Abstand vor die Einfügemarke zugreifen: zwei benachbarte HR-Elemente. Wiederholen Sie die Tastenkombination um entfernte Fokusräume zu erreichen. '
74 },
75 {
76 name: 'Zugang nächster Schwerpunkt Raumbefehl ',
77 legend: 'Drücken Sie $ { accessNextSpace }, um den nächsten unerreichbar Fokus Leerzeichen nach dem Cursor zum Beispiel auf: zwei benachbarten HR Elemente. Wiederholen Sie die Tastenkombination zum fernen Fokus Bereiche zu erreichen. '
78 },
79 {
80 name: 'Eingabehilfen',
81 legend: 'Drücken Sie ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Feststell',
89 escape: 'Escape',
90 pageUp: 'Bild auf',
91 pageDown: 'Bild ab',
92 leftArrow: 'Linke Pfeiltaste',
93 upArrow: 'Obere Pfeiltaste',
94 rightArrow: 'Rechte Pfeiltaste',
95 downArrow: 'Untere Pfeiltaste',
96 insert: 'Einfügen',
97 leftWindowKey: 'Linke Windowstaste',
98 rightWindowKey: 'Rechte Windowstaste',
99 selectKey: 'Taste auswählen',
100 numpad0: 'Ziffernblock 0',
101 numpad1: 'Ziffernblock 1',
102 numpad2: 'Ziffernblock 2',
103 numpad3: 'Ziffernblock 3',
104 numpad4: 'Ziffernblock 4',
105 numpad5: 'Ziffernblock 5',
106 numpad6: 'Ziffernblock 6',
107 numpad7: 'Ziffernblock 7',
108 numpad8: 'Ziffernblock 8',
109 numpad9: 'Ziffernblock 9',
110 multiply: 'Multiplizieren',
111 add: 'Addieren',
112 subtract: 'Subtrahieren',
113 decimalPoint: 'Punkt',
114 divide: 'Dividieren',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Ziffernblock feststellen',
128 scrollLock: 'Rollen',
129 semiColon: 'Semikolon',
130 equalSign: 'Gleichheitszeichen',
131 comma: 'Komma',
132 dash: 'Bindestrich',
133 period: 'Punkt',
134 forwardSlash: 'Schrägstrich',
135 graveAccent: 'Gravis',
136 openBracket: 'Öffnende eckige Klammer',
137 backSlash: 'Rückwärtsgewandter Schrägstrich',
138 closeBracket: 'Schließende eckige Klammer',
139 singleQuote: 'Einfaches Anführungszeichen'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/el.js b/sources/plugins/a11yhelp/dialogs/lang/el.js
new file mode 100644
index 0000000..11febeb
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/el.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'el', {
7 title: 'Οδηγίες Προσβασιμότητας',
8 contents: 'Περιεχόμενα Βοήθειας. Πατήστε ESC για κλείσιμο.',
9 legend: [
10 {
11 name: 'Γενικά',
12 items: [
13 {
14 name: 'Εργαλειοθήκη Επεξεργαστή',
15 legend: 'Πατήστε ${toolbarFocus} για να περιηγηθείτε στην γραμμή εργαλείων. Μετακινηθείτε ανάμεσα στις ομάδες της γραμμής εργαλείων με TAB και SHIFT+TAB. Μετακινηθείτε ανάμεσα στα κουμπιά εργαλείων με το ΔΕΞΙ ή ΑΡΙΣΤΕΡΟ ΒΕΛΑΚΙ. Πατήστε ΔΙΑΣΤΗΜΑ ή ENTER για να ενεργοποιήσετε το ενεργό κουμπί εργαλείου.'
16 },
17
18 {
19 name: 'Παράθυρο Διαλόγου Επεξεργαστή',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Αναδυόμενο Μενού Επεξεργαστή',
26 legend: 'Πατήστε ${contextMenu} ή APPLICATION KEY για να ανοίξετε το αναδυόμενο μενού. Μετά μετακινηθείτε στην επόμενη επιλογή του μενού με TAB ή ΚΑΤΩ ΒΕΛΑΚΙ. Μετακινηθείτε στην προηγούμενη επιλογή με SHIFT+TAB ή το ΠΑΝΩ ΒΕΛΑΚΙ. Πατήστε ΔΙΑΣΤΗΜΑ ή ENTER για να επιλέξτε το τρέχων στοιχείο. Ανοίξτε το αναδυόμενο μενού της τρέχουσας επιλογής με ΔΙΑΣΤΗΜΑ ή ENTER ή το ΔΕΞΙ ΒΕΛΑΚΙ. Μεταβείτε πίσω στο αρχικό στοιχείο μενού με το ESC ή το ΑΡΙΣΤΕΡΟ ΒΕΛΑΚΙ. Κλείστε το αναδυόμενο μενού με ESC.'
27 },
28
29 {
30 name: 'Κουτί Λίστας Επεξεργαστών',
31 legend: 'Μέσα σε ένα κουτί λίστας, μετακινηθείτε στο επόμενο στοιχείο με TAB ή ΚΑΤΩ ΒΕΛΑΚΙ. Μετακινηθείτε στο προηγούμενο στοιχείο με SHIFT+TAB ή το ΠΑΝΩ ΒΕΛΑΚΙ. Πατήστε ΔΙΑΣΤΗΜΑ ή ENTER για να επιλέξετε ένα στοιχείο. Πατήστε ESC για να κλείσετε το κουτί της λίστας.'
32 },
33
34 {
35 name: 'Μπάρα Διαδρομών Στοιχείων Επεξεργαστή',
36 legend: 'Πατήστε ${elementsPathFocus} για να περιηγηθείτε στην μπάρα διαδρομών στοιχείων του επεξεργαστή. Μετακινηθείτε στο κουμπί του επόμενου στοιχείου με το TAB ή το ΔΕΞΙ ΒΕΛΑΚΙ. Μετακινηθείτε στο κουμπί του προηγούμενου στοιχείου με το SHIFT+TAB ή το ΑΡΙΣΤΕΡΟ ΒΕΛΑΚΙ. Πατήστε ΔΙΑΣΤΗΜΑ ή ENTER για να επιλέξετε το στοιχείο στον επεξεργαστή.'
37 }
38 ]
39 },
40 {
41 name: 'Εντολές',
42 items: [
43 {
44 name: 'Εντολή αναίρεσης',
45 legend: 'Πατήστε ${undo}'
46 },
47 {
48 name: 'Εντολή επανάληψης',
49 legend: 'Πατήστε ${redo}'
50 },
51 {
52 name: 'Εντολή έντονης γραφής',
53 legend: 'Πατήστε ${bold}'
54 },
55 {
56 name: 'Εντολή πλάγιας γραφής',
57 legend: 'Πατήστε ${italic}'
58 },
59 {
60 name: 'Εντολή υπογράμμισης',
61 legend: 'Πατήστε ${underline}'
62 },
63 {
64 name: 'Εντολή συνδέσμου',
65 legend: 'Πατήστε ${link}'
66 },
67 {
68 name: 'Εντολή Σύμπτηξης Εργαλειοθήκης',
69 legend: 'Πατήστε ${toolbarCollapse}'
70 },
71 {
72 name: 'Πρόσβαση στην προηγούμενη εντολή του χώρου εστίασης ',
73 legend: 'Πατήστε ${accessPreviousSpace} για να έχετε πρόσβαση στον πιο κοντινό χώρο εστίασης πριν το δρομέα, για παράδειγμα: δύο παρακείμενα στοιχεία ΥΕ. Επαναλάβετε το συνδυασμό πλήκτρων για να φθάσετε στους χώρους μακρινής εστίασης. '
74 },
75 {
76 name: 'Πρόσβαση στην επόμενη εντολή του χώρου εστίασης',
77 legend: 'Πατήστε ${accessNextSpace} για να έχετε πρόσβαση στον πιο κοντινό χώρο εστίασης μετά το δρομέα, για παράδειγμα: δύο παρακείμενα στοιχεία ΥΕ. Επαναλάβετε το συνδυασμό πλήκτρων για τους χώρους μακρινής εστίασης. '
78 },
79 {
80 name: 'Βοήθεια Προσβασιμότητας',
81 legend: 'Πατήστε ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Αριστερό Βέλος',
93 upArrow: 'Πάνω Βέλος',
94 rightArrow: 'Δεξί Βέλος',
95 downArrow: 'Κάτω Βέλος',
96 insert: 'Insert ',
97 leftWindowKey: 'Αριστερό Πλήκτρο Windows',
98 rightWindowKey: 'Δεξί Πλήκτρο Windows',
99 selectKey: 'Πλήκτρο Select',
100 numpad0: 'Αριθμητικό πληκτρολόγιο 0',
101 numpad1: 'Αριθμητικό Πληκτρολόγιο 1',
102 numpad2: 'Αριθμητικό πληκτρολόγιο 2',
103 numpad3: 'Αριθμητικό πληκτρολόγιο 3',
104 numpad4: 'Αριθμητικό πληκτρολόγιο 4',
105 numpad5: 'Αριθμητικό πληκτρολόγιο 5',
106 numpad6: 'Αριθμητικό πληκτρολόγιο 6',
107 numpad7: 'Αριθμητικό πληκτρολόγιο 7',
108 numpad8: 'Αριθμητικό πληκτρολόγιο 8',
109 numpad9: 'Αριθμητικό πληκτρολόγιο 9',
110 multiply: 'Πολλαπλασιασμός',
111 add: 'Πρόσθεση',
112 subtract: 'Αφαίρεση',
113 decimalPoint: 'Υποδιαστολή',
114 divide: 'Διαίρεση',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: '6',
121 f7: '7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Ερωτηματικό',
130 equalSign: 'Σύμβολο Ισότητας',
131 comma: 'Κόμμα',
132 dash: 'Παύλα',
133 period: 'Τελεία',
134 forwardSlash: 'Κάθετος',
135 graveAccent: 'Βαρεία',
136 openBracket: 'Άνοιγμα Παρένθεσης',
137 backSlash: 'Ανάστροφη Κάθετος',
138 closeBracket: 'Κλείσιμο Παρένθεσης',
139 singleQuote: 'Απόστροφος'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/en-gb.js b/sources/plugins/a11yhelp/dialogs/lang/en-gb.js
new file mode 100644
index 0000000..98bf636
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/en-gb.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'en-gb', {
7 title: 'Accessibility Instructions',
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Editor Toolbar',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box',
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar',
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands',
42 items: [
43 {
44 name: ' Undo command',
45 legend: 'Press ${undo}'
46 },
47 {
48 name: ' Redo command',
49 legend: 'Press ${redo}'
50 },
51 {
52 name: ' Bold command',
53 legend: 'Press ${bold}'
54 },
55 {
56 name: ' Italic command',
57 legend: 'Press ${italic}'
58 },
59 {
60 name: ' Underline command',
61 legend: 'Press ${underline}'
62 },
63 {
64 name: ' Link command',
65 legend: 'Press ${link}'
66 },
67 {
68 name: ' Toolbar Collapse command',
69 legend: 'Press ${toolbarCollapse}'
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help',
81 legend: 'Press ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Left Arrow',
93 upArrow: 'Up Arrow',
94 rightArrow: 'Right Arrow',
95 downArrow: 'Down Arrow',
96 insert: 'Insert',
97 leftWindowKey: 'Left Windows key',
98 rightWindowKey: 'Right Windows key',
99 selectKey: 'Select key',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Multiply',
111 add: 'Add',
112 subtract: 'Subtract',
113 decimalPoint: 'Decimal Point',
114 divide: 'Divide',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semicolon',
130 equalSign: 'Equal Sign',
131 comma: 'Comma',
132 dash: 'Dash',
133 period: 'Period',
134 forwardSlash: 'Forward Slash',
135 graveAccent: 'Grave Accent',
136 openBracket: 'Open Bracket',
137 backSlash: 'Backslash',
138 closeBracket: 'Close Bracket',
139 singleQuote: 'Single Quote'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/en.js b/sources/plugins/a11yhelp/dialogs/lang/en.js
new file mode 100644
index 0000000..fee0b4e
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/en.js
@@ -0,0 +1,159 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'en', {
7 title: 'Accessibility Instructions',
8 contents: 'Help Contents. To close this dialog press ESC.',
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Editor Toolbar',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. ' +
16 'Move to the next and previous toolbar group with TAB and SHIFT+TAB. ' +
17 'Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. ' +
18 'Press SPACE or ENTER to activate the toolbar button.'
19 },
20
21 {
22 name: 'Editor Dialog',
23 legend:
24 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. ' +
25 'When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. ' +
26 'With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.'
27 },
28
29 {
30 name: 'Editor Context Menu',
31 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. ' +
32 'Then move to next menu option with TAB or DOWN ARROW. ' +
33 'Move to previous option with SHIFT+TAB or UP ARROW. ' +
34 'Press SPACE or ENTER to select the menu option. ' +
35 'Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. ' +
36 'Go back to parent menu item with ESC or LEFT ARROW. ' +
37 'Close context menu with ESC.'
38 },
39
40 {
41 name: 'Editor List Box',
42 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. ' +
43 'Move to previous list item with SHIFT+TAB or UP ARROW. ' +
44 'Press SPACE or ENTER to select the list option. ' +
45 'Press ESC to close the list-box.'
46 },
47
48 {
49 name: 'Editor Element Path Bar',
50 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. ' +
51 'Move to next element button with TAB or RIGHT ARROW. ' +
52 'Move to previous button with SHIFT+TAB or LEFT ARROW. ' +
53 'Press SPACE or ENTER to select the element in editor.'
54 }
55 ]
56 },
57 {
58 name: 'Commands',
59 items: [
60 {
61 name: ' Undo command',
62 legend: 'Press ${undo}'
63 },
64 {
65 name: ' Redo command',
66 legend: 'Press ${redo}'
67 },
68 {
69 name: ' Bold command',
70 legend: 'Press ${bold}'
71 },
72 {
73 name: ' Italic command',
74 legend: 'Press ${italic}'
75 },
76 {
77 name: ' Underline command',
78 legend: 'Press ${underline}'
79 },
80 {
81 name: ' Link command',
82 legend: 'Press ${link}'
83 },
84 {
85 name: ' Toolbar Collapse command',
86 legend: 'Press ${toolbarCollapse}'
87 },
88 {
89 name: ' Access previous focus space command',
90 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, ' +
91 'for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.'
92 },
93 {
94 name: ' Access next focus space command',
95 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, ' +
96 'for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.'
97 },
98 {
99 name: ' Accessibility Help',
100 legend: 'Press ${a11yHelp}'
101 }
102 ]
103 }
104 ],
105 tab: 'Tab',
106 pause: 'Pause',
107 capslock: 'Caps Lock',
108 escape: 'Escape',
109 pageUp: 'Page Up',
110 pageDown: 'Page Down',
111 leftArrow: 'Left Arrow',
112 upArrow: 'Up Arrow',
113 rightArrow: 'Right Arrow',
114 downArrow: 'Down Arrow',
115 insert: 'Insert',
116 leftWindowKey: 'Left Windows key',
117 rightWindowKey: 'Right Windows key',
118 selectKey: 'Select key',
119 numpad0: 'Numpad 0',
120 numpad1: 'Numpad 1',
121 numpad2: 'Numpad 2',
122 numpad3: 'Numpad 3',
123 numpad4: 'Numpad 4',
124 numpad5: 'Numpad 5',
125 numpad6: 'Numpad 6',
126 numpad7: 'Numpad 7',
127 numpad8: 'Numpad 8',
128 numpad9: 'Numpad 9',
129 multiply: 'Multiply',
130 add: 'Add',
131 subtract: 'Subtract',
132 decimalPoint: 'Decimal Point',
133 divide: 'Divide',
134 f1: 'F1',
135 f2: 'F2',
136 f3: 'F3',
137 f4: 'F4',
138 f5: 'F5',
139 f6: 'F6',
140 f7: 'F7',
141 f8: 'F8',
142 f9: 'F9',
143 f10: 'F10',
144 f11: 'F11',
145 f12: 'F12',
146 numLock: 'Num Lock',
147 scrollLock: 'Scroll Lock',
148 semiColon: 'Semicolon',
149 equalSign: 'Equal Sign',
150 comma: 'Comma',
151 dash: 'Dash',
152 period: 'Period',
153 forwardSlash: 'Forward Slash',
154 graveAccent: 'Grave Accent',
155 openBracket: 'Open Bracket',
156 backSlash: 'Backslash',
157 closeBracket: 'Close Bracket',
158 singleQuote: 'Single Quote'
159} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/eo.js b/sources/plugins/a11yhelp/dialogs/lang/eo.js
new file mode 100644
index 0000000..c2bc106
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/eo.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'eo', {
7 title: 'Uzindikoj pri atingeblo',
8 contents: 'Helpilenhavo. Por fermi tiun dialogon, premu la ESKAPAN klavon.',
9 legend: [
10 {
11 name: 'Ĝeneralaĵoj',
12 items: [
13 {
14 name: 'Ilbreto de la redaktilo',
15 legend: 'Premu ${toolbarFocus} por atingi la ilbreton. Moviĝu al la sekva aŭ antaŭa grupoj de la ilbreto per la klavoj TABA kaj MAJUSKLIGA+TABA. Moviĝu al la sekva aŭ antaŭa butonoj de la ilbreto per la klavoj SAGO DEKSTREN kaj SAGO MALDEKSTREN. Premu la SPACETklavon aŭ la ENENklavon por aktivigi la ilbretbutonon.'
16 },
17
18 {
19 name: 'Redaktildialogo',
20 legend:
21 'En dialogo, premu la TABAN klavon por navigi al la sekva dialogelemento, premu la MAJUSKLIGAN+TABAN klavon por iri al la antaŭa dialogelemento, premu la ENEN klavon por sendi la dialogon, premu la ESKAPAN klavon por nuligi la dialogon. Kiam dialogo havas multajn langetojn, eblas atingi la langetliston aŭ per ALT+F10 aŭ per la TABA klavo kiel parton de la dialoga taba ordo. En langetlisto, moviĝu al la sekva kaj antaŭa langeto per la klavoj SAGO DEKSTREN KAJ MALDEKSTREN respektive.'
22 },
23
24 {
25 name: 'Kunteksta menuo de la redaktilo',
26 legend: 'Premu ${contextMenu} aŭ entajpu la KLAVKOMBINAĴON por malfermi la kuntekstan menuon. Poste moviĝu al la sekva opcio de la menuo per la klavoj TABA aŭ SAGO SUBEN. Moviĝu al la antaŭa opcio per la klavoj MAJUSKLGA + TABA aŭ SAGO SUPREN. Premu la SPACETklavon aŭ ENENklavon por selekti la menuopcion. Malfermu la submenuon de la kuranta opcio per la SPACETklavo aŭ la ENENklavo aŭ la SAGO DEKSTREN. Revenu al la elemento de la patra menuo per la klavoj ESKAPA aŭ SAGO MALDEKSTREN. Fermu la kuntekstan menuon per la ESKAPA klavo.'
27 },
28
29 {
30 name: 'Fallisto de la redaktilo',
31 legend: 'En fallisto, moviĝu al la sekva listelemento per la klavoj TABA aŭ SAGO SUBEN. Moviĝu al la antaŭa listelemento per la klavoj MAJUSKLIGA+TABA aŭ SAGO SUPREN. Premu la SPACETklavon aŭ ENENklavon por selekti la opcion en la listo. Premu la ESKAPAN klavon por fermi la falmenuon.'
32 },
33
34 {
35 name: 'Breto indikanta la vojon al la redaktilelementoj',
36 legend: 'Premu ${elementsPathFocus} por navigi al la breto indikanta la vojon al la redaktilelementoj. Moviĝu al la butono de la sekva elemento per la klavoj TABA aŭ SAGO DEKSTREN. Moviĝu al la butono de la antaŭa elemento per la klavoj MAJUSKLIGA+TABA aŭ SAGO MALDEKSTREN. Premu la SPACETklavon aŭ ENENklavon por selekti la elementon en la redaktilo.'
37 }
38 ]
39 },
40 {
41 name: 'Komandoj',
42 items: [
43 {
44 name: 'Komando malfari',
45 legend: 'Premu ${undo}'
46 },
47 {
48 name: 'Komando refari',
49 legend: 'Premu ${redo}'
50 },
51 {
52 name: 'Komando grasa',
53 legend: 'Premu ${bold}'
54 },
55 {
56 name: 'Komando kursiva',
57 legend: 'Premu ${italic}'
58 },
59 {
60 name: 'Komando substreki',
61 legend: 'Premu ${underline}'
62 },
63 {
64 name: 'Komando ligilo',
65 legend: 'Premu ${link}'
66 },
67 {
68 name: 'Komando faldi la ilbreton',
69 legend: 'Premu ${toolbarCollapse}'
70 },
71 {
72 name: 'Komando por atingi la antaŭan fokusan spacon',
73 legend: 'Press ${accessPreviousSpace} por atingi la plej proksiman neatingeblan fokusan spacon antaŭ la kursoro, ekzemple : du kuntuŝiĝajn HR elementojn. Ripetu la klavkombinaĵon por atingi malproksimajn fokusajn spacojn.'
74 },
75 {
76 name: 'Komando por atingi la sekvan fokusan spacon',
77 legend: 'Press ${accessNextSpace} por atingi la plej proksiman neatingeblan fokusan spacon post la kursoro, ekzemple : du kuntuŝiĝajn HR elementojn. Ripetu la klavkombinajôn por atingi malproksimajn fokusajn spacojn'
78 },
79 {
80 name: 'Helpilo pri atingeblo',
81 legend: 'Premu ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabo',
87 pause: 'Paŭzo',
88 capslock: 'Majuskla baskulo',
89 escape: 'Eskapa klavo',
90 pageUp: 'Antaŭa Paĝo',
91 pageDown: 'Sekva Paĝo',
92 leftArrow: 'Sago Maldekstren',
93 upArrow: 'Sago Supren',
94 rightArrow: 'Sago Dekstren',
95 downArrow: 'Sago Suben',
96 insert: 'Enmeti',
97 leftWindowKey: 'Maldekstra Windows-klavo',
98 rightWindowKey: 'Dekstra Windows-klavo',
99 selectKey: 'Selektklavo',
100 numpad0: 'Nombra Klavaro 0',
101 numpad1: 'Nombra Klavaro 1',
102 numpad2: 'Nombra Klavaro 2',
103 numpad3: 'Nombra Klavaro 3',
104 numpad4: 'Nombra Klavaro 4',
105 numpad5: 'Nombra Klavaro 5',
106 numpad6: 'Nombra Klavaro 6',
107 numpad7: 'Nombra Klavaro 7',
108 numpad8: 'Nombra Klavaro 8',
109 numpad9: 'Nombra Klavaro 9',
110 multiply: 'Obligi',
111 add: 'Almeti',
112 subtract: 'Subtrahi',
113 decimalPoint: 'Dekuma Punkto',
114 divide: 'Dividi',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Nombra Baskulo',
128 scrollLock: 'Ruluma Baskulo',
129 semiColon: 'Punktokomo',
130 equalSign: 'Egalsigno',
131 comma: 'Komo',
132 dash: 'Haltostreko',
133 period: 'Punkto',
134 forwardSlash: 'Oblikvo',
135 graveAccent: 'Malakuto',
136 openBracket: 'Malferma Krampo',
137 backSlash: 'Retroklino',
138 closeBracket: 'Ferma Krampo',
139 singleQuote: 'Citilo'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/es.js b/sources/plugins/a11yhelp/dialogs/lang/es.js
new file mode 100644
index 0000000..b1eaa20
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/es.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'es', {
7 title: 'Instrucciones de accesibilidad',
8 contents: 'Ayuda. Para cerrar presione ESC.',
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Barra de herramientas del editor',
15 legend: 'Presiona ${toolbarFocus} para navegar por la barra de herramientas. Para moverse por los distintos grupos de herramientas usa las teclas TAB y MAY+TAB. Para moverse por las distintas herramientas usa FLECHA DERECHA o FECHA IZQUIERDA. Presiona "espacio" o "intro" para activar la herramienta.'
16 },
17
18 {
19 name: 'Editor de diálogo',
20 legend:
21 'Dentro del diálogo, presione TAB para navegar a los siguientes elementos de diálogo, presione SHIFT+TAB para moverse a los anteriores elementos de diálogo, presione ENTER para enviar el diálogo, presiona ESC para cancelar el diálogo. Cuando el diálogo tiene multiples pestañas, la lista de pestañas puede ser abarcada con ALT + F10 or con TAB como parte del orden de pestañas del diálogo. ECon la pestaña enfocada, puede moverse a la siguiente o anterior pestaña con las FLECHAS IZQUIRDA y DERECHA respectivamente.'
22 },
23
24 {
25 name: 'Editor del menú contextual',
26 legend: 'Presiona ${contextMenu} o TECLA MENÚ para abrir el menú contextual. Entonces muévete a la siguiente opción del menú con TAB o FLECHA ABAJO. Muévete a la opción previa con SHIFT + TAB o FLECHA ARRIBA. Presiona ESPACIO o ENTER para seleccionar la opción del menú. Abre el submenú de la opción actual con ESPACIO o ENTER o FLECHA DERECHA. Regresa al elemento padre del menú con ESC o FLECHA IZQUIERDA. Cierra el menú contextual con ESC.'
27 },
28
29 {
30 name: 'Lista del Editor',
31 legend: 'Dentro de una lista, te mueves al siguiente elemento de la lista con TAB o FLECHA ABAJO. Te mueves al elemento previo de la lista con SHIFT+TAB o FLECHA ARRIBA. Presiona ESPACIO o ENTER para elegir la opción de la lista. Presiona ESC para cerrar la lista.'
32 },
33
34 {
35 name: 'Barra de Ruta del Elemento en el Editor',
36 legend: 'Presiona ${elementsPathFocus} para navegar a los elementos de la barra de ruta. Te mueves al siguiente elemento botón con TAB o FLECHA DERECHA. Te mueves al botón previo con SHIFT+TAB o FLECHA IZQUIERDA. Presiona ESPACIO o ENTER para seleccionar el elemento en el editor.'
37 }
38 ]
39 },
40 {
41 name: 'Comandos',
42 items: [
43 {
44 name: 'Comando deshacer',
45 legend: 'Presiona ${undo}'
46 },
47 {
48 name: 'Comando rehacer',
49 legend: 'Presiona ${redo}'
50 },
51 {
52 name: 'Comando negrita',
53 legend: 'Presiona ${bold}'
54 },
55 {
56 name: 'Comando itálica',
57 legend: 'Presiona ${italic}'
58 },
59 {
60 name: 'Comando subrayar',
61 legend: 'Presiona ${underline}'
62 },
63 {
64 name: 'Comando liga',
65 legend: 'Presiona ${liga}'
66 },
67 {
68 name: 'Comando colapsar barra de herramientas',
69 legend: 'Presiona ${toolbarCollapse}'
70 },
71 {
72 name: 'Comando accesar el anterior espacio de foco',
73 legend: 'Presiona ${accessPreviousSpace} para accesar el espacio de foco no disponible más cercano anterior al cursor, por ejemplo: dos elementos HR adyacentes. Repite la combinación de teclas para alcanzar espacios de foco distantes.'
74 },
75 {
76 name: 'Comando accesar el siguiente spacio de foco',
77 legend: 'Presiona ${accessNextSpace} para accesar el espacio de foco no disponible más cercano después del cursor, por ejemplo: dos elementos HR adyacentes. Repite la combinación de teclas para alcanzar espacios de foco distantes.'
78 },
79 {
80 name: 'Ayuda de Accesibilidad',
81 legend: 'Presiona ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulador',
87 pause: 'Pausa',
88 capslock: 'Bloq. Mayús.',
89 escape: 'Escape',
90 pageUp: 'Regresar Página',
91 pageDown: 'Avanzar Página',
92 leftArrow: 'Flecha Izquierda',
93 upArrow: 'Flecha Arriba',
94 rightArrow: 'Flecha Derecha',
95 downArrow: 'Flecha Abajo',
96 insert: 'Insertar',
97 leftWindowKey: 'Tecla Windows Izquierda',
98 rightWindowKey: 'Tecla Windows Derecha',
99 selectKey: 'Tecla de Selección',
100 numpad0: 'Tecla 0 del teclado numérico',
101 numpad1: 'Tecla 1 del teclado numérico',
102 numpad2: 'Tecla 2 del teclado numérico',
103 numpad3: 'Tecla 3 del teclado numérico',
104 numpad4: 'Tecla 4 del teclado numérico',
105 numpad5: 'Tecla 5 del teclado numérico',
106 numpad6: 'Tecla 6 del teclado numérico',
107 numpad7: 'Tecla 7 del teclado numérico',
108 numpad8: 'Tecla 8 del teclado numérico',
109 numpad9: 'Tecla 9 del teclado numérico',
110 multiply: 'Multiplicar',
111 add: 'Sumar',
112 subtract: 'Restar',
113 decimalPoint: 'Punto Decimal',
114 divide: 'Dividir',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Punto y coma',
130 equalSign: 'Signo de Igual',
131 comma: 'Coma',
132 dash: 'Guión',
133 period: 'Punto',
134 forwardSlash: 'Diagonal',
135 graveAccent: 'Acento Grave',
136 openBracket: 'Abrir llave',
137 backSlash: 'Diagonal Invertida',
138 closeBracket: 'Cerrar llave',
139 singleQuote: 'Comillas simples'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/et.js b/sources/plugins/a11yhelp/dialogs/lang/et.js
new file mode 100644
index 0000000..0146089
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/et.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'et', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Abi sisu. Selle dialoogi sulgemiseks vajuta ESC klahvi.',
9 legend: [
10 {
11 name: 'Üldine',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/eu.js b/sources/plugins/a11yhelp/dialogs/lang/eu.js
new file mode 100644
index 0000000..b53748f
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/eu.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'eu', {
7 title: 'Erabilerraztasunaren argibideak',
8 contents: 'Laguntzaren edukiak. Elkarrizketa-koadro hau ixteko sakatu ESC.',
9 legend: [
10 {
11 name: 'Orokorra',
12 items: [
13 {
14 name: 'Editorearen tresna-barra',
15 legend: 'Sakatu ${toolbarFocus} tresna-barrara nabigatzeko. Tresna-barrako aurreko eta hurrengo taldera joateko erabili TAB eta MAIUS+TAB. Tresna-barrako aurreko eta hurrengo botoira joateko erabili ESKUIN-GEZIA eta EZKER-GEZIA. Sakatu ZURIUNEA edo SARTU tresna-barrako botoia aktibatzeko.'
16 },
17
18 {
19 name: 'Editorearen elkarrizketa-koadroa',
20 legend:
21 'Elkarrizketa-koadro baten barruan sakatu TAB hurrengo elementura nabigatzeko, sakatu MAIUS+TAB aurreko elementura joateko, sakatu SARTU elkarrizketa-koadroa bidaltzeko eta sakatu ESC uzteko. Elkarrizketa-koadro batek hainbat fitxa dituenean, ALT+F10 erabiliz irits daiteke fitxen zerrendara, edo TAB erabiliz. Fokoa fitxen zerrendak duenean, aurreko eta hurrengo fitxetara joateko erabili EZKER-GEZIA eta ESKUIN-GEZIA.'
22 },
23
24 {
25 name: 'Editorearen testuinguru-menua',
26 legend: 'Sakatu ${contextMenu} edo APLIKAZIO TEKLA testuinguru-menua irekitzeko. Menuko hurrengo aukerara joateko erabili TAB edo BEHERA GEZIA. Aurreko aukerara nabigatzeko erabili MAIUS+TAB edo GORA GEZIA. Sakatu ZURIUNEA edo SARTU menuko aukera hautatzeko. Ireki uneko aukeraren azpi-menua ZURIUNEA edo SARTU edo ESKUIN-GEZIA erabiliz. Menuko aukera gurasora itzultzeko erabili ESC edo EZKER-GEZIA. Testuinguru-menua ixteko sakatu ESC.'
27 },
28
29 {
30 name: 'Editorearen zerrenda-koadroa',
31 legend: 'Zerrenda-koadro baten barruan, zerrendako hurrengo elementura joateko erabili TAB edo BEHERA GEZIA. Zerrendako aurreko elementura nabigatzeko MAIUS+TAB edo GORA GEZIA. Sakatu ZURIUNEA edo SARTU zerrendako aukera hautatzeko. Sakatu ESC zerrenda-koadroa ixteko.'
32 },
33
34 {
35 name: 'Editorearen elementuaren bide-barra',
36 legend: 'Sakatu ${elementsPathFocus} elementuaren bide-barrara nabigatzeko. Hurrengo elementuaren botoira joateko erabili TAB edo ESKUIN-GEZIA. Aurreko botoira joateko aldiz erabili MAIUS+TAB edo EZKER-GEZIA. Elementua editorean hautatzeko sakatu ZURIUNEA edo SARTU.'
37 }
38 ]
39 },
40 {
41 name: 'Komandoak',
42 items: [
43 {
44 name: 'Desegin komandoa',
45 legend: 'Sakatu ${undo}'
46 },
47 {
48 name: 'Berregin komandoa',
49 legend: 'Sakatu ${redo}'
50 },
51 {
52 name: 'Lodia komandoa',
53 legend: 'Sakatu ${bold}'
54 },
55 {
56 name: 'Etzana komandoa',
57 legend: 'Sakatu ${italic}'
58 },
59 {
60 name: 'Azpimarratu komandoa',
61 legend: 'Sakatu ${underline}'
62 },
63 {
64 name: 'Esteka komandoa',
65 legend: 'Sakatu ${link}'
66 },
67 {
68 name: 'Tolestu tresna-barra komandoa',
69 legend: 'Sakatu ${toolbarCollapse}'
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: 'Erabilerraztasunaren laguntza',
81 legend: 'Sakatu ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabuladorea',
87 pause: 'Pausatu',
88 capslock: 'Blok Maius',
89 escape: 'Ihes',
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Ezker-gezia',
93 upArrow: 'Gora gezia',
94 rightArrow: 'Eskuin-gezia',
95 downArrow: 'Behera gezia',
96 insert: 'Txertatu',
97 leftWindowKey: 'Ezkerreko Windows tekla',
98 rightWindowKey: 'Eskuineko Windows tekla',
99 selectKey: 'Hautatu tekla',
100 numpad0: 'Zenbakizko teklatua 0',
101 numpad1: 'Zenbakizko teklatua 1',
102 numpad2: 'Zenbakizko teklatua 2',
103 numpad3: 'Zenbakizko teklatua 3',
104 numpad4: 'Zenbakizko teklatua 4',
105 numpad5: 'Zenbakizko teklatua 5',
106 numpad6: 'Zenbakizko teklatua 6',
107 numpad7: 'Zenbakizko teklatua 7',
108 numpad8: 'Zenbakizko teklatua 8',
109 numpad9: 'Zenbakizko teklatua 9',
110 multiply: 'Biderkatu',
111 add: 'Gehitu',
112 subtract: 'Kendu',
113 decimalPoint: 'Koma hamartarra',
114 divide: 'Zatitu',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Blok Zenb',
128 scrollLock: 'Blok Korr',
129 semiColon: 'Puntu eta koma',
130 equalSign: 'Berdin zeinua',
131 comma: 'Koma',
132 dash: 'Marratxoa',
133 period: 'Puntua',
134 forwardSlash: 'Barra',
135 graveAccent: 'Azentu kamutsa',
136 openBracket: 'Parentesia ireki',
137 backSlash: 'Alderantzizko barra',
138 closeBracket: 'Itxi parentesia',
139 singleQuote: 'Komatxo bakuna'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/fa.js b/sources/plugins/a11yhelp/dialogs/lang/fa.js
new file mode 100644
index 0000000..88072f0
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/fa.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'fa', {
7 title: 'دستورالعمل‌های دسترسی',
8 contents: 'راهنمای فهرست مطالب. برای بستن این کادر محاوره‌ای ESC را فشار دهید.',
9 legend: [
10 {
11 name: 'عمومی',
12 items: [
13 {
14 name: 'نوار ابزار ویرایشگر',
15 legend: '${toolbarFocus} را برای باز کردن نوار ابزار بفشارید. با کلید Tab و Shift+Tab در مجموعه نوار ابزار بعدی و قبلی حرکت کنید. برای حرکت در کلید نوار ابزار قبلی و بعدی با کلید جهت‌نمای راست و چپ جابجا شوید. کلید Space یا Enter را برای فعال کردن کلید نوار ابزار بفشارید.'
16 },
17
18 {
19 name: 'پنجره محاورهای ویرایشگر',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'منوی متنی ویرایشگر',
26 legend: '${contextMenu} یا کلید برنامههای کاربردی را برای باز کردن منوی متن را بفشارید. سپس میتوانید برای حرکت به گزینه بعدی منو با کلید Tab و یا کلید جهتنمای پایین جابجا شوید. حرکت به گزینه قبلی با Shift+Tab یا کلید جهتنمای بالا. فشردن Space یا Enter برای انتخاب یک گزینه از منو. باز کردن زیر شاخه گزینه منو جاری با کلید Space یا Enter و یا کلید جهتنمای راست و چپ. بازگشت به منوی والد با کلید Esc یا کلید جهتنمای چپ. بستن منوی متن با Esc.'
27 },
28
29 {
30 name: 'جعبه فهرست ویرایشگر',
31 legend: 'در داخل جعبه لیست، قلم دوم از اقلام لیست بعدی را با TAB و یا Arrow Down حرکت دهید. انتقال به قلم دوم از اقلام لیست قبلی را با SHIFT + TAB یا UP ARROW. کلید Space یا ENTER را برای انتخاب گزینه لیست بفشارید. کلید ESC را برای بستن جعبه لیست بفشارید.'
32 },
33
34 {
35 name: 'ویرایشگر عنصر نوار راه',
36 legend: 'برای رفتن به مسیر عناصر ${elementsPathFocus} را بفشارید. حرکت به کلید عنصر بعدی با کلید Tab یا کلید جهت‌نمای راست. برگشت به کلید قبلی با Shift+Tab یا کلید جهت‌نمای چپ. فشردن Space یا Enter برای انتخاب یک عنصر در ویرایشگر.'
37 }
38 ]
39 },
40 {
41 name: 'فرمان‌ها',
42 items: [
43 {
44 name: 'بازگشت به آخرین فرمان',
45 legend: 'فشردن ${undo}'
46 },
47 {
48 name: 'انجام مجدد فرمان',
49 legend: 'فشردن ${redo}'
50 },
51 {
52 name: 'فرمان درشت کردن متن',
53 legend: 'فشردن ${bold}'
54 },
55 {
56 name: 'فرمان کج کردن متن',
57 legend: 'فشردن ${italic}'
58 },
59 {
60 name: 'فرمان زیرخطدار کردن متن',
61 legend: 'فشردن ${underline}'
62 },
63 {
64 name: 'فرمان پیوند دادن',
65 legend: 'فشردن ${link}'
66 },
67 {
68 name: 'بستن نوار ابزار فرمان',
69 legend: 'فشردن ${toolbarCollapse}'
70 },
71 {
72 name: 'دسترسی به فرمان محل تمرکز قبلی',
73 legend: 'فشردن ${accessPreviousSpace} برای دسترسی به نزدیک‌ترین فضای قابل دسترسی تمرکز قبل از هشتک، برای مثال: دو عنصر مجاور HR -خط افقی-. تکرار کلید ترکیبی برای رسیدن به فضاهای تمرکز از راه دور.'
74 },
75 {
76 name: 'دسترسی به فضای دستور بعدی',
77 legend: 'برای دسترسی به نزدیک‌ترین فضای تمرکز غیر قابل دسترس، ${accessNextSpace} را پس از علامت هشتک بفشارید، برای مثال: دو عنصر مجاور HR -خط افقی-. کلید ترکیبی را برای رسیدن به فضای تمرکز تکرار کنید.'
78 },
79 {
80 name: 'راهنمای دسترسی',
81 legend: 'فشردن ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'برگه',
87 pause: 'توقف',
88 capslock: 'Caps Lock',
89 escape: 'گریز',
90 pageUp: 'صفحه به بالا',
91 pageDown: 'صفحه به پایین',
92 leftArrow: 'پیکان چپ',
93 upArrow: 'پیکان بالا',
94 rightArrow: 'پیکان راست',
95 downArrow: 'پیکان پایین',
96 insert: 'ورود',
97 leftWindowKey: 'کلید چپ ویندوز',
98 rightWindowKey: 'کلید راست ویندوز',
99 selectKey: 'انتخاب کلید',
100 numpad0: 'کلید شماره 0',
101 numpad1: 'کلید شماره 1',
102 numpad2: 'کلید شماره 2',
103 numpad3: 'کلید شماره 3',
104 numpad4: 'کلید شماره 4',
105 numpad5: 'کلید شماره 5',
106 numpad6: 'کلید شماره 6',
107 numpad7: 'کلید شماره 7',
108 numpad8: 'کلید شماره 8',
109 numpad9: 'کلید شماره 9',
110 multiply: 'ضرب',
111 add: 'افزودن',
112 subtract: 'تفریق',
113 decimalPoint: 'نقطه‌ی اعشار',
114 divide: 'جدا کردن',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semicolon',
130 equalSign: 'علامت تساوی',
131 comma: 'کاما',
132 dash: 'خط تیره',
133 period: 'دوره',
134 forwardSlash: 'Forward Slash',
135 graveAccent: 'Grave Accent',
136 openBracket: 'Open Bracket',
137 backSlash: 'Backslash',
138 closeBracket: 'Close Bracket',
139 singleQuote: 'Single Quote'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/fi.js b/sources/plugins/a11yhelp/dialogs/lang/fi.js
new file mode 100644
index 0000000..093d409
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/fi.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'fi', {
7 title: 'Saavutettavuus ohjeet',
8 contents: 'Ohjeen sisällöt. Sulkeaksesi tämän dialogin paina ESC.',
9 legend: [
10 {
11 name: 'Yleinen',
12 items: [
13 {
14 name: 'Editorin työkalupalkki',
15 legend: 'Paina ${toolbarFocus} siirtyäksesi työkalupalkkiin. Siirry seuraavaan ja edelliseen työkalupalkin ryhmään TAB ja SHIFT+TAB näppäimillä. Siirry seuraavaan ja edelliseen työkalupainikkeeseen käyttämällä NUOLI OIKEALLE tai NUOLI VASEMMALLE näppäimillä. Paina VÄLILYÖNTI tai ENTER näppäintä aktivoidaksesi työkalupainikkeen.'
16 },
17
18 {
19 name: 'Editorin dialogi',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editorin oheisvalikko',
26 legend: 'Paina ${contextMenu} tai SOVELLUSPAINIKETTA avataksesi oheisvalikon. Liiku seuraavaan valikon vaihtoehtoon TAB tai NUOLI ALAS näppäimillä. Siirry edelliseen vaihtoehtoon SHIFT+TAB tai NUOLI YLÖS näppäimillä. Paina VÄLILYÖNTI tai ENTER valitaksesi valikon kohdan. Avataksesi nykyisen kohdan alivalikon paina VÄLILYÖNTI tai ENTER tai NUOLI OIKEALLE painiketta. Siirtyäksesi takaisin valikon ylemmälle tasolle paina ESC tai NUOLI vasemmalle. Oheisvalikko suljetaan ESC painikkeella.'
27 },
28
29 {
30 name: 'Editorin listalaatikko',
31 legend: 'Listalaatikon sisällä siirry seuraavaan listan kohtaan TAB tai NUOLI ALAS painikkeilla. Siirry edelliseen listan kohtaan SHIFT+TAB tai NUOLI YLÖS painikkeilla. Paina VÄLILYÖNTI tai ENTER valitaksesi listan vaihtoehdon. Paina ESC sulkeaksesi listalaatikon.'
32 },
33
34 {
35 name: 'Editorin elementtipolun palkki',
36 legend: 'Paina ${elementsPathFocus} siirtyäksesi elementtipolun palkkiin. Siirry seuraavaan elementtipainikkeeseen TAB tai NUOLI OIKEALLE painikkeilla. Siirry aiempaan painikkeeseen SHIFT+TAB tai NUOLI VASEMMALLE painikkeilla. Paina VÄLILYÖNTI tai ENTER valitaksesi elementin editorissa.'
37 }
38 ]
39 },
40 {
41 name: 'Komennot',
42 items: [
43 {
44 name: 'Peruuta komento',
45 legend: 'Paina ${undo}'
46 },
47 {
48 name: 'Tee uudelleen komento',
49 legend: 'Paina ${redo}'
50 },
51 {
52 name: 'Lihavoi komento',
53 legend: 'Paina ${bold}'
54 },
55 {
56 name: 'Kursivoi komento',
57 legend: 'Paina ${italic}'
58 },
59 {
60 name: 'Alleviivaa komento',
61 legend: 'Paina ${underline}'
62 },
63 {
64 name: 'Linkki komento',
65 legend: 'Paina ${link}'
66 },
67 {
68 name: 'Pienennä työkalupalkki komento',
69 legend: 'Paina ${toolbarCollapse}'
70 },
71 {
72 name: 'Siirry aiempaan fokustilaan komento',
73 legend: 'Paina ${accessPreviousSpace} siiryäksesi lähimpään kursorin edellä olevaan saavuttamattomaan fokustilaan, esimerkiksi: kaksi vierekkäistä HR elementtiä. Toista näppäinyhdistelmää päästäksesi kauempana oleviin fokustiloihin.'
74 },
75 {
76 name: 'Siirry seuraavaan fokustilaan komento',
77 legend: 'Paina ${accessPreviousSpace} siiryäksesi lähimpään kursorin jälkeen olevaan saavuttamattomaan fokustilaan, esimerkiksi: kaksi vierekkäistä HR elementtiä. Toista näppäinyhdistelmää päästäksesi kauempana oleviin fokustiloihin.'
78 },
79 {
80 name: 'Saavutettavuus ohjeet',
81 legend: 'Paina ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numeronäppäimistö 0',
101 numpad1: 'Numeronäppäimistö 1',
102 numpad2: 'Numeronäppäimistö 2',
103 numpad3: 'Numeronäppäimistö 3',
104 numpad4: 'Numeronäppäimistö 4',
105 numpad5: 'Numeronäppäimistö 5',
106 numpad6: 'Numeronäppäimistö 6',
107 numpad7: 'Numeronäppäimistö 7',
108 numpad8: 'Numeronäppäimistö 8',
109 numpad9: 'Numeronäppäimistö 9',
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Puolipiste',
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Pilkku',
132 dash: 'Dash', // MISSING
133 period: 'Piste',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/fo.js b/sources/plugins/a11yhelp/dialogs/lang/fo.js
new file mode 100644
index 0000000..efce724
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/fo.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'fo', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'General', // MISSING
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Falda',
111 add: 'Pluss',
112 subtract: 'Frádráttar',
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Býta',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semikolon',
130 equalSign: 'Javnatekn',
131 comma: 'Komma',
132 dash: 'Dash', // MISSING
133 period: 'Punktum',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/fr-ca.js b/sources/plugins/a11yhelp/dialogs/lang/fr-ca.js
new file mode 100644
index 0000000..c87c586
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/fr-ca.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'fr-ca', {
7 title: 'Instructions d\'accessibilité',
8 contents: 'Contenu de l\'aide. Pour fermer cette fenêtre, appuyez sur ESC.',
9 legend: [
10 {
11 name: 'Général',
12 items: [
13 {
14 name: 'Barre d\'outil de l\'éditeur',
15 legend: 'Appuyer sur ${toolbarFocus} pour accéder à la barre d\'outils. Se déplacer vers les groupes suivant ou précédent de la barre d\'outil avec les touches TAB et SHIFT+TAB. Se déplacer vers les boutons suivant ou précédent de la barre d\'outils avec les touches FLECHE DROITE et FLECHE GAUCHE. Appuyer sur la barre d\'espace ou la touche ENTRER pour activer le bouton de barre d\'outils.'
16 },
17
18 {
19 name: 'Dialogue de l\'éditeur',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Menu contextuel de l\'éditeur',
26 legend: 'Appuyer sur ${contextMenu} ou entrer le RACCOURCI CLAVIER pour ouvrir le menu contextuel. Puis se déplacer vers l\'option suivante du menu avec les touches TAB ou FLECHE BAS. Se déplacer vers l\'option précédente avec les touches SHIFT+TAB ou FLECHE HAUT. appuyer sur la BARRE D\'ESPACE ou la touche ENTREE pour sélectionner l\'option du menu. Oovrir le sous-menu de l\'option courante avec la BARRE D\'ESPACE ou les touches ENTREE ou FLECHE DROITE. Revenir à l\'élément de menu parent avec les touches ESC ou FLECHE GAUCHE. Fermer le menu contextuel avec ESC.'
27 },
28
29 {
30 name: 'Menu déroulant de l\'éditeur',
31 legend: 'A l\'intérieur d\'une liste en menu déroulant, se déplacer vers l\'élément suivant de la liste avec les touches TAB ou FLECHE BAS. Se déplacer vers l\'élément précédent de la liste avec les touches SHIFT+TAB ou FLECHE HAUT. Appuyer sur la BARRE D\'ESPACE ou sur ENTREE pour sélectionner l\'option dans la liste. Appuyer sur ESC pour fermer le menu déroulant.'
32 },
33
34 {
35 name: 'Barre d\'emplacement des éléments de l\'éditeur',
36 legend: 'Appuyer sur ${elementsPathFocus} pour naviguer vers la barre d\'emplacement des éléments de léditeur. Se déplacer vers le bouton d\'élément suivant avec les touches TAB ou FLECHE DROITE. Se déplacer vers le bouton d\'élément précédent avec les touches SHIFT+TAB ou FLECHE GAUCHE. Appuyer sur la BARRE D\'ESPACE ou sur ENTREE pour sélectionner l\'élément dans l\'éditeur.'
37 }
38 ]
39 },
40 {
41 name: 'Commandes',
42 items: [
43 {
44 name: 'Annuler',
45 legend: 'Appuyer sur ${undo}'
46 },
47 {
48 name: 'Refaire',
49 legend: 'Appuyer sur ${redo}'
50 },
51 {
52 name: 'Gras',
53 legend: 'Appuyer sur ${bold}'
54 },
55 {
56 name: 'Italique',
57 legend: 'Appuyer sur ${italic}'
58 },
59 {
60 name: 'Souligné',
61 legend: 'Appuyer sur ${underline}'
62 },
63 {
64 name: 'Lien',
65 legend: 'Appuyer sur ${link}'
66 },
67 {
68 name: 'Enrouler la barre d\'outils',
69 legend: 'Appuyer sur ${toolbarCollapse}'
70 },
71 {
72 name: 'Accéder à l\'objet de focus précédent',
73 legend: 'Appuyer ${accessPreviousSpace} pour accéder au prochain espace disponible avant le curseur, par exemple: deux éléments HR adjacents. Répéter la combinaison pour joindre les éléments d\'espaces distantes.'
74 },
75 {
76 name: 'Accéder au prochain objet de focus',
77 legend: 'Appuyer ${accessNextSpace} pour accéder au prochain espace disponible après le curseur, par exemple: deux éléments HR adjacents. Répéter la combinaison pour joindre les éléments d\'espaces distantes.'
78 },
79 {
80 name: 'Aide d\'accessibilité',
81 legend: 'Appuyer sur ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/fr.js b/sources/plugins/a11yhelp/dialogs/lang/fr.js
new file mode 100644
index 0000000..9727639
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/fr.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'fr', {
7 title: 'Instructions d\'accessibilité',
8 contents: 'Contenu de l\'aide. Pour fermer cette fenêtre, appuyez sur la touche Échap.',
9 legend: [
10 {
11 name: 'Général',
12 items: [
13 {
14 name: 'Barre d\'outils de l\'éditeur',
15 legend: 'Appuyer sur ${toolbarFocus} pour accéder à la barre d\'outils. Se déplacer vers le groupe suivant ou précédent de la barre d\'outils avec les touches Tab et Maj+Tab. Se déplacer vers le bouton suivant ou précédent de la barre d\'outils avec les touches Flèche droite et Flèche gauche. Appuyer sur la barre d\'espace ou la touche Entrée pour activer le bouton de barre d\'outils.'
16 },
17
18 {
19 name: 'Fenêtre de l\'éditeur',
20 legend:
21 'Dans une boîte de dialogue, appuyer sur Tab pour passer à l\'élément suivant, appuyer sur Maj+Tab pour passer à l\'élément précédent, appuyer sur Entrée pour valider, appuyer sur Échap pour annuler. Quand une boîte de dialogue possède des onglets, la liste peut être atteinte avec Alt+F10 ou avec Tab. Dans la liste des onglets, se déplacer vers le suivant et le précédent avec les touches Flèche droite et Flèche gauche respectivement.'
22 },
23
24 {
25 name: 'Menu contextuel de l\'éditeur',
26 legend: 'Appuyer sur ${contextMenu} ou sur la touche Menu pour ouvrir le menu contextuel. Se déplacer ensuite vers l\'option suivante du menu avec les touches Tab ou Flèche bas. Se déplacer vers l\'option précédente avec les touches Maj+Tab ou Flèche haut. Appuyer sur la barre d\'espace ou la touche Entrée pour sélectionner l\'option du menu. Appuyer sur la barre d\'espace, la touche Entrée ou Flèche droite pour ouvrir le sous-menu de l\'option sélectionnée. Revenir à l\'élément de menu parent avec la touche Échap ou Flèche gauche. Fermer le menu contextuel avec Échap.'
27 },
28
29 {
30 name: 'Zone de liste de l\'éditeur',
31 legend: 'Dans une liste en menu déroulant, se déplacer vers l\'élément suivant de la liste avec les touches Tab ou Flèche bas. Se déplacer vers l\'élément précédent de la liste avec les touches Maj+Tab ou Flèche haut. Appuyer sur la barre d\'espace ou sur Entrée pour sélectionner l\'option dans la liste. Appuyer sur Échap pour fermer le menu déroulant.'
32 },
33
34 {
35 name: 'Barre du chemin d\'éléments de l\'éditeur',
36 legend: 'Appuyer sur ${elementsPathFocus} pour naviguer vers la barre du fil d\'Ariane des éléments. Se déplacer vers le bouton de l\'élément suivant avec les touches Tab ou Flèche droite. Se déplacer vers le bouton précédent avec les touches Maj+Tab ou Flèche gauche. Appuyer sur la barre d\'espace ou sur Entrée pour sélectionner l\'élément dans l\'éditeur.'
37 }
38 ]
39 },
40 {
41 name: 'Commandes',
42 items: [
43 {
44 name: ' Annuler la commande',
45 legend: 'Appuyer sur ${undo}'
46 },
47 {
48 name: 'Commande restaurer',
49 legend: 'Appuyer sur ${redo}'
50 },
51 {
52 name: ' Commande gras',
53 legend: 'Appuyer sur ${bold}'
54 },
55 {
56 name: ' Commande italique',
57 legend: 'Appuyer sur ${italic}'
58 },
59 {
60 name: ' Commande souligné',
61 legend: 'Appuyer sur ${underline}'
62 },
63 {
64 name: ' Commande lien',
65 legend: 'Appuyer sur ${link}'
66 },
67 {
68 name: ' Commande enrouler la barre d\'outils',
69 legend: 'Appuyer sur ${toolbarCollapse}'
70 },
71 {
72 name: 'Commande d\'accès à l\'élément sélectionnable précédent',
73 legend: 'Appuyer sur ${accessNextSpace} pour accéder à l\'élément sélectionnable inatteignable le plus proche avant le curseur, par exemple : deux lignes horizontales adjacentes. Répéter la combinaison de touches pour atteindre les éléments sélectionnables précédents.'
74 },
75 {
76 name: 'Commande d\'accès à l\'élément sélectionnable suivant',
77 legend: 'Appuyer sur ${accessNextSpace} pour accéder à l\'élément sélectionnable inatteignable le plus proche après le curseur, par exemple : deux lignes horizontales adjacentes. Répéter la combinaison de touches pour atteindre les éléments sélectionnables suivants.'
78 },
79 {
80 name: ' Aide sur l\'accessibilité',
81 legend: 'Appuyer sur ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulation',
87 pause: 'Pause',
88 capslock: 'Verr. Maj.',
89 escape: 'Échap',
90 pageUp: 'Page supérieure',
91 pageDown: 'Page suivante',
92 leftArrow: 'Flèche gauche',
93 upArrow: 'Flèche haut',
94 rightArrow: 'Flèche droite',
95 downArrow: 'Flèche basse',
96 insert: 'Inser',
97 leftWindowKey: 'Touche Windows gauche',
98 rightWindowKey: 'Touche Windows droite',
99 selectKey: 'Touche Sélectionner',
100 numpad0: '0 du pavé numérique',
101 numpad1: '1 du pavé numérique',
102 numpad2: '2 du pavé numérique',
103 numpad3: '3 du pavé numérique',
104 numpad4: '4 du pavé numérique',
105 numpad5: '5 du pavé numérique',
106 numpad6: '6 du pavé numérique',
107 numpad7: '7 du pavé numérique',
108 numpad8: 'Pavé numérique 8',
109 numpad9: '9 du pavé numérique',
110 multiply: 'Multiplier',
111 add: 'Plus',
112 subtract: 'Moins',
113 decimalPoint: 'Point décimal',
114 divide: 'Diviser',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Verr. Num.',
128 scrollLock: 'Arrêt défil.',
129 semiColon: 'Point-virgule',
130 equalSign: 'Signe égal',
131 comma: 'Virgule',
132 dash: 'Tiret',
133 period: 'Point',
134 forwardSlash: 'Barre oblique',
135 graveAccent: 'Accent grave',
136 openBracket: 'Parenthèse ouvrante',
137 backSlash: 'Barre oblique inverse',
138 closeBracket: 'Parenthèse fermante',
139 singleQuote: 'Apostrophe'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/gl.js b/sources/plugins/a11yhelp/dialogs/lang/gl.js
new file mode 100644
index 0000000..4978330
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/gl.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'gl', {
7 title: 'Instrucións de accesibilidade',
8 contents: 'Axuda. Para pechar este diálogo prema ESC.',
9 legend: [
10 {
11 name: 'Xeral',
12 items: [
13 {
14 name: 'Barra de ferramentas do editor',
15 legend: 'Prema ${toolbarFocus} para navegar pola barra de ferramentas. Para moverse polos distintos grupos de ferramentas use as teclas TAB e MAIÚS+TAB. Para moverse polas distintas ferramentas use FRECHA DEREITA ou FRECHA ESQUERDA. Prema ESPAZO ou INTRO para activar o botón da barra de ferramentas.'
16 },
17
18 {
19 name: 'Editor de diálogo',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor do menú contextual',
26 legend: 'Prema ${contextMenu} ou a TECLA MENÚ para abrir o menú contextual. A seguir móvase á seguinte opción do menú con TAB ou FRECHA ABAIXO. Móvase á opción anterior con MAIÚS + TAB ou FRECHA ARRIBA. Prema ESPAZO ou INTRO para seleccionar a opción do menú. Abra o submenú da opción actual con ESPAZO ou INTRO ou FRECHA DEREITA. Regrese ao elemento principal do menú con ESC ou FRECHA ESQUERDA. Peche o menú contextual con ESC.'
27 },
28
29 {
30 name: 'Lista do editor',
31 legend: 'Dentro dunha lista, móvase ao seguinte elemento da lista con TAB ou FRECHA ABAIXO. Móvase ao elemento anterior da lista con MAIÚS+TAB ou FRECHA ARRIBA. Prema ESPAZO ou INTRO para escoller a opción da lista. Prema ESC para pechar a lista.'
32 },
33
34 {
35 name: 'Barra da ruta ao elemento no editor',
36 legend: 'Prema ${elementsPathFocus} para navegar ata os elementos da barra de ruta. Móvase ao seguinte elemento botón con TAB ou FRECHA DEREITA. Móvase ao botón anterior con MAIÚS+TAB ou FRECHA ESQUERDA. Prema ESPAZO ou INTRO para seleccionar o elemento no editor.'
37 }
38 ]
39 },
40 {
41 name: 'Ordes',
42 items: [
43 {
44 name: 'Orde «desfacer»',
45 legend: 'Prema ${undo}'
46 },
47 {
48 name: 'Orde «refacer»',
49 legend: 'Prema ${redo}'
50 },
51 {
52 name: 'Orde «negra»',
53 legend: 'Prema ${bold}'
54 },
55 {
56 name: 'Orde «cursiva»',
57 legend: 'Prema ${italic}'
58 },
59 {
60 name: 'Orde «subliñar»',
61 legend: 'Prema ${underline}'
62 },
63 {
64 name: 'Orde «ligazón»',
65 legend: 'Prema ${link}'
66 },
67 {
68 name: 'Orde «contraer a barra de ferramentas»',
69 legend: 'Prema ${toolbarCollapse}'
70 },
71 {
72 name: 'Orde «acceder ao anterior espazo en foco»',
73 legend: 'Prema ${accessPreviousSpace} para acceder ao espazo máis próximo de foco inalcanzábel anterior ao cursor, por exemplo: dous elementos HR adxacentes. Repita a combinación de teclas para chegar a espazos de foco distantes.'
74 },
75 {
76 name: 'Orde «acceder ao seguinte espazo en foco»',
77 legend: 'Prema ${accessNextSpace} para acceder ao espazo máis próximo de foco inalcanzábel posterior ao cursor, por exemplo: dous elementos HR adxacentes. Repita a combinación de teclas para chegar a espazos de foco distantes.'
78 },
79 {
80 name: 'Axuda da accesibilidade',
81 legend: 'Prema ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulador',
87 pause: 'Pausa',
88 capslock: 'Bloq. Maiús',
89 escape: 'Escape',
90 pageUp: 'Páxina arriba',
91 pageDown: 'Páxina abaixo',
92 leftArrow: 'Frecha esquerda',
93 upArrow: 'Frecha arriba',
94 rightArrow: 'Frecha dereita',
95 downArrow: 'Frecha abaixo',
96 insert: 'Inserir',
97 leftWindowKey: 'Tecla Windows esquerda',
98 rightWindowKey: 'Tecla Windows dereita',
99 selectKey: 'Escolla a tecla',
100 numpad0: 'Tec. numérico 0',
101 numpad1: 'Tec. numérico 1',
102 numpad2: 'Tec. numérico 2',
103 numpad3: 'Tec. numérico 3',
104 numpad4: 'Tec. numérico 4',
105 numpad5: 'Tec. numérico 5',
106 numpad6: 'Tec. numérico 6',
107 numpad7: 'Tec. numérico 7',
108 numpad8: 'Tec. numérico 8',
109 numpad9: 'Tec. numérico 9',
110 multiply: 'Multiplicar',
111 add: 'Sumar',
112 subtract: 'Restar',
113 decimalPoint: 'Punto decimal',
114 divide: 'Dividir',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Bloq. num.',
128 scrollLock: 'Bloq. despraz.',
129 semiColon: 'Punto e coma',
130 equalSign: 'Signo igual',
131 comma: 'Coma',
132 dash: 'Guión',
133 period: 'Punto',
134 forwardSlash: 'Barra inclinada',
135 graveAccent: 'Acento grave',
136 openBracket: 'Abrir corchete',
137 backSlash: 'Barra invertida',
138 closeBracket: 'Pechar corchete',
139 singleQuote: 'Comiña simple'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/gu.js b/sources/plugins/a11yhelp/dialogs/lang/gu.js
new file mode 100644
index 0000000..30eb2cd
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/gu.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'gu', {
7 title: 'એક્ક્ષેબિલિટી ની વિગતો',
8 contents: 'હેલ્પ. આ બંધ કરવા ESC દબાવો.',
9 legend: [
10 {
11 name: 'જનરલ',
12 items: [
13 {
14 name: 'એડિટર ટૂલબાર',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'એડિટર ડાયલોગ',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'કમાંડસ',
42 items: [
43 {
44 name: 'અન્ડું કમાંડ',
45 legend: '$ દબાવો {undo}'
46 },
47 {
48 name: 'ફરી કરો કમાંડ',
49 legend: '$ દબાવો {redo}'
50 },
51 {
52 name: 'બોલ્દનો કમાંડ',
53 legend: '$ દબાવો {bold}'
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/he.js b/sources/plugins/a11yhelp/dialogs/lang/he.js
new file mode 100644
index 0000000..24b8572
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/he.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'he', {
7 title: 'הוראות נגישות',
8 contents: 'הוראות נגישות. לסגירה לחץ אסקייפ (ESC).',
9 legend: [
10 {
11 name: 'כללי',
12 items: [
13 {
14 name: 'סרגל הכלים',
15 legend: 'לחץ על ${toolbarFocus} כדי לנווט לסרגל הכלים. עבור לכפתור הבא עם מקש הטאב (TAB) או חץ שמאלי. עבור לכפתור הקודם עם מקש השיפט (SHIFT) + טאב (TAB) או חץ ימני. לחץ רווח או אנטר (ENTER) כדי להפעיל את הכפתור הנבחר.'
16 },
17
18 {
19 name: 'דיאלוגים (חלונות תשאול)',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'תפריט ההקשר (Context Menu)',
26 legend: 'לחץ ${contextMenu} או APPLICATION KEYכדי לפתוח את תפריט ההקשר. עבור לאפשרות הבאה עם טאב (TAB) או חץ למטה. עבור לאפשרות הקודמת עם שיפט (SHIFT) + טאב (TAB) או חץ למעלה. לחץ רווח או אנטר (ENTER) כדי לבחור את האפשרות. פתח את תת התפריט (Sub-menu) של האפשרות הנוכחית עם רווח או אנטר (ENTER) או חץ שמאלי. חזור לתפריט האב עם אסקייפ (ESC) או חץ שמאלי. סגור את תפריט ההקשר עם אסקייפ (ESC).'
27 },
28
29 {
30 name: 'תפריטים צפים (List boxes)',
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'עץ אלמנטים (Elements Path)',
36 legend: 'לחץ ${elementsPathFocus} כדי לנווט לעץ האלמנטים. עבור לפריט הבא עם טאב (TAB) או חץ ימני. עבור לפריט הקודם עם שיפט (SHIFT) + טאב (TAB) או חץ שמאלי. לחץ רווח או אנטר (ENTER) כדי לבחור את האלמנט בעורך.'
37 }
38 ]
39 },
40 {
41 name: 'פקודות',
42 items: [
43 {
44 name: ' ביטול צעד אחרון',
45 legend: 'לחץ ${undo}'
46 },
47 {
48 name: ' חזרה על צעד אחרון',
49 legend: 'לחץ ${redo}'
50 },
51 {
52 name: ' הדגשה',
53 legend: 'לחץ ${bold}'
54 },
55 {
56 name: ' הטייה',
57 legend: 'לחץ ${italic}'
58 },
59 {
60 name: ' הוספת קו תחתון',
61 legend: 'לחץ ${underline}'
62 },
63 {
64 name: ' הוספת לינק',
65 legend: 'לחץ ${link}'
66 },
67 {
68 name: ' כיווץ סרגל הכלים',
69 legend: 'לחץ ${toolbarCollapse}'
70 },
71 {
72 name: 'גישה למיקום המיקוד הקודם',
73 legend: 'לחץ ${accessPreviousSpace} כדי לגשת למיקום המיקוד הלא-נגיש הקרוב לפני הסמן, למשל בין שני אלמנטים סמוכים מסוג HR. חזור על צירוף מקשים זה כדי להגיע למקומות מיקוד רחוקים יותר.'
74 },
75 {
76 name: 'גישה למיקום המיקוד הבא',
77 legend: 'לחץ ${accessNextSpace} כדי לגשת למיקום המיקוד הלא-נגיש הקרוב אחרי הסמן, למשל בין שני אלמנטים סמוכים מסוג HR. חזור על צירוף מקשים זה כדי להגיע למקומות מיקוד רחוקים יותר.'
78 },
79 {
80 name: ' הוראות נגישות',
81 legend: 'לחץ ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'חץ שמאלה',
93 upArrow: 'חץ למעלה',
94 rightArrow: 'חץ ימינה',
95 downArrow: 'חץ למטה',
96 insert: 'הכנס',
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'בחר מקש',
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'הוסף',
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'סלאש',
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'סלאש הפוך',
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'ציטוט יחיד'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/hi.js b/sources/plugins/a11yhelp/dialogs/lang/hi.js
new file mode 100644
index 0000000..308c5ef
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/hi.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'hi', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'सामान्य',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/hr.js b/sources/plugins/a11yhelp/dialogs/lang/hr.js
new file mode 100644
index 0000000..b05273e
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/hr.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'hr', {
7 title: 'Upute dostupnosti',
8 contents: 'Sadržaj pomoći. Za zatvaranje pritisnite ESC.',
9 legend: [
10 {
11 name: 'Općenito',
12 items: [
13 {
14 name: 'Alatna traka',
15 legend: 'Pritisni ${toolbarFocus} za navigaciju do alatne trake. Pomicanje do prethodne ili sljedeće alatne grupe vrši se pomoću SHIFT+TAB i TAB. Pomicanje do prethodnog ili sljedećeg gumba u alatnoj traci vrši se pomoću lijeve i desne strelice kursora. Pritisnite SPACE ili ENTER za aktivaciju alatne trake.'
16 },
17
18 {
19 name: 'Dijalog',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Kontekstni izbornik',
26 legend: 'Pritisnite ${contextMenu} ili APPLICATION tipku za otvaranje kontekstnog izbornika. Pomicanje se vrši TAB ili strelicom kursora prema dolje ili SHIFT+TAB ili strelica kursora prema gore. SPACE ili ENTER odabiru opciju izbornika. Otvorite podizbornik trenutne opcije sa SPACE, ENTER ili desna strelica kursora. Povratak na prethodni izbornik vrši se sa ESC ili lijevom strelicom kursora. Zatvaranje se vrši pritiskom na tipku ESC.'
27 },
28
29 {
30 name: 'Lista',
31 legend: 'Unutar list-boxa, pomicanje na sljedeću stavku vrši se sa TAB ili strelica kursora prema dolje. Na prethodnu sa SHIFT+TAB ili strelica prema gore. Pritiskom na SPACE ili ENTER odabire se stavka ili ESC za zatvaranje.'
32 },
33
34 {
35 name: 'Traka putanje elemenata',
36 legend: 'Pritisnite ${elementsPathFocus} za navigaciju po putanji elemenata. Pritisnite TAB ili desnu strelicu kursora za pomicanje na sljedeći element ili SHIFT+TAB ili lijeva strelica kursora za pomicanje na prethodni element. Pritiskom na SPACE ili ENTER vrši se odabir elementa.'
37 }
38 ]
39 },
40 {
41 name: 'Naredbe',
42 items: [
43 {
44 name: 'Vrati naredbu',
45 legend: 'Pritisni ${undo}'
46 },
47 {
48 name: 'Ponovi naredbu',
49 legend: 'Pritisni ${redo}'
50 },
51 {
52 name: 'Bold naredba',
53 legend: 'Pritisni ${bold}'
54 },
55 {
56 name: 'Italic naredba',
57 legend: 'Pritisni ${italic}'
58 },
59 {
60 name: 'Underline naredba',
61 legend: 'Pritisni ${underline}'
62 },
63 {
64 name: 'Link naredba',
65 legend: 'Pritisni ${link}'
66 },
67 {
68 name: 'Smanji alatnu traku naredba',
69 legend: 'Pritisni ${toolbarCollapse}'
70 },
71 {
72 name: 'Access previous focus space naredba',
73 legend: 'Pritisni ${accessPreviousSpace} za pristup najbližem nedostupnom razmaku prije kursora, npr.: dva spojena HR elementa. Ponovnim pritiskom dohvatiti će se sljedeći nedostupni razmak.'
74 },
75 {
76 name: 'Access next focus space naredba',
77 legend: 'Pritisni ${accessNextSpace} za pristup najbližem nedostupnom razmaku nakon kursora, npr.: dva spojena HR elementa. Ponovnim pritiskom dohvatiti će se sljedeći nedostupni razmak.'
78 },
79 {
80 name: 'Pomoć za dostupnost',
81 legend: 'Pritisni ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/hu.js b/sources/plugins/a11yhelp/dialogs/lang/hu.js
new file mode 100644
index 0000000..f14f17d
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/hu.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'hu', {
7 title: 'Kisegítő utasítások',
8 contents: 'Súgó tartalmak. A párbeszédablak bezárásához nyomjon ESC-et.',
9 legend: [
10 {
11 name: 'Általános',
12 items: [
13 {
14 name: 'Szerkesztő Eszköztár',
15 legend: 'Nyomjon ${toolbarFocus} hogy kijelölje az eszköztárat. A következő és előző eszköztár csoporthoz a TAB és SHIFT+TAB-al juthat el. A következő és előző eszköztár gombhoz a BAL NYÍL vagy JOBB NYÍL gombbal juthat el. Nyomjon SPACE-t vagy ENTER-t hogy aktiválja az eszköztár gombot.'
16 },
17
18 {
19 name: 'Szerkesző párbeszéd ablak',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Szerkesztő helyi menü',
26 legend: 'Nyomjon ${contextMenu}-t vagy ALKALMAZÁS BILLENTYŰT a helyi menü megnyitásához. Ezután a következő menüpontra léphet a TAB vagy LEFELÉ NYÍLLAL. Az előző opciót a SHIFT+TAB vagy FELFELÉ NYÍLLAL érheti el. Nyomjon SPACE-t vagy ENTER-t a menüpont kiválasztásához. A jelenlegi menüpont almenüjének megnyitásához nyomjon SPACE-t vagy ENTER-t, vagy JOBB NYILAT. A főmenühöz való visszatéréshez nyomjon ESC-et vagy BAL NYILAT. A helyi menü bezárása az ESC billentyűvel lehetséges.'
27 },
28
29 {
30 name: 'Szerkesztő lista',
31 legend: 'A listán belül a következő elemre a TAB vagy LEFELÉ NYÍLLAL mozoghat. Az előző elem kiválasztásához nyomjon SHIFT+TAB-ot vagy FELFELÉ NYILAT. Nyomjon SPACE-t vagy ENTER-t az elem kiválasztásához. Az ESC billentyű megnyomásával bezárhatja a listát.'
32 },
33
34 {
35 name: 'Szerkesztő elem utak sáv',
36 legend: 'Nyomj ${elementsPathFocus} hogy kijelöld a elemek út sávját. A következő elem gombhoz a TAB-al vagy a JOBB NYÍLLAL juthatsz el. Az előző gombhoz a SHIFT+TAB vagy BAL NYÍLLAL mehetsz. A SPACE vagy ENTER billentyűvel kiválaszthatod az elemet a szerkesztőben.'
37 }
38 ]
39 },
40 {
41 name: 'Parancsok',
42 items: [
43 {
44 name: 'Parancs visszavonása',
45 legend: 'Nyomj ${undo}'
46 },
47 {
48 name: 'Parancs megismétlése',
49 legend: 'Nyomjon ${redo}'
50 },
51 {
52 name: 'Félkövér parancs',
53 legend: 'Nyomjon ${bold}'
54 },
55 {
56 name: 'Dőlt parancs',
57 legend: 'Nyomjon ${italic}'
58 },
59 {
60 name: 'Aláhúzott parancs',
61 legend: 'Nyomjon ${underline}'
62 },
63 {
64 name: 'Link parancs',
65 legend: 'Nyomjon ${link}'
66 },
67 {
68 name: 'Szerkesztősáv összecsukása parancs',
69 legend: 'Nyomjon ${toolbarCollapse}'
70 },
71 {
72 name: 'Hozzáférés az előző fókusz helyhez parancs',
73 legend: 'Nyomj ${accessNextSpace} hogy hozzáférj a legközelebbi elérhetetlen fókusz helyhez a hiányjel előtt, például: két szomszédos HR elemhez. Ismételd meg a billentyűkombinációt hogy megtaláld a távolabbi fókusz helyeket.'
74 },
75 {
76 name: 'Hozzáférés a következő fókusz helyhez parancs',
77 legend: 'Nyomj ${accessNextSpace} hogy hozzáférj a legközelebbi elérhetetlen fókusz helyhez a hiányjel után, például: két szomszédos HR elemhez. Ismételd meg a billentyűkombinációt hogy megtaláld a távolabbi fókusz helyeket.'
78 },
79 {
80 name: 'Kisegítő súgó',
81 legend: 'Nyomjon ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'balra nyíl',
93 upArrow: 'felfelé nyíl',
94 rightArrow: 'jobbra nyíl',
95 downArrow: 'lefelé nyíl',
96 insert: 'Insert',
97 leftWindowKey: 'bal Windows-billentyű',
98 rightWindowKey: 'jobb Windows-billentyű',
99 selectKey: 'Billentyű választása',
100 numpad0: 'Számbillentyűk 0',
101 numpad1: 'Számbillentyűk 1',
102 numpad2: 'Számbillentyűk 2',
103 numpad3: 'Számbillentyűk 3',
104 numpad4: 'Számbillentyűk 4',
105 numpad5: 'Számbillentyűk 5',
106 numpad6: 'Számbillentyűk 6',
107 numpad7: 'Számbillentyűk 7',
108 numpad8: 'Számbillentyűk 8',
109 numpad9: 'Számbillentyűk 9',
110 multiply: 'Szorzás',
111 add: 'Hozzáadás',
112 subtract: 'Kivonás',
113 decimalPoint: 'Tizedespont',
114 divide: 'Osztás',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Pontosvessző',
130 equalSign: 'Egyenlőségjel',
131 comma: 'Vessző',
132 dash: 'Kötőjel',
133 period: 'Pont',
134 forwardSlash: 'Perjel',
135 graveAccent: 'Visszafelé dőlő ékezet',
136 openBracket: 'Nyitó szögletes zárójel',
137 backSlash: 'fordított perjel',
138 closeBracket: 'Záró szögletes zárójel',
139 singleQuote: 'szimpla idézőjel'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/id.js b/sources/plugins/a11yhelp/dialogs/lang/id.js
new file mode 100644
index 0000000..7799b38
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/id.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'id', {
7 title: 'Instruksi Accessibility',
8 contents: 'Bantuan. Tekan ESC untuk menutup dialog ini.',
9 legend: [
10 {
11 name: 'Umum',
12 items: [
13 {
14 name: 'Toolbar Editor',
15 legend: 'Tekan ${toolbarFocus} untuk berpindah ke toolbar. Untuk berpindah ke group toolbar selanjutnya dan sebelumnya gunakan TAB dan SHIFT+TAB. Untuk berpindah ke tombol toolbar selanjutnya dan sebelumnya gunakan RIGHT ARROW atau LEFT ARROW. Tekan SPASI atau ENTER untuk mengaktifkan tombol toolbar.'
16 },
17
18 {
19 name: 'Dialog Editor',
20 legend:
21 'Pada jendela dialog, tekan TAB untuk berpindah pada elemen dialog selanjutnya, tekan SHIFT+TAB untuk berpindah pada elemen dialog sebelumnya, tekan ENTER untuk submit dialog, tekan ESC untuk membatalkan dialog. Pada dialog dengan multi tab, daftar tab dapat diakses dengan ALT+F10 ataupun dengan tombol TAB sesuai urutan tab pada dialog. Jika daftar tab aktif terpilih, untuk berpindah tab dapat menggunakan RIGHT dan LEFT ARROW.'
22 },
23
24 {
25 name: 'Context Menu Editor',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'List Box Editor',
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/it.js b/sources/plugins/a11yhelp/dialogs/lang/it.js
new file mode 100644
index 0000000..55ecadc
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/it.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'it', {
7 title: 'Istruzioni di Accessibilità',
8 contents: 'Contenuti di Aiuto. Per chiudere questa finestra premi ESC.',
9 legend: [
10 {
11 name: 'Generale',
12 items: [
13 {
14 name: 'Barra degli strumenti Editor',
15 legend: 'Premere ${toolbarFocus} per passare alla barra degli strumenti. Usare TAB per spostarsi al gruppo successivo, MAIUSC+TAB per spostarsi a quello precedente. Usare FRECCIA DESTRA per spostarsi al pulsante successivo, FRECCIA SINISTRA per spostarsi a quello precedente. Premere SPAZIO o INVIO per attivare il pulsante della barra degli strumenti.'
16 },
17
18 {
19 name: 'Finestra Editor',
20 legend:
21 'All\'interno di una finestra di dialogo è possibile premere TAB per passare all\'elemento successivo della finestra, MAIUSC+TAB per passare a quello precedente; premere INVIO per inviare i dati della finestra, oppure ESC per annullare l\'operazione. Quando una finestra di dialogo ha più schede, è possibile passare all\'elenco delle schede sia con ALT+F10 che con TAB, in base all\'ordine delle tabulazioni della finestra. Quando l\'elenco delle schede è attivo, premere la FRECCIA DESTRA o la FRECCIA SINISTRA per passare rispettivamente alla scheda successiva o a quella precedente.'
22 },
23
24 {
25 name: 'Menù contestuale Editor',
26 legend: 'Premi ${contextMenu} o TASTO APPLICAZIONE per aprire il menu contestuale. Dunque muoviti all\'opzione successiva del menu con il tasto TAB o con la Freccia Sotto. Muoviti all\'opzione precedente con MAIUSC+TAB o con Freccia Sopra. Premi SPAZIO o INVIO per scegliere l\'opzione di menu. Apri il sottomenu dell\'opzione corrente con SPAZIO o INVIO oppure con la Freccia Destra. Torna indietro al menu superiore con ESC oppure Freccia Sinistra. Chiudi il menu contestuale con ESC.'
27 },
28
29 {
30 name: 'Box Lista Editor',
31 legend: 'All\'interno di un elenco di opzioni, per spostarsi all\'elemento successivo premere TAB oppure FRECCIA GIÙ. Per spostarsi all\'elemento precedente usare SHIFT+TAB oppure FRECCIA SU. Premere SPAZIO o INVIO per selezionare l\'elemento della lista. Premere ESC per chiudere l\'elenco di opzioni.'
32 },
33
34 {
35 name: 'Barra percorso elementi editor',
36 legend: 'Premere ${elementsPathFocus} per passare agli elementi della barra del percorso. Usare TAB o FRECCIA DESTRA per passare al pulsante successivo. Per passare al pulsante precedente premere MAIUSC+TAB o FRECCIA SINISTRA. Premere SPAZIO o INVIO per selezionare l\'elemento nell\'editor.'
37 }
38 ]
39 },
40 {
41 name: 'Comandi',
42 items: [
43 {
44 name: ' Annulla comando',
45 legend: 'Premi ${undo}'
46 },
47 {
48 name: ' Ripeti comando',
49 legend: 'Premi ${redo}'
50 },
51 {
52 name: ' Comando Grassetto',
53 legend: 'Premi ${bold}'
54 },
55 {
56 name: ' Comando Corsivo',
57 legend: 'Premi ${italic}'
58 },
59 {
60 name: ' Comando Sottolineato',
61 legend: 'Premi ${underline}'
62 },
63 {
64 name: ' Comando Link',
65 legend: 'Premi ${link}'
66 },
67 {
68 name: ' Comando riduci barra degli strumenti',
69 legend: 'Premi ${toolbarCollapse}'
70 },
71 {
72 name: 'Comando di accesso al precedente spazio di focus',
73 legend: 'Premi ${accessPreviousSpace} per accedere il più vicino spazio di focus non raggiungibile prima del simbolo caret, per esempio due elementi HR adiacenti. Ripeti la combinazione di tasti per raggiungere spazi di focus distanti.'
74 },
75 {
76 name: 'Comando di accesso al prossimo spazio di focus',
77 legend: 'Premi ${accessNextSpace} per accedere il più vicino spazio di focus non raggiungibile dopo il simbolo caret, per esempio due elementi HR adiacenti. Ripeti la combinazione di tasti per raggiungere spazi di focus distanti.'
78 },
79 {
80 name: ' Aiuto Accessibilità',
81 legend: 'Premi ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pausa',
88 capslock: 'Bloc Maiusc',
89 escape: 'Esc',
90 pageUp: 'Pagina sù',
91 pageDown: 'Pagina giù',
92 leftArrow: 'Freccia sinistra',
93 upArrow: 'Freccia su',
94 rightArrow: 'Freccia destra',
95 downArrow: 'Freccia giù',
96 insert: 'Ins',
97 leftWindowKey: 'Tasto di Windows sinistro',
98 rightWindowKey: 'Tasto di Windows destro',
99 selectKey: 'Tasto di selezione',
100 numpad0: '0 sul tastierino numerico',
101 numpad1: '1 sul tastierino numerico',
102 numpad2: '2 sul tastierino numerico',
103 numpad3: '3 sul tastierino numerico',
104 numpad4: '4 sul tastierino numerico',
105 numpad5: '5 sul tastierino numerico',
106 numpad6: '6 sul tastierino numerico',
107 numpad7: '7 sul tastierino numerico',
108 numpad8: '8 sul tastierino numerico',
109 numpad9: '9 sul tastierino numerico',
110 multiply: 'Moltiplicazione',
111 add: 'Più',
112 subtract: 'Sottrazione',
113 decimalPoint: 'Punto decimale',
114 divide: 'Divisione',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Bloc Num',
128 scrollLock: 'Bloc Scorr',
129 semiColon: 'Punto-e-virgola',
130 equalSign: 'Segno di uguale',
131 comma: 'Virgola',
132 dash: 'Trattino',
133 period: 'Punto',
134 forwardSlash: 'Barra',
135 graveAccent: 'Accento grave',
136 openBracket: 'Parentesi quadra aperta',
137 backSlash: 'Barra rovesciata',
138 closeBracket: 'Parentesi quadra chiusa',
139 singleQuote: 'Apostrofo'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ja.js b/sources/plugins/a11yhelp/dialogs/lang/ja.js
new file mode 100644
index 0000000..9053e37
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ja.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ja', {
7 title: 'ユーザー補助の説明',
8 contents: 'ヘルプ このダイアログを閉じるには ESCを押してください。',
9 legend: [
10 {
11 name: '全般',
12 items: [
13 {
14 name: 'エディターツールバー',
15 legend: '${toolbarFocus} を押すとツールバーのオン/オフ操作ができます。カーソルをツールバーのグループで移動させるにはTabかSHIFT+Tabを押します。グループ内でカーソルを移動させるには、右カーソルか左カーソルを押します。スペースキーやエンターを押すとボタンを有効/無効にすることができます。'
16 },
17
18 {
19 name: '編集ダイアログ',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'エディターのメニュー',
26 legend: '${contextMenu} キーかAPPLICATION KEYを押すとコンテキストメニューが開きます。Tabか下カーソルでメニューのオプション選択が下に移動します。戻るには、SHIFT+Tabか上カーソルです。スペースもしくはENTERキーでメニューオプションを決定できます。現在選んでいるオプションのサブメニューを開くには、スペース、もしくは右カーソルを押します。サブメニューから親メニューに戻るには、ESCか左カーソルを押してください。ESCでコンテキストメニュー自体をキャンセルできます。'
27 },
28
29 {
30 name: 'エディターリストボックス',
31 legend: 'リストボックス内で移動するには、Tabか下カーソルで次のアイテムへ移動します。SHIFT+Tabで前のアイテムに戻ります。リストのオプションを選択するには、スペースもしくは、ENTERを押してください。リストボックスを閉じるには、ESCを押してください。'
32 },
33
34 {
35 name: 'エディター要素パスバー',
36 legend: '${elementsPathFocus} を押すとエレメントパスバーを操作出来ます。Tabか右カーソルで次のエレメントを選択できます。前のエレメントを選択するには、SHIFT+Tabか左カーソルです。スペースもしくは、ENTERでエディタ内の対象エレメントを選択出来ます。'
37 }
38 ]
39 },
40 {
41 name: 'コマンド',
42 items: [
43 {
44 name: '元に戻す',
45 legend: '${undo} をクリック'
46 },
47 {
48 name: 'やり直し',
49 legend: '${redo} をクリック'
50 },
51 {
52 name: '太字',
53 legend: '${bold} をクリック'
54 },
55 {
56 name: '斜体 ',
57 legend: '${italic} をクリック'
58 },
59 {
60 name: '下線',
61 legend: '${underline} をクリック'
62 },
63 {
64 name: 'リンク',
65 legend: '${link} をクリック'
66 },
67 {
68 name: 'ツールバーを縮める',
69 legend: '${toolbarCollapse} をクリック'
70 },
71 {
72 name: '前のカーソル移動のできないポイントへ',
73 legend: '${accessPreviousSpace} を押すとカーソルより前にあるカーソルキーで入り込めないスペースへ移動できます。例えば、HRエレメントが2つ接している場合などです。離れた場所へは、複数回キーを押します。'
74 },
75 {
76 name: '次のカーソル移動のできないポイントへ',
77 legend: '${accessNextSpace} を押すとカーソルより後ろにあるカーソルキーで入り込めないスペースへ移動できます。例えば、HRエレメントが2つ接している場合などです。離れた場所へは、複数回キーを押します。'
78 },
79 {
80 name: 'ユーザー補助ヘルプ',
81 legend: '${a11yHelp} をクリック'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: '左矢印',
93 upArrow: '上矢印',
94 rightArrow: '右矢印',
95 downArrow: '下矢印',
96 insert: 'Insert',
97 leftWindowKey: '左Windowキー',
98 rightWindowKey: '右のWindowキー',
99 selectKey: 'Select',
100 numpad0: 'Num 0',
101 numpad1: 'Num 1',
102 numpad2: 'Num 2',
103 numpad3: 'Num 3',
104 numpad4: 'Num 4',
105 numpad5: 'Num 5',
106 numpad6: 'Num 6',
107 numpad7: 'Num 7',
108 numpad8: 'Num 8',
109 numpad9: 'Num 9',
110 multiply: '掛ける',
111 add: '足す',
112 subtract: '引く',
113 decimalPoint: '小数点',
114 divide: '割る',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'セミコロン',
130 equalSign: 'イコール記号',
131 comma: 'カンマ',
132 dash: 'ダッシュ',
133 period: 'ピリオド',
134 forwardSlash: 'フォワードスラッシュ',
135 graveAccent: 'グレイヴアクセント',
136 openBracket: '開きカッコ',
137 backSlash: 'バックスラッシュ',
138 closeBracket: '閉じカッコ',
139 singleQuote: 'シングルクォート'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/km.js b/sources/plugins/a11yhelp/dialogs/lang/km.js
new file mode 100644
index 0000000..4cdd048
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/km.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'km', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'មាតិកា​ជំនួយ។ ដើម្បី​បិទ​ផ្ទាំង​នេះ សូម​ចុច ESC ។',
9 legend: [
10 {
11 name: 'ទូទៅ',
12 items: [
13 {
14 name: 'របារ​ឧបករណ៍​កម្មវិធី​និពន្ធ',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'ផ្ទាំង​កម្មវិធីនិពន្ធ',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'ម៉ីនុយបរិបទអ្នកកែសម្រួល',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'ប្រអប់បញ្ជីអ្នកកែសម្រួល',
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'ពាក្យបញ្ជា',
42 items: [
43 {
44 name: 'ការ​បញ្ជា​មិនធ្វើវិញ',
45 legend: 'ចុច ${undo}'
46 },
47 {
48 name: 'ការបញ្ជា​ធ្វើវិញ',
49 legend: 'ចុច ${redo}'
50 },
51 {
52 name: 'ការបញ្ជា​អក្សរ​ដិត',
53 legend: 'ចុច ${bold}'
54 },
55 {
56 name: 'ការបញ្ជា​អក្សរ​ទ្រេត',
57 legend: 'ចុច ${italic}'
58 },
59 {
60 name: 'ពាក្យបញ្ជា​បន្ទាត់​ពីក្រោម',
61 legend: 'ចុច ${underline}'
62 },
63 {
64 name: 'ពាក្យបញ្ជា​តំណ',
65 legend: 'ចុច ${link}'
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: 'ជំនួយ​ពី​ភាព​ងាយស្រួល',
81 legend: 'ជួយ ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'ផ្អាក',
88 capslock: 'Caps Lock', // MISSING
89 escape: 'ចាកចេញ',
90 pageUp: 'ទំព័រ​លើ',
91 pageDown: 'ទំព័រ​ក្រោម',
92 leftArrow: 'ព្រួញ​ឆ្វេង',
93 upArrow: 'ព្រួញ​លើ',
94 rightArrow: 'ព្រួញ​ស្ដាំ',
95 downArrow: 'ព្រួញ​ក្រោម',
96 insert: 'បញ្ចូល',
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'ជ្រើស​គ្រាប់​ចុច',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'គុណ',
111 add: 'បន្ថែម',
112 subtract: 'ដក',
113 decimalPoint: 'ចំណុចទសភាគ',
114 divide: 'ចែក',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'បិទ​រំកិល',
129 semiColon: 'ចុច​ក្បៀស',
130 equalSign: 'សញ្ញា​អឺរ៉ូ',
131 comma: 'ក្បៀស',
132 dash: 'Dash', // MISSING
133 period: 'ចុច',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'តង្កៀប​បើក',
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'តង្កៀប​បិទ',
139 singleQuote: 'បន្តក់​មួយ'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ko.js b/sources/plugins/a11yhelp/dialogs/lang/ko.js
new file mode 100644
index 0000000..e5ed192
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ko.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ko', {
7 title: '접근성 설명',
8 contents: '도움말. 이 창을 닫으시려면 ESC 를 누르세요.',
9 legend: [
10 {
11 name: '일반',
12 items: [
13 {
14 name: '편집기 툴바',
15 legend: '툴바를 탐색하시려면 ${toolbarFocus} 를 투르세요. 이전/다음 툴바 그룹으로 이동하시려면 TAB 키 또는 SHIFT+TAB 키를 누르세요. 이전/다음 툴바 버튼으로 이동하시려면 오른쪽 화살표 키 또는 왼쪽 화살표 키를 누르세요. 툴바 버튼을 활성화 하려면 SPACE 키 또는 ENTER 키를 누르세요.'
16 },
17
18 {
19 name: '편집기 다이얼로그',
20 legend:
21 'TAB 키를 누르면 다음 대화상자로 이동하고, SHIFT+TAB 키를 누르면 이전 대화상자로 이동합니다. 대화상자를 제출하려면 ENTER 키를 누르고, ESC 키를 누르면 대화상자를 취소합니다. 대화상자에 탭이 여러개 있을 때, ALT+F10 키 또는 TAB 키를 누르면 순서에 따라 탭 목록에 도달할 수 있습니다. 탭 목록에 초점이 맞을 때, 오른쪽과 왼쪽 화살표 키를 이용하면 각각 다음과 이전 탭으로 이동할 수 있습니다.'
22 },
23
24 {
25 name: '편집기 환경 메뉴',
26 legend: '${contextMenu} 또는 어플리케이션 키를 누르면 환경-메뉴를 열 수 있습니다. 환경-메뉴에서 TAB 키 또는 아래 화살표 키를 누르면 다음 메뉴 옵션으로 이동할 수 있습니다. 이전 옵션으로 이동은 SHIFT+TAB 키 또는 위 화살표 키를 눌러서 할 수 있습니다. 스페이스 키 또는 ENTER 키를 눌러서 메뉴 옵션을 선택할 수 있습니다. 스페이스 키 또는 ENTER 키 또는 오른쪽 화살표 키를 눌러서 하위 메뉴를 열 수 있습니다. 부모 메뉴 항목으로 돌아가려면 ESC 키 또는 왼쪽 화살표 키를 누릅니다. ESC 키를 눌러서 환경-메뉴를 닫습니다.'
27 },
28
29 {
30 name: '편집기 목록 박스',
31 legend: '리스트-박스 내에서, 목록의 다음 항목으로 이동하려면 TAB 키 또는 아래쪽 화살표 키를 누릅니다. 목록의 이전 항목으로 이동하려면 SHIFT+TAB 키 또는 위쪽 화살표 키를 누릅니다. 스페이스 키 또는 ENTER 키를 누르면 목록의 해당 옵션을 선택합니다. ESC 키를 눌러서 리스트-박스를 닫을 수 있습니다.'
32 },
33
34 {
35 name: '편집기 요소 경로 막대',
36 legend: '${elementsPathFocus}를 눌러서 요소 경로 막대를 탐색할 수 있습니다. 다음 요소로 이동하려면 TAB 키 또는 오른쪽 화살표 키를 누릅니다. SHIFT+TAB 키 또는 왼쪽 화살표 키를 누르면 이전 버튼으로 이동할 수 있습니다. 스페이스 키나 ENTER 키를 누르면 편집기의 해당 항목을 선택합니다.'
37 }
38 ]
39 },
40 {
41 name: '명령',
42 items: [
43 {
44 name: ' 명령 실행 취소',
45 legend: '${undo} 누르시오'
46 },
47 {
48 name: ' 명령 다시 실행',
49 legend: '${redo} 누르시오'
50 },
51 {
52 name: ' 굵게 명령',
53 legend: '${bold} 누르시오'
54 },
55 {
56 name: ' 기울임 꼴 명령',
57 legend: '${italic} 누르시오'
58 },
59 {
60 name: ' 밑줄 명령',
61 legend: '${underline} 누르시오'
62 },
63 {
64 name: ' 링크 명령',
65 legend: '${link} 누르시오'
66 },
67 {
68 name: ' 툴바 줄이기 명령',
69 legend: '${toolbarCollapse} 누르시오'
70 },
71 {
72 name: ' 이전 포커스 공간 접근 명령',
73 legend: '탈자 기호(^) 이전에 ${accessPreviousSpace} 를 누르면, 접근 불가능하면서 가장 가까운 포커스 영역에 접근합니다. 예를 들면, 두 인접한 HR 요소가 있습니다. 키 조합을 반복해서 멀리있는 포커스 영역들에 도달할 수 있습니다.'
74 },
75 {
76 name: '다음 포커스 공간 접근 명령',
77 legend: '탈자 기호(^) 다음에 ${accessNextSpace} 를 누르면, 접근 불가능하면서 가장 가까운 포커스 영역에 접근합니다. 예를 들면, 두 인접한 HR 요소가 있습니다. 키 조합을 반복해서 멀리있는 포커스 영역들에 도달할 수 있습니다. '
78 },
79 {
80 name: ' 접근성 도움말',
81 legend: '${a11yHelp} 누르시오'
82 }
83 ]
84 }
85 ],
86 tab: '탭 키',
87 pause: '일시정지 키',
88 capslock: '캡스 록 키',
89 escape: '이스케이프 키',
90 pageUp: '페이지 업 키',
91 pageDown: '페이지 다운 키',
92 leftArrow: '왼쪽 화살표 키',
93 upArrow: '위쪽 화살표 키',
94 rightArrow: '오른쪽 화살표 키',
95 downArrow: '아래쪽 화살표 키',
96 insert: '인서트 키',
97 leftWindowKey: '왼쪽 윈도우 키',
98 rightWindowKey: '오른쪽 윈도우 키',
99 selectKey: '셀렉트 키',
100 numpad0: '숫자 패드 0 키',
101 numpad1: '숫자 패드 1 키',
102 numpad2: '숫자 패드 2 키',
103 numpad3: '숫자 패드 3 키',
104 numpad4: '숫자 패드 4 키',
105 numpad5: '숫자 패드 5 키',
106 numpad6: '숫자 패드 6 키',
107 numpad7: '숫자 패드 7 키',
108 numpad8: '숫자 패드 8 키',
109 numpad9: '숫자 패드 9 키',
110 multiply: '곱셈(*) 키',
111 add: '덧셈(+) 키',
112 subtract: '뺄셈(-) 키',
113 decimalPoint: '온점(.) 키',
114 divide: '나눗셈(/) 키',
115 f1: 'F1 키',
116 f2: 'F2 키',
117 f3: 'F3 키',
118 f4: 'F4 키',
119 f5: 'F5 키',
120 f6: 'F6 키',
121 f7: 'F7 키',
122 f8: 'F8 키',
123 f9: 'F9 키',
124 f10: 'F10 키',
125 f11: 'F11 키',
126 f12: 'F12 키',
127 numLock: 'Num Lock 키',
128 scrollLock: 'Scroll Lock 키',
129 semiColon: '세미콜론(;) 키',
130 equalSign: '등호(=) 키',
131 comma: '쉼표(,) 키',
132 dash: '대시(-) 키',
133 period: '온점(.) 키',
134 forwardSlash: '슬래시(/) 키',
135 graveAccent: '억음 악센트(`) 키',
136 openBracket: '브라켓 열기([) 키',
137 backSlash: '역슬래시(\\\\) 키',
138 closeBracket: '브라켓 닫기(]) 키',
139 singleQuote: '외 따옴표(\') 키'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ku.js b/sources/plugins/a11yhelp/dialogs/lang/ku.js
new file mode 100644
index 0000000..3f044a2
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ku.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ku', {
7 title: 'ڕێنمای لەبەردەستدابوون',
8 contents: 'پێکهاتەی یارمەتی. کلیك ESC بۆ داخستنی ئەم دیالۆگه.',
9 legend: [
10 {
11 name: 'گشتی',
12 items: [
13 {
14 name: 'تووڵامرازی دەستكاریكەر',
15 legend: 'کلیك ${toolbarFocus} بۆ ڕابەری تووڵامراز. بۆ گواستنەوەی پێشوو داهاتووی گرووپی تووڵامرازی داگرتنی کلیلی TAB لەگەڵ‌ SHIFT+TAB. بۆ گواستنەوەی پێشوو داهاتووی دووگمەی تووڵامرازی لەڕێی کلیلی تیری دەستی ڕاست یان کلیلی تیری دەستی چەپ. کلیکی کلیلی SPACE یان ENTER بۆ چالاککردنی دووگمەی تووڵامراز.'
16 },
17
18 {
19 name: 'دیالۆگی دەستكاریكەر',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.'
22 },
23
24 {
25 name: 'پێڕستی سەرنووسەر',
26 legend: 'کلیك ${contextMenu} یان دوگمەی لیسته‌(Menu) بۆ کردنەوەی لیستەی دەق. بۆ چوونە هەڵبژاردەیەکی تر له‌ لیسته‌ کلیکی کلیلی TAB یان کلیلی تیری ڕوو لەخوارەوه‌ بۆ چوون بۆ هەڵبژاردەی پێشوو کلیکی کلیلی SHIFT+TAB یان کلیلی تیری ڕوو له‌ سەرەوە. داگرتنی کلیلی SPACE یان ENTER بۆ هەڵبژاردنی هەڵبژاردەی لیسته‌. بۆ کردنەوەی لقی ژێر لیسته‌ لەهەڵبژاردەی لیستە کلیکی کلیلی SPACE یان ENTER یان کلیلی تیری دەستی ڕاست. بۆ گەڕانەوه بۆ سەرەوەی لیسته‌ کلیکی کلیلی ESC یان کلیلی تیری دەستی چەپ. بۆ داخستنی لیستە کلیكی کلیلی ESC بکە.'
27 },
28
29 {
30 name: 'لیستی سنووقی سەرنووسەر',
31 legend: 'لەناو سنوقی لیست, چۆن بۆ هەڵنبژاردەی لیستێکی تر کلیکی کلیلی TAB یان کلیلی تیری ڕوو لەخوار. چوون بۆ هەڵبژاردەی لیستی پێشوو کلیکی کلیلی SHIFT+TAB یان کلیلی تیری ڕوو لەسەرەوه‌. کلیکی کلیلی SPACE یان ENTER بۆ دیاریکردنی ‌هەڵبژاردەی لیست. کلیکی کلیلی ESC بۆ داخستنی سنوقی لیست.'
32 },
33
34 {
35 name: 'تووڵامرازی توخم',
36 legend: 'کلیك ${elementsPathFocus} بۆ ڕابەری تووڵامرازی توخمەکان. چوون بۆ دوگمەی توخمێکی تر کلیکی کلیلی TAB یان کلیلی تیری دەستی ڕاست. چوون بۆ دوگمەی توخمی پێشوو کلیلی SHIFT+TAB یان کلیکی کلیلی تیری دەستی چەپ. داگرتنی کلیلی SPACE یان ENTER بۆ دیاریکردنی توخمەکه‌ لەسەرنووسه.'
37 }
38 ]
39 },
40 {
41 name: 'فەرمانەکان',
42 items: [
43 {
44 name: 'پووچکردنەوەی فەرمان',
45 legend: 'کلیك ${undo}'
46 },
47 {
48 name: 'هەڵگەڕانەوەی فەرمان',
49 legend: 'کلیك ${redo}'
50 },
51 {
52 name: 'فەرمانی دەقی قەڵەو',
53 legend: 'کلیك ${bold}'
54 },
55 {
56 name: 'فەرمانی دەقی لار',
57 legend: 'کلیك ${italic}'
58 },
59 {
60 name: 'فەرمانی ژێرهێڵ',
61 legend: 'کلیك ${underline}'
62 },
63 {
64 name: 'فەرمانی به‌ستەر',
65 legend: 'کلیك ${link}'
66 },
67 {
68 name: 'شاردەنەوەی تووڵامراز',
69 legend: 'کلیك ${toolbarCollapse}'
70 },
71 {
72 name: 'چوونەناو سەرنجدانی پێشوی فەرمانی بۆشایی',
73 legend: 'کلیک ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.'
74 },
75 {
76 name: 'چوونەناو سەرنجدانی داهاتووی فەرمانی بۆشایی',
77 legend: 'کلیک ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.'
78 },
79 {
80 name: 'دەستپێگەیشتنی یارمەتی',
81 legend: 'کلیك ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Left Arrow',
93 upArrow: 'Up Arrow',
94 rightArrow: 'Right Arrow',
95 downArrow: 'Down Arrow',
96 insert: 'Insert',
97 leftWindowKey: 'پەنجەرەی چەپ',
98 rightWindowKey: 'پەنجەرەی ڕاست',
99 selectKey: 'Select',
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: '1',
102 numpad2: '2',
103 numpad3: '3',
104 numpad4: '4',
105 numpad5: '5',
106 numpad6: '6',
107 numpad7: '7',
108 numpad8: '8',
109 numpad9: '9',
110 multiply: '*',
111 add: '+',
112 subtract: '-',
113 decimalPoint: '.',
114 divide: '/',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: ';',
130 equalSign: '=',
131 comma: ',',
132 dash: '-',
133 period: '.',
134 forwardSlash: '/',
135 graveAccent: '`',
136 openBracket: '[',
137 backSlash: '\\\\',
138 closeBracket: '}',
139 singleQuote: '\''
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/lt.js b/sources/plugins/a11yhelp/dialogs/lang/lt.js
new file mode 100644
index 0000000..c27e3ba
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/lt.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'lt', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Bendros savybės',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/lv.js b/sources/plugins/a11yhelp/dialogs/lang/lv.js
new file mode 100644
index 0000000..aac4129
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/lv.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'lv', {
7 title: 'Pieejamības instrukcija',
8 contents: 'Palīdzības saturs. Lai aizvērtu ciet šo dialogu nospiediet ESC.',
9 legend: [
10 {
11 name: 'Galvenais',
12 items: [
13 {
14 name: 'Redaktora rīkjosla',
15 legend: 'Nospiediet ${toolbarFocus} lai pārvietotos uz rīkjoslu. Lai pārvietotos uz nākošo vai iepriekšējo rīkjoslas grupu izmantojiet pogu TAB un SHIFT+TAB. Lai pārvietotos uz nākošo vai iepriekšējo rīkjoslas pogu izmantojiet Kreiso vai Labo bultiņu. Nospiediet Atstarpi vai ENTER lai aktivizētu rīkjosla pogu.'
16 },
17
18 {
19 name: 'Redaktora dialoga logs',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Redaktora satura izvēle',
26 legend: 'Nospiediet ${contextMenu} vai APPLICATION KEY lai atvērtu satura izvēlni. Lai pārvietotos uz nākošo izvēlnes opciju izmantojiet pogu TAB vai pogu Bultiņu uz leju. Lai pārvietotos uz iepriekšējo opciju izmantojiet SHIFT+TAB vai pogu Bultiņa uz augšu. Nospiediet SPACE vai ENTER lai izvelētos izvēlnes opciju. Atveriet tekošajā opcija apakšizvēlni ar SAPCE vai ENTER ka ari to var izdarīt ar Labo bultiņu. Lai atgrieztos atpakaļ uz sakuma izvēlni nospiediet ESC vai Kreiso bultiņu. Lai aizvērtu ciet izvēlnes saturu nospiediet ESC.'
27 },
28
29 {
30 name: 'Redaktora saraksta lauks',
31 legend: 'Saraksta laukā, lai pārvietotos uz nākošo saraksta elementu nospiediet TAB vai pogu Bultiņa uz leju. Lai pārvietotos uz iepriekšējo saraksta elementu nospiediet SHIFT+TAB vai pogu Bultiņa uz augšu. Nospiediet SPACE vai ENTER lai izvēlētos saraksta opcijas. Nospiediet ESC lai aizvērtu saraksta lauku.'
32 },
33
34 {
35 name: 'Redaktora elementa ceļa josla',
36 legend: 'Nospiediet ${elementsPathFocus} lai pārvietotos uz elementa ceļa joslu. Lai pārvietotos uz nākošo elementa pogu izmantojiet TAB vai Labo bultiņu. Lai pārvietotos uz iepriekšējo elementa pogu izmantojiet SHIFT+TAB vai Kreiso bultiņu. Nospiediet SPACE vai ENTER lai izvēlētos elementu redaktorā.'
37 }
38 ]
39 },
40 {
41 name: 'Komandas',
42 items: [
43 {
44 name: 'Komanda atcelt darbību',
45 legend: 'Nospiediet ${undo}'
46 },
47 {
48 name: 'Komanda atkārtot darbību',
49 legend: 'Nospiediet ${redo}'
50 },
51 {
52 name: 'Treknraksta komanda',
53 legend: 'Nospiediet ${bold}'
54 },
55 {
56 name: 'Kursīva komanda',
57 legend: 'Nospiediet ${italic}'
58 },
59 {
60 name: 'Apakšsvītras komanda ',
61 legend: 'Nospiediet ${underline}'
62 },
63 {
64 name: 'Hipersaites komanda',
65 legend: 'Nospiediet ${link}'
66 },
67 {
68 name: 'Rīkjoslas aizvēršanas komanda',
69 legend: 'Nospiediet ${toolbarCollapse}'
70 },
71 {
72 name: 'Piekļūt iepriekšējai fokusa vietas komandai',
73 legend: 'Nospiediet ${accessPreviousSpace} lai piekļūtu tuvākajai nepieejamajai fokusa vietai pirms kursora. Piemēram: diviem blakus esošiem līnijas HR elementiem. Atkārtojiet taustiņu kombināciju lai piekļūtu pie tālākām vietām.'
74 },
75 {
76 name: 'Piekļūt nākošā fokusa apgabala komandai',
77 legend: 'Nospiediet ${accessNextSpace} lai piekļūtu tuvākajai nepieejamajai fokusa vietai pēc kursora. Piemēram: diviem blakus esošiem līnijas HR elementiem. Atkārtojiet taustiņu kombināciju lai piekļūtu pie tālākām vietām.'
78 },
79 {
80 name: 'Pieejamības palīdzība',
81 legend: 'Nospiediet ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/mk.js b/sources/plugins/a11yhelp/dialogs/lang/mk.js
new file mode 100644
index 0000000..8316358
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/mk.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'mk', {
7 title: 'Инструкции за пристапност',
8 contents: 'Содржина на делот за помош. За да го затворите овој дијалог притиснете ESC.',
9 legend: [
10 {
11 name: 'Општо',
12 items: [
13 {
14 name: 'Мени за уредувачот',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Дијалот за едиторот',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Контекст-мени на уредувачот',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Наредби',
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Пауза',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Up',
92 leftArrow: 'Стрелка лево',
93 upArrow: 'Стрелка горе',
94 rightArrow: 'Стрелка десно',
95 downArrow: 'Стрелка доле',
96 insert: 'Insert',
97 leftWindowKey: 'Лево Windows копче',
98 rightWindowKey: 'Десно Windows копче',
99 selectKey: 'Select копче',
100 numpad0: 'Нум. таст. 0',
101 numpad1: 'Нум. таст. 1',
102 numpad2: 'Нум. таст. 2',
103 numpad3: 'Нум. таст. 3',
104 numpad4: 'Нум. таст. 4',
105 numpad5: 'Нум. таст. 5',
106 numpad6: 'Нум. таст. 6',
107 numpad7: 'Нум. таст. 7',
108 numpad8: 'Нум. таст. 8',
109 numpad9: 'Нум. таст. 9',
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/mn.js b/sources/plugins/a11yhelp/dialogs/lang/mn.js
new file mode 100644
index 0000000..eb11634
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/mn.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'mn', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Ерөнхий',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/nb.js b/sources/plugins/a11yhelp/dialogs/lang/nb.js
new file mode 100644
index 0000000..ccfeb66
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/nb.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'nb', {
7 title: 'Instruksjoner for tilgjengelighet',
8 contents: 'Innhold for hjelp. Trykk ESC for å lukke denne dialogen.',
9 legend: [
10 {
11 name: 'Generelt',
12 items: [
13 {
14 name: 'Verktøylinje for editor',
15 legend: 'Trykk ${toolbarFocus} for å navigere til verktøylinjen. Flytt til neste og forrige verktøylinjegruppe med TAB og SHIFT+TAB. Flytt til neste og forrige verktøylinjeknapp med HØYRE PILTAST og VENSTRE PILTAST. Trykk MELLOMROM eller ENTER for å aktivere verktøylinjeknappen.'
16 },
17
18 {
19 name: 'Dialog for editor',
20 legend:
21 'Mens du er i en dialog, trykk TAB for å navigere til neste dialogelement, trykk SHIFT+TAB for å flytte til forrige dialogelement, trykk ENTER for å akseptere dialogen, trykk ESC for å avbryte dialogen. Når en dialog har flere faner, kan fanelisten nås med enten ALT+F10 eller med TAB. Når fanelisten er fokusert, går man til neste og forrige fane med henholdsvis HØYRE og VENSTRE PILTAST.'
22 },
23
24 {
25 name: 'Kontekstmeny for editor',
26 legend: 'Trykk ${contextMenu} eller MENYKNAPP for å åpne kontekstmeny. Gå til neste alternativ i menyen med TAB eller PILTAST NED. Gå til forrige alternativ med SHIFT+TAB eller PILTAST OPP. Trykk MELLOMROM eller ENTER for å velge menyalternativet. Åpne undermenyen på valgt alternativ med MELLOMROM eller ENTER eller HØYRE PILTAST. Gå tilbake til overordnet menyelement med ESC eller VENSTRE PILTAST. Lukk kontekstmenyen med ESC.'
27 },
28
29 {
30 name: 'Listeboks for editor',
31 legend: 'I en listeboks, gå til neste alternativ i listen med TAB eller PILTAST NED. Gå til forrige alternativ i listen med SHIFT+TAB eller PILTAST OPP. Trykk MELLOMROM eller ENTER for å velge alternativet i listen. Trykk ESC for å lukke listeboksen.'
32 },
33
34 {
35 name: 'Verktøylinje for elementsti',
36 legend: 'Trykk ${elementsPathFocus} for å navigere til verktøylinjen som viser elementsti. Gå til neste elementknapp med TAB eller HØYRE PILTAST. Gå til forrige elementknapp med SHIFT+TAB eller VENSTRE PILTAST. Trykk MELLOMROM eller ENTER for å velge elementet i editoren.'
37 }
38 ]
39 },
40 {
41 name: 'Hurtigtaster',
42 items: [
43 {
44 name: 'Angre',
45 legend: 'Trykk ${undo}'
46 },
47 {
48 name: 'Gjør om',
49 legend: 'Trykk ${redo}'
50 },
51 {
52 name: 'Fet tekst',
53 legend: 'Trykk ${bold}'
54 },
55 {
56 name: 'Kursiv tekst',
57 legend: 'Trykk ${italic}'
58 },
59 {
60 name: 'Understreking',
61 legend: 'Trykk ${underline}'
62 },
63 {
64 name: 'Lenke',
65 legend: 'Trykk ${link}'
66 },
67 {
68 name: 'Skjul verktøylinje',
69 legend: 'Trykk ${toolbarCollapse}'
70 },
71 {
72 name: 'Gå til forrige fokusområde',
73 legend: 'Trykk ${accessPreviousSpace} for å komme til nærmeste fokusområde før skrivemarkøren som ikke kan nås på vanlig måte, for eksempel to tilstøtende HR-elementer. Gjenta tastekombinasjonen for å komme til fokusområder lenger unna i dokumentet.'
74 },
75 {
76 name: 'Gå til neste fokusområde',
77 legend: 'Trykk ${accessNextSpace} for å komme til nærmeste fokusområde etter skrivemarkøren som ikke kan nås på vanlig måte, for eksempel to tilstøtende HR-elementer. Gjenta tastekombinasjonen for å komme til fokusområder lenger unna i dokumentet.'
78 },
79 {
80 name: 'Hjelp for tilgjengelighet',
81 legend: 'Trykk ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulator',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Venstre piltast',
93 upArrow: 'Opp-piltast',
94 rightArrow: 'Høyre piltast',
95 downArrow: 'Ned-piltast',
96 insert: 'Insert',
97 leftWindowKey: 'Venstre Windows-tast',
98 rightWindowKey: 'Høyre Windows-tast',
99 selectKey: 'Velg nøkkel',
100 numpad0: 'Numerisk tastatur 0',
101 numpad1: 'Numerisk tastatur 1',
102 numpad2: 'Numerisk tastatur 2',
103 numpad3: 'Numerisk tastatur 3',
104 numpad4: 'Numerisk tastatur 4',
105 numpad5: 'Numerisk tastatur 5',
106 numpad6: 'Numerisk tastatur 6',
107 numpad7: 'Numerisk tastatur 7',
108 numpad8: 'Numerisk tastatur 8',
109 numpad9: 'Numerisk tastatur 9',
110 multiply: 'Multipliser',
111 add: 'Legg til',
112 subtract: 'Trekk fra',
113 decimalPoint: 'Desimaltegn',
114 divide: 'Divider',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semikolon',
130 equalSign: 'Likhetstegn',
131 comma: 'Komma',
132 dash: 'Bindestrek',
133 period: 'Punktum',
134 forwardSlash: 'Forover skråstrek',
135 graveAccent: 'Grav aksent',
136 openBracket: 'Åpne parentes',
137 backSlash: 'Bakover skråstrek',
138 closeBracket: 'Lukk parentes',
139 singleQuote: 'Enkelt sitattegn'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/nl.js b/sources/plugins/a11yhelp/dialogs/lang/nl.js
new file mode 100644
index 0000000..00d53ea
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/nl.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'nl', {
7 title: 'Toegankelijkheidsinstructies',
8 contents: 'Help-inhoud. Druk op ESC om dit dialoog te sluiten.',
9 legend: [
10 {
11 name: 'Algemeen',
12 items: [
13 {
14 name: 'Werkbalk tekstverwerker',
15 legend: 'Druk op ${toolbarFocus} om naar de werkbalk te navigeren. Om te schakelen naar de volgende en vorige werkbalkgroep, gebruik TAB en SHIFT+TAB. Om te schakelen naar de volgende en vorige werkbalkknop, gebruik de PIJL RECHTS en PIJL LINKS. Druk op SPATIE of ENTER om een werkbalkknop te activeren.'
16 },
17
18 {
19 name: 'Dialoog tekstverwerker',
20 legend:
21 'In een dialoogvenster, druk op TAB om te navigeren naar het volgende veld. Druk op SHIFT+TAB om naar het vorige veld te navigeren. Druk op ENTER om het dialoogvenster te verzenden. Druk op ESC om het dialoogvenster te sluiten. Bij dialoogvensters met meerdere tabbladen kan de tabset bereikt worden met ALT+F10 of met TAB als onderdeel van de tabvolgorde in het dialoogvenster. Als de tabset focus heeft, kun je schakalen naar het volgende en vorige tabblad met respectievelijk PIJL RECHTS en PIJL LINKS.'
22 },
23
24 {
25 name: 'Contextmenu tekstverwerker',
26 legend: 'Druk op ${contextMenu} of APPLICATION KEY om het contextmenu te openen. Schakel naar de volgende menuoptie met TAB of PIJL OMLAAG. Schakel naar de vorige menuoptie met SHIFT+TAB of PIJL OMHOOG. Druk op SPATIE of ENTER om een menuoptie te selecteren. Op een submenu van de huidige optie met SPATIE, ENTER of PIJL RECHTS. Ga terug naar de bovenliggende menuoptie met ESC of PIJL LINKS. Sluit het contextmenu met ESC.'
27 },
28
29 {
30 name: 'Keuzelijst tekstverwerker',
31 legend: 'In een keuzelijst, schakel naar het volgende item met TAB of PIJL OMLAAG. Schakel naar het vorige item met SHIFT+TAB of PIJL OMHOOG. Druk op SPATIE of ENTER om het item te selecteren. Druk op ESC om de keuzelijst te sluiten.'
32 },
33
34 {
35 name: 'Elementenpad werkbalk tekstverwerker',
36 legend: 'Druk op ${elementsPathFocus} om naar het elementenpad te navigeren. Om te schakelen naar het volgende element, gebruik TAB of PIJL RECHTS. Om te schakelen naar het vorige element, gebruik SHIFT+TAB or PIJL LINKS. Druk op SPATIE of ENTER om een element te selecteren in de tekstverwerker.'
37 }
38 ]
39 },
40 {
41 name: 'Opdrachten',
42 items: [
43 {
44 name: 'Ongedaan maken opdracht',
45 legend: 'Druk op ${undo}'
46 },
47 {
48 name: 'Opnieuw uitvoeren opdracht',
49 legend: 'Druk op ${redo}'
50 },
51 {
52 name: 'Vetgedrukt opdracht',
53 legend: 'Druk op ${bold}'
54 },
55 {
56 name: 'Cursief opdracht',
57 legend: 'Druk op ${italic}'
58 },
59 {
60 name: 'Onderstrepen opdracht',
61 legend: 'Druk op ${underline}'
62 },
63 {
64 name: 'Link opdracht',
65 legend: 'Druk op ${link}'
66 },
67 {
68 name: 'Werkbalk inklappen opdracht',
69 legend: 'Druk op ${toolbarCollapse}'
70 },
71 {
72 name: 'Ga naar vorige focus spatie commando',
73 legend: 'Druk ${accessPreviousSpace} om toegang te verkrijgen tot de dichtstbijzijnde onbereikbare focus spatie voor de caret, bijvoorbeeld: twee aangrenzende HR elementen. Herhaal de toetscombinatie om de verste focus spatie te bereiken.'
74 },
75 {
76 name: 'Ga naar volgende focus spatie commando',
77 legend: 'Druk ${accessNextSpace} om toegang te verkrijgen tot de dichtstbijzijnde onbereikbare focus spatie na de caret, bijvoorbeeld: twee aangrenzende HR elementen. Herhaal de toetscombinatie om de verste focus spatie te bereiken.'
78 },
79 {
80 name: 'Toegankelijkheidshulp',
81 legend: 'Druk op ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Pijl naar links',
93 upArrow: 'Pijl omhoog',
94 rightArrow: 'Pijl naar rechts',
95 downArrow: 'Pijl naar beneden',
96 insert: 'Invoegen',
97 leftWindowKey: 'Linker Windows-toets',
98 rightWindowKey: 'Rechter Windows-toets',
99 selectKey: 'Selecteer toets',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Vermenigvuldigen',
111 add: 'Toevoegen',
112 subtract: 'Aftrekken',
113 decimalPoint: 'Decimaalteken',
114 divide: 'Delen',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Puntkomma',
130 equalSign: 'Is gelijk-teken',
131 comma: 'Komma',
132 dash: 'Koppelteken',
133 period: 'Punt',
134 forwardSlash: 'Slash',
135 graveAccent: 'Accent grave',
136 openBracket: 'Vierkant haakje openen',
137 backSlash: 'Backslash',
138 closeBracket: 'Vierkant haakje sluiten',
139 singleQuote: 'Apostrof'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/no.js b/sources/plugins/a11yhelp/dialogs/lang/no.js
new file mode 100644
index 0000000..4402ddf
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/no.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'no', {
7 title: 'Instruksjoner for tilgjengelighet',
8 contents: 'Innhold for hjelp. Trykk ESC for å lukke denne dialogen.',
9 legend: [
10 {
11 name: 'Generelt',
12 items: [
13 {
14 name: 'Verktøylinje for editor',
15 legend: 'Trykk ${toolbarFocus} for å navigere til verktøylinjen. Flytt til neste og forrige verktøylinjegruppe med TAB og SHIFT+TAB. Flytt til neste og forrige verktøylinjeknapp med HØYRE PILTAST og VENSTRE PILTAST. Trykk MELLOMROM eller ENTER for å aktivere verktøylinjeknappen.'
16 },
17
18 {
19 name: 'Dialog for editor',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Kontekstmeny for editor',
26 legend: 'Trykk ${contextMenu} eller MENYKNAPP for å åpne kontekstmeny. Gå til neste alternativ i menyen med TAB eller PILTAST NED. Gå til forrige alternativ med SHIFT+TAB eller PILTAST OPP. Trykk MELLOMROM eller ENTER for å velge menyalternativet. Åpne undermenyen på valgt alternativ med MELLOMROM eller ENTER eller HØYRE PILTAST. Gå tilbake til overordnet menyelement med ESC eller VENSTRE PILTAST. Lukk kontekstmenyen med ESC.'
27 },
28
29 {
30 name: 'Listeboks for editor',
31 legend: 'I en listeboks, gå til neste alternativ i listen med TAB eller PILTAST NED. Gå til forrige alternativ i listen med SHIFT+TAB eller PILTAST OPP. Trykk MELLOMROM eller ENTER for å velge alternativet i listen. Trykk ESC for å lukke listeboksen.'
32 },
33
34 {
35 name: 'Verktøylinje for elementsti',
36 legend: 'Trykk ${elementsPathFocus} for å navigere til verktøylinjen som viser elementsti. Gå til neste elementknapp med TAB eller HØYRE PILTAST. Gå til forrige elementknapp med SHIFT+TAB eller VENSTRE PILTAST. Trykk MELLOMROM eller ENTER for å velge elementet i editoren.'
37 }
38 ]
39 },
40 {
41 name: 'Kommandoer',
42 items: [
43 {
44 name: 'Angre',
45 legend: 'Trykk ${undo}'
46 },
47 {
48 name: 'Gjør om',
49 legend: 'Trykk ${redo}'
50 },
51 {
52 name: 'Fet tekst',
53 legend: 'Trykk ${bold}'
54 },
55 {
56 name: 'Kursiv tekst',
57 legend: 'Trykk ${italic}'
58 },
59 {
60 name: 'Understreking',
61 legend: 'Trykk ${underline}'
62 },
63 {
64 name: 'Link',
65 legend: 'Trykk ${link}'
66 },
67 {
68 name: 'Skjul verktøylinje',
69 legend: 'Trykk ${toolbarCollapse}'
70 },
71 {
72 name: 'Gå til forrige fokusområde',
73 legend: 'Trykk ${accessPreviousSpace} for å komme til nærmeste fokusområde før skrivemarkøren som ikke kan nås på vanlig måte, for eksempel to tilstøtende HR-elementer. Gjenta tastekombinasjonen for å komme til fokusområder lenger unna i dokumentet.'
74 },
75 {
76 name: 'Gå til neste fokusområde',
77 legend: 'Trykk ${accessNextSpace} for å komme til nærmeste fokusområde etter skrivemarkøren som ikke kan nås på vanlig måte, for eksempel to tilstøtende HR-elementer. Gjenta tastekombinasjonen for å komme til fokusområder lenger unna i dokumentet.'
78 },
79 {
80 name: 'Hjelp for tilgjengelighet',
81 legend: 'Trykk ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/oc.js b/sources/plugins/a11yhelp/dialogs/lang/oc.js
new file mode 100644
index 0000000..8df209d
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/oc.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'oc', {
7 title: 'Instruccions d\'accessibilitat',
8 contents: 'Contengut de l\'ajuda. Per tampar aquesta fenèstra, quichatz sus la tòca Escap.',
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Barra d\'aisinas de l\'editor',
15 legend: 'Quichar sus ${toolbarFocus} per accedir a la barra d\'aisinas. Se desplaçar cap al groupe seguent o precedent de la barra d\'aisinas amb las tòcas Tab e Maj+Tab. Se desplaçar cap al boton seguent o precedent de la barra d\'aisinas amb las tòcas Sageta dreita e Sageta esquèrra. Quichar sus la barra d\'espaci o la tòca Entrada per activer lo boton de barra d\'aisinas.'
16 },
17
18 {
19 name: 'Fenèstra de l\'editor',
20 legend:
21 'Dins una bóstia de dialòg, quichar sus Tab per passar a l\'element seguent, quichar sus Maj+Tab per passar a l\'element precedent, quichar sus Entrada per validar, quichar sus Escap per anullar. Quand una bóstia de dialòg possedís des onglets, la lista pòt èsser atenta amb Alt+F10 o amb Tab. Dins la lista dels onglets, se desplaçar cap al seguent e lo precedent amb las tòcas Sageta dreita e Sageta esquèrra respectivament.'
22 },
23
24 {
25 name: 'Menú contextual de l\'editor',
26 legend: 'Quichar sus ${contextMenu} o sus la tòca Menú per dobrir lo menú contextual. Se desplaçar ensuite cap a l\'opcion seguenta del menú amb las tòcas Tab o Sageta bas. Se desplaçar cap a l\'opcion precedenta amb las tòcas Maj+Tab o Sageta naut. Quichar sus la barra d\'espaci o la tòca Entrada per seleccionar l\'opcion del menu. Quichar sus la barra d\'espaci, la tòca Entrada o Sageta dreita per dobrir lo sosmenú de l\'opcion seleccionada. Tornar a l\'element de menú parent amb la tòca Escap o Sageta esquèrra. Tampar lo menú contextual amb Escap.'
27 },
28
29 {
30 name: 'Zòna de lista de l\'editor',
31 legend: 'Dins una lista en menú desenrotlant, se desplaçar cap a l\'element seguent de la lista amb las tòcas Tab o Sageta bas. Se desplaçar cap a l\'element precedent de la lista amb las tòcas Maj+Tab o Sageta naut. Quichar sus la barra d\'espaci o sus Entrada per seleccionar l\'opcion dins la lista. Quichar sus Escap per tampar lo menú desenrotlant.'
32 },
33
34 {
35 name: 'Barra del camin d\'elements de l\'editor',
36 legend: 'Quichar sus ${elementsPathFocus} per naviguer cap a la barra del fial d\'Ariana dels elements. Se desplaçar cap al boton de l\'element seguent amb las tòcas Tab o Sageta dreita. Se desplaçar cap al boton precedent amb las tòcas Maj+Tab o Sageta esquèrra. Quichar sus la barra d\'espaci o sus Entrada per seleccionar l\'element dins l\'editor.'
37 }
38 ]
39 },
40 {
41 name: 'Comandas',
42 items: [
43 {
44 name: 'Anullar la comanda',
45 legend: 'Quichar sus ${undo}'
46 },
47 {
48 name: 'Comanda restablir',
49 legend: 'Quichar sus ${redo}'
50 },
51 {
52 name: ' Comanda gras',
53 legend: 'Quichar sus ${bold}'
54 },
55 {
56 name: ' Comanda italica',
57 legend: 'Quichar sus ${italic}'
58 },
59 {
60 name: ' Comanda solinhat',
61 legend: 'Quichar sus ${underline}'
62 },
63 {
64 name: ' Comanda ligam',
65 legend: 'Quichar sus ${link}'
66 },
67 {
68 name: 'Comanda enrotlar la barra d\'aisinas',
69 legend: 'Quichar sus ${toolbarCollapse}'
70 },
71 {
72 name: 'Comanda d\'accès a l\'element seleccionable precedent',
73 legend: 'Quichar sus ${accessNextSpace} per accedir a l\'element seleccionable inategnible lo mai pròche abans lo cursor, per exemple : doas linhas orizontalas adjacentas. Repetir la combinason de tòcas per aténher los elements seleccionables precedents.'
74 },
75 {
76 name: 'Comanda d\'accès a l\'element seleccionable seguent',
77 legend: 'Quichar sus ${accessNextSpace} per accedir a l\'element seleccionable inatenhible lo mai pròche aprèp lo cursor, per exemple : doas linhas orizontalas adjacentas. Repetir la combinason de tòcas per aténher los elements seleccionables seguents.'
78 },
79 {
80 name: ' Ajuda sus l\'accessibilitat',
81 legend: 'Quichar sus ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tabulacion',
87 pause: 'Pausa',
88 capslock: 'Verr. Maj.',
89 escape: 'Escap',
90 pageUp: 'Pagina superiora',
91 pageDown: 'Pagina seguenta',
92 leftArrow: 'Sageta esquèrra',
93 upArrow: 'Sageta naut',
94 rightArrow: 'Sageta dreita',
95 downArrow: 'Sageta bassa',
96 insert: 'Inser',
97 leftWindowKey: 'Tòca Windows esquèrra',
98 rightWindowKey: 'Tòca Windows dreita',
99 selectKey: 'Tòca Seleccionar',
100 numpad0: '0 del pavat numeric',
101 numpad1: '1 del pavat numeric',
102 numpad2: '2 del pavat numeric',
103 numpad3: '3 del pavat numeric',
104 numpad4: '4 del pavat numeric',
105 numpad5: '5 del pavat numeric',
106 numpad6: '6 del pavat numeric',
107 numpad7: '7 del pavat numeric',
108 numpad8: 'Pavat numeric 8',
109 numpad9: '9 del pavat numeric',
110 multiply: 'Multiplicar',
111 add: 'Plus',
112 subtract: 'Mens',
113 decimalPoint: 'Punt decimal',
114 divide: 'Devesir',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Verr. Num.',
128 scrollLock: 'Arrèst desfil.',
129 semiColon: 'Punt-virgula',
130 equalSign: 'Signe egal',
131 comma: 'Virgula',
132 dash: 'Jonhent',
133 period: 'Punt',
134 forwardSlash: 'Barra oblica',
135 graveAccent: 'Accent grèu',
136 openBracket: 'Parentèsi dobèrta',
137 backSlash: 'Barra oblica invèrsa',
138 closeBracket: 'Parentèsi tampanta',
139 singleQuote: 'Apostròfa'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/pl.js b/sources/plugins/a11yhelp/dialogs/lang/pl.js
new file mode 100644
index 0000000..825ea08
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/pl.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'pl', {
7 title: 'Instrukcje dotyczące dostępności',
8 contents: 'Zawartość pomocy. Wciśnij ESC, aby zamknąć to okno.',
9 legend: [
10 {
11 name: 'Informacje ogólne',
12 items: [
13 {
14 name: 'Pasek narzędzi edytora',
15 legend: 'Naciśnij ${toolbarFocus}, by przejść do paska narzędzi. Przejdź do następnej i poprzedniej grupy narzędzi używając TAB oraz SHIFT+TAB. Przejdź do następnego i poprzedniego przycisku paska narzędzi za pomocą STRZAŁKI W PRAWO lub STRZAŁKI W LEWO. Naciśnij SPACJĘ lub ENTER by aktywować przycisk paska narzędzi.'
16 },
17
18 {
19 name: 'Okno dialogowe edytora',
20 legend:
21 'Wewnątrz okna dialogowego naciśnij TAB, by przejść do kolejnego elementu tego okna lub SHIFT+TAB, by przejść do poprzedniego elementu okna. Naciśnij ENTER w celu zatwierdzenia opcji okna dialogowego lub ESC w celu anulowania zmian. Jeśli okno dialogowe ma kilka zakładek, do listy zakładek można przejść za pomocą ALT+F10 lub TAB. Gdy lista zakładek jest aktywna, możesz przejść do kolejnej i poprzedniej zakładki za pomocą STRZAŁKI W PRAWO i STRZAŁKI W LEWO.'
22 },
23
24 {
25 name: 'Menu kontekstowe edytora',
26 legend: 'Wciśnij ${contextMenu} lub PRZYCISK APLIKACJI aby otworzyć menu kontekstowe. Przejdź do następnej pozycji menu wciskając TAB lub STRZAŁKĘ W DÓŁ. Przejdź do poprzedniej pozycji menu wciskając SHIFT + TAB lub STRZAŁKĘ W GÓRĘ. Wciśnij SPACJĘ lub ENTER aby wygrać pozycję menu. Otwórz pod-menu obecnej pozycji wciskając SPACJĘ lub ENTER lub STRZAŁKĘ W PRAWO. Wróć do pozycji nadrzędnego menu wciskając ESC lub STRZAŁKĘ W LEWO. Zamknij menu wciskając ESC.'
27 },
28
29 {
30 name: 'Lista w edytorze',
31 legend: 'Wewnątrz listy przejdź do kolejnego elementu listy za pomocą przycisku TAB lub STRZAŁKI W DÓŁ. Przejdź do poprzedniego elementu listy za pomocą SHIFT+TAB lub STRZAŁKI W GÓRĘ. Naciśnij SPACJĘ lub ENTER w celu wybrania opcji z listy. Naciśnij ESC, by zamknąć listę.'
32 },
33
34 {
35 name: 'Pasek ścieżki elementów edytora',
36 legend: 'Naciśnij ${elementsPathFocus} w celu przejścia do paska ścieżki elementów edytora. W celu przejścia do kolejnego elementu naciśnij klawisz TAB lub STRZAŁKI W PRAWO. W celu przejścia do poprzedniego elementu naciśnij klawisze SHIFT+TAB lub STRZAŁKI W LEWO. By wybrać element w edytorze, użyj klawisza SPACJI lub ENTER.'
37 }
38 ]
39 },
40 {
41 name: 'Polecenia',
42 items: [
43 {
44 name: 'Polecenie Cofnij',
45 legend: 'Naciśnij ${undo}'
46 },
47 {
48 name: 'Polecenie Ponów',
49 legend: 'Naciśnij ${redo}'
50 },
51 {
52 name: 'Polecenie Pogrubienie',
53 legend: 'Naciśnij ${bold}'
54 },
55 {
56 name: 'Polecenie Kursywa',
57 legend: 'Naciśnij ${italic}'
58 },
59 {
60 name: 'Polecenie Podkreślenie',
61 legend: 'Naciśnij ${underline}'
62 },
63 {
64 name: 'Polecenie Wstaw/ edytuj odnośnik',
65 legend: 'Naciśnij ${link}'
66 },
67 {
68 name: 'Polecenie schowaj pasek narzędzi',
69 legend: 'Naciśnij ${toolbarCollapse}'
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: 'Pomoc dotycząca dostępności',
81 legend: 'Naciśnij ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Strzałka w lewo',
93 upArrow: 'Strzałka w górę',
94 rightArrow: 'Strzałka w prawo',
95 downArrow: 'Strzałka w dół',
96 insert: 'Insert',
97 leftWindowKey: 'Lewy klawisz Windows',
98 rightWindowKey: 'Prawy klawisz Windows',
99 selectKey: 'Klawisz wyboru',
100 numpad0: 'Klawisz 0 na klawiaturze numerycznej',
101 numpad1: 'Klawisz 1 na klawiaturze numerycznej',
102 numpad2: 'Klawisz 2 na klawiaturze numerycznej',
103 numpad3: 'Klawisz 3 na klawiaturze numerycznej',
104 numpad4: 'Klawisz 4 na klawiaturze numerycznej',
105 numpad5: 'Klawisz 5 na klawiaturze numerycznej',
106 numpad6: 'Klawisz 6 na klawiaturze numerycznej',
107 numpad7: 'Klawisz 7 na klawiaturze numerycznej',
108 numpad8: 'Klawisz 8 na klawiaturze numerycznej',
109 numpad9: 'Klawisz 9 na klawiaturze numerycznej',
110 multiply: 'Przemnóż',
111 add: 'Plus',
112 subtract: 'Minus',
113 decimalPoint: 'Separator dziesiętny',
114 divide: 'Podziel',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Średnik',
130 equalSign: 'Znak równości',
131 comma: 'Przecinek',
132 dash: 'Pauza',
133 period: 'Kropka',
134 forwardSlash: 'Ukośnik prawy',
135 graveAccent: 'Akcent słaby',
136 openBracket: 'Nawias kwadratowy otwierający',
137 backSlash: 'Ukośnik lewy',
138 closeBracket: 'Nawias kwadratowy zamykający',
139 singleQuote: 'Apostrof'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/pt-br.js b/sources/plugins/a11yhelp/dialogs/lang/pt-br.js
new file mode 100644
index 0000000..030df98
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/pt-br.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'pt-br', {
7 title: 'Instruções de Acessibilidade',
8 contents: 'Conteúdo da Ajuda. Para fechar este diálogo pressione ESC.',
9 legend: [
10 {
11 name: 'Geral',
12 items: [
13 {
14 name: 'Barra de Ferramentas do Editor',
15 legend: 'Pressione ${toolbarFocus} para navegar para a barra de ferramentas. Mova para o anterior ou próximo grupo de ferramentas com TAB e SHIFT+TAB. Mova para o anterior ou próximo botão com SETA PARA DIREITA or SETA PARA ESQUERDA. Pressione ESPAÇO ou ENTER para ativar o botão da barra de ferramentas.'
16 },
17
18 {
19 name: 'Diálogo do Editor',
20 legend:
21 'Dentro de um diálogo, pressione TAB para navegar para o próximo elemento. Pressione SHIFT+TAB para mover para o elemento anterior. Pressione ENTER ara enviar o diálogo. pressione ESC para cancelar o diálogo. Quando um diálogo tem múltiplas abas, a lista de abas pode ser acessada com ALT+F10 ou TAB, como parte da ordem de tabulação do diálogo. Com a lista de abas em foco, mova para a próxima aba e para a aba anterior com a SETA DIREITA ou SETA ESQUERDA, respectivamente.'
22 },
23
24 {
25 name: 'Menu de Contexto do Editor',
26 legend: 'Pressione ${contextMenu} ou TECLA DE MENU para abrir o menu de contexto, então mova para a próxima opção com TAB ou SETA PARA BAIXO. Mova para a anterior com SHIFT+TAB ou SETA PARA CIMA. Pressione ESPAÇO ou ENTER para selecionar a opção do menu. Abra o submenu da opção atual com ESPAÇO ou ENTER ou SETA PARA DIREITA. Volte para o menu pai com ESC ou SETA PARA ESQUERDA. Feche o menu de contexto com ESC.'
27 },
28
29 {
30 name: 'Caixa de Lista do Editor',
31 legend: 'Dentro de uma caixa de lista, mova para o próximo item com TAB ou SETA PARA BAIXO. Mova para o item anterior com SHIFT+TAB ou SETA PARA CIMA. Pressione ESPAÇO ou ENTER para selecionar uma opção na lista. Pressione ESC para fechar a caixa de lista.'
32 },
33
34 {
35 name: 'Barra de Caminho do Elementos do Editor',
36 legend: 'Pressione ${elementsPathFocus} para a barra de caminho dos elementos. Mova para o próximo botão de elemento com TAB ou SETA PARA DIREITA. Mova para o botão anterior com SHIFT+TAB ou SETA PARA ESQUERDA. Pressione ESPAÇO ou ENTER para selecionar o elemento no editor.'
37 }
38 ]
39 },
40 {
41 name: 'Comandos',
42 items: [
43 {
44 name: ' Comando Desfazer',
45 legend: 'Pressione ${undo}'
46 },
47 {
48 name: ' Comando Refazer',
49 legend: 'Pressione ${redo}'
50 },
51 {
52 name: ' Comando Negrito',
53 legend: 'Pressione ${bold}'
54 },
55 {
56 name: ' Comando Itálico',
57 legend: 'Pressione ${italic}'
58 },
59 {
60 name: ' Comando Sublinhado',
61 legend: 'Pressione ${underline}'
62 },
63 {
64 name: ' Comando Link',
65 legend: 'Pressione ${link}'
66 },
67 {
68 name: ' Comando Fechar Barra de Ferramentas',
69 legend: 'Pressione ${toolbarCollapse}'
70 },
71 {
72 name: 'Acessar o comando anterior de spaço de foco',
73 legend: 'Pressione ${accessNextSpace} para acessar o espaço de foco não alcançável mais próximo antes do cursor, por exemplo: dois elementos HR adjacentes. Repita a combinação de teclas para alcançar espaços de foco distantes.'
74 },
75 {
76 name: 'Acessar próximo fomando de spaço de foco',
77 legend: 'Pressione ${accessNextSpace} para acessar o espaço de foco não alcançável mais próximo após o cursor, por exemplo: dois elementos HR adjacentes. Repita a combinação de teclas para alcançar espaços de foco distantes.'
78 },
79 {
80 name: ' Ajuda de Acessibilidade',
81 legend: 'Pressione ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tecla Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Seta à Esquerda',
93 upArrow: 'Seta à Cima',
94 rightArrow: 'Seta à Direita',
95 downArrow: 'Seta à Baixo',
96 insert: 'Insert',
97 leftWindowKey: 'Tecla do Windows Esquerda',
98 rightWindowKey: 'Tecla do Windows Direita',
99 selectKey: 'Tecla Selecionar',
100 numpad0: '0 do Teclado Numérico',
101 numpad1: '1 do Teclado Numérico',
102 numpad2: '2 do Teclado Numérico',
103 numpad3: '3 do Teclado Numérico',
104 numpad4: '4 do Teclado Numérico',
105 numpad5: '5 do Teclado Numérico',
106 numpad6: '6 do Teclado Numérico',
107 numpad7: '7 do Teclado Numérico',
108 numpad8: '8 do Teclado Numérico',
109 numpad9: '9 do Teclado Numérico',
110 multiply: 'Multiplicar',
111 add: 'Mais',
112 subtract: 'Subtrair',
113 decimalPoint: 'Ponto',
114 divide: 'Dividir',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Ponto-e-vírgula',
130 equalSign: 'Igual',
131 comma: 'Vírgula',
132 dash: 'Hífen',
133 period: 'Ponto',
134 forwardSlash: 'Barra',
135 graveAccent: 'Acento Grave',
136 openBracket: 'Abrir Conchetes',
137 backSlash: 'Contra-barra',
138 closeBracket: 'Fechar Colchetes',
139 singleQuote: 'Aspas Simples'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/pt.js b/sources/plugins/a11yhelp/dialogs/lang/pt.js
new file mode 100644
index 0000000..986a377
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/pt.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'pt', {
7 title: 'Instruções de acessibilidade',
8 contents: 'Conteúdo de ajuda. Use a tecla ESC para fechar esta janela.',
9 legend: [
10 {
11 name: 'Geral',
12 items: [
13 {
14 name: 'Barra de ferramentas do editor',
15 legend: 'Clique em ${toolbarFocus} para navegar na barra de ferramentas. Para navegar entre o grupo da barra de ferramentas anterior e seguinte use TAB e SHIFT+TAB. Para navegar entre o botão da barra de ferramentas seguinte e anterior use a SETA DIREITA ou SETA ESQUERDA. Carregue em ESPAÇO ou ENTER para ativar o botão da barra de ferramentas.'
16 },
17
18 {
19 name: 'Janela do editor',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Menu de contexto do editor',
26 legend: 'Clique em ${contextMenu} ou TECLA APLICAÇÃO para abrir o menu de contexto. Depois vá para a opção do menu seguinte com TAB ou SETA PARA BAIXO. Vá para a opção anterior com SHIFT+TAB ou SETA PARA CIMA. Pressione ESPAÇO ou ENTER para selecionar a opção do menu. Abra o submenu da opção atual com ESPAÇO, ENTER ou SETA DIREITA. GVá para o item do menu parente com ESC ou SETA ESQUERDA. Feche o menu de contexto com ESC.'
27 },
28
29 {
30 name: 'Editor de caixa em lista',
31 legend: 'Dentro de uma lista, para navegar para o item seguinte da lista use TAB ou SETA PARA BAIXO. Para o item anterior da lista use SHIFT+TAB ou SETA PARA BAIXO. Carregue em ESPAÇO ou ENTER para selecionar a opção lista. Carregue em ESC para fechar a caixa da lista.'
32 },
33
34 {
35 name: 'Editor da barra de caminho dos elementos',
36 legend: 'Clique em ${elementsPathFocus} para navegar na barra de caminho dos elementos. Para o botão do elemento seguinte use TAB ou SETA DIREITA. para o botão anterior use SHIFT+TAB ou SETA ESQUERDA. Carregue em ESPAÇO ou ENTER para selecionar o elemento no editor.'
37 }
38 ]
39 },
40 {
41 name: 'Comandos',
42 items: [
43 {
44 name: 'Comando de anular',
45 legend: 'Carregar ${undo}'
46 },
47 {
48 name: 'Comando de refazer',
49 legend: 'Clique ${redo}'
50 },
51 {
52 name: 'Comando de negrito',
53 legend: 'Pressione ${bold}'
54 },
55 {
56 name: 'Comando de itálico',
57 legend: 'Pressione ${italic}'
58 },
59 {
60 name: 'Comando de sublinhado',
61 legend: 'Pressione ${underline}'
62 },
63 {
64 name: 'Comando de hiperligação',
65 legend: 'Pressione ${link}'
66 },
67 {
68 name: 'Comando de ocultar barra de ferramentas',
69 legend: 'Pressione ${toolbarCollapse}'
70 },
71 {
72 name: 'Aceder ao comando espaço de foco anterior',
73 legend: 'Clique em ${accessPreviousSpace} para aceder ao espaço do focos inalcançável mais perto antes do sinal de omissão, por exemplo: dois elementos HR adjacentes. Repetir a combinação da chave para alcançar os espaços dos focos distantes.'
74 },
75 {
76 name: 'Acesso comando do espaço focus seguinte',
77 legend: 'Pressione ${accessNextSpace} para aceder ao espaço do focos inalcançável mais perto depois do sinal de omissão, por exemplo: dois elementos HR adjacentes. Repetir a combinação da chave para alcançar os espaços dos focos distantes.'
78 },
79 {
80 name: 'Ajuda a acessibilidade',
81 legend: 'Pressione ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pausa',
88 capslock: 'Maiúsculas',
89 escape: 'Esc',
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Seta esquerda',
93 upArrow: 'Seta para cima',
94 rightArrow: 'Seta direita',
95 downArrow: 'Seta para baixo',
96 insert: 'Inserir',
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiplicar',
111 add: 'Adicionar',
112 subtract: 'Subtrair',
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Separar',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Vírgula',
132 dash: 'Cardinal',
133 period: 'Ponto',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Acento grave',
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Plica'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ro.js b/sources/plugins/a11yhelp/dialogs/lang/ro.js
new file mode 100644
index 0000000..a182bbd
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ro.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ro', {
7 title: 'Instrucțiuni de accesibilitate',
8 contents: 'Cuprins. Pentru a închide acest dialog, apăsați tasta ESC.',
9 legend: [
10 {
11 name: 'General',
12 items: [
13 {
14 name: 'Editează bara instrumente.',
15 legend: 'Apasă ${toolbarFocus} pentru a naviga prin bara de instrumente. Pentru a te mișca prin grupurile de instrumente folosește tastele TAB și SHIFT+TAB. Pentru a te mișca intre diverse instrumente folosește tastele SĂGEATĂ DREAPTA sau SĂGEATĂ STÂNGA. Apasă butonul SPAȚIU sau ENTER pentru activarea instrumentului.'
16 },
17
18 {
19 name: 'Dialog editor',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor meniu contextual',
26 legend: 'Apasă ${contextMenu} sau TASTA MENIU pentru a deschide meniul contextual. Treci la următoarea opțiune din meniu cu TAB sau SĂGEATĂ JOS. Treci la opțiunea anterioară cu SHIFT+TAB sau SĂGEATĂ SUS. Apasă SPAȚIU sau ENTER pentru a selecta opțiunea din meniu. Deschide sub-meniul opțiunii curente cu SPAȚIU sau ENTER sau SĂGEATĂ DREAPTA. Revino la elementul din meniul părinte cu ESC sau SĂGEATĂ STÂNGA. Închide meniul de context cu ESC.'
27 },
28
29 {
30 name: 'Editor Casetă Listă',
31 legend: 'În interiorul unei liste, treci la următorull element cu TAB sau SĂGEATĂ JOS. Treci la elementul anterior din listă cu SHIFT+TAB sau SĂGEATĂ SUS. Apasă SPAȚIU sau ENTER pentru a selecta opțiunea din listă. Apasă ESC pentru a închide lista.'
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Comenzi',
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Apasă ${undo}'
46 },
47 {
48 name: 'Comanda precedentă',
49 legend: 'Apasă ${redo}'
50 },
51 {
52 name: 'Comanda Îngroșat',
53 legend: 'Apasă ${bold}'
54 },
55 {
56 name: 'Comanda Inclinat',
57 legend: 'Apasă ${italic}'
58 },
59 {
60 name: 'Comanda Subliniere',
61 legend: 'Apasă ${underline}'
62 },
63 {
64 name: 'Comanda Legatură',
65 legend: 'Apasă ${link}'
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ru.js b/sources/plugins/a11yhelp/dialogs/lang/ru.js
new file mode 100644
index 0000000..19d502a
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ru.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ru', {
7 title: 'Горячие клавиши',
8 contents: 'Помощь. Для закрытия этого окна нажмите ESC.',
9 legend: [
10 {
11 name: 'Основное',
12 items: [
13 {
14 name: 'Панель инструментов',
15 legend: 'Нажмите ${toolbarFocus} для перехода к панели инструментов. Для перемещения между группами панели инструментов используйте TAB и SHIFT+TAB. Для перемещения между кнопками панели иструментов используйте кнопки ВПРАВО или ВЛЕВО. Нажмите ПРОБЕЛ или ENTER для запуска кнопки панели инструментов.'
16 },
17
18 {
19 name: 'Диалоги',
20 legend:
21 'Внутри диалога, нажмите TAB чтобы перейти к следующему элементу диалога, нажмите SHIFT+TAB чтобы перейти к предыдущему элементу диалога, нажмите ENTER чтобы отправить диалог, нажмите ESC чтобы отменить диалог. Когда диалоговое окно имеет несколько вкладок, получить доступ к панели вкладок как части диалога можно нажатием или сочетания ALT+F10 или TAB, при этом активные элементы диалога будут перебираться с учетом порядка табуляции. При активной панели вкладок, переход к следующей или предыдущей вкладке осуществляется нажатием стрелки "ВПРАВО" или стрелки "ВЛЕВО" соответственно.'
22 },
23
24 {
25 name: 'Контекстное меню',
26 legend: 'Нажмите ${contextMenu} или клавишу APPLICATION, чтобы открыть контекстное меню. Затем перейдите к следующему пункту меню с помощью TAB или стрелкой "ВНИЗ". Переход к предыдущей опции - SHIFT+TAB или стрелкой "ВВЕРХ". Нажмите SPACE, или ENTER, чтобы задействовать опцию меню. Открыть подменю текущей опции - SPACE или ENTER или стрелкой "ВПРАВО". Возврат к родительскому пункту меню - ESC или стрелкой "ВЛЕВО". Закрытие контекстного меню - ESC.'
27 },
28
29 {
30 name: 'Редактор списка',
31 legend: 'Внутри окна списка, переход к следующему пункту списка - TAB или стрелкой "ВНИЗ". Переход к предыдущему пункту списка - SHIFT+TAB или стрелкой "ВВЕРХ". Нажмите SPACE, или ENTER, чтобы задействовать опцию списка. Нажмите ESC, чтобы закрыть окно списка.'
32 },
33
34 {
35 name: 'Путь к элементу',
36 legend: 'Нажмите ${elementsPathFocus}, чтобы перейти к панели пути элементов. Переход к следующей кнопке элемента - TAB или стрелкой "ВПРАВО". Переход к предыдущей кнопку - SHIFT+TAB или стрелкой "ВЛЕВО". Нажмите SPACE, или ENTER, чтобы выбрать элемент в редакторе.'
37 }
38 ]
39 },
40 {
41 name: 'Команды',
42 items: [
43 {
44 name: 'Отменить',
45 legend: 'Нажмите ${undo}'
46 },
47 {
48 name: 'Повторить',
49 legend: 'Нажмите ${redo}'
50 },
51 {
52 name: 'Полужирный',
53 legend: 'Нажмите ${bold}'
54 },
55 {
56 name: 'Курсив',
57 legend: 'Нажмите ${italic}'
58 },
59 {
60 name: 'Подчеркнутый',
61 legend: 'Нажмите ${underline}'
62 },
63 {
64 name: 'Гиперссылка',
65 legend: 'Нажмите ${link}'
66 },
67 {
68 name: 'Свернуть панель инструментов',
69 legend: 'Нажмите ${toolbarCollapse}'
70 },
71 {
72 name: 'Команды доступа к предыдущему фокусному пространству',
73 legend: 'Нажмите ${accessPreviousSpace}, чтобы обратиться к ближайшему недостижимому фокусному пространству перед символом "^", например: два смежных HR элемента. Повторите комбинацию клавиш, чтобы достичь отдаленных фокусных пространств.'
74 },
75 {
76 name: 'Команды доступа к следующему фокусному пространству',
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.'
78 },
79 {
80 name: 'Справка по горячим клавишам',
81 legend: 'Нажмите ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Esc',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Стрелка влево',
93 upArrow: 'Стрелка вверх',
94 rightArrow: 'Стрелка вправо',
95 downArrow: 'Стрелка вниз',
96 insert: 'Insert',
97 leftWindowKey: 'Левая клавиша Windows',
98 rightWindowKey: 'Правая клавиша Windows',
99 selectKey: 'Выбрать',
100 numpad0: 'Цифра 0',
101 numpad1: 'Цифра 1',
102 numpad2: 'Цифра 2',
103 numpad3: 'Цифра 3',
104 numpad4: 'Цифра 4',
105 numpad5: 'Цифра 5',
106 numpad6: 'Цифра 6',
107 numpad7: 'Цифра 7',
108 numpad8: 'Цифра 8',
109 numpad9: 'Цифра 9',
110 multiply: 'Умножить',
111 add: 'Плюс',
112 subtract: 'Вычесть',
113 decimalPoint: 'Десятичная точка',
114 divide: 'Делить',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Точка с запятой',
130 equalSign: 'Равно',
131 comma: 'Запятая',
132 dash: 'Тире',
133 period: 'Точка',
134 forwardSlash: 'Наклонная черта',
135 graveAccent: 'Апостроф',
136 openBracket: 'Открыть скобку',
137 backSlash: 'Обратная наклонная черта',
138 closeBracket: 'Закрыть скобку',
139 singleQuote: 'Одинарная кавычка'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/si.js b/sources/plugins/a11yhelp/dialogs/lang/si.js
new file mode 100644
index 0000000..14d94ad
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/si.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'si', {
7 title: 'ළඟා වියහැකි ',
8 contents: 'උදව් සඳහා අන්තර්ගතය.නික්මයෙමට ESC බොත්තම ඔබන්න',
9 legend: [
10 {
11 name: 'පොදු කරුණු',
12 items: [
13 {
14 name: 'සංස්කරණ මෙවලම් ',
15 legend: 'ඔබන්න ${මෙවලම් තීරු අවධානය} මෙවලම් තීරුවේ එහා මෙහා යෑමට.ඉදිරියට යෑමට හා ආපසු යෑමට මෙවලම් තීරුකාණ්ඩය හා TAB හා SHIFT+TAB .ඉදිරියට යෑමට හා ආපසු යෑමට මෙවලම් තීරු බොත්තම සමග RIGHT ARROW හෝ LEFT ARROW.මෙවලම් තීරු බොත්තම සක්‍රිය කර ගැනීමට SPACE හෝ ENTER බොත්තම ඔබන්න.'
16 },
17
18 {
19 name: 'සංස්කරණ ',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'සංස්කරණ අඩංගුවට ',
26 legend: 'ඔබන්න ${අන්තර්ගත මෙනුව} හෝ APPLICATION KEY අන්තර්ගත-මෙනුව විවුරතකිරීමට. ඊළඟ මෙනුව-ව්කල්පයන්ට යෑමට TAB හෝ DOWN ARROW බොත්තම ද, පෙර විකල්පයන්ටයෑමට SHIFT+TAB හෝ UP ARROW බොත්තම ද, මෙනුව-ව්කල්පයන් තේරීමට SPACE හෝ ENTER බොත්තම ද, දැනට විවුර්තව ඇති උප-මෙනුවක වීකල්ප තේරීමට SPACE හෝ ENTER හෝ RIGHT ARROW ද, නැවත පෙර ප්‍රධාන මෙනුවට යෑමට ESC හෝ LEFT ARROW බොත්තම ද. අන්තර්ගත-මෙනුව වැසීමට ESC බොත්තම ද ඔබන්න.'
27 },
28
29 {
30 name: 'සංස්කරණ තේරුම් ',
31 legend: 'තේරුම් කොටුව තුළ , ඊළඟ අයිතමයට යෑමට TAB හෝ DOWN ARROW , පෙර අයිතමයට යෑමට SHIFT+TAB හෝ UP ARROW . අයිතම විකල්පයන් තේරීමට SPACE හෝ ENTER ,තේරුම් කොටුව වැසීමට ESC බොත්තම් ද ඔබන්න.'
32 },
33
34 {
35 name: 'සංස්කරණ අංග සහිත ',
36 legend: 'ඔබන්න ${මෙවලම් තීරු අවධානය} මෙවලම් තීරුවේ එහා මෙහා යෑමට.ඉදිරියට යෑමට හා ආපසු යෑමට මෙවලම් තීරුකාණ්ඩය හා TAB හා SHIFT+TAB .ඉදිරියට යෑමට හා ආපසු යෑමට මෙවලම් තීරු බොත්තම සමග RIGHT ARROW හෝ LEFT ARROW.මෙවලම් තීරු බොත්තම සක්‍රිය කර ගැනීමට SPACE හෝ ENTER බොත්තම ඔබන්න.'
37 }
38 ]
39 },
40 {
41 name: 'විධාන',
42 items: [
43 {
44 name: 'විධානය වෙනස් ',
45 legend: 'ඔබන්න ${වෙනස් කිරීම}'
46 },
47 {
48 name: 'විධාන නැවත් පෙර පරිදිම වෙනස්කර ගැනීම.',
49 legend: 'ඔබන්න ${නැවත් පෙර පරිදිම වෙනස්කර ගැනීම}'
50 },
51 {
52 name: 'තද අකුරින් විධාන',
53 legend: 'ඔබන්න ${තද }'
54 },
55 {
56 name: 'බැධී අකුරු විධාන',
57 legend: 'ඔබන්න ${බැධී අකුරු }'
58 },
59 {
60 name: 'යටින් ඉරි ඇද ඇති විධාන.',
61 legend: 'ඔබන්න ${යටින් ඉරි ඇද ඇති}'
62 },
63 {
64 name: 'සම්බන්ධිත විධාන',
65 legend: 'ඔබන්න ${සම්බන්ධ }'
66 },
67 {
68 name: 'මෙවලම් තීරු හැකුලුම් විධාන',
69 legend: 'ඔබන්න ${මෙවලම් තීරු හැකුලුම් }'
70 },
71 {
72 name: 'යොමුවීමට පෙර වැදගත් විධාන',
73 legend: 'ඔබන්න ${යොමුවීමට ඊළඟ }'
74 },
75 {
76 name: 'යොමුවීමට ඊළග වැදගත් විධාන',
77 legend: 'ඔබන්න ${යොමුවීමට ඊළඟ }'
78 },
79 {
80 name: 'ප්‍රවේශ ',
81 legend: 'ඔබන්න ${a11y }'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sk.js b/sources/plugins/a11yhelp/dialogs/lang/sk.js
new file mode 100644
index 0000000..2d74c3b
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sk.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sk', {
7 title: 'Inštrukcie prístupnosti',
8 contents: 'Pomocný obsah. Pre zatvorenie tohto okna, stlačte ESC.',
9 legend: [
10 {
11 name: 'Všeobecne',
12 items: [
13 {
14 name: 'Lišta nástrojov editora',
15 legend: 'Stlačte ${toolbarFocus} pre navigáciu na lištu nástrojov. Medzi ďalšou a predchádzajúcou lištou nástrojov sa pohybujete s TAB a SHIFT+TAB. Medzi ďalším a predchádzajúcim tlačidlom na lište nástrojov sa pohybujete s pravou šípkou a ľavou šípkou. Stlačte medzerník alebo ENTER pre aktiváciu tlačidla lišty nástrojov.'
16 },
17
18 {
19 name: 'Editorový dialóg',
20 legend:
21 'V dialógovom okne stlačte TAB pre presun na ďalší prvok, SHIFT+TAB pre presun na predchádzajúci prvok, ENTER pre odoslanie, ESC pre zrušenie. Keď má dialógové okno viacero kariet, zoznam kariet dosiahnete buď stlačením ALT+F10 alebo s TAB v príslušnom poradí kariet. So zameraným zoznamom kariet sa pohybujte k ďalšej alebo predchádzajúcej karte cez PRAVÚ a ĽAVÚ ŠÍPKU.'
22 },
23
24 {
25 name: 'Editorové kontextové menu',
26 legend: 'Stlačte ${contextMenu} alebo APPLICATION KEY pre otvorenie kontextového menu. Potom sa presúvajte na ďalšie možnosti menu s TAB alebo dolnou šípkou. Presunte sa k predchádzajúcej možnosti s SHIFT+TAB alebo hornou šípkou. Stlačte medzerník alebo ENTER pre výber možnosti menu. Otvorte pod-menu danej možnosti s medzerníkom, alebo ENTER, alebo pravou šípkou. Vráťte sa späť do položky rodičovského menu s ESC alebo ľavou šípkou. Zatvorte kontextové menu s ESC.'
27 },
28
29 {
30 name: 'Editorov box zoznamu',
31 legend: 'V boxe zoznamu, presuňte sa na ďalšiu položku v zozname s TAB alebo dolnou šípkou. Presuňte sa k predchádzajúcej položke v zozname so SHIFT+TAB alebo hornou šípkou. Stlačte medzerník alebo ENTER pre výber možnosti zoznamu. Stlačte ESC pre zatvorenie boxu zoznamu.'
32 },
33
34 {
35 name: 'Editorove pásmo cesty prvku',
36 legend: 'Stlačte ${elementsPathFocus} pre navigovanie na pásmo cesty elementu. Presuňte sa na tlačidlo ďalšieho prvku s TAB alebo pravou šípkou. Presuňte sa k predchádzajúcemu tlačidlu s SHIFT+TAB alebo ľavou šípkou. Stlačte medzerník alebo ENTER pre výber prvku v editore.'
37 }
38 ]
39 },
40 {
41 name: 'Príkazy',
42 items: [
43 {
44 name: 'Vrátiť príkazy',
45 legend: 'Stlačte ${undo}'
46 },
47 {
48 name: 'Nanovo vrátiť príkaz',
49 legend: 'Stlačte ${redo}'
50 },
51 {
52 name: 'Príkaz na stučnenie',
53 legend: 'Stlačte ${bold}'
54 },
55 {
56 name: 'Príkaz na kurzívu',
57 legend: 'Stlačte ${italic}'
58 },
59 {
60 name: 'Príkaz na podčiarknutie',
61 legend: 'Stlačte ${underline}'
62 },
63 {
64 name: 'Príkaz na odkaz',
65 legend: 'Stlačte ${link}'
66 },
67 {
68 name: 'Príkaz na zbalenie lišty nástrojov',
69 legend: 'Stlačte ${toolbarCollapse}'
70 },
71 {
72 name: 'Prejsť na predchádzajúcu zamerateľnú medzeru príkazu',
73 legend: 'Stlačte ${accessPreviousSpace} pre prístup na najbližšie nedosiahnuteľné zamerateľné medzery pred vsuvkuo. Napríklad: dve za sebou idúce horizontálne čiary. Opakujte kombináciu klávesov pre dosiahnutie vzdialených zamerateľných medzier.'
74 },
75 {
76 name: 'Prejsť na ďalší ',
77 legend: 'Stlačte ${accessNextSpace} pre prístup na najbližšie nedosiahnuteľné zamerateľné medzery po vsuvke. Napríklad: dve za sebou idúce horizontálne čiary. Opakujte kombináciu klávesov pre dosiahnutie vzdialených zamerateľných medzier.'
78 },
79 {
80 name: 'Pomoc prístupnosti',
81 legend: 'Stlačte ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Stránka hore',
91 pageDown: 'Stránka dole',
92 leftArrow: 'Šípka naľavo',
93 upArrow: 'Šípka hore',
94 rightArrow: 'Šípka napravo',
95 downArrow: 'Šípka dole',
96 insert: 'Insert',
97 leftWindowKey: 'Ľavé Windows tlačidlo',
98 rightWindowKey: 'Pravé Windows tlačidlo',
99 selectKey: 'Tlačidlo Select',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Násobenie',
111 add: 'Sčítanie',
112 subtract: 'Odčítanie',
113 decimalPoint: 'Desatinná čiarka',
114 divide: 'Delenie',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Bodkočiarka',
130 equalSign: 'Rovná sa',
131 comma: 'Čiarka',
132 dash: 'Pomĺčka',
133 period: 'Bodka',
134 forwardSlash: 'Lomítko',
135 graveAccent: 'Zdôrazňovanie prízvuku',
136 openBracket: 'Hranatá zátvorka otváracia',
137 backSlash: 'Backslash',
138 closeBracket: 'Hranatá zátvorka zatváracia',
139 singleQuote: 'Jednoduché úvodzovky'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sl.js b/sources/plugins/a11yhelp/dialogs/lang/sl.js
new file mode 100644
index 0000000..bb38713
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sl.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sl', {
7 title: 'Navodila za dostopnost',
8 contents: 'Vsebina pomoči. Če želite zapreti pogovorno okno, pritisnite ESC.',
9 legend: [
10 {
11 name: 'Splošno',
12 items: [
13 {
14 name: 'Orodna vrstica urejevalnika',
15 legend: 'Pritisnite ${toolbarFocus} za pomik v orodno vrstico. Z TAB in SHIFT+TAB se pomikate na naslednjo in prejšnjo skupino orodne vrstice. Z DESNO PUŠČICO ali LEVO PUŠČICO se pomikate na naslednji in prejšnji gumb orodne vrstice. Pritisnite SPACE ali ENTER, da aktivirate gumb orodne vrstice.'
16 },
17
18 {
19 name: 'Urejevalno Pogovorno Okno',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Kontekstni meni urejevalnika',
26 legend: 'Pritisnite ${contextMenu} ali APPLICATION KEY, da odprete kontekstni meni. Nato se premaknite na naslednjo možnost menija s tipko TAB ali PUŠČICA DOL. Premakniti se na prejšnjo možnost z SHIFT + TAB ali PUŠČICA GOR. Pritisnite SPACE ali ENTER za izbiro možnosti menija. Odprite podmeni trenutne možnosti menija s tipko SPACE ali ENTER ali DESNA PUŠČICA. Vrnite se na matični element menija s tipko ESC ali LEVA PUŠČICA. Zaprite kontekstni meni z ESC.'
27 },
28
29 {
30 name: 'Urejevalno Seznamsko Polje',
31 legend: 'Znotraj seznama, se premaknete na naslednji element seznama s tipko TAB ali PUŠČICO DOL. Z SHIFT+TAB ali PUŠČICO GOR se premaknete na prejšnji element seznama. Pritisnite tipko SPACE ali ENTER za izbiro elementa. Pritisnite tipko ESC, da zaprete seznam.'
32 },
33
34 {
35 name: 'Urejevalna vrstica poti elementa',
36 legend: 'Pritisnite ${elementsPathFocus} za pomikanje po vrstici elementnih poti. S TAB ali DESNA PUŠČICA se premaknete na naslednji gumb elementa. Z SHIFT+TAB ali LEVO PUŠČICO se premaknete na prejšnji gumb elementa. Pritisnite SPACE ali ENTER za izbiro elementa v urejevalniku.'
37 }
38 ]
39 },
40 {
41 name: 'Ukazi',
42 items: [
43 {
44 name: 'Razveljavi ukaz',
45 legend: 'Pritisnite ${undo}'
46 },
47 {
48 name: 'Ponovi ukaz',
49 legend: 'Pritisnite ${redo}'
50 },
51 {
52 name: 'Krepki ukaz',
53 legend: 'Pritisnite ${bold}'
54 },
55 {
56 name: 'Ležeči ukaz',
57 legend: 'Pritisnite ${italic}'
58 },
59 {
60 name: 'Poudarni ukaz',
61 legend: 'Pritisnite ${underline}'
62 },
63 {
64 name: 'Ukaz povezave',
65 legend: 'Pritisnite ${link}'
66 },
67 {
68 name: 'Skrči Orodno Vrstico Ukaz',
69 legend: 'Pritisnite ${toolbarCollapse}'
70 },
71 {
72 name: 'Dostop do prejšnjega ukaza ostrenja',
73 legend: 'Pritisnite ${accessPreviousSpace} za dostop do najbližjega nedosegljivega osredotočenega prostora pred strešico, npr.: dva sosednja HR elementa. Ponovite kombinacijo tipk, da dosežete oddaljene osredotočene prostore.'
74 },
75 {
76 name: 'Dostop do naslednjega ukaza ostrenja',
77 legend: 'Pritisnite ${accessNextSpace} za dostop do najbližjega nedosegljivega osredotočenega prostora po strešici, npr.: dva sosednja HR elementa. Ponovite kombinacijo tipk, da dosežete oddaljene osredotočene prostore.'
78 },
79 {
80 name: 'Pomoč dostopnosti',
81 legend: 'Pritisnite ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Puščica levo',
93 upArrow: 'Puščica gor',
94 rightArrow: 'Puščica desno',
95 downArrow: 'Puščica dol',
96 insert: 'Insert',
97 leftWindowKey: 'Leva tipka Windows',
98 rightWindowKey: 'Desna tipka Windows',
99 selectKey: 'Select tipka',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Zmnoži',
111 add: 'Dodaj',
112 subtract: 'Odštej',
113 decimalPoint: 'Decimalna vejica',
114 divide: 'Deli',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Podpičje',
130 equalSign: 'Enačaj',
131 comma: 'Vejica',
132 dash: 'Vezaj',
133 period: 'Pika',
134 forwardSlash: 'Desna poševnica',
135 graveAccent: 'Krativec',
136 openBracket: 'Oklepaj',
137 backSlash: 'Leva poševnica',
138 closeBracket: 'Zaklepaj',
139 singleQuote: 'Opuščaj'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sq.js b/sources/plugins/a11yhelp/dialogs/lang/sq.js
new file mode 100644
index 0000000..c5947cc
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sq.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sq', {
7 title: 'Udhëzimet e Qasjes',
8 contents: 'Përmbajtja ndihmëse. Për ta mbyllur dialogun shtyp ESC.',
9 legend: [
10 {
11 name: 'Të përgjithshme',
12 items: [
13 {
14 name: 'Shiriti i Redaktuesit',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Dialogu i Redaktuesit',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Komandat',
42 items: [
43 {
44 name: 'Rikthe komandën',
45 legend: 'Shtyp ${undo}'
46 },
47 {
48 name: 'Ribëj komandën',
49 legend: 'Shtyp ${redo}'
50 },
51 {
52 name: 'Komanda e trashjes së tekstit',
53 legend: 'Shtyp ${bold}'
54 },
55 {
56 name: 'Komanda kursive',
57 legend: 'Shtyp ${italic}'
58 },
59 {
60 name: 'Komanda e nënvijëzimit',
61 legend: 'Shtyp ${underline}'
62 },
63 {
64 name: 'Komanda e Nyjes',
65 legend: 'Shtyp ${link}'
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Shtyp ${toolbarCollapse}'
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: 'Ndihmë Qasjeje',
81 legend: 'Shtyp ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Fletë',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Shenja majtas',
93 upArrow: 'Shenja sipër',
94 rightArrow: 'Shenja djathtas',
95 downArrow: 'Shenja poshtë',
96 insert: 'Shto',
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Shto',
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semicolon',
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Presje',
132 dash: 'vizë',
133 period: 'Pikë',
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Hape kllapën',
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Mbylle kllapën',
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sr-latn.js b/sources/plugins/a11yhelp/dialogs/lang/sr-latn.js
new file mode 100644
index 0000000..5b743ac
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sr-latn.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sr-latn', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Opšte',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sr.js b/sources/plugins/a11yhelp/dialogs/lang/sr.js
new file mode 100644
index 0000000..0e3e979
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sr.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sr', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Опште',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Commands', // MISSING
42 items: [
43 {
44 name: ' Undo command', // MISSING
45 legend: 'Press ${undo}' // MISSING
46 },
47 {
48 name: ' Redo command', // MISSING
49 legend: 'Press ${redo}' // MISSING
50 },
51 {
52 name: ' Bold command', // MISSING
53 legend: 'Press ${bold}' // MISSING
54 },
55 {
56 name: ' Italic command', // MISSING
57 legend: 'Press ${italic}' // MISSING
58 },
59 {
60 name: ' Underline command', // MISSING
61 legend: 'Press ${underline}' // MISSING
62 },
63 {
64 name: ' Link command', // MISSING
65 legend: 'Press ${link}' // MISSING
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/sv.js b/sources/plugins/a11yhelp/dialogs/lang/sv.js
new file mode 100644
index 0000000..4962b95
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/sv.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'sv', {
7 title: 'Hjälpmedelsinstruktioner',
8 contents: 'Hjälpinnehåll. För att stänga denna dialogruta trycker du på ESC.',
9 legend: [
10 {
11 name: 'Allmänt',
12 items: [
13 {
14 name: 'Editor verktygsfält',
15 legend: 'Tryck på ${toolbarFocus} för att navigera till verktygsfältet. Flytta till nästa och föregående verktygsfältsgrupp med TAB och SHIFT+TAB. Flytta till nästa och föregående knapp i verktygsfältet med HÖGERPIL eller VÄNSTERPIL. Tryck SPACE eller ENTER för att aktivera knappen i verktygsfältet.'
16 },
17
18 {
19 name: 'Dialogeditor',
20 legend:
21 'Inuti en dialogruta, tryck TAB för att navigera till nästa fält i dialogrutan, tryck SKIFT+TAB för att flytta till föregående fält, tryck ENTER för att skicka. Du avbryter och stänger dialogen med ESC. För dialogrutor som har flera flikar, tryck ALT+F10 eller TAB för att navigera till fliklistan. med fliklistan vald flytta till nästa och föregående flik med HÖGER- eller VÄNSTERPIL.'
22 },
23
24 {
25 name: 'Editor för innehållsmeny',
26 legend: 'Tryck på $ {contextMenu} eller PROGRAMTANGENTEN för att öppna snabbmenyn. Flytta sedan till nästa menyalternativ med TAB eller NEDPIL. Flytta till föregående alternativ med SHIFT + TABB eller UPPIL. Tryck Space eller ENTER för att välja menyalternativ. Öppna undermeny av nuvarande alternativ med SPACE eller ENTER eller HÖGERPIL. Gå tillbaka till överordnade menyalternativ med ESC eller VÄNSTERPIL. Stäng snabbmenyn med ESC.'
27 },
28
29 {
30 name: 'Editor för list-box',
31 legend: 'Inuti en list-box, gå till nästa listobjekt med TAB eller NEDPIL. Flytta till föregående listobjekt med SHIFT+TAB eller UPPIL. Tryck SPACE eller ENTER för att välja listan alternativet. Tryck ESC för att stänga list-boxen.'
32 },
33
34 {
35 name: 'Editor för elementens sökväg',
36 legend: 'Tryck på ${elementsPathFocus} för att navigera till verktygsfältet för elementens sökvägar. Flytta till nästa elementknapp med TAB eller HÖGERPIL. Flytta till föregående knapp med SKIFT+TAB eller VÄNSTERPIL. Tryck SPACE eller ENTER för att välja element i redigeraren.'
37 }
38 ]
39 },
40 {
41 name: 'Kommandon',
42 items: [
43 {
44 name: 'Ångra kommando',
45 legend: 'Tryck på ${undo}'
46 },
47 {
48 name: 'Gör om kommando',
49 legend: 'Tryck på ${redo}'
50 },
51 {
52 name: 'Kommandot fet stil',
53 legend: 'Tryck på ${bold}'
54 },
55 {
56 name: 'Kommandot kursiv',
57 legend: 'Tryck på ${italic}'
58 },
59 {
60 name: 'Kommandot understruken',
61 legend: 'Tryck på ${underline}'
62 },
63 {
64 name: 'Kommandot länk',
65 legend: 'Tryck på ${link}'
66 },
67 {
68 name: 'Verktygsfält Dölj kommandot',
69 legend: 'Tryck på ${toolbarCollapse}'
70 },
71 {
72 name: 'Gå till föregående fokus plats',
73 legend: 'Tryck på ${accessPreviousSpace} för att gå till närmast onåbara utrymme före markören, exempel: två intilliggande HR element. Repetera tangentkombinationen för att gå till nästa.'
74 },
75 {
76 name: 'Tillgå nästa fokuskommandots utrymme',
77 legend: 'Tryck ${accessNextSpace} på för att komma åt den närmaste onåbar fokus utrymme efter cirkumflex, till exempel: två intilliggande HR element. Upprepa tangentkombinationen för att nå avlägsna fokus utrymmen.'
78 },
79 {
80 name: 'Hjälp om tillgänglighet',
81 legend: 'Tryck ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Paus',
88 capslock: 'Caps lock',
89 escape: 'Escape',
90 pageUp: 'Sida Up',
91 pageDown: 'Sida Ned',
92 leftArrow: 'Vänsterpil',
93 upArrow: 'Uppil',
94 rightArrow: 'Högerpil',
95 downArrow: 'Nedåtpil',
96 insert: 'Infoga',
97 leftWindowKey: 'Vänster Windowstangent',
98 rightWindowKey: 'Höger Windowstangent',
99 selectKey: 'Välj tangent',
100 numpad0: 'Nummer 0',
101 numpad1: 'Nummer 1',
102 numpad2: 'Nummer 2',
103 numpad3: 'Nummer 3',
104 numpad4: 'Nummer 4',
105 numpad5: 'Nummer 5',
106 numpad6: 'Nummer 6',
107 numpad7: 'Nummer 7',
108 numpad8: 'Nummer 8',
109 numpad9: 'Nummer 9',
110 multiply: 'Multiplicera',
111 add: 'Addera',
112 subtract: 'Minus',
113 decimalPoint: 'Decimalpunkt',
114 divide: 'Dividera',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Semikolon',
130 equalSign: 'Lika med tecken',
131 comma: 'Komma',
132 dash: 'Minus',
133 period: 'Punkt',
134 forwardSlash: 'Snedstreck framåt',
135 graveAccent: 'Accent',
136 openBracket: 'Öppningsparentes',
137 backSlash: 'Snedstreck bakåt',
138 closeBracket: 'Slutparentes',
139 singleQuote: 'Enkelt Citattecken'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/th.js b/sources/plugins/a11yhelp/dialogs/lang/th.js
new file mode 100644
index 0000000..1382894
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/th.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'th', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'ทั่วไป',
12 items: [
13 {
14 name: 'แถบเครื่องมือสำหรับเครื่องมือช่วยพิมพ์',
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'คำสั่ง',
42 items: [
43 {
44 name: 'เลิกทำคำสั่ง',
45 legend: 'วาง ${undo}'
46 },
47 {
48 name: 'คำสั่งสำหรับทำซ้ำ',
49 legend: 'วาง ${redo}'
50 },
51 {
52 name: 'คำสั่งสำหรับตัวหนา',
53 legend: 'วาง ${bold}'
54 },
55 {
56 name: 'คำสั่งสำหรับตัวเอียง',
57 legend: 'วาง ${italic}'
58 },
59 {
60 name: 'คำสั่งสำหรับขีดเส้นใต้',
61 legend: 'วาง ${underline}'
62 },
63 {
64 name: 'คำสั่งสำหรับลิงก์',
65 legend: 'วาง ${link}'
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: 'Press ${toolbarCollapse}' // MISSING
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: 'Press ${a11yHelp}' // MISSING
82 }
83 ]
84 }
85 ],
86 tab: 'Tab', // MISSING
87 pause: 'Pause', // MISSING
88 capslock: 'Caps Lock', // MISSING
89 escape: 'Escape', // MISSING
90 pageUp: 'Page Up', // MISSING
91 pageDown: 'Page Down', // MISSING
92 leftArrow: 'Left Arrow', // MISSING
93 upArrow: 'Up Arrow', // MISSING
94 rightArrow: 'Right Arrow', // MISSING
95 downArrow: 'Down Arrow', // MISSING
96 insert: 'Insert', // MISSING
97 leftWindowKey: 'Left Windows key', // MISSING
98 rightWindowKey: 'Right Windows key', // MISSING
99 selectKey: 'Select key', // MISSING
100 numpad0: 'Numpad 0', // MISSING
101 numpad1: 'Numpad 1', // MISSING
102 numpad2: 'Numpad 2', // MISSING
103 numpad3: 'Numpad 3', // MISSING
104 numpad4: 'Numpad 4', // MISSING
105 numpad5: 'Numpad 5', // MISSING
106 numpad6: 'Numpad 6', // MISSING
107 numpad7: 'Numpad 7', // MISSING
108 numpad8: 'Numpad 8', // MISSING
109 numpad9: 'Numpad 9', // MISSING
110 multiply: 'Multiply', // MISSING
111 add: 'Add', // MISSING
112 subtract: 'Subtract', // MISSING
113 decimalPoint: 'Decimal Point', // MISSING
114 divide: 'Divide', // MISSING
115 f1: 'F1', // MISSING
116 f2: 'F2', // MISSING
117 f3: 'F3', // MISSING
118 f4: 'F4', // MISSING
119 f5: 'F5', // MISSING
120 f6: 'F6', // MISSING
121 f7: 'F7', // MISSING
122 f8: 'F8', // MISSING
123 f9: 'F9', // MISSING
124 f10: 'F10', // MISSING
125 f11: 'F11', // MISSING
126 f12: 'F12', // MISSING
127 numLock: 'Num Lock', // MISSING
128 scrollLock: 'Scroll Lock', // MISSING
129 semiColon: 'Semicolon', // MISSING
130 equalSign: 'Equal Sign', // MISSING
131 comma: 'Comma', // MISSING
132 dash: 'Dash', // MISSING
133 period: 'Period', // MISSING
134 forwardSlash: 'Forward Slash', // MISSING
135 graveAccent: 'Grave Accent', // MISSING
136 openBracket: 'Open Bracket', // MISSING
137 backSlash: 'Backslash', // MISSING
138 closeBracket: 'Close Bracket', // MISSING
139 singleQuote: 'Single Quote' // MISSING
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/tr.js b/sources/plugins/a11yhelp/dialogs/lang/tr.js
new file mode 100644
index 0000000..15306a5
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/tr.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'tr', {
7 title: 'Erişilebilirlik Talimatları',
8 contents: 'Yardım içeriği. Bu pencereyi kapatmak için ESC tuşuna basın.',
9 legend: [
10 {
11 name: 'Genel',
12 items: [
13 {
14 name: 'Düzenleyici Araç Çubuğu',
15 legend: 'Araç çubuğunda gezinmek için ${toolbarFocus} basın. TAB ve SHIFT+TAB ile önceki ve sonraki araç çubuğu grubuna taşıyın. SAĞ OK veya SOL OK ile önceki ve sonraki bir araç çubuğu düğmesini hareket ettirin. SPACE tuşuna basın veya araç çubuğu düğmesini etkinleştirmek için ENTER tuşna basın.'
16 },
17
18 {
19 name: 'Diyalog Düzenleyici',
20 legend:
21 'Dialog penceresi içinde, sonraki iletişim alanına gitmek için SEKME tuşuna basın, önceki alana geçmek için SHIFT + TAB tuşuna basın, pencereyi göndermek için ENTER tuşuna basın, dialog penceresini iptal etmek için ESC tuşuna basın. Birden çok sekme sayfaları olan diyalogların, sekme listesine gitmek için ALT + F10 tuşlarına basın. Sonra TAB veya SAĞ OK sonraki sekmeye taşıyın. SHIFT + TAB veya SOL OK ile önceki sekmeye geçin. Sekme sayfayı seçmek için SPACE veya ENTER tuşuna basın.'
22 },
23
24 {
25 name: 'İçerik Menü Editörü',
26 legend: 'İçerik menüsünü açmak için ${contextMenu} veya UYGULAMA TUŞU\'na basın. Daha sonra SEKME veya AŞAĞI OK ile bir sonraki menü seçeneği taşıyın. SHIFT + TAB veya YUKARI OK ile önceki seçeneğe gider. Menü seçeneğini seçmek için SPACE veya ENTER tuşuna basın. Seçili seçeneğin alt menüsünü SPACE ya da ENTER veya SAĞ OK açın. Üst menü öğesini geçmek için ESC veya SOL OK ile geri dönün. ESC ile bağlam menüsünü kapatın.'
27 },
28
29 {
30 name: 'Liste Kutusu Editörü',
31 legend: 'Liste kutusu içinde, bir sonraki liste öğesine SEKME VEYA AŞAĞI OK ile taşıyın. SHIFT+TAB veya YUKARI önceki liste öğesi taşıyın. Liste seçeneği seçmek için SPACE veya ENTER tuşuna basın. Liste kutusunu kapatmak için ESC tuşuna basın.'
32 },
33
34 {
35 name: 'Element Yol Çubuğu Editörü',
36 legend: 'Elementlerin yol çubuğunda gezinmek için ${ElementsPathFocus} basın. SEKME veya SAĞ OK ile sonraki element düğmesine taşıyın. SHIFT+TAB veya SOL OK önceki düğmeye hareket ettirin. Editör içindeki elementi seçmek için ENTER veya SPACE tuşuna basın.'
37 }
38 ]
39 },
40 {
41 name: 'Komutlar',
42 items: [
43 {
44 name: 'Komutu geri al',
45 legend: '$(undo)\'ya basın'
46 },
47 {
48 name: 'Komutu geri al',
49 legend: '${redo} basın'
50 },
51 {
52 name: ' Kalın komut',
53 legend: '${bold} basın'
54 },
55 {
56 name: ' İtalik komutu',
57 legend: '${italic} basın'
58 },
59 {
60 name: ' Alttan çizgi komutu',
61 legend: '${underline} basın'
62 },
63 {
64 name: ' Bağlantı komutu',
65 legend: '${link} basın'
66 },
67 {
68 name: ' Araç çubuğu Toplama komutu',
69 legend: '${toolbarCollapse} basın'
70 },
71 {
72 name: 'Önceki komut alanına odaklan',
73 legend: 'Düzeltme imleçinden önce, en yakın uzaktaki alana erişmek için ${accessPreviousSpace} basın, örneğin: iki birleşik HR elementleri. Aynı tuş kombinasyonu tekrarıyla diğer alanlarada ulaşın.'
74 },
75 {
76 name: 'Sonraki komut alanına odaklan',
77 legend: 'Düzeltme imleçinden sonra, en yakın uzaktaki alana erişmek için ${accessNextSpace} basın, örneğin: iki birleşik HR elementleri. Aynı tuş kombinasyonu tekrarıyla diğer alanlarada ulaşın.'
78 },
79 {
80 name: 'Erişilebilirlik Yardımı',
81 legend: '${a11yHelp}\'e basın'
82 }
83 ]
84 }
85 ],
86 tab: 'Sekme tuşu',
87 pause: 'Durdurma tuşu',
88 capslock: 'Büyük harf tuşu',
89 escape: 'Vazgeç tuşu',
90 pageUp: 'Sayfa Yukarı',
91 pageDown: 'Sayfa Aşağı',
92 leftArrow: 'Sol ok',
93 upArrow: 'Yukarı ok',
94 rightArrow: 'Sağ ok',
95 downArrow: 'Aşağı ok',
96 insert: 'Araya gir',
97 leftWindowKey: 'Sol windows tuşu',
98 rightWindowKey: 'Sağ windows tuşu',
99 selectKey: 'Seçme tuşu',
100 numpad0: 'Nümerik 0',
101 numpad1: 'Nümerik 1',
102 numpad2: 'Nümerik 2',
103 numpad3: 'Nümerik 3',
104 numpad4: 'Nümerik 4',
105 numpad5: 'Nümerik 5',
106 numpad6: 'Nümerik 6',
107 numpad7: 'Nümerik 7',
108 numpad8: 'Nümerik 8',
109 numpad9: 'Nümerik 9',
110 multiply: 'Çarpma',
111 add: 'Toplama',
112 subtract: 'Çıkarma',
113 decimalPoint: 'Ondalık işareti',
114 divide: 'Bölme',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lk',
128 scrollLock: 'Scr Lk',
129 semiColon: 'Noktalı virgül',
130 equalSign: 'Eşittir',
131 comma: 'Virgül',
132 dash: 'Eksi',
133 period: 'Nokta',
134 forwardSlash: 'İleri eğik çizgi',
135 graveAccent: 'Üst tırnak',
136 openBracket: 'Parantez aç',
137 backSlash: 'Ters eğik çizgi',
138 closeBracket: 'Parantez kapa',
139 singleQuote: 'Tek tırnak'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/tt.js b/sources/plugins/a11yhelp/dialogs/lang/tt.js
new file mode 100644
index 0000000..bdd9847
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/tt.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'tt', {
7 title: 'Accessibility Instructions', // MISSING
8 contents: 'Help Contents. To close this dialog press ESC.', // MISSING
9 legend: [
10 {
11 name: 'Гомуми',
12 items: [
13 {
14 name: 'Editor Toolbar', // MISSING
15 legend: 'Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button.' // MISSING
16 },
17
18 {
19 name: 'Editor Dialog', // MISSING
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Editor Context Menu', // MISSING
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC.' // MISSING
27 },
28
29 {
30 name: 'Editor List Box', // MISSING
31 legend: 'Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box.' // MISSING
32 },
33
34 {
35 name: 'Editor Element Path Bar', // MISSING
36 legend: 'Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor.' // MISSING
37 }
38 ]
39 },
40 {
41 name: 'Командалар',
42 items: [
43 {
44 name: 'Кайтару',
45 legend: '${undo} басыгыз'
46 },
47 {
48 name: 'Кабатлау',
49 legend: '${redo} басыгыз'
50 },
51 {
52 name: 'Калын',
53 legend: '${bold} басыгыз'
54 },
55 {
56 name: 'Курсив',
57 legend: '${italic} басыгыз'
58 },
59 {
60 name: 'Астына сызылган',
61 legend: '${underline} басыгыз'
62 },
63 {
64 name: 'Сылталама',
65 legend: '${link} басыгыз'
66 },
67 {
68 name: ' Toolbar Collapse command', // MISSING
69 legend: '${toolbarCollapse} басыгыз'
70 },
71 {
72 name: ' Access previous focus space command', // MISSING
73 legend: 'Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
74 },
75 {
76 name: ' Access next focus space command', // MISSING
77 legend: 'Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces.' // MISSING
78 },
79 {
80 name: ' Accessibility Help', // MISSING
81 legend: '${a11yHelp} басыгыз'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Тыныш',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Сул якка ук',
93 upArrow: 'Өскә таба ук',
94 rightArrow: 'Уң якка ук',
95 downArrow: 'Аска таба ук',
96 insert: 'Өстәү',
97 leftWindowKey: 'Сул Windows төймəсе',
98 rightWindowKey: 'Уң Windows төймəсе',
99 selectKey: 'Select төймəсе',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Тапкырлау',
111 add: 'Кушу',
112 subtract: 'Алу',
113 decimalPoint: 'Унарлы нокта',
114 divide: 'Бүлү',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Нокталы өтер',
130 equalSign: 'Тигезлек билгесе',
131 comma: 'Өтер',
132 dash: 'Сызык',
133 period: 'Дәрәҗә',
134 forwardSlash: 'Кыек сызык',
135 graveAccent: 'Гравис',
136 openBracket: 'Җәя ачу',
137 backSlash: 'Кире кыек сызык',
138 closeBracket: 'Җәя ябу',
139 singleQuote: 'Бер иңле куштырнаклар'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/ug.js b/sources/plugins/a11yhelp/dialogs/lang/ug.js
new file mode 100644
index 0000000..1771562
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/ug.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'ug', {
7 title: 'قوشۇمچە چۈشەندۈرۈش',
8 contents: 'ياردەم مەزمۇنى. بۇ سۆزلەشكۈنى ياپماقچى بولسىڭىز ESC نى بېسىڭ.',
9 legend: [
10 {
11 name: 'ئادەتتىكى',
12 items: [
13 {
14 name: 'قورال بالداق تەھرىر',
15 legend: '${toolbarFocus} بېسىلسا قورال بالداققا يېتەكلەيدۇ، TAB ياكى SHIFT+TAB ئارقىلىق قورال بالداق گۇرۇپپىسى تاللىنىدۇ، ئوڭ سول يا ئوقتا توپچا تاللىنىدۇ، بوشلۇق ياكى Enter كۇنۇپكىسىدا تاللانغان توپچىنى قوللىنىدۇ.'
16 },
17
18 {
19 name: 'تەھرىرلىگۈچ سۆزلەشكۈسى',
20 legend:
21 'سۆزلەشكۈدە TAB كۇنۇپكىسىدا كېيىنكى سۆز بۆلىكىگە يۆتكىلىدۇ، SHIFT+TAB بىرىكمە كۇنۇپكىسىدا ئالدىنقى سۆز بۆلىكىگە يۆتكىلىدۇ، ENTER كۇنۇپكىسىدا سۆزلەشكۈنى تاپشۇرىدۇ، ESC كۇنۇپكىسى سۆزلەشكۈدىن ۋاز كېچىدۇ. كۆپ بەتكۈچلۈك سۆزلەشكۈگە نىسبەتەن، ALT+F10 دا بەتكۈچ تىزىمىغا يۆتكەيدۇ. ئاندىن TAB كۇنۇپكىسى ياكى ئوڭ يا ئوق كۇنۇپكىسى كېيىنكى بەتكۈچكە يۆتكەيدۇ؛SHIFT+ TAB كۇنۇپكىسى ياكى سول يا ئوق كۇنۇپكىسى ئالدىنقى بەتكۈچكە يۆتكەيدۇ. بوشلۇق كۇنۇپكىسى ياكى ENTER كۇنۇپكىسى بەتكۈچنى تاللايدۇ.'
22 },
23
24 {
25 name: 'تەھرىرلىگۈچ تىل مۇھىت تىزىملىكى',
26 legend: '${contextMenu} ياكى ئەپ كۇنۇپكىسىدا تىل مۇھىت تىزىملىكىنى ئاچىدۇ. ئاندىن TAB ياكى ئاستى يا ئوق كۇنۇپكىسىدا كېيىنكى تىزىملىك تۈرىگە يۆتكەيدۇ؛ SHIFT+TAB ياكى ئۈستى يا ئوق كۇنۇپكىسىدا ئالدىنقى تىزىملىك تۈرىگە يۆتكەيدۇ. بوشلۇق ياكى ENTER كۇنۇپكىسىدا تىزىملىك تۈرىنى تاللايدۇ. بوشلۇق، ENTER ياكى ئوڭ يا ئوق كۇنۇپكىسىدا تارماق تىزىملىكنى ئاچىدۇ. قايتىش تىزىملىكىگە ESC ياكى سول يا ئوق كۇنۇپكىسى ئىشلىتىلىدۇ. ESC كۇنۇپكىسىدا تىل مۇھىت تىزىملىكى تاقىلىدۇ.'
27 },
28
29 {
30 name: 'تەھرىرلىگۈچ تىزىمى',
31 legend: 'تىزىم قۇتىسىدا، كېيىنكى تىزىم تۈرىگە يۆتكەشتە TAB ياكى ئاستى يا ئوق كۇنۇپكىسى ئىشلىتىلىدۇ. ئالدىنقى تىزىم تۈرىگە يۆتكەشتە SHIFT+TAB ياكى ئۈستى يا ئوق كۇنۇپكىسى ئىشلىتىلىدۇ. بوشلۇق ياكى ENTER كۇنۇپكىسىدا تىزىم تۈرىنى تاللايدۇ.ESC كۇنۇپكىسىدا تىزىم قۇتىسىنى يىغىدۇ.'
32 },
33
34 {
35 name: 'تەھرىرلىگۈچ ئېلېمېنت يول بالداق',
36 legend: '${elementsPathFocus} بېسىلسا ئېلېمېنت يول بالداققا يېتەكلەيدۇ، TAB ياكى ئوڭ يا ئوقتا كېيىنكى ئېلېمېنت تاللىنىدۇ، SHIFT+TAB ياكى سول يا ئوقتا ئالدىنقى ئېلېمېنت تاللىنىدۇ، بوشلۇق ياكى Enter كۇنۇپكىسىدا تەھرىرلىگۈچتىكى ئېلېمېنت تاللىنىدۇ.'
37 }
38 ]
39 },
40 {
41 name: 'بۇيرۇق',
42 items: [
43 {
44 name: 'بۇيرۇقتىن يېنىۋال',
45 legend: '${undo} نى بېسىڭ'
46 },
47 {
48 name: 'قايتىلاش بۇيرۇقى',
49 legend: '${redo} نى بېسىڭ'
50 },
51 {
52 name: 'توملىتىش بۇيرۇقى',
53 legend: '${bold} نى بېسىڭ'
54 },
55 {
56 name: 'يانتۇ بۇيرۇقى',
57 legend: '${italic} نى بېسىڭ'
58 },
59 {
60 name: 'ئاستى سىزىق بۇيرۇقى',
61 legend: '${underline} نى بېسىڭ'
62 },
63 {
64 name: 'ئۇلانما بۇيرۇقى',
65 legend: '${link} نى بېسىڭ'
66 },
67 {
68 name: 'قورال بالداق قاتلاش بۇيرۇقى',
69 legend: '${toolbarCollapse} نى بېسىڭ'
70 },
71 {
72 name: 'ئالدىنقى فوكۇس نۇقتىسىنى زىيارەت قىلىدىغان بۇيرۇق',
73 legend: '${accessPreviousSpace} بېسىپ ^ بەلگىسىگە ئەڭ يېقىن زىيارەت قىلغىلى بولمايدىغان فوكۇس نۇقتا رايونىنىڭ ئالدىنى زىيارەت قىلىدۇ، مەسىلەن: ئۆز ئارا قوشنا ئىككى HR ئېلېمېنت. بۇ بىرىكمە كۇنۇپكا تەكرارلانسا يىراقتىكى فوكۇس نۇقتا رايونىغا يەتكىلى بولىدۇ.'
74 },
75 {
76 name: 'كېيىنكى فوكۇس نۇقتىسىنى زىيارەت قىلىدىغان بۇيرۇق',
77 legend: '${accessNextSpace} بېسىپ ^ بەلگىسىگە ئەڭ يېقىن زىيارەت قىلغىلى بولمايدىغان فوكۇس نۇقتا رايونىنىڭ كەينىنى زىيارەت قىلىدۇ، مەسىلەن: ئۆز ئارا قوشنا ئىككى HR ئېلېمېنت. بۇ بىرىكمە كۇنۇپكا تەكرارلانسا يىراقتىكى فوكۇس نۇقتا رايونىغا يەتكىلى بولىدۇ.'
78 },
79 {
80 name: 'توسالغۇسىز لايىھە چۈشەندۈرۈشى',
81 legend: '${a11yHelp} نى بېسىڭ'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Escape',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'سول يا ئوق',
93 upArrow: 'ئۈستى يا ئوق',
94 rightArrow: 'ئوڭ يا ئوق',
95 downArrow: 'ئاستى يا ئوق',
96 insert: 'قىستۇر',
97 leftWindowKey: 'سول Windows كۇنۇپكىسى',
98 rightWindowKey: 'ئوڭ Windows كۇنۇپكىسى',
99 selectKey: 'تاللاش كۇنۇپكىسى',
100 numpad0: 'سان تاختا 0',
101 numpad1: 'سان تاختا 1',
102 numpad2: 'سان تاختا 2',
103 numpad3: 'سان تاختا 3',
104 numpad4: 'سان تاختا 4',
105 numpad5: 'سان تاختا 5',
106 numpad6: 'سان تاختا 6',
107 numpad7: 'سان تاختا 7',
108 numpad8: 'سان تاختا 8',
109 numpad9: 'سان تاختا 9',
110 multiply: 'يۇلتۇز كۇنۇپكىسى',
111 add: 'قوشۇش',
112 subtract: 'ئېلىش',
113 decimalPoint: 'كەسىر چېكىت',
114 divide: 'بۆلۈش',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'سان قۇلۇپ كۇنۇپكىسى',
128 scrollLock: 'سۈرگۈچ قۇلۇپ كۇنۇپكىسى',
129 semiColon: 'چېكىتلىك پەش',
130 equalSign: 'تەڭلىك بەلگىسى',
131 comma: 'پەش',
132 dash: 'سىزىقچە',
133 period: 'چېكىت',
134 forwardSlash: 'سولغا يانتۇ سىزىق',
135 graveAccent: 'ئۇرغۇ بەلگىسى',
136 openBracket: 'ئېچىلغان تىرناق',
137 backSlash: 'ئوڭغا يانتۇ سىزىق',
138 closeBracket: 'يېپىلغان تىرناق',
139 singleQuote: 'يالاڭ پەش'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/uk.js b/sources/plugins/a11yhelp/dialogs/lang/uk.js
new file mode 100644
index 0000000..d1e8589
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/uk.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'uk', {
7 title: 'Спеціальні Інструкції',
8 contents: 'Довідка. Натисніть ESC і вона зникне.',
9 legend: [
10 {
11 name: 'Основне',
12 items: [
13 {
14 name: 'Панель Редактора',
15 legend: 'Натисніть ${toolbarFocus} для переходу до панелі інструментів. Для переміщення між групами панелі інструментів використовуйте TAB і SHIFT+TAB. Для переміщення між кнопками панелі іструментів використовуйте кнопки СТРІЛКА ВПРАВО або ВЛІВО. Натисніть ПРОПУСК або ENTER для запуску кнопки панелі інструментів.'
16 },
17
18 {
19 name: 'Діалог Редактора',
20 legend:
21 'Усередині діалогу, натисніть TAB щоб перейти до наступного елементу діалогу, натисніть SHIFT+TAB щоб перейти до попереднього елемента діалогу, натисніть ENTER щоб відправити діалог, натисніть ESC щоб скасувати діалог. Коли діалогове вікно має декілька вкладок, отримати доступ до панелі вкладок як частині діалогу можна натисканням або поєднання ALT+F10 або TAB, при цьому активні елементи діалогу будуть перебиратися з урахуванням порядку табуляції. При активній панелі вкладок, перехід до наступної або попередньої вкладці здійснюється натисканням стрілки "ВПРАВО" або стрілки "ВЛЕВО" відповідно.'
22 },
23
24 {
25 name: 'Контекстне Меню Редактора',
26 legend: 'Press ${contextMenu} or APPLICATION KEY to open context-menu. Потім перейдіть до наступного пункту меню за допомогою TAB або СТРІЛКИ ВНИЗ. Натисніть ПРОПУСК або ENTER для вибору параметру меню. Відкрийте підменю поточного параметру, натиснувши ПРОПУСК або ENTER або СТРІЛКУ ВПРАВО. Перейдіть до батьківського елемента меню, натиснувши ESC або СТРІЛКУ ВЛІВО. Закрийте контекстне меню, натиснувши ESC.'
27 },
28
29 {
30 name: 'Скринька Списків Редактора',
31 legend: 'Усередині списку, перехід до наступного пункту списку виконується клавішею TAB або СТРІЛКА ВНИЗ. Перехід до попереднього елемента списку клавішею SHIFT+TAB або СТРІЛКА ВГОРУ. Натисніть ПРОПУСК або ENTER, щоб вибрати параметр списку. Натисніть клавішу ESC, щоб закрити список.'
32 },
33
34 {
35 name: 'Шлях до елемента редактора',
36 legend: 'Натисніть ${elementsPathFocus} для навігації між елементами панелі. Перейдіть до наступного елемента кнопкою TAB або СТРІЛКА ВПРАВО. Перейдіть до попереднього елемента кнопкою SHIFT+TAB або СТРІЛКА ВЛІВО. Натисніть ПРОПУСК або ENTER для вибору елемента в редакторі.'
37 }
38 ]
39 },
40 {
41 name: 'Команди',
42 items: [
43 {
44 name: 'Відмінити команду',
45 legend: 'Натисніть ${undo}'
46 },
47 {
48 name: 'Повторити',
49 legend: 'Натисніть ${redo}'
50 },
51 {
52 name: 'Жирний',
53 legend: 'Натисніть ${bold}'
54 },
55 {
56 name: 'Курсив',
57 legend: 'Натисніть ${italic}'
58 },
59 {
60 name: 'Підкреслений',
61 legend: 'Натисніть ${underline}'
62 },
63 {
64 name: 'Посилання',
65 legend: 'Натисніть ${link}'
66 },
67 {
68 name: 'Згорнути панель інструментів',
69 legend: 'Натисніть ${toolbarCollapse}'
70 },
71 {
72 name: 'Доступ до попереднього місця фокусування',
73 legend: 'Натисніть ${accessNextSpace} для доступу до найближчої недосяжної області фокусування перед кареткою, наприклад: два сусідні елементи HR. Повторіть комбінацію клавіш для досягнення віддалених областей фокусування.'
74 },
75 {
76 name: 'Доступ до наступного місця фокусування',
77 legend: 'Натисніть ${accessNextSpace} для доступу до найближчої недосяжної області фокусування після каретки, наприклад: два сусідні елементи HR. Повторіть комбінацію клавіш для досягнення віддалених областей фокусування.'
78 },
79 {
80 name: 'Допомога з доступності',
81 legend: 'Натисніть ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Esc',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: 'Ліва стрілка',
93 upArrow: 'Стрілка вгору',
94 rightArrow: 'Права стрілка',
95 downArrow: 'Стрілка вниз',
96 insert: 'Вставити',
97 leftWindowKey: 'Ліва клавіша Windows',
98 rightWindowKey: 'Права клавіша Windows',
99 selectKey: 'Виберіть клавішу',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: 'Множення',
111 add: 'Додати',
112 subtract: 'Віднімання',
113 decimalPoint: 'Десяткова кома',
114 divide: 'Ділення',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Крапка з комою',
130 equalSign: 'Знак рівності',
131 comma: 'Кома',
132 dash: 'Тире',
133 period: 'Період',
134 forwardSlash: 'Коса риска',
135 graveAccent: 'Гравіс',
136 openBracket: 'Відкрити дужку',
137 backSlash: 'Зворотна коса риска',
138 closeBracket: 'Закрити дужку',
139 singleQuote: 'Одинарні лапки'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/vi.js b/sources/plugins/a11yhelp/dialogs/lang/vi.js
new file mode 100644
index 0000000..497deb2
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/vi.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'vi', {
7 title: 'Hướng dẫn trợ năng',
8 contents: 'Nội dung Hỗ trợ. Nhấn ESC để đóng hộp thoại.',
9 legend: [
10 {
11 name: 'Chung',
12 items: [
13 {
14 name: 'Thanh công cụ soạn thảo',
15 legend: 'Nhấn ${toolbarFocus} để điều hướng đến thanh công cụ. Nhấn TAB và SHIFT+TAB để chuyển đến nhóm thanh công cụ khác. Nhấn MŨI TÊN PHẢI hoặc MŨI TÊN TRÁI để chuyển sang nút khác trên thanh công cụ. Nhấn PHÍM CÁCH hoặc ENTER để kích hoạt nút trên thanh công cụ.'
16 },
17
18 {
19 name: 'Hộp thoại Biên t',
20 legend:
21 'Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively.' // MISSING
22 },
23
24 {
25 name: 'Trình đơn Ngữ cảnh cBộ soạn thảo',
26 legend: 'Nhấn ${contextMenu} hoặc PHÍM ỨNG DỤNG để mở thực đơn ngữ cảnh. Sau đó nhấn TAB hoặc MŨI TÊN XUỐNG để di chuyển đến tuỳ chọn tiếp theo của thực đơn. Nhấn SHIFT+TAB hoặc MŨI TÊN LÊN để quay lại tuỳ chọn trước. Nhấn DẤU CÁCH hoặc ENTER để chọn tuỳ chọn của thực đơn. Nhấn DẤU CÁCH hoặc ENTER hoặc MŨI TÊN SANG PHẢI để mở thực đơn con của tuỳ chọn hiện tại. Nhấn ESC hoặc MŨI TÊN SANG TRÁI để quay trở lại thực đơn gốc. Nhấn ESC để đóng thực đơn ngữ cảnh.'
27 },
28
29 {
30 name: 'Hộp danh sách trình biên tập',
31 legend: 'Trong một danh sách chọn, di chuyển đối tượng tiếp theo với phím TAB hoặc phím mũi tên hướng xuống. Di chuyển đến đối tượng trước đó bằng cách nhấn tổ hợp phím SHIFT+TAB hoặc mũi tên hướng lên. Phím khoảng cách hoặc phím ENTER để chọn các tùy chọn trong danh sách. Nhấn phím ESC để đóng lại danh sách chọn.'
32 },
33
34 {
35 name: 'Thanh đường dẫn các đối tượng',
36 legend: 'Nhấn ${elementsPathFocus} để điều hướng các đối tượng trong thanh đường dẫn. Di chuyển đến đối tượng tiếp theo bằng phím TAB hoặc phím mũi tên bên phải. Di chuyển đến đối tượng trước đó bằng tổ hợp phím SHIFT+TAB hoặc phím mũi tên bên trái. Nhấn phím khoảng cách hoặc ENTER để chọn đối tượng trong trình soạn thảo.'
37 }
38 ]
39 },
40 {
41 name: 'Lệnh',
42 items: [
43 {
44 name: 'Làm lại lện',
45 legend: 'Ấn ${undo}'
46 },
47 {
48 name: 'Làm lại lệnh',
49 legend: 'Ấn ${redo}'
50 },
51 {
52 name: 'Lệnh in đậm',
53 legend: 'Ấn ${bold}'
54 },
55 {
56 name: 'Lệnh in nghiêng',
57 legend: 'Ấn ${italic}'
58 },
59 {
60 name: 'Lệnh gạch dưới',
61 legend: 'Ấn ${underline}'
62 },
63 {
64 name: 'Lệnh liên kết',
65 legend: 'Nhấn ${link}'
66 },
67 {
68 name: 'Lệnh hiển thị thanh công cụ',
69 legend: 'Nhấn${toolbarCollapse}'
70 },
71 {
72 name: 'Truy cập đến lệnh tập trung vào khoảng cách trước đó',
73 legend: 'Ấn ${accessPreviousSpace} để truy cập đến phần tập trung khoảng cách sau phần còn sót lại của khoảng cách gần nhất vốn không tác động đến được , thí dụ: hai yếu tố điều chỉnh HR. Lặp lại các phím kết họep này để vươn đến phần khoảng cách.'
74 },
75 {
76 name: 'Truy cập phần đối tượng lệnh khoảng trống',
77 legend: 'Ấn ${accessNextSpace} để truy cập đến phần tập trung khoảng cách sau phần còn sót lại của khoảng cách gần nhất vốn không tác động đến được , thí dụ: hai yếu tố điều chỉnh HR. Lặp lại các phím kết họep này để vươn đến phần khoảng cách.'
78 },
79 {
80 name: 'Trợ giúp liên quan',
81 legend: 'Nhấn ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Phím Tab',
87 pause: 'Phím Pause',
88 capslock: 'Phím Caps Lock',
89 escape: 'Phím Escape',
90 pageUp: 'Phím Page Up',
91 pageDown: 'Phím Page Down',
92 leftArrow: 'Phím Left Arrow',
93 upArrow: 'Phím Up Arrow',
94 rightArrow: 'Phím Right Arrow',
95 downArrow: 'Phím Down Arrow',
96 insert: 'Chèn',
97 leftWindowKey: 'Phím Left Windows',
98 rightWindowKey: 'Phím Right Windows ',
99 selectKey: 'Chọn phím',
100 numpad0: 'Phím 0',
101 numpad1: 'Phím 1',
102 numpad2: 'Phím 2',
103 numpad3: 'Phím 3',
104 numpad4: 'Phím 4',
105 numpad5: 'Phím 5',
106 numpad6: 'Phím 6',
107 numpad7: 'Phím 7',
108 numpad8: 'Phím 8',
109 numpad9: 'Phím 9',
110 multiply: 'Nhân',
111 add: 'Thêm',
112 subtract: 'Trừ',
113 decimalPoint: 'Điểm số thập phân',
114 divide: 'Chia',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: 'Dấu chấm phẩy',
130 equalSign: 'Đăng nhập bằng',
131 comma: 'Dấu phẩy',
132 dash: 'Dấu gạch ngang',
133 period: 'Phím .',
134 forwardSlash: 'Phím /',
135 graveAccent: 'Phím `',
136 openBracket: 'Open Bracket',
137 backSlash: 'Dấu gạch chéo ngược',
138 closeBracket: 'Gần giá đỡ',
139 singleQuote: 'Trích dẫn'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/zh-cn.js b/sources/plugins/a11yhelp/dialogs/lang/zh-cn.js
new file mode 100644
index 0000000..d2d0f2b
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/zh-cn.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'zh-cn', {
7 title: '辅助功能说明',
8 contents: '帮助内容。要关闭此对话框请按 ESC 键。',
9 legend: [
10 {
11 name: '常规',
12 items: [
13 {
14 name: '编辑器工具栏',
15 legend: '按 ${toolbarFocus} 切换到工具栏,使用 TAB 键和 SHIFT+TAB 组合键移动到上一个和下一个工具栏组。使用左右箭头键移动到上一个或下一个工具栏按钮。按空格键或回车键以选中工具栏按钮。'
16 },
17
18 {
19 name: '编辑器对话框',
20 legend:
21 '在对话框内,按 TAB 键移动到下一个字段,按 SHIFT + TAB 组合键移动到上一个字段,按 ENTER 键提交对话框,按 ESC 键取消对话框。对于有多选项卡的对话框,可以按 ALT + F10 直接切换到或者按 TAB 键逐步移到选项卡列表,当焦点移到选项卡列表时可以用左右箭头键来移动到前后的选项卡。'
22 },
23
24 {
25 name: '编辑器上下文菜单',
26 legend: '用 ${contextMenu} 或者“应用程序键”打开上下文菜单。然后用 TAB 键或者下箭头键来移动到下一个菜单项;SHIFT + TAB 组合键或者上箭头键移动到上一个菜单项。用 SPACE 键或者 ENTER 键选择菜单项。用 SPACE 键,ENTER 键或者右箭头键打开子菜单。返回菜单用 ESC 键或者左箭头键。用 ESC 键关闭上下文菜单。'
27 },
28
29 {
30 name: '编辑器列表框',
31 legend: '在列表框中,移到下一列表项用 TAB 键或者下箭头键。移到上一列表项用SHIFT+TAB 组合键或者上箭头键,用 SPACE 键或者 ENTER 键选择列表项。用 ESC 键收起列表框。'
32 },
33
34 {
35 name: '编辑器元素路径栏',
36 legend: '按 ${elementsPathFocus} 以导航到元素路径栏,使用 TAB 键或右箭头键选择下一个元素,使用 SHIFT+TAB 组合键或左箭头键选择上一个元素,按空格键或回车键以选定编辑器里的元素。'
37 }
38 ]
39 },
40 {
41 name: '命令',
42 items: [
43 {
44 name: ' 撤消命令',
45 legend: '按 ${undo}'
46 },
47 {
48 name: ' 重做命令',
49 legend: '按 ${redo}'
50 },
51 {
52 name: ' 加粗命令',
53 legend: '按 ${bold}'
54 },
55 {
56 name: ' 倾斜命令',
57 legend: '按 ${italic}'
58 },
59 {
60 name: ' 下划线命令',
61 legend: '按 ${underline}'
62 },
63 {
64 name: ' 链接命令',
65 legend: '按 ${link}'
66 },
67 {
68 name: ' 工具栏折叠命令',
69 legend: '按 ${toolbarCollapse}'
70 },
71 {
72 name: '访问前一个焦点区域的命令',
73 legend: '按 ${accessPreviousSpace} 访问^符号前最近的不可访问的焦点区域,例如:两个相邻的 HR 元素。重复此组合按键可以到达远处的焦点区域。'
74 },
75 {
76 name: '访问下一个焦点区域命令',
77 legend: '按 ${accessNextSpace} 以访问^符号后最近的不可访问的焦点区域。例如:两个相邻的 HR 元素。重复此组合按键可以到达远处的焦点区域。'
78 },
79 {
80 name: '辅助功能帮助',
81 legend: '按 ${a11yHelp}'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab 键',
87 pause: '暂停键',
88 capslock: '大写锁定键',
89 escape: 'Esc 键',
90 pageUp: '上翻页键',
91 pageDown: '下翻页键',
92 leftArrow: '向左箭头键',
93 upArrow: '向上箭头键',
94 rightArrow: '向右箭头键',
95 downArrow: '向下箭头键',
96 insert: '插入键',
97 leftWindowKey: '左 WIN 键',
98 rightWindowKey: '右 WIN 键',
99 selectKey: '选择键',
100 numpad0: '小键盘 0 键',
101 numpad1: '小键盘 1 键',
102 numpad2: '小键盘 2 键',
103 numpad3: '小键盘 3 键',
104 numpad4: '小键盘 4 键',
105 numpad5: '小键盘 5 键',
106 numpad6: '小键盘 6 键',
107 numpad7: '小键盘 7 键',
108 numpad8: '小键盘 8 键',
109 numpad9: '小键盘 9 键',
110 multiply: '星号键',
111 add: '加号键',
112 subtract: '减号键',
113 decimalPoint: '小数点键',
114 divide: '除号键',
115 f1: 'F1 键',
116 f2: 'F2 键',
117 f3: 'F3 键',
118 f4: 'F4 键',
119 f5: 'F5 键',
120 f6: 'F6 键',
121 f7: 'F7 键',
122 f8: 'F8 键',
123 f9: 'F9 键',
124 f10: 'F10 键',
125 f11: 'F11 键',
126 f12: 'F12 键',
127 numLock: '数字锁定键',
128 scrollLock: '滚动锁定键',
129 semiColon: '分号键',
130 equalSign: '等号键',
131 comma: '逗号键',
132 dash: '短划线键',
133 period: '句号键',
134 forwardSlash: '斜杠键',
135 graveAccent: '重音符键',
136 openBracket: '左中括号键',
137 backSlash: '反斜杠键',
138 closeBracket: '右中括号键',
139 singleQuote: '单引号键'
140} );
diff --git a/sources/plugins/a11yhelp/dialogs/lang/zh.js b/sources/plugins/a11yhelp/dialogs/lang/zh.js
new file mode 100644
index 0000000..0fe1310
--- /dev/null
+++ b/sources/plugins/a11yhelp/dialogs/lang/zh.js
@@ -0,0 +1,140 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'a11yhelp', 'zh', {
7 title: '輔助工具指南',
8 contents: '說明內容。若要關閉此對話框請按「ESC」。',
9 legend: [
10 {
11 name: '一般',
12 items: [
13 {
14 name: '編輯器工具列',
15 legend: '請按 ${toolbarFocus} 以導覽到工具列。利用 TAB 或 SHIFT+TAB 以便移動到下一個及前一個工具列群組。利用右方向鍵或左方向鍵以便移動到下一個及上一個工具列按鈕。按下空白鍵或 ENTER 鍵啟用工具列按鈕。'
16 },
17
18 {
19 name: '編輯器對話方塊',
20 legend:
21 '在對話框中,按下 TAB 鍵以導覽到下一個對話框元素,按下 SHIFT+TAB 以移動到上一個對話框元素,按下 ENTER 以遞交對話框,按下 ESC 以取消對話框。當對話框有多個分頁時,可以使用 ALT+F10 或是在對話框分頁順序中的一部份按下 TAB 以使用分頁列表。焦點在分頁列表上時,分別使用右方向鍵及左方向鍵移動到下一個及上一個分頁。'
22 },
23
24 {
25 name: '編輯器內容功能表',
26 legend: '請按下「${contextMenu}」或是「應用程式鍵」以開啟內容選單。以「TAB」或是「↓」鍵移動到下一個選單選項。以「SHIFT + TAB」或是「↑」鍵移動到上一個選單選項。按下「空白鍵」或是「ENTER」鍵以選取選單選項。以「空白鍵」或「ENTER」或「→」開啟目前選項之子選單。以「ESC」或「←」回到父選單。以「ESC」鍵關閉內容選單」。'
27 },
28
29 {
30 name: '編輯器清單方塊',
31 legend: '在清單方塊中,使用 TAB 或下方向鍵移動到下一個列表項目。使用 SHIFT+TAB 或上方向鍵移動到上一個列表項目。按下空白鍵或 ENTER 以選取列表選項。按下 ESC 以關閉清單方塊。'
32 },
33
34 {
35 name: '編輯器元件路徑工具列',
36 legend: '請按 ${elementsPathFocus} 以瀏覽元素路徑列。利用 TAB 或右方向鍵以便移動到下一個元素按鈕。利用 SHIFT 或左方向鍵以便移動到上一個按鈕。按下空白鍵或 ENTER 鍵來選取在編輯器中的元素。'
37 }
38 ]
39 },
40 {
41 name: '命令',
42 items: [
43 {
44 name: '復原命令',
45 legend: '請按下「${undo}」'
46 },
47 {
48 name: '重複命令',
49 legend: '請按下「 ${redo}」'
50 },
51 {
52 name: '粗體命令',
53 legend: '請按下「${bold}」'
54 },
55 {
56 name: '斜體',
57 legend: '請按下「${italic}」'
58 },
59 {
60 name: '底線命令',
61 legend: '請按下「${underline}」'
62 },
63 {
64 name: '連結',
65 legend: '請按下「${link}」'
66 },
67 {
68 name: '隱藏工具列',
69 legend: '請按下「${toolbarCollapse}」'
70 },
71 {
72 name: '存取前一個焦點空間命令',
73 legend: '請按下 ${accessPreviousSpace} 以存取最近但無法靠近之插字符號前的焦點空間。舉例:二個相鄰的 HR 元素。\r\n重複按鍵以存取較遠的焦點空間。'
74 },
75 {
76 name: '存取下一個焦點空間命令',
77 legend: '請按下 ${accessNextSpace} 以存取最近但無法靠近之插字符號後的焦點空間。舉例:二個相鄰的 HR 元素。\r\n重複按鍵以存取較遠的焦點空間。'
78 },
79 {
80 name: '協助工具說明',
81 legend: '請按下「${a11yHelp}」'
82 }
83 ]
84 }
85 ],
86 tab: 'Tab',
87 pause: 'Pause',
88 capslock: 'Caps Lock',
89 escape: 'Esc',
90 pageUp: 'Page Up',
91 pageDown: 'Page Down',
92 leftArrow: '向左箭號',
93 upArrow: '向上鍵號',
94 rightArrow: '向右鍵號',
95 downArrow: '向下鍵號',
96 insert: '插入',
97 leftWindowKey: '左方 Windows 鍵',
98 rightWindowKey: '右方 Windows 鍵',
99 selectKey: '選擇鍵',
100 numpad0: 'Numpad 0',
101 numpad1: 'Numpad 1',
102 numpad2: 'Numpad 2',
103 numpad3: 'Numpad 3',
104 numpad4: 'Numpad 4',
105 numpad5: 'Numpad 5',
106 numpad6: 'Numpad 6',
107 numpad7: 'Numpad 7',
108 numpad8: 'Numpad 8',
109 numpad9: 'Numpad 9',
110 multiply: '乘號',
111 add: '新增',
112 subtract: '減號',
113 decimalPoint: '小數點',
114 divide: '除號',
115 f1: 'F1',
116 f2: 'F2',
117 f3: 'F3',
118 f4: 'F4',
119 f5: 'F5',
120 f6: 'F6',
121 f7: 'F7',
122 f8: 'F8',
123 f9: 'F9',
124 f10: 'F10',
125 f11: 'F11',
126 f12: 'F12',
127 numLock: 'Num Lock',
128 scrollLock: 'Scroll Lock',
129 semiColon: '分號',
130 equalSign: '等號',
131 comma: '逗號',
132 dash: '虛線',
133 period: '句點',
134 forwardSlash: '斜線',
135 graveAccent: '抑音符號',
136 openBracket: '左方括號',
137 backSlash: '反斜線',
138 closeBracket: '右方括號',
139 singleQuote: '單引號'
140} );
diff --git a/sources/plugins/a11yhelp/plugin.js b/sources/plugins/a11yhelp/plugin.js
new file mode 100644
index 0000000..9e2925a
--- /dev/null
+++ b/sources/plugins/a11yhelp/plugin.js
@@ -0,0 +1,51 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Plugin definition for the a11yhelp, which provides a dialog
8 * with accessibility related help.
9 */
10
11( function() {
12 var pluginName = 'a11yhelp',
13 commandName = 'a11yHelp';
14
15 CKEDITOR.plugins.add( pluginName, {
16 requires: 'dialog',
17
18 // List of available localizations.
19 // jscs:disable
20 availableLangs: { af:1,ar:1,az:1,bg:1,ca:1,cs:1,cy:1,da:1,de:1,'de-ch':1,el:1,en:1,'en-gb':1,eo:1,es:1,et:1,eu:1,fa:1,fi:1,fo:1,fr:1,'fr-ca':1,gl:1,gu:1,he:1,hi:1,hr:1,hu:1,id:1,it:1,ja:1,km:1,ko:1,ku:1,lt:1,lv:1,mk:1,mn:1,nb:1,nl:1,no:1,oc:1,pl:1,pt:1,'pt-br':1,ro:1,ru:1,si:1,sk:1,sl:1,sq:1,sr:1,'sr-latn':1,sv:1,th:1,tr:1,tt:1,ug:1,uk:1,vi:1,zh:1,'zh-cn':1 },
21 // jscs:enable
22
23 init: function( editor ) {
24 var plugin = this;
25 editor.addCommand( commandName, {
26 exec: function() {
27 var langCode = editor.langCode;
28 langCode =
29 plugin.availableLangs[ langCode ] ? langCode :
30 plugin.availableLangs[ langCode.replace( /-.*/, '' ) ] ? langCode.replace( /-.*/, '' ) :
31 'en';
32
33 CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( plugin.path + 'dialogs/lang/' + langCode + '.js' ), function() {
34 editor.lang.a11yhelp = plugin.langEntries[ langCode ];
35 editor.openDialog( commandName );
36 } );
37 },
38 modes: { wysiwyg: 1, source: 1 },
39 readOnly: 1,
40 canUndo: false
41 } );
42
43 editor.setKeystroke( CKEDITOR.ALT + 48 /*0*/, 'a11yHelp' );
44 CKEDITOR.dialog.add( commandName, this.path + 'dialogs/a11yhelp.js' );
45
46 editor.on( 'ariaEditorHelpLabel', function( evt ) {
47 evt.data.label = editor.lang.common.editorHelp;
48 } );
49 }
50 } );
51} )();
diff --git a/sources/plugins/basicstyles/icons/bold.png b/sources/plugins/basicstyles/icons/bold.png
new file mode 100644
index 0000000..d714916
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/bold.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/bold.png b/sources/plugins/basicstyles/icons/hidpi/bold.png
new file mode 100644
index 0000000..2de207d
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/bold.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/italic.png b/sources/plugins/basicstyles/icons/hidpi/italic.png
new file mode 100644
index 0000000..2c2dae4
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/italic.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/strike.png b/sources/plugins/basicstyles/icons/hidpi/strike.png
new file mode 100644
index 0000000..19c5e22
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/strike.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/subscript.png b/sources/plugins/basicstyles/icons/hidpi/subscript.png
new file mode 100644
index 0000000..585d59b
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/subscript.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/superscript.png b/sources/plugins/basicstyles/icons/hidpi/superscript.png
new file mode 100644
index 0000000..9daa12a
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/superscript.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/hidpi/underline.png b/sources/plugins/basicstyles/icons/hidpi/underline.png
new file mode 100644
index 0000000..6653814
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/hidpi/underline.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/italic.png b/sources/plugins/basicstyles/icons/italic.png
new file mode 100644
index 0000000..5f8aaae
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/italic.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/strike.png b/sources/plugins/basicstyles/icons/strike.png
new file mode 100644
index 0000000..5842b7a
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/strike.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/subscript.png b/sources/plugins/basicstyles/icons/subscript.png
new file mode 100644
index 0000000..db11f78
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/subscript.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/superscript.png b/sources/plugins/basicstyles/icons/superscript.png
new file mode 100644
index 0000000..3df28d2
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/superscript.png
Binary files differ
diff --git a/sources/plugins/basicstyles/icons/underline.png b/sources/plugins/basicstyles/icons/underline.png
new file mode 100644
index 0000000..160be92
--- /dev/null
+++ b/sources/plugins/basicstyles/icons/underline.png
Binary files differ
diff --git a/sources/plugins/basicstyles/lang/af.js b/sources/plugins/basicstyles/lang/af.js
new file mode 100644
index 0000000..bcceb14
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/af.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'af', {
6 bold: 'Vet',
7 italic: 'Skuins',
8 strike: 'Deurgestreep',
9 subscript: 'Onderskrif',
10 superscript: 'Bo-skrif',
11 underline: 'Onderstreep'
12} );
diff --git a/sources/plugins/basicstyles/lang/ar.js b/sources/plugins/basicstyles/lang/ar.js
new file mode 100644
index 0000000..fb4adc6
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ar.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ar', {
6 bold: 'عريض',
7 italic: 'مائل',
8 strike: 'يتوسطه خط',
9 subscript: 'منخفض',
10 superscript: 'مرتفع',
11 underline: 'تسطير'
12} );
diff --git a/sources/plugins/basicstyles/lang/az.js b/sources/plugins/basicstyles/lang/az.js
new file mode 100644
index 0000000..097a1ec
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/az.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'az', {
6 bold: 'Qalın',
7 italic: 'Kursiv',
8 strike: 'Üstüxətli',
9 subscript: 'Aşağı indeks',
10 superscript: 'Yuxarı indeks',
11 underline: 'Altdan xətt'
12} );
diff --git a/sources/plugins/basicstyles/lang/bg.js b/sources/plugins/basicstyles/lang/bg.js
new file mode 100644
index 0000000..56f6f7d
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/bg.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'bg', {
6 bold: 'Удебелен',
7 italic: 'Наклонен',
8 strike: 'Зачертан текст',
9 subscript: 'Индексиран текст',
10 superscript: 'Суперскрипт',
11 underline: 'Подчертан'
12} );
diff --git a/sources/plugins/basicstyles/lang/bn.js b/sources/plugins/basicstyles/lang/bn.js
new file mode 100644
index 0000000..fd790a4
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/bn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'bn', {
6 bold: 'বোল্ড',
7 italic: 'বাঁকা',
8 strike: 'স্ট্রাইক থ্রু',
9 subscript: 'অধোলেখ',
10 superscript: 'অভিলেখ',
11 underline: 'আন্ডারলাইন'
12} );
diff --git a/sources/plugins/basicstyles/lang/bs.js b/sources/plugins/basicstyles/lang/bs.js
new file mode 100644
index 0000000..9188f98
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/bs.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'bs', {
6 bold: 'Boldiraj',
7 italic: 'Ukosi',
8 strike: 'Precrtaj',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Podvuci'
12} );
diff --git a/sources/plugins/basicstyles/lang/ca.js b/sources/plugins/basicstyles/lang/ca.js
new file mode 100644
index 0000000..2924d1e
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ca', {
6 bold: 'Negreta',
7 italic: 'Cursiva',
8 strike: 'Ratllat',
9 subscript: 'Subíndex',
10 superscript: 'Superíndex',
11 underline: 'Subratllat'
12} );
diff --git a/sources/plugins/basicstyles/lang/cs.js b/sources/plugins/basicstyles/lang/cs.js
new file mode 100644
index 0000000..737c648
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/cs.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'cs', {
6 bold: 'Tučné',
7 italic: 'Kurzíva',
8 strike: 'Přeškrtnuté',
9 subscript: 'Dolní index',
10 superscript: 'Horní index',
11 underline: 'Podtržené'
12} );
diff --git a/sources/plugins/basicstyles/lang/cy.js b/sources/plugins/basicstyles/lang/cy.js
new file mode 100644
index 0000000..3acb736
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/cy.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'cy', {
6 bold: 'Bras',
7 italic: 'Italig',
8 strike: 'Llinell Trwyddo',
9 subscript: 'Is-sgript',
10 superscript: 'Uwchsgript',
11 underline: 'Tanlinellu'
12} );
diff --git a/sources/plugins/basicstyles/lang/da.js b/sources/plugins/basicstyles/lang/da.js
new file mode 100644
index 0000000..0b1f3e8
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/da.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'da', {
6 bold: 'Fed',
7 italic: 'Kursiv',
8 strike: 'Gennemstreget',
9 subscript: 'Sænket skrift',
10 superscript: 'Hævet skrift',
11 underline: 'Understreget'
12} );
diff --git a/sources/plugins/basicstyles/lang/de-ch.js b/sources/plugins/basicstyles/lang/de-ch.js
new file mode 100644
index 0000000..2370c04
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/de-ch.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'de-ch', {
6 bold: 'Fett',
7 italic: 'Kursiv',
8 strike: 'Durchgestrichen',
9 subscript: 'Tiefgestellt',
10 superscript: 'Hochgestellt',
11 underline: 'Unterstrichen'
12} );
diff --git a/sources/plugins/basicstyles/lang/de.js b/sources/plugins/basicstyles/lang/de.js
new file mode 100644
index 0000000..fbc92e4
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/de.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'de', {
6 bold: 'Fett',
7 italic: 'Kursiv',
8 strike: 'Durchgestrichen',
9 subscript: 'Tiefgestellt',
10 superscript: 'Hochgestellt',
11 underline: 'Unterstrichen'
12} );
diff --git a/sources/plugins/basicstyles/lang/el.js b/sources/plugins/basicstyles/lang/el.js
new file mode 100644
index 0000000..2c72cda
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/el.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'el', {
6 bold: 'Έντονη',
7 italic: 'Πλάγια',
8 strike: 'Διακριτή Διαγραφή',
9 subscript: 'Δείκτης',
10 superscript: 'Εκθέτης',
11 underline: 'Υπογράμμιση'
12} );
diff --git a/sources/plugins/basicstyles/lang/en-au.js b/sources/plugins/basicstyles/lang/en-au.js
new file mode 100644
index 0000000..6b9dc7e
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/en-au.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'en-au', {
6 bold: 'Bold',
7 italic: 'Italic',
8 strike: 'Strike Through',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Underline'
12} );
diff --git a/sources/plugins/basicstyles/lang/en-ca.js b/sources/plugins/basicstyles/lang/en-ca.js
new file mode 100644
index 0000000..612b2b8
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/en-ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'en-ca', {
6 bold: 'Bold',
7 italic: 'Italic',
8 strike: 'Strike Through',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Underline'
12} );
diff --git a/sources/plugins/basicstyles/lang/en-gb.js b/sources/plugins/basicstyles/lang/en-gb.js
new file mode 100644
index 0000000..418058e
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/en-gb.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'en-gb', {
6 bold: 'Bold',
7 italic: 'Italic',
8 strike: 'Strike Through',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Underline'
12} );
diff --git a/sources/plugins/basicstyles/lang/en.js b/sources/plugins/basicstyles/lang/en.js
new file mode 100644
index 0000000..3c9bc32
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/en.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'en', {
6 bold: 'Bold',
7 italic: 'Italic',
8 strike: 'Strikethrough',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Underline'
12} );
diff --git a/sources/plugins/basicstyles/lang/eo.js b/sources/plugins/basicstyles/lang/eo.js
new file mode 100644
index 0000000..995f0c3
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/eo.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'eo', {
6 bold: 'Grasa',
7 italic: 'Kursiva',
8 strike: 'Trastreko',
9 subscript: 'Suba indico',
10 superscript: 'Supra indico',
11 underline: 'Substreko'
12} );
diff --git a/sources/plugins/basicstyles/lang/es.js b/sources/plugins/basicstyles/lang/es.js
new file mode 100644
index 0000000..baaf99f
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/es.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'es', {
6 bold: 'Negrita',
7 italic: 'Cursiva',
8 strike: 'Tachado',
9 subscript: 'Subíndice',
10 superscript: 'Superíndice',
11 underline: 'Subrayado'
12} );
diff --git a/sources/plugins/basicstyles/lang/et.js b/sources/plugins/basicstyles/lang/et.js
new file mode 100644
index 0000000..8dee05e
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/et.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'et', {
6 bold: 'Paks',
7 italic: 'Kursiiv',
8 strike: 'Läbijoonitud',
9 subscript: 'Allindeks',
10 superscript: 'Ülaindeks',
11 underline: 'Allajoonitud'
12} );
diff --git a/sources/plugins/basicstyles/lang/eu.js b/sources/plugins/basicstyles/lang/eu.js
new file mode 100644
index 0000000..7017540
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/eu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'eu', {
6 bold: 'Lodia',
7 italic: 'Etzana',
8 strike: 'Marratua',
9 subscript: 'Azpi-indizea',
10 superscript: 'Goi-indizea',
11 underline: 'Azpimarratu'
12} );
diff --git a/sources/plugins/basicstyles/lang/fa.js b/sources/plugins/basicstyles/lang/fa.js
new file mode 100644
index 0000000..49343fb
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/fa.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'fa', {
6 bold: 'درشت',
7 italic: 'خمیده',
8 strike: 'خط‌خورده',
9 subscript: 'زیرنویس',
10 superscript: 'بالانویس',
11 underline: 'زیرخط‌دار'
12} );
diff --git a/sources/plugins/basicstyles/lang/fi.js b/sources/plugins/basicstyles/lang/fi.js
new file mode 100644
index 0000000..5e1fbce
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/fi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'fi', {
6 bold: 'Lihavoitu',
7 italic: 'Kursivoitu',
8 strike: 'Yliviivattu',
9 subscript: 'Alaindeksi',
10 superscript: 'Yläindeksi',
11 underline: 'Alleviivattu'
12} );
diff --git a/sources/plugins/basicstyles/lang/fo.js b/sources/plugins/basicstyles/lang/fo.js
new file mode 100644
index 0000000..f48b73a
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/fo.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'fo', {
6 bold: 'Feit skrift',
7 italic: 'Skráskrift',
8 strike: 'Yvirstrikað',
9 subscript: 'Lækkað skrift',
10 superscript: 'Hækkað skrift',
11 underline: 'Undirstrikað'
12} );
diff --git a/sources/plugins/basicstyles/lang/fr-ca.js b/sources/plugins/basicstyles/lang/fr-ca.js
new file mode 100644
index 0000000..6b8ffbf
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/fr-ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'fr-ca', {
6 bold: 'Gras',
7 italic: 'Italique',
8 strike: 'Barré',
9 subscript: 'Indice',
10 superscript: 'Exposant',
11 underline: 'Souligné'
12} );
diff --git a/sources/plugins/basicstyles/lang/fr.js b/sources/plugins/basicstyles/lang/fr.js
new file mode 100644
index 0000000..022e438
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/fr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'fr', {
6 bold: 'Gras',
7 italic: 'Italique',
8 strike: 'Barré',
9 subscript: 'Indice',
10 superscript: 'Exposant',
11 underline: 'Souligné'
12} );
diff --git a/sources/plugins/basicstyles/lang/gl.js b/sources/plugins/basicstyles/lang/gl.js
new file mode 100644
index 0000000..ebd5aa4
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/gl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'gl', {
6 bold: 'Negra',
7 italic: 'Cursiva',
8 strike: 'Riscado',
9 subscript: 'Subíndice',
10 superscript: 'Superíndice',
11 underline: 'Subliñado'
12} );
diff --git a/sources/plugins/basicstyles/lang/gu.js b/sources/plugins/basicstyles/lang/gu.js
new file mode 100644
index 0000000..fc043b4
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/gu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'gu', {
6 bold: 'બોલ્ડ/સ્પષ્ટ',
7 italic: 'ઇટેલિક, ત્રાંસા',
8 strike: 'છેકી નાખવું',
9 subscript: 'એક ચિહ્નની નીચે કરેલું બીજું ચિહ્ન',
10 superscript: 'એક ચિહ્ન ઉપર કરેલું બીજું ચિહ્ન.',
11 underline: 'અન્ડર્લાઇન, નીચે લીટી'
12} );
diff --git a/sources/plugins/basicstyles/lang/he.js b/sources/plugins/basicstyles/lang/he.js
new file mode 100644
index 0000000..16b16a4
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/he.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'he', {
6 bold: 'מודגש',
7 italic: 'נטוי',
8 strike: 'כתיב מחוק',
9 subscript: 'כתיב תחתון',
10 superscript: 'כתיב עליון',
11 underline: 'קו תחתון'
12} );
diff --git a/sources/plugins/basicstyles/lang/hi.js b/sources/plugins/basicstyles/lang/hi.js
new file mode 100644
index 0000000..2b2fcb5
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/hi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'hi', {
6 bold: 'बोल्ड',
7 italic: 'इटैलिक',
8 strike: 'स्ट्राइक थ्रू',
9 subscript: 'अधोलेख',
10 superscript: 'अभिलेख',
11 underline: 'रेखांकण'
12} );
diff --git a/sources/plugins/basicstyles/lang/hr.js b/sources/plugins/basicstyles/lang/hr.js
new file mode 100644
index 0000000..6ddfb31
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/hr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'hr', {
6 bold: 'Podebljaj',
7 italic: 'Ukosi',
8 strike: 'Precrtano',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Potcrtano'
12} );
diff --git a/sources/plugins/basicstyles/lang/hu.js b/sources/plugins/basicstyles/lang/hu.js
new file mode 100644
index 0000000..41d3a32
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/hu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'hu', {
6 bold: 'Félkövér',
7 italic: 'Dőlt',
8 strike: 'Áthúzott',
9 subscript: 'Alsó index',
10 superscript: 'Felső index',
11 underline: 'Aláhúzott'
12} );
diff --git a/sources/plugins/basicstyles/lang/id.js b/sources/plugins/basicstyles/lang/id.js
new file mode 100644
index 0000000..39e916d
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/id.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'id', {
6 bold: 'Huruf Tebal',
7 italic: 'Huruf Miring',
8 strike: 'Strikethrough', // MISSING
9 subscript: 'Subscript', // MISSING
10 superscript: 'Superscript', // MISSING
11 underline: 'Garis Bawah'
12} );
diff --git a/sources/plugins/basicstyles/lang/is.js b/sources/plugins/basicstyles/lang/is.js
new file mode 100644
index 0000000..d22f80a
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/is.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'is', {
6 bold: 'Feitletrað',
7 italic: 'Skáletrað',
8 strike: 'Yfirstrikað',
9 subscript: 'Niðurskrifað',
10 superscript: 'Uppskrifað',
11 underline: 'Undirstrikað'
12} );
diff --git a/sources/plugins/basicstyles/lang/it.js b/sources/plugins/basicstyles/lang/it.js
new file mode 100644
index 0000000..12d5594
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/it.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'it', {
6 bold: 'Grassetto',
7 italic: 'Corsivo',
8 strike: 'Barrato',
9 subscript: 'Pedice',
10 superscript: 'Apice',
11 underline: 'Sottolineato'
12} );
diff --git a/sources/plugins/basicstyles/lang/ja.js b/sources/plugins/basicstyles/lang/ja.js
new file mode 100644
index 0000000..1d7ba09
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ja.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ja', {
6 bold: '太字',
7 italic: '斜体',
8 strike: '打ち消し線',
9 subscript: '下付き',
10 superscript: '上付き',
11 underline: '下線'
12} );
diff --git a/sources/plugins/basicstyles/lang/ka.js b/sources/plugins/basicstyles/lang/ka.js
new file mode 100644
index 0000000..e1ea391
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ka.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ka', {
6 bold: 'მსხვილი',
7 italic: 'დახრილი',
8 strike: 'გადახაზული',
9 subscript: 'ინდექსი',
10 superscript: 'ხარისხი',
11 underline: 'გახაზული'
12} );
diff --git a/sources/plugins/basicstyles/lang/km.js b/sources/plugins/basicstyles/lang/km.js
new file mode 100644
index 0000000..a55d004
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/km.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'km', {
6 bold: 'ដិត',
7 italic: 'ទ្រេត',
8 strike: 'គូស​បន្ទាត់​ចំ​កណ្ដាល',
9 subscript: 'អក្សរតូចក្រោម',
10 superscript: 'អក្សរតូចលើ',
11 underline: 'គូស​បន្ទាត់​ក្រោម'
12} );
diff --git a/sources/plugins/basicstyles/lang/ko.js b/sources/plugins/basicstyles/lang/ko.js
new file mode 100644
index 0000000..7a61f11
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ko.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ko', {
6 bold: '굵게',
7 italic: '기울임꼴',
8 strike: '취소선',
9 subscript: '아래 첨자',
10 superscript: '위 첨자',
11 underline: '밑줄'
12} );
diff --git a/sources/plugins/basicstyles/lang/ku.js b/sources/plugins/basicstyles/lang/ku.js
new file mode 100644
index 0000000..fa3c16d
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ku.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ku', {
6 bold: 'قەڵەو',
7 italic: 'لار',
8 strike: 'لێدان',
9 subscript: 'ژێرنووس',
10 superscript: 'سەرنووس',
11 underline: 'ژێرهێڵ'
12} );
diff --git a/sources/plugins/basicstyles/lang/lt.js b/sources/plugins/basicstyles/lang/lt.js
new file mode 100644
index 0000000..edb6949
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/lt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'lt', {
6 bold: 'Pusjuodis',
7 italic: 'Kursyvas',
8 strike: 'Perbrauktas',
9 subscript: 'Apatinis indeksas',
10 superscript: 'Viršutinis indeksas',
11 underline: 'Pabrauktas'
12} );
diff --git a/sources/plugins/basicstyles/lang/lv.js b/sources/plugins/basicstyles/lang/lv.js
new file mode 100644
index 0000000..4efd61f
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/lv.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'lv', {
6 bold: 'Treknināts',
7 italic: 'Kursīvs',
8 strike: 'Pārsvītrots',
9 subscript: 'Apakšrakstā',
10 superscript: 'Augšrakstā',
11 underline: 'Pasvītrots'
12} );
diff --git a/sources/plugins/basicstyles/lang/mk.js b/sources/plugins/basicstyles/lang/mk.js
new file mode 100644
index 0000000..7d56475
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/mk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'mk', {
6 bold: 'Здебелено',
7 italic: 'Накривено',
8 strike: 'Прецртано',
9 subscript: 'Долен индекс',
10 superscript: 'Горен индекс',
11 underline: 'Подвлечено'
12} );
diff --git a/sources/plugins/basicstyles/lang/mn.js b/sources/plugins/basicstyles/lang/mn.js
new file mode 100644
index 0000000..71fa4da
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/mn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'mn', {
6 bold: 'Тод бүдүүн',
7 italic: 'Налуу',
8 strike: 'Дундуур нь зураастай болгох',
9 subscript: 'Суурь болгох',
10 superscript: 'Зэрэг болгох',
11 underline: 'Доогуур нь зураастай болгох'
12} );
diff --git a/sources/plugins/basicstyles/lang/ms.js b/sources/plugins/basicstyles/lang/ms.js
new file mode 100644
index 0000000..0fd97ee
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ms.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ms', {
6 bold: 'Bold',
7 italic: 'Italic',
8 strike: 'Strike Through',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Underline'
12} );
diff --git a/sources/plugins/basicstyles/lang/nb.js b/sources/plugins/basicstyles/lang/nb.js
new file mode 100644
index 0000000..6ab2325
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/nb.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'nb', {
6 bold: 'Fet',
7 italic: 'Kursiv',
8 strike: 'Gjennomstreking',
9 subscript: 'Senket skrift',
10 superscript: 'Hevet skrift',
11 underline: 'Understreking'
12} );
diff --git a/sources/plugins/basicstyles/lang/nl.js b/sources/plugins/basicstyles/lang/nl.js
new file mode 100644
index 0000000..b2ddb86
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/nl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'nl', {
6 bold: 'Vet',
7 italic: 'Cursief',
8 strike: 'Doorhalen',
9 subscript: 'Subscript',
10 superscript: 'Superscript',
11 underline: 'Onderstrepen'
12} );
diff --git a/sources/plugins/basicstyles/lang/no.js b/sources/plugins/basicstyles/lang/no.js
new file mode 100644
index 0000000..9fdcf1b
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/no.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'no', {
6 bold: 'Fet',
7 italic: 'Kursiv',
8 strike: 'Gjennomstreking',
9 subscript: 'Senket skrift',
10 superscript: 'Hevet skrift',
11 underline: 'Understreking'
12} );
diff --git a/sources/plugins/basicstyles/lang/oc.js b/sources/plugins/basicstyles/lang/oc.js
new file mode 100644
index 0000000..56d7df0
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/oc.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'oc', {
6 bold: 'Gras',
7 italic: 'Italica',
8 strike: 'Raiat',
9 subscript: 'Indici',
10 superscript: 'Exponent',
11 underline: 'Solinhat'
12} );
diff --git a/sources/plugins/basicstyles/lang/pl.js b/sources/plugins/basicstyles/lang/pl.js
new file mode 100644
index 0000000..5739141
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/pl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'pl', {
6 bold: 'Pogrubienie',
7 italic: 'Kursywa',
8 strike: 'Przekreślenie',
9 subscript: 'Indeks dolny',
10 superscript: 'Indeks górny',
11 underline: 'Podkreślenie'
12} );
diff --git a/sources/plugins/basicstyles/lang/pt-br.js b/sources/plugins/basicstyles/lang/pt-br.js
new file mode 100644
index 0000000..b1bbd20
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/pt-br.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'pt-br', {
6 bold: 'Negrito',
7 italic: 'Itálico',
8 strike: 'Tachado',
9 subscript: 'Subscrito',
10 superscript: 'Sobrescrito',
11 underline: 'Sublinhado'
12} );
diff --git a/sources/plugins/basicstyles/lang/pt.js b/sources/plugins/basicstyles/lang/pt.js
new file mode 100644
index 0000000..7421106
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/pt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'pt', {
6 bold: 'Negrito',
7 italic: 'Itálico',
8 strike: 'Rasurado',
9 subscript: 'Superior à linha',
10 superscript: 'Superior à linha',
11 underline: 'Sublinhado'
12} );
diff --git a/sources/plugins/basicstyles/lang/ro.js b/sources/plugins/basicstyles/lang/ro.js
new file mode 100644
index 0000000..e760a45
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ro.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ro', {
6 bold: 'Îngroşat (bold)',
7 italic: 'Înclinat (italic)',
8 strike: 'Tăiat (strike through)',
9 subscript: 'Indice (subscript)',
10 superscript: 'Putere (superscript)',
11 underline: 'Subliniat (underline)'
12} );
diff --git a/sources/plugins/basicstyles/lang/ru.js b/sources/plugins/basicstyles/lang/ru.js
new file mode 100644
index 0000000..0a38898
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ru.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ru', {
6 bold: 'Полужирный',
7 italic: 'Курсив',
8 strike: 'Зачеркнутый',
9 subscript: 'Подстрочный индекс',
10 superscript: 'Надстрочный индекс',
11 underline: 'Подчеркнутый'
12} );
diff --git a/sources/plugins/basicstyles/lang/si.js b/sources/plugins/basicstyles/lang/si.js
new file mode 100644
index 0000000..58b5a45
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/si.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'si', {
6 bold: 'තද අකුරින් ලියනලද',
7 italic: 'බැධීඅකුරින් ලියන ලද',
8 strike: 'Strikethrough', // MISSING
9 subscript: 'Subscript', // MISSING
10 superscript: 'Superscript', // MISSING
11 underline: 'යටින් ඉරි අදින ලද'
12} );
diff --git a/sources/plugins/basicstyles/lang/sk.js b/sources/plugins/basicstyles/lang/sk.js
new file mode 100644
index 0000000..42e351d
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sk', {
6 bold: 'Tučné',
7 italic: 'Kurzíva',
8 strike: 'Prečiarknuté',
9 subscript: 'Dolný index',
10 superscript: 'Horný index',
11 underline: 'Podčiarknuté'
12} );
diff --git a/sources/plugins/basicstyles/lang/sl.js b/sources/plugins/basicstyles/lang/sl.js
new file mode 100644
index 0000000..3ccb5ba
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sl', {
6 bold: 'Krepko',
7 italic: 'Ležeče',
8 strike: 'Prečrtano',
9 subscript: 'Podpisano',
10 superscript: 'Nadpisano',
11 underline: 'Podčrtano'
12} );
diff --git a/sources/plugins/basicstyles/lang/sq.js b/sources/plugins/basicstyles/lang/sq.js
new file mode 100644
index 0000000..5c6d704
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sq.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sq', {
6 bold: 'Trash',
7 italic: 'Pjerrët',
8 strike: 'Nëpërmes',
9 subscript: 'Nën-skriptë',
10 superscript: 'Super-skriptë',
11 underline: 'Nënvijëzuar'
12} );
diff --git a/sources/plugins/basicstyles/lang/sr-latn.js b/sources/plugins/basicstyles/lang/sr-latn.js
new file mode 100644
index 0000000..535dd50
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sr-latn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sr-latn', {
6 bold: 'Podebljano',
7 italic: 'Kurziv',
8 strike: 'Precrtano',
9 subscript: 'Indeks',
10 superscript: 'Stepen',
11 underline: 'Podvučeno'
12} );
diff --git a/sources/plugins/basicstyles/lang/sr.js b/sources/plugins/basicstyles/lang/sr.js
new file mode 100644
index 0000000..2e7564e
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sr', {
6 bold: 'Подебљано',
7 italic: 'Курзив',
8 strike: 'Прецртано',
9 subscript: 'Индекс',
10 superscript: 'Степен',
11 underline: 'Подвучено'
12} );
diff --git a/sources/plugins/basicstyles/lang/sv.js b/sources/plugins/basicstyles/lang/sv.js
new file mode 100644
index 0000000..efa20a8
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/sv.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'sv', {
6 bold: 'Fet',
7 italic: 'Kursiv',
8 strike: 'Genomstruken',
9 subscript: 'Nedsänkta tecken',
10 superscript: 'Upphöjda tecken',
11 underline: 'Understruken'
12} );
diff --git a/sources/plugins/basicstyles/lang/th.js b/sources/plugins/basicstyles/lang/th.js
new file mode 100644
index 0000000..82cab00
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/th.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'th', {
6 bold: 'ตัวหนา',
7 italic: 'ตัวเอียง',
8 strike: 'ตัวขีดเส้นทับ',
9 subscript: 'ตัวห้อย',
10 superscript: 'ตัวยก',
11 underline: 'ตัวขีดเส้นใต้'
12} );
diff --git a/sources/plugins/basicstyles/lang/tr.js b/sources/plugins/basicstyles/lang/tr.js
new file mode 100644
index 0000000..0e36c82
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/tr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'tr', {
6 bold: 'Kalın',
7 italic: 'İtalik',
8 strike: 'Üstü Çizgili',
9 subscript: 'Alt Simge',
10 superscript: 'Üst Simge',
11 underline: 'Altı Çizgili'
12} );
diff --git a/sources/plugins/basicstyles/lang/tt.js b/sources/plugins/basicstyles/lang/tt.js
new file mode 100644
index 0000000..c8da547
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/tt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'tt', {
6 bold: 'Калын',
7 italic: 'Курсив',
8 strike: 'Сызылган',
9 subscript: 'Аскы индекс',
10 superscript: 'Өске индекс',
11 underline: 'Астына сызылган'
12} );
diff --git a/sources/plugins/basicstyles/lang/ug.js b/sources/plugins/basicstyles/lang/ug.js
new file mode 100644
index 0000000..aa28429
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/ug.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'ug', {
6 bold: 'توم',
7 italic: 'يانتۇ',
8 strike: 'ئۆچۈرۈش سىزىقى',
9 subscript: 'تۆۋەن ئىندېكس',
10 superscript: 'يۇقىرى ئىندېكس',
11 underline: 'ئاستى سىزىق'
12} );
diff --git a/sources/plugins/basicstyles/lang/uk.js b/sources/plugins/basicstyles/lang/uk.js
new file mode 100644
index 0000000..3ec1acc
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/uk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'uk', {
6 bold: 'Жирний',
7 italic: 'Курсив',
8 strike: 'Закреслений',
9 subscript: 'Нижній індекс',
10 superscript: 'Верхній індекс',
11 underline: 'Підкреслений'
12} );
diff --git a/sources/plugins/basicstyles/lang/vi.js b/sources/plugins/basicstyles/lang/vi.js
new file mode 100644
index 0000000..c0aaa69
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/vi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'vi', {
6 bold: 'Đậm',
7 italic: 'Nghiêng',
8 strike: 'Gạch xuyên ngang',
9 subscript: 'Chỉ số dưới',
10 superscript: 'Chỉ số trên',
11 underline: 'Gạch chân'
12} );
diff --git a/sources/plugins/basicstyles/lang/zh-cn.js b/sources/plugins/basicstyles/lang/zh-cn.js
new file mode 100644
index 0000000..f43d23d
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/zh-cn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'zh-cn', {
6 bold: '加粗',
7 italic: '倾斜',
8 strike: '删除线',
9 subscript: '下标',
10 superscript: '上标',
11 underline: '下划线'
12} );
diff --git a/sources/plugins/basicstyles/lang/zh.js b/sources/plugins/basicstyles/lang/zh.js
new file mode 100644
index 0000000..d74943c
--- /dev/null
+++ b/sources/plugins/basicstyles/lang/zh.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'basicstyles', 'zh', {
6 bold: '粗體',
7 italic: '斜體',
8 strike: '刪除線',
9 subscript: '下標',
10 superscript: '上標',
11 underline: '底線'
12} );
diff --git a/sources/plugins/basicstyles/plugin.js b/sources/plugins/basicstyles/plugin.js
new file mode 100644
index 0000000..4a6325a
--- /dev/null
+++ b/sources/plugins/basicstyles/plugin.js
@@ -0,0 +1,209 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'basicstyles', {
7 // jscs:disable maximumLineLength
8 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
9 // jscs:enable maximumLineLength
10 icons: 'bold,italic,underline,strike,subscript,superscript', // %REMOVE_LINE_CORE%
11 hidpi: true, // %REMOVE_LINE_CORE%
12 init: function( editor ) {
13 var order = 0;
14 // All buttons use the same code to register. So, to avoid
15 // duplications, let's use this tool function.
16 var addButtonCommand = function( buttonName, buttonLabel, commandName, styleDefiniton ) {
17 // Disable the command if no definition is configured.
18 if ( !styleDefiniton )
19 return;
20
21 var style = new CKEDITOR.style( styleDefiniton ),
22 forms = contentForms[ commandName ];
23
24 // Put the style as the most important form.
25 forms.unshift( style );
26
27 // Listen to contextual style activation.
28 editor.attachStyleStateChange( style, function( state ) {
29 !editor.readOnly && editor.getCommand( commandName ).setState( state );
30 } );
31
32 // Create the command that can be used to apply the style.
33 editor.addCommand( commandName, new CKEDITOR.styleCommand( style, {
34 contentForms: forms
35 } ) );
36
37 // Register the button, if the button plugin is loaded.
38 if ( editor.ui.addButton ) {
39 editor.ui.addButton( buttonName, {
40 label: buttonLabel,
41 command: commandName,
42 toolbar: 'basicstyles,' + ( order += 10 )
43 } );
44 }
45 };
46
47 var contentForms = {
48 bold: [
49 'strong',
50 'b',
51 [ 'span', function( el ) {
52 var fw = el.styles[ 'font-weight' ];
53 return fw == 'bold' || +fw >= 700;
54 } ]
55 ],
56
57 italic: [
58 'em',
59 'i',
60 [ 'span', function( el ) {
61 return el.styles[ 'font-style' ] == 'italic';
62 } ]
63 ],
64
65 underline: [
66 'u',
67 [ 'span', function( el ) {
68 return el.styles[ 'text-decoration' ] == 'underline';
69 } ]
70 ],
71
72 strike: [
73 's',
74 'strike',
75 [ 'span', function( el ) {
76 return el.styles[ 'text-decoration' ] == 'line-through';
77 } ]
78 ],
79
80 subscript: [
81 'sub'
82 ],
83
84 superscript: [
85 'sup'
86 ]
87 },
88 config = editor.config,
89 lang = editor.lang.basicstyles;
90
91 addButtonCommand( 'Bold', lang.bold, 'bold', config.coreStyles_bold );
92 addButtonCommand( 'Italic', lang.italic, 'italic', config.coreStyles_italic );
93 addButtonCommand( 'Underline', lang.underline, 'underline', config.coreStyles_underline );
94 addButtonCommand( 'Strike', lang.strike, 'strike', config.coreStyles_strike );
95 addButtonCommand( 'Subscript', lang.subscript, 'subscript', config.coreStyles_subscript );
96 addButtonCommand( 'Superscript', lang.superscript, 'superscript', config.coreStyles_superscript );
97
98 editor.setKeystroke( [
99 [ CKEDITOR.CTRL + 66 /*B*/, 'bold' ],
100 [ CKEDITOR.CTRL + 73 /*I*/, 'italic' ],
101 [ CKEDITOR.CTRL + 85 /*U*/, 'underline' ]
102 ] );
103 }
104} );
105
106// Basic Inline Styles.
107
108/**
109 * The style definition that applies the **bold** style to the text.
110 *
111 * Read more in the [documentation](#!/guide/dev_basicstyles)
112 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
113 *
114 * config.coreStyles_bold = { element: 'b', overrides: 'strong' };
115 *
116 * config.coreStyles_bold = {
117 * element: 'span',
118 * attributes: { 'class': 'Bold' }
119 * };
120 *
121 * @cfg
122 * @member CKEDITOR.config
123 */
124CKEDITOR.config.coreStyles_bold = { element: 'strong', overrides: 'b' };
125
126/**
127 * The style definition that applies the *italics* style to the text.
128 *
129 * Read more in the [documentation](#!/guide/dev_basicstyles)
130 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
131 *
132 * config.coreStyles_italic = { element: 'i', overrides: 'em' };
133 *
134 * CKEDITOR.config.coreStyles_italic = {
135 * element: 'span',
136 * attributes: { 'class': 'Italic' }
137 * };
138 *
139 * @cfg
140 * @member CKEDITOR.config
141 */
142CKEDITOR.config.coreStyles_italic = { element: 'em', overrides: 'i' };
143
144/**
145 * The style definition that applies the <u>underline</u> style to the text.
146 *
147 * Read more in the [documentation](#!/guide/dev_basicstyles)
148 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
149 *
150 * CKEDITOR.config.coreStyles_underline = {
151 * element: 'span',
152 * attributes: { 'class': 'Underline' }
153 * };
154 *
155 * @cfg
156 * @member CKEDITOR.config
157 */
158CKEDITOR.config.coreStyles_underline = { element: 'u' };
159
160/**
161 * The style definition that applies the <strike>strikethrough</strike> style to the text.
162 *
163 * Read more in the [documentation](#!/guide/dev_basicstyles)
164 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
165 *
166 * CKEDITOR.config.coreStyles_strike = {
167 * element: 'span',
168 * attributes: { 'class': 'Strikethrough' },
169 * overrides: 'strike'
170 * };
171 *
172 * @cfg
173 * @member CKEDITOR.config
174 */
175CKEDITOR.config.coreStyles_strike = { element: 's', overrides: 'strike' };
176
177/**
178 * The style definition that applies the subscript style to the text.
179 *
180 * Read more in the [documentation](#!/guide/dev_basicstyles)
181 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
182 *
183 * CKEDITOR.config.coreStyles_subscript = {
184 * element: 'span',
185 * attributes: { 'class': 'Subscript' },
186 * overrides: 'sub'
187 * };
188 *
189 * @cfg
190 * @member CKEDITOR.config
191 */
192CKEDITOR.config.coreStyles_subscript = { element: 'sub' };
193
194/**
195 * The style definition that applies the superscript style to the text.
196 *
197 * Read more in the [documentation](#!/guide/dev_basicstyles)
198 * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
199 *
200 * CKEDITOR.config.coreStyles_superscript = {
201 * element: 'span',
202 * attributes: { 'class': 'Superscript' },
203 * overrides: 'sup'
204 * };
205 *
206 * @cfg
207 * @member CKEDITOR.config
208 */
209CKEDITOR.config.coreStyles_superscript = { element: 'sup' };
diff --git a/sources/plugins/button/lang/af.js b/sources/plugins/button/lang/af.js
new file mode 100644
index 0000000..6ccebfa
--- /dev/null
+++ b/sources/plugins/button/lang/af.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'af', {
7 selectedLabel: '%1 uitgekies'
8} );
diff --git a/sources/plugins/button/lang/ar.js b/sources/plugins/button/lang/ar.js
new file mode 100644
index 0000000..025068d
--- /dev/null
+++ b/sources/plugins/button/lang/ar.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ar', {
7 selectedLabel: '%1 (محدد)'
8} );
diff --git a/sources/plugins/button/lang/az.js b/sources/plugins/button/lang/az.js
new file mode 100644
index 0000000..30ac85e
--- /dev/null
+++ b/sources/plugins/button/lang/az.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'az', {
7 selectedLabel: '%1 (seçilib)'
8} );
diff --git a/sources/plugins/button/lang/bg.js b/sources/plugins/button/lang/bg.js
new file mode 100644
index 0000000..0b146bb
--- /dev/null
+++ b/sources/plugins/button/lang/bg.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'bg', {
7 selectedLabel: '%1 (Избрано)'
8} );
diff --git a/sources/plugins/button/lang/ca.js b/sources/plugins/button/lang/ca.js
new file mode 100644
index 0000000..0891d49
--- /dev/null
+++ b/sources/plugins/button/lang/ca.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ca', {
7 selectedLabel: '%1 (Seleccionat)'
8} );
diff --git a/sources/plugins/button/lang/cs.js b/sources/plugins/button/lang/cs.js
new file mode 100644
index 0000000..552a05c
--- /dev/null
+++ b/sources/plugins/button/lang/cs.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'cs', {
7 selectedLabel: '%1 (Vybráno)'
8} );
diff --git a/sources/plugins/button/lang/da.js b/sources/plugins/button/lang/da.js
new file mode 100644
index 0000000..255dcc5
--- /dev/null
+++ b/sources/plugins/button/lang/da.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'da', {
7 selectedLabel: '%1 (Valgt)'
8} );
diff --git a/sources/plugins/button/lang/de-ch.js b/sources/plugins/button/lang/de-ch.js
new file mode 100644
index 0000000..63430d7
--- /dev/null
+++ b/sources/plugins/button/lang/de-ch.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'de-ch', {
7 selectedLabel: '%1 (Ausgewählt)'
8} );
diff --git a/sources/plugins/button/lang/de.js b/sources/plugins/button/lang/de.js
new file mode 100644
index 0000000..dca3daa
--- /dev/null
+++ b/sources/plugins/button/lang/de.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'de', {
7 selectedLabel: '%1 (Ausgewählt)'
8} );
diff --git a/sources/plugins/button/lang/el.js b/sources/plugins/button/lang/el.js
new file mode 100644
index 0000000..1718816
--- /dev/null
+++ b/sources/plugins/button/lang/el.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'el', {
7 selectedLabel: '%1 (Επιλεγμένο)'
8} );
diff --git a/sources/plugins/button/lang/en-gb.js b/sources/plugins/button/lang/en-gb.js
new file mode 100644
index 0000000..d7daefc
--- /dev/null
+++ b/sources/plugins/button/lang/en-gb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'en-gb', {
7 selectedLabel: '%1 (Selected)'
8} );
diff --git a/sources/plugins/button/lang/en.js b/sources/plugins/button/lang/en.js
new file mode 100644
index 0000000..d5c4088
--- /dev/null
+++ b/sources/plugins/button/lang/en.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'en', {
7 selectedLabel: '%1 (Selected)'
8} );
diff --git a/sources/plugins/button/lang/eo.js b/sources/plugins/button/lang/eo.js
new file mode 100644
index 0000000..acf0c13
--- /dev/null
+++ b/sources/plugins/button/lang/eo.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'eo', {
7 selectedLabel: '%1 (Selektita)'
8} );
diff --git a/sources/plugins/button/lang/es.js b/sources/plugins/button/lang/es.js
new file mode 100644
index 0000000..cb46c6f
--- /dev/null
+++ b/sources/plugins/button/lang/es.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'es', {
7 selectedLabel: '%1 (Seleccionado)'
8} );
diff --git a/sources/plugins/button/lang/eu.js b/sources/plugins/button/lang/eu.js
new file mode 100644
index 0000000..c49d92a
--- /dev/null
+++ b/sources/plugins/button/lang/eu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'eu', {
7 selectedLabel: '%1 (hautatuta)'
8} );
diff --git a/sources/plugins/button/lang/fa.js b/sources/plugins/button/lang/fa.js
new file mode 100644
index 0000000..358c88a
--- /dev/null
+++ b/sources/plugins/button/lang/fa.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'fa', {
7 selectedLabel: '%1 (انتخاب شده)'
8} );
diff --git a/sources/plugins/button/lang/fi.js b/sources/plugins/button/lang/fi.js
new file mode 100644
index 0000000..4822e74
--- /dev/null
+++ b/sources/plugins/button/lang/fi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'fi', {
7 selectedLabel: '%1 (Valittu)'
8} );
diff --git a/sources/plugins/button/lang/fr.js b/sources/plugins/button/lang/fr.js
new file mode 100644
index 0000000..1b1c6d3
--- /dev/null
+++ b/sources/plugins/button/lang/fr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'fr', {
7 selectedLabel: '%1 (Sélectionné)'
8} );
diff --git a/sources/plugins/button/lang/gl.js b/sources/plugins/button/lang/gl.js
new file mode 100644
index 0000000..3e4e0b7
--- /dev/null
+++ b/sources/plugins/button/lang/gl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'gl', {
7 selectedLabel: '%1 (seleccionado)'
8} );
diff --git a/sources/plugins/button/lang/he.js b/sources/plugins/button/lang/he.js
new file mode 100644
index 0000000..c67afb6
--- /dev/null
+++ b/sources/plugins/button/lang/he.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'he', {
7 selectedLabel: '1% (סומן)'
8} );
diff --git a/sources/plugins/button/lang/hu.js b/sources/plugins/button/lang/hu.js
new file mode 100644
index 0000000..0dffac1
--- /dev/null
+++ b/sources/plugins/button/lang/hu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'hu', {
7 selectedLabel: '%1 (Kiválasztva)'
8} );
diff --git a/sources/plugins/button/lang/id.js b/sources/plugins/button/lang/id.js
new file mode 100644
index 0000000..f973ffc
--- /dev/null
+++ b/sources/plugins/button/lang/id.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'id', {
7 selectedLabel: '%1(Dipilih)'
8} );
diff --git a/sources/plugins/button/lang/it.js b/sources/plugins/button/lang/it.js
new file mode 100644
index 0000000..359dc9a
--- /dev/null
+++ b/sources/plugins/button/lang/it.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'it', {
7 selectedLabel: '%1 (selezionato)'
8} );
diff --git a/sources/plugins/button/lang/ja.js b/sources/plugins/button/lang/ja.js
new file mode 100644
index 0000000..e2b064f
--- /dev/null
+++ b/sources/plugins/button/lang/ja.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ja', {
7 selectedLabel: '%1 (選択中)'
8} );
diff --git a/sources/plugins/button/lang/km.js b/sources/plugins/button/lang/km.js
new file mode 100644
index 0000000..9437a2f
--- /dev/null
+++ b/sources/plugins/button/lang/km.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'km', {
7 selectedLabel: '%1 (បាន​ជ្រើស​រើស)'
8} );
diff --git a/sources/plugins/button/lang/ko.js b/sources/plugins/button/lang/ko.js
new file mode 100644
index 0000000..64ad966
--- /dev/null
+++ b/sources/plugins/button/lang/ko.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ko', {
7 selectedLabel: '%1 (선택됨)'
8} );
diff --git a/sources/plugins/button/lang/ku.js b/sources/plugins/button/lang/ku.js
new file mode 100644
index 0000000..d342dd0
--- /dev/null
+++ b/sources/plugins/button/lang/ku.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ku', {
7 selectedLabel: '%1 (هەڵبژێردراو)'
8} );
diff --git a/sources/plugins/button/lang/lt.js b/sources/plugins/button/lang/lt.js
new file mode 100644
index 0000000..b492bd5
--- /dev/null
+++ b/sources/plugins/button/lang/lt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'lt', {
7 selectedLabel: '%1 (Pasirinkta)'
8} );
diff --git a/sources/plugins/button/lang/nb.js b/sources/plugins/button/lang/nb.js
new file mode 100644
index 0000000..8d38121
--- /dev/null
+++ b/sources/plugins/button/lang/nb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'nb', {
7 selectedLabel: '%1 (Valgt)'
8} );
diff --git a/sources/plugins/button/lang/nl.js b/sources/plugins/button/lang/nl.js
new file mode 100644
index 0000000..3e00f80
--- /dev/null
+++ b/sources/plugins/button/lang/nl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'nl', {
7 selectedLabel: '%1 (Geselecteerd)'
8} );
diff --git a/sources/plugins/button/lang/no.js b/sources/plugins/button/lang/no.js
new file mode 100644
index 0000000..e6252b1
--- /dev/null
+++ b/sources/plugins/button/lang/no.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'no', {
7 selectedLabel: '%1 (Valgt)'
8} );
diff --git a/sources/plugins/button/lang/oc.js b/sources/plugins/button/lang/oc.js
new file mode 100644
index 0000000..cb91761
--- /dev/null
+++ b/sources/plugins/button/lang/oc.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'oc', {
7 selectedLabel: '%1 (Seleccionat)'
8} );
diff --git a/sources/plugins/button/lang/pl.js b/sources/plugins/button/lang/pl.js
new file mode 100644
index 0000000..304d07a
--- /dev/null
+++ b/sources/plugins/button/lang/pl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'pl', {
7 selectedLabel: '%1 (Wybrany)'
8} );
diff --git a/sources/plugins/button/lang/pt-br.js b/sources/plugins/button/lang/pt-br.js
new file mode 100644
index 0000000..e3fdf84
--- /dev/null
+++ b/sources/plugins/button/lang/pt-br.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'pt-br', {
7 selectedLabel: '%1 (Selecionado)'
8} );
diff --git a/sources/plugins/button/lang/pt.js b/sources/plugins/button/lang/pt.js
new file mode 100644
index 0000000..e02c45a
--- /dev/null
+++ b/sources/plugins/button/lang/pt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'pt', {
7 selectedLabel: '%1 (Selecionado)'
8} );
diff --git a/sources/plugins/button/lang/ro.js b/sources/plugins/button/lang/ro.js
new file mode 100644
index 0000000..0669dd5
--- /dev/null
+++ b/sources/plugins/button/lang/ro.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ro', {
7 selectedLabel: '%1 (Selectat)'
8} );
diff --git a/sources/plugins/button/lang/ru.js b/sources/plugins/button/lang/ru.js
new file mode 100644
index 0000000..085f6ee
--- /dev/null
+++ b/sources/plugins/button/lang/ru.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ru', {
7 selectedLabel: '%1 (Выбрано)'
8} );
diff --git a/sources/plugins/button/lang/sk.js b/sources/plugins/button/lang/sk.js
new file mode 100644
index 0000000..12bec80
--- /dev/null
+++ b/sources/plugins/button/lang/sk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'sk', {
7 selectedLabel: '%1 (Vybrané)'
8} );
diff --git a/sources/plugins/button/lang/sl.js b/sources/plugins/button/lang/sl.js
new file mode 100644
index 0000000..c6633ae
--- /dev/null
+++ b/sources/plugins/button/lang/sl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'sl', {
7 selectedLabel: '%1 (Izbrano)'
8} );
diff --git a/sources/plugins/button/lang/sq.js b/sources/plugins/button/lang/sq.js
new file mode 100644
index 0000000..2e53e4c
--- /dev/null
+++ b/sources/plugins/button/lang/sq.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'sq', {
7 selectedLabel: '%1 (Përzgjedhur)'
8} );
diff --git a/sources/plugins/button/lang/sv.js b/sources/plugins/button/lang/sv.js
new file mode 100644
index 0000000..b89e475
--- /dev/null
+++ b/sources/plugins/button/lang/sv.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'sv', {
7 selectedLabel: '%1 (Vald)'
8} );
diff --git a/sources/plugins/button/lang/tr.js b/sources/plugins/button/lang/tr.js
new file mode 100644
index 0000000..30d3670
--- /dev/null
+++ b/sources/plugins/button/lang/tr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'tr', {
7 selectedLabel: '%1 (Seçilmiş)'
8} );
diff --git a/sources/plugins/button/lang/tt.js b/sources/plugins/button/lang/tt.js
new file mode 100644
index 0000000..6324922
--- /dev/null
+++ b/sources/plugins/button/lang/tt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'tt', {
7 selectedLabel: '%1 (Сайланган)'
8} );
diff --git a/sources/plugins/button/lang/ug.js b/sources/plugins/button/lang/ug.js
new file mode 100644
index 0000000..fa3a90c
--- /dev/null
+++ b/sources/plugins/button/lang/ug.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'ug', {
7 selectedLabel: '%1 (تاللاندى)'
8} );
diff --git a/sources/plugins/button/lang/uk.js b/sources/plugins/button/lang/uk.js
new file mode 100644
index 0000000..7b49fe2
--- /dev/null
+++ b/sources/plugins/button/lang/uk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'uk', {
7 selectedLabel: '%1 (Вибрано)'
8} );
diff --git a/sources/plugins/button/lang/vi.js b/sources/plugins/button/lang/vi.js
new file mode 100644
index 0000000..b6a5911
--- /dev/null
+++ b/sources/plugins/button/lang/vi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'vi', {
7 selectedLabel: '%1 (Đã chọn)'
8} );
diff --git a/sources/plugins/button/lang/zh-cn.js b/sources/plugins/button/lang/zh-cn.js
new file mode 100644
index 0000000..fade7d7
--- /dev/null
+++ b/sources/plugins/button/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'zh-cn', {
7 selectedLabel: '已选中 %1 项'
8} );
diff --git a/sources/plugins/button/lang/zh.js b/sources/plugins/button/lang/zh.js
new file mode 100644
index 0000000..7479462
--- /dev/null
+++ b/sources/plugins/button/lang/zh.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'button', 'zh', {
7 selectedLabel: '%1 (已選取)'
8} );
diff --git a/sources/plugins/button/plugin.js b/sources/plugins/button/plugin.js
new file mode 100644
index 0000000..6d2db33
--- /dev/null
+++ b/sources/plugins/button/plugin.js
@@ -0,0 +1,389 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var template = '<a id="{id}"' +
8 ' class="cke_button cke_button__{name} cke_button_{state} {cls}"' +
9 ( CKEDITOR.env.gecko && !CKEDITOR.env.hc ? '' : ' href="javascript:void(\'{titleJs}\')"' ) +
10 ' title="{title}"' +
11 ' tabindex="-1"' +
12 ' hidefocus="true"' +
13 ' role="button"' +
14 ' aria-labelledby="{id}_label"' +
15 ' aria-describedby="{id}_description"' +
16 ' aria-haspopup="{hasArrow}"' +
17 ' aria-disabled="{ariaDisabled}"';
18
19 // Some browsers don't cancel key events in the keydown but in the
20 // keypress.
21 // TODO: Check if really needed.
22 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
23 template += ' onkeypress="return false;"';
24
25 // With Firefox, we need to force the button to redraw, otherwise it
26 // will remain in the focus state.
27 if ( CKEDITOR.env.gecko )
28 template += ' onblur="this.style.cssText = this.style.cssText;"';
29
30 template += ' onkeydown="return CKEDITOR.tools.callFunction({keydownFn},event);"' +
31 ' onfocus="return CKEDITOR.tools.callFunction({focusFn},event);" ' +
32 ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188
33 '="CKEDITOR.tools.callFunction({clickFn},this);return false;">' +
34 '<span class="cke_button_icon cke_button__{iconName}_icon" style="{style}"';
35
36
37 template += '>&nbsp;</span>' +
38 '<span id="{id}_label" class="cke_button_label cke_button__{name}_label" aria-hidden="false">{label}</span>' +
39 '<span id="{id}_description" class="cke_button_label" aria-hidden="false">{ariaShortcut}</span>' +
40 '{arrowHtml}' +
41 '</a>';
42
43 var templateArrow = '<span class="cke_button_arrow">' +
44 // BLACK DOWN-POINTING TRIANGLE
45 ( CKEDITOR.env.hc ? '&#9660;' : '' ) +
46 '</span>';
47
48 var btnArrowTpl = CKEDITOR.addTemplate( 'buttonArrow', templateArrow ),
49 btnTpl = CKEDITOR.addTemplate( 'button', template );
50
51 CKEDITOR.plugins.add( 'button', {
52 lang: 'af,ar,az,bg,ca,cs,da,de,de-ch,el,en,en-gb,eo,es,eu,fa,fi,fr,gl,he,hu,id,it,ja,km,ko,ku,lt,nb,nl,no,oc,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
53 beforeInit: function( editor ) {
54 editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );
55 }
56 } );
57
58 /**
59 * Button UI element.
60 *
61 * @readonly
62 * @property {String} [='button']
63 * @member CKEDITOR
64 */
65 CKEDITOR.UI_BUTTON = 'button';
66
67 /**
68 * Represents a button UI element. This class should not be called directly. To
69 * create new buttons use {@link CKEDITOR.ui#addButton} instead.
70 *
71 * @class
72 * @constructor Creates a button class instance.
73 * @param {Object} definition The button definition.
74 */
75 CKEDITOR.ui.button = function( definition ) {
76 CKEDITOR.tools.extend( this, definition,
77 // Set defaults.
78 {
79 title: definition.label,
80 click: definition.click ||
81 function( editor ) {
82 editor.execCommand( definition.command );
83 }
84 } );
85
86 this._ = {};
87 };
88
89 /**
90 * Represents the button handler object.
91 *
92 * @class
93 * @singleton
94 * @extends CKEDITOR.ui.handlerDefinition
95 */
96 CKEDITOR.ui.button.handler = {
97 /**
98 * Transforms a button definition in a {@link CKEDITOR.ui.button} instance.
99 *
100 * @member CKEDITOR.ui.button.handler
101 * @param {Object} definition
102 * @returns {CKEDITOR.ui.button}
103 */
104 create: function( definition ) {
105 return new CKEDITOR.ui.button( definition );
106 }
107 };
108
109 /** @class CKEDITOR.ui.button */
110 CKEDITOR.ui.button.prototype = {
111 /**
112 * Renders the button.
113 *
114 * @param {CKEDITOR.editor} editor The editor instance which this button is
115 * to be used by.
116 * @param {Array} output The output array to which the HTML code related to
117 * this button should be appended.
118 */
119 render: function( editor, output ) {
120 function updateState() {
121 // "this" is a CKEDITOR.ui.button instance.
122 var mode = editor.mode;
123
124 if ( mode ) {
125 // Restore saved button state.
126 var state = this.modes[ mode ] ? modeStates[ mode ] !== undefined ? modeStates[ mode ] : CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
127
128 state = editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state;
129
130 this.setState( state );
131
132 // Let plugin to disable button.
133 if ( this.refresh )
134 this.refresh();
135 }
136 }
137
138 var env = CKEDITOR.env,
139 id = this._.id = CKEDITOR.tools.getNextId(),
140 stateName = '',
141 command = this.command,
142 // Get the command name.
143 clickFn,
144 keystroke,
145 shortcut;
146
147 this._.editor = editor;
148
149 var instance = {
150 id: id,
151 button: this,
152 editor: editor,
153 focus: function() {
154 var element = CKEDITOR.document.getById( id );
155 element.focus();
156 },
157 execute: function() {
158 this.button.click( editor );
159 },
160 attach: function( editor ) {
161 this.button.attach( editor );
162 }
163 };
164
165 var keydownFn = CKEDITOR.tools.addFunction( function( ev ) {
166 if ( instance.onkey ) {
167 ev = new CKEDITOR.dom.event( ev );
168 return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
169 }
170 } );
171
172 var focusFn = CKEDITOR.tools.addFunction( function( ev ) {
173 var retVal;
174
175 if ( instance.onfocus )
176 retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );
177
178 return retVal;
179 } );
180
181 var selLocked = 0;
182
183 instance.clickFn = clickFn = CKEDITOR.tools.addFunction( function() {
184
185 // Restore locked selection in Opera.
186 if ( selLocked ) {
187 editor.unlockSelection( 1 );
188 selLocked = 0;
189 }
190 instance.execute();
191
192 // Fixed iOS focus issue when your press disabled button (#12381).
193 if ( env.iOS ) {
194 editor.focus();
195 }
196 } );
197
198
199 // Indicate a mode sensitive button.
200 if ( this.modes ) {
201 var modeStates = {};
202
203 editor.on( 'beforeModeUnload', function() {
204 if ( editor.mode && this._.state != CKEDITOR.TRISTATE_DISABLED )
205 modeStates[ editor.mode ] = this._.state;
206 }, this );
207
208 // Update status when activeFilter, mode or readOnly changes.
209 editor.on( 'activeFilterChange', updateState, this );
210 editor.on( 'mode', updateState, this );
211 // If this button is sensitive to readOnly state, update it accordingly.
212 !this.readOnly && editor.on( 'readOnly', updateState, this );
213
214 } else if ( command ) {
215 // Get the command instance.
216 command = editor.getCommand( command );
217
218 if ( command ) {
219 command.on( 'state', function() {
220 this.setState( command.state );
221 }, this );
222
223 stateName += ( command.state == CKEDITOR.TRISTATE_ON ? 'on' : command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' : 'off' );
224 }
225 }
226
227 // For button that has text-direction awareness on selection path.
228 if ( this.directional ) {
229 editor.on( 'contentDirChanged', function( evt ) {
230 var el = CKEDITOR.document.getById( this._.id ),
231 icon = el.getFirst();
232
233 var pathDir = evt.data;
234
235 // Make a minor direction change to become style-able for the skin icon.
236 if ( pathDir != editor.lang.dir )
237 el.addClass( 'cke_' + pathDir );
238 else
239 el.removeClass( 'cke_ltr' ).removeClass( 'cke_rtl' );
240
241 // Inline style update for the plugin icon.
242 icon.setAttribute( 'style', CKEDITOR.skin.getIconStyle( iconName, pathDir == 'rtl', this.icon, this.iconOffset ) );
243 }, this );
244 }
245
246 if ( !command ) {
247 stateName += 'off';
248 } else {
249 keystroke = editor.getCommandKeystroke( command );
250
251 if ( keystroke ) {
252 shortcut = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard, keystroke );
253 }
254 }
255
256 var name = this.name || this.command,
257 iconName = name;
258
259 // Check if we're pointing to an icon defined by another command. (#9555)
260 if ( this.icon && !( /\./ ).test( this.icon ) ) {
261 iconName = this.icon;
262 this.icon = null;
263 }
264
265 var params = {
266 id: id,
267 name: name,
268 iconName: iconName,
269 label: this.label,
270 cls: this.className || '',
271 state: stateName,
272 ariaDisabled: stateName == 'disabled' ? 'true' : 'false',
273 title: this.title + ( shortcut ? ' (' + shortcut.display + ')' : '' ),
274 ariaShortcut: shortcut ? editor.lang.common.keyboardShortcut + ' ' + shortcut.aria : '',
275 titleJs: env.gecko && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),
276 hasArrow: this.hasArrow ? 'true' : 'false',
277 keydownFn: keydownFn,
278 focusFn: focusFn,
279 clickFn: clickFn,
280 style: CKEDITOR.skin.getIconStyle( iconName, ( editor.lang.dir == 'rtl' ), this.icon, this.iconOffset ),
281 arrowHtml: this.hasArrow ? btnArrowTpl.output() : ''
282 };
283
284 btnTpl.output( params, output );
285
286 if ( this.onRender )
287 this.onRender();
288
289 return instance;
290 },
291
292 /**
293 * Sets the button state.
294 *
295 * @param {Number} state Indicates the button state. One of {@link CKEDITOR#TRISTATE_ON},
296 * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.
297 */
298 setState: function( state ) {
299 if ( this._.state == state )
300 return false;
301
302 this._.state = state;
303
304 var element = CKEDITOR.document.getById( this._.id );
305
306 if ( element ) {
307 element.setState( state, 'cke_button' );
308
309 state == CKEDITOR.TRISTATE_DISABLED ?
310 element.setAttribute( 'aria-disabled', true ) :
311 element.removeAttribute( 'aria-disabled' );
312
313 if ( !this.hasArrow ) {
314 // Note: aria-pressed attribute should not be added to menuButton instances. (#11331)
315 state == CKEDITOR.TRISTATE_ON ?
316 element.setAttribute( 'aria-pressed', true ) :
317 element.removeAttribute( 'aria-pressed' );
318 } else {
319 var newLabel = state == CKEDITOR.TRISTATE_ON ?
320 this._.editor.lang.button.selectedLabel.replace( /%1/g, this.label ) : this.label;
321 CKEDITOR.document.getById( this._.id + '_label' ).setText( newLabel );
322 }
323
324 return true;
325 } else {
326 return false;
327 }
328 },
329
330 /**
331 * Gets the button state.
332 *
333 * @returns {Number} The button state. One of {@link CKEDITOR#TRISTATE_ON},
334 * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.
335 */
336 getState: function() {
337 return this._.state;
338 },
339
340 /**
341 * Returns this button's {@link CKEDITOR.feature} instance.
342 *
343 * It may be this button instance if it has at least one of
344 * `allowedContent` and `requiredContent` properties. Otherwise,
345 * if a command is bound to this button by the `command` property, then
346 * that command will be returned.
347 *
348 * This method implements the {@link CKEDITOR.feature#toFeature} interface method.
349 *
350 * @since 4.1
351 * @param {CKEDITOR.editor} Editor instance.
352 * @returns {CKEDITOR.feature} The feature.
353 */
354 toFeature: function( editor ) {
355 if ( this._.feature )
356 return this._.feature;
357
358 var feature = this;
359
360 // If button isn't a feature, return command if is bound.
361 if ( !this.allowedContent && !this.requiredContent && this.command )
362 feature = editor.getCommand( this.command ) || feature;
363
364 return this._.feature = feature;
365 }
366 };
367
368 /**
369 * Adds a button definition to the UI elements list.
370 *
371 * editorInstance.ui.addButton( 'MyBold', {
372 * label: 'My Bold',
373 * command: 'bold',
374 * toolbar: 'basicstyles,1'
375 * } );
376 *
377 * @member CKEDITOR.ui
378 * @param {String} name The button name.
379 * @param {Object} definition The button definition.
380 * @param {String} definition.label The textual part of the button (if visible) and its tooltip.
381 * @param {String} definition.command The command to be executed once the button is activated.
382 * @param {String} definition.toolbar The {@link CKEDITOR.config#toolbarGroups toolbar group} into which
383 * the button will be added. An optional index value (separated by a comma) determines the button position within the group.
384 */
385 CKEDITOR.ui.prototype.addButton = function( name, definition ) {
386 this.add( name, CKEDITOR.UI_BUTTON, definition );
387 };
388
389} )();
diff --git a/sources/plugins/clipboard/dev/clipboard.html b/sources/plugins/clipboard/dev/clipboard.html
new file mode 100644
index 0000000..735d00e
--- /dev/null
+++ b/sources/plugins/clipboard/dev/clipboard.html
@@ -0,0 +1,190 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Clipboard playground &ndash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link href="../../../samples/old/sample.css" rel="stylesheet">
12 <style>
13body {
14 margin: 0;
15}
16
17#editables, #console
18{
19 width: 48%;
20}
21#editable {
22 padding: 5px 10px;
23}
24
25#console {
26 position: fixed;
27 top: 10px;
28 right: 30px;
29 height: 500px;
30 border: solid 3px #555;
31 overflow: auto;
32}
33#console > p {
34 border-bottom: solid 1px #555;
35 margin: 0;
36 padding: 0 5px;
37 background: rgba(0, 0, 0, 0.25);
38 transition: background-color 1s;
39}
40#console > p.old {
41 background: rgba(0, 0, 0, 0);
42}
43#console time, #console .prompt {
44 padding: 0 5px;
45 display: inline-block;
46}
47#console time {
48 background: #999;
49 background: rgba(0, 0, 0, 0.5 );
50 color: #FFF;
51 margin-left: -5px;
52}
53#console .prompt {
54 background: #DDD;
55 background: rgba(0, 0, 0, 0.1 );
56 min-width: 200px;
57}
58.someClass {
59 color: blue;
60}
61.specChar {
62 color: #777;
63 background-color: #EEE;
64 background-color: rgba(0, 0, 0, 0.1);
65 font-size: 0.8em;
66 border-radius: 2px;
67 padding: 1px;
68}
69 </style>
70</head>
71<body>
72 <h1 class="samples">
73 CKEditor Sample &mdash; clipboard plugin playground
74 </h1>
75 <div id="editables">
76 <p>
77 <label for="editor1">
78 Editor 1:</label>
79 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
80 </p>
81 <p>
82 <label for="editor2">
83 Editor 2:</label>
84 <textarea cols="80" id="editor2" name="editor2" rows="10">&lt;p&gt;This is more &lt;strong class="MsoNormal"&gt;sample text&lt;/strong&gt;.&lt;/p&gt;</textarea>
85 </p>
86 <p>
87 <label for="editor3">
88 Editor 3:</label>
89 <textarea cols="80" id="editor3" name="editor3" rows="10">&lt;p&gt;This editor &lt;strong&gt;forces pasting in text mode&lt;/strong&gt; by listening for "beforePaste" event.&lt;/p&gt;</textarea>
90 </p>
91 <p>
92 <label for="editor4">
93 Editor 4:</label>
94 <textarea cols="80" id="editor4" name="editor4" rows="10">&lt;p&gt;This editor &lt;strong&gt;forces pasting in text mode&lt;/strong&gt; by "forcePasteAsPlainText" config option.&lt;/p&gt;</textarea>
95 </p>
96 <p>
97 <label for="editor5">
98 Editor 5:</label>
99 <textarea cols="80" id="editor5" name="editor5" rows="10">Editor with autoParagraphing set to off.</textarea>
100 </p>
101 <div id="editor6" contenteditable="true" style="font-family: Georgia; font-size: 14px">
102 <h1>Editor 6</h1>
103 <p>Content content content.</p>
104 <p class="someClass">Styled by <code>.someClass</code>.</p>
105 </div>
106 </div>
107 <div id="console">
108 </div>
109 <script>
110( function()
111{
112 'use strict';
113
114 var log = window.__log = function( title, msg ) {
115 var msgEl = new CKEDITOR.dom.element( 'p' ),
116 consoleEl = CKEDITOR.document.getById( 'console' ),
117 time = new Date().toString().match( /\d\d:\d\d:\d\d/ )[ 0 ],
118 format = function( tpl ) {
119 return tpl.replace( /{time}/g, time ).replace( '{title}', title ).replace( '{msg}', msg || '' );
120 };
121
122 window.console && console.log && console.log( format( '[{time}] {title}: {msg}' ) );
123
124 msg = ( msg || '' ).replace( /\r/g, '{\\r}' ).replace( /\n/g, '{\\n}' ).replace( /\t/g, '{\\t}' );
125 msg = CKEDITOR.tools.htmlEncode( msg );
126 msg = msg.replace( /\{(\\\w)\}/g, '<code class="specChar">$1</code>' );
127
128 msgEl.setHtml( format( '<time datetime="{time}">{time}</time><span class="prompt">{title}</span> {msg}' ) );
129 consoleEl.append( msgEl );
130 consoleEl.$.scrollTop = consoleEl.$.scrollHeight;
131 setTimeout( function() { msgEl.addClass( 'old' ); }, 250 );
132 };
133
134 var observe = function( editor, num ) {
135 var p = 'EDITOR ' + num + ' > ';
136
137 editor.on( 'paste', function( event ) {
138 log( p + 'paste(prior:-1)', event.data.type + ' - "' + event.data.dataValue + '"' );
139 }, null, null, -1 );
140 editor.on( 'paste', function( event ) {
141 log( p + 'paste(prior:10)', event.data.type + ' - "' + event.data.dataValue + '"' );
142 } );
143 editor.on( 'paste', function( event ) {
144 log( p + 'paste(prior:999)', event.data.type + ' - "' + event.data.dataValue + '"' );
145 }, null, null, 999 );
146 editor.on( 'beforePaste', function( event ) {
147 log( p + 'beforePaste', event.data.type );
148 } );
149 editor.on( 'beforePaste', function( event ) {
150 log( p + 'beforePaste(prior:999)', event.data.type );
151 }, null, null, 999 );
152 editor.on( 'afterPaste', function( event ) {
153 log( p + 'afterPaste' );
154 } );
155 editor.on( 'copy', function( event ) {
156 log( p + 'copy' );
157 } );
158 editor.on( 'cut', function( event ) {
159 log( p + 'cut' );
160 } );
161 };
162
163 CKEDITOR.disableAutoInline = true;
164 var config = {
165 height: 120,
166 toolbar: [ [ 'Source' ] ],
167 allowedContent: true
168 },
169 editor1 = CKEDITOR.replace( 'editor1', config ),
170 editor2 = CKEDITOR.replace( 'editor2', config ),
171 editor3 = CKEDITOR.replace( 'editor3', config ),
172 editor4 = CKEDITOR.replace( 'editor4', CKEDITOR.tools.extend( { forcePasteAsPlainText: true }, config ) ),
173 editor5 = CKEDITOR.replace( 'editor5', CKEDITOR.tools.extend( { autoParagraph: false }, config ) ),
174 editor6 = CKEDITOR.inline( document.getElementById( 'editor6' ), config );
175
176 editor3.on( 'beforePaste', function( evt ) {
177 evt.data.type = 'text';
178 } );
179
180 observe( editor1, 1 );
181 observe( editor2, 2 );
182 observe( editor3, 3 );
183 observe( editor4, 4 );
184 observe( editor5, 5 );
185 observe( editor6, 6 );
186
187})();
188 </script>
189</body>
190</html>
diff --git a/sources/plugins/clipboard/dev/console.js b/sources/plugins/clipboard/dev/console.js
new file mode 100644
index 0000000..96ccd81
--- /dev/null
+++ b/sources/plugins/clipboard/dev/console.js
@@ -0,0 +1,49 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/* global CKCONSOLE */
7
8'use strict';
9
10( function() {
11 var pasteType, pasteValue;
12
13 CKCONSOLE.add( 'paste', {
14 panels: [
15 {
16 type: 'box',
17 content:
18 '<ul class="ckconsole_list">' +
19 '<li>type: <span class="ckconsole_value" data-value="type"></span></li>' +
20 '<li>value: <span class="ckconsole_value" data-value="value"></span></li>' +
21 '</ul>',
22
23 refresh: function() {
24 return {
25 header: 'Paste',
26 type: pasteType,
27 value: pasteValue
28 };
29 },
30
31 refreshOn: function( editor, refresh ) {
32 editor.on( 'paste', function( evt ) {
33 pasteType = evt.data.type;
34 pasteValue = CKEDITOR.tools.htmlEncode( evt.data.dataValue );
35 refresh();
36 } );
37 }
38 },
39 {
40 type: 'log',
41 on: function( editor, log, logFn ) {
42 editor.on( 'paste', function( evt ) {
43 logFn( 'paste; type:' + evt.data.type )();
44 } );
45 }
46 }
47 ]
48 } );
49} )();
diff --git a/sources/plugins/clipboard/dev/dnd.html b/sources/plugins/clipboard/dev/dnd.html
new file mode 100644
index 0000000..2dfb2be
--- /dev/null
+++ b/sources/plugins/clipboard/dev/dnd.html
@@ -0,0 +1,185 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Manual test for #11460</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../dev/console/console.js"></script>
12 <script src="../../../plugins/clipboard/dev/console.js"></script>
13 <link rel="stylesheet" href="../../../samples/old/sample.css">
14 <style type="text/css">
15 h2 {
16 margin: 10px 0px 4px 0px;
17 padding: 0;
18 font-size: 14px;
19 }
20 h3 {
21 margin: 5px 0px 2px 0px;
22 padding: 0;
23 font-size: 12px;
24 }
25 </style>
26</head>
27<body>
28 <h1 class="samples">
29 Manual test for #11460
30 </h1>
31 <h2>Description (<a href="javascript:hideshow('description');">hide/show</a>)</h2>
32 <div id="description" class="description">
33 <p>Test internal D&amp;D in the editor, dropping content from an external source (helpers, MS Word) and D&amp;D between editors. Keep in mind that internal D&amp;D is the most complex operation because editor have to handle two ranges at the same time.</p>
34 <h3>Expected behavior:</h3>
35 <ul>
36 <li>proper drop position,</li>
37 <li>in the internal and cross editor D&amp;D: dragged content should be removed,</li>
38 <li>dropped content should be (more less) the same as dragged content,</li>
39 <li>paste event should be fired,</li>
40 <li>undo should work properly (one undo operation for one D&amp;D),</li>
41 <li>no crashes, nor errors,</li>
42 </ul>
43 <h3>Drag scenarios:</h3>
44 <ul>
45 <li>drag simple text,</li>
46 <li>drag table cell/cells,</li>
47 <li>drag link,</li>
48 <li>drag helpers textarea content,</li>
49 <li>drag helpers html content,</li>
50 <li>drag content from MS Word.</li>
51 </ul>
52 <h3>Drop scenarios:</h3>
53 <ul>
54 <li>drop in the different paragraph (before and after),</li>
55 <li>drop in the same paragraph (before and after),</li>
56 <li>drop in the same text node (before and after),</li>
57 <li>drop between text lines,</li>
58 <li>drop on the whitespace next to the header,</li>
59 <li>drop on the whitespace on the left side from the quote,</li>
60 <li>drop into a cell.</li>
61 </ul>
62 <h3>Known issues (not part of this ticket):</h3>
63 <ul>
64 <li>because of <a href="http://dev.ckeditor.com/ticket/11636">#11636</a> dragged content is not correct in some cases (e.g. when you drag part of the link),</li>
65 <li>drag position needs clean up after D&amp;D (e.g. remove empty paragraphs, fix table),</li>
66 <li>drop position needs clean up after D&amp;D (e.g. add spaces before/after dropped content, apply parents styles, break paragraph when one paragraph is dropped at the end to the other paragraph),</li>
67 <li>in the external D&amp;D: Chrome add plenty of addition tags.</li>
68 </ul>
69 </div>
70 <div>
71 <h2>Helpers (<a href="javascript:hideshow('helpers');">hide/show</a>)</h2>
72 <div id="helpers">
73 <textarea style="width:49%; height:50px; float: left;">Lorem ipsum dolor sit amet, consectetur adipiscing elit. In commodo vulputate tempor. Sed <b>at</b> elit.</textarea>
74 <div style="width:49%; height:50px; float: right;">
75 Lorem ipsum <b>dolor</b> sit <i>amet</i>, consectetur adipiscing elit. In commodo vulputate tempor. Sed &lt;b&gt;at elit&lt;/b&gt; vel ligula mollis aliquet a ac odio.
76 <pre>
77Aenean cursus egestas ipsum.
78 </pre>
79 </div>
80 <div style="clear:both;"></div>
81 </div>
82 </div>
83 <div>
84 <h2>Classic editor (<a href="javascript:hideshow('classic-editor');">hide/show</a>)</h2>
85 <div id="classic-editor">
86 <textarea cols="80" id="classic" name="classic" rows="10">
87 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;../../../samples/assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
88 </textarea>
89 </div>
90 </div>
91 <div>
92 <h2>Inline editor (<a href="javascript:hideshow('inline');">hide/show</a>)</h2>
93 <div id="inline" contenteditable="true">
94 <h1><img alt="Saturn V carrying Apollo 11" class="right" src="../../../samples/assets/sample.jpg" /> Apollo 11</h1>
95
96 <p><b>Apollo 11</b> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p>
97
98 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
99
100 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
101
102 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
103
104 <blockquote>
105 <p>One small step for [a] man, one giant leap for mankind.</p>
106 </blockquote>
107
108 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
109
110 <blockquote>
111 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
112 </blockquote>
113
114 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
115
116 <table align="right" border="1" bordercolor="#ccc" cellpadding="5" cellspacing="0" style="border-collapse:collapse;margin:10px 0 10px 15px;">
117 <caption><strong>Mission crew</strong></caption>
118 <thead>
119 <tr>
120 <th scope="col">Position</th>
121 <th scope="col">Astronaut</th>
122 </tr>
123 </thead>
124 <tbody>
125 <tr>
126 <td>Commander</td>
127 <td>Neil A. Armstrong</td>
128 </tr>
129 <tr>
130 <td>Command Module Pilot</td>
131 <td>Michael Collins</td>
132 </tr>
133 <tr>
134 <td>Lunar Module Pilot</td>
135 <td>Edwin &quot;Buzz&quot; E. Aldrin, Jr.</td>
136 </tr>
137 </tbody>
138 </table>
139
140 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
141
142 <ol>
143 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
144 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
145 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
146 </ol>
147
148 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
149
150 <hr />
151 <p style="text-align: right;"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p>
152 </div>
153 </div>
154 <script type="text/javascript">
155 CKEDITOR.disableAutoInline = true;
156
157 function hideshow( id ) {
158 var element = CKEDITOR.document.getById( id );
159
160 if( element.getStyle( 'display' ) == 'none' )
161 element.show();
162 else
163 element.hide();
164 }
165
166 CKEDITOR.replace( 'classic' );
167 CKEDITOR.inline( 'inline' );
168
169 CKCONSOLE.addEventPanel( 'dragstart', [ '$', 'target', 'dataTransfer' ] );
170 CKCONSOLE.addEventPanel( 'dragend', [ '$', 'target', 'dataTransfer' ] );
171 CKCONSOLE.addEventPanel( 'drop',
172 [ '$', 'target', 'dataTransfer', 'dragRange', 'dropRange' ] );
173
174 CKCONSOLE.create( 'dragstart', { editor: 'classic' } );
175 CKCONSOLE.create( 'drop', { editor: 'classic' } );
176 CKCONSOLE.create( 'paste', { editor: 'classic' } );
177 CKCONSOLE.create( 'dragend', { editor: 'classic' } );
178
179 CKCONSOLE.create( 'dragstart', { editor: 'inline' } );
180 CKCONSOLE.create( 'drop', { editor: 'inline' } );
181 CKCONSOLE.create( 'paste', { editor: 'inline' } );
182 CKCONSOLE.create( 'dragend', { editor: 'inline' } );
183 </script>
184</body>
185</html>
diff --git a/sources/plugins/clipboard/dialogs/paste.js b/sources/plugins/clipboard/dialogs/paste.js
new file mode 100644
index 0000000..80ce29f
--- /dev/null
+++ b/sources/plugins/clipboard/dialogs/paste.js
@@ -0,0 +1,254 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.dialog.add( 'paste', function( editor ) {
7 var lang = editor.lang.clipboard,
8 clipboard = CKEDITOR.plugins.clipboard,
9 lastDataTransfer;
10
11 function onPasteFrameLoad( win ) {
12 var doc = new CKEDITOR.dom.document( win.document ),
13 body = doc.getBody(),
14 script = doc.getById( 'cke_actscrpt' );
15
16 script && script.remove();
17
18 body.setAttribute( 'contenteditable', true );
19
20 // Forward dataTransfer (#13883).
21 body.on( clipboard.mainPasteEvent, function( evt ) {
22 var dataTransfer = clipboard.initPasteDataTransfer( evt );
23
24 if ( !lastDataTransfer ) {
25 lastDataTransfer = dataTransfer;
26 } else
27 // For two paste with the same dataTransfer we can use that dataTransfer (two internal pastes are
28 // considered as an internal paste).
29 if ( dataTransfer != lastDataTransfer ) {
30 // If there were two paste with different DataTransfer objects create a new, empty, data transfer
31 // and use it (one internal and one external paste are considered as external paste).
32 lastDataTransfer = clipboard.initPasteDataTransfer();
33 }
34 } );
35
36 // IE before version 8 will leave cursor blinking inside the document after
37 // editor blurred unless we clean up the selection. (#4716)
38 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) {
39 doc.getWindow().on( 'blur', function() {
40 doc.$.selection.empty();
41 } );
42 }
43
44 doc.on( 'keydown', function( e ) {
45 var domEvent = e.data,
46 key = domEvent.getKeystroke(),
47 processed;
48
49 switch ( key ) {
50 case 27:
51 this.hide();
52 processed = 1;
53 break;
54
55 case 9:
56 case CKEDITOR.SHIFT + 9:
57 this.changeFocus( 1 );
58 processed = 1;
59 }
60
61 processed && domEvent.preventDefault();
62 }, this );
63
64 editor.fire( 'ariaWidget', new CKEDITOR.dom.element( win.frameElement ) );
65
66 // Handle pending focus.
67 if ( doc.getWindow().getFrame().removeCustomData( 'pendingFocus' ) )
68 body.focus();
69 }
70
71 // If pasteDialogCommit wasn't canceled by e.g. editor.getClipboardData
72 // then fire paste event.
73 // Do not use editor#paste, because it would start from beforePaste event.
74 editor.on( 'pasteDialogCommit', function( evt ) {
75 if ( evt.data )
76 editor.fire( 'paste', {
77 type: 'auto',
78 dataValue: evt.data.dataValue,
79 method: 'paste',
80 dataTransfer: evt.data.dataTransfer || clipboard.initPasteDataTransfer()
81 } );
82 }, null, null, 1000 );
83
84 return {
85 title: lang.title,
86
87 minWidth: CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
88 minHeight: CKEDITOR.env.quirks ? 250 : 245,
89 onShow: function() {
90 // FIREFOX BUG: Force the browser to render the dialog to make the to-be-
91 // inserted iframe editable. (#3366)
92 this.parts.dialog.$.offsetHeight;
93
94 this.setupContent();
95
96 // Set dialog title to the custom value (set e.g. in editor.openDialog callback) and reset this value.
97 // If custom title not set, use default one.
98 this.parts.title.setHtml( this.customTitle || lang.title );
99 this.customTitle = null;
100 },
101
102 onLoad: function() {
103 if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) && editor.lang.dir == 'rtl' )
104 this.parts.contents.setStyle( 'overflow', 'hidden' );
105 },
106
107 onOk: function() {
108 this.commitContent();
109 },
110
111 contents: [ {
112 id: 'general',
113 label: editor.lang.common.generalTab,
114 elements: [
115 {
116 type: 'html',
117 id: 'securityMsg',
118 html: '<div style="white-space:normal;width:340px">' + lang.securityMsg + '</div>'
119 },
120 {
121 type: 'html',
122 id: 'pasteMsg',
123 html: '<div style="white-space:normal;width:340px">' + lang.pasteMsg + '</div>'
124 },
125 {
126 type: 'html',
127 id: 'editing_area',
128 style: 'width:100%;height:100%',
129 html: '',
130 focus: function() {
131 var iframe = this.getInputElement(),
132 doc = iframe.getFrameDocument(),
133 body = doc.getBody();
134
135 // Frame content may not loaded at the moment.
136 if ( !body || body.isReadOnly() )
137 iframe.setCustomData( 'pendingFocus', 1 );
138 else
139 body.focus();
140 },
141 setup: function() {
142 var dialog = this.getDialog();
143 var htmlToLoad = '<html dir="' + editor.config.contentsLangDirection + '"' +
144 ' lang="' + ( editor.config.contentsLanguage || editor.langCode ) + '">' +
145 '<head><style>body{margin:3px;height:95%;word-break:break-all;}</style></head><body>' +
146 '<script id="cke_actscrpt" type="text/javascript">' +
147 'window.parent.CKEDITOR.tools.callFunction(' + CKEDITOR.tools.addFunction( onPasteFrameLoad, dialog ) + ',this);' +
148 '</script></body>' +
149 '</html>';
150
151 var src =
152 CKEDITOR.env.air ?
153 'javascript:void(0)' : // jshint ignore:line
154 ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ?
155 'javascript:void((function(){' + encodeURIComponent( // jshint ignore:line
156 'document.open();' +
157 '(' + CKEDITOR.tools.fixDomain + ')();' +
158 'document.close();'
159 ) + '})())"'
160 : '';
161
162 var iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' +
163 ' class="cke_pasteframe"' +
164 ' frameborder="0" ' +
165 ' allowTransparency="true"' +
166 ' src="' + src + '"' +
167 ' aria-label="' + lang.pasteArea + '"' +
168 ' aria-describedby="' + dialog.getContentElement( 'general', 'pasteMsg' ).domId + '"' +
169 '></iframe>' );
170
171 // Reset last data transfer.
172 lastDataTransfer = null;
173
174 iframe.on( 'load', function( e ) {
175 e.removeListener();
176
177 var doc = iframe.getFrameDocument();
178 doc.write( htmlToLoad );
179
180 editor.focusManager.add( doc.getBody() );
181
182 if ( CKEDITOR.env.air )
183 onPasteFrameLoad.call( this, doc.getWindow().$ );
184 }, dialog );
185
186 iframe.setCustomData( 'dialog', dialog );
187
188 var container = this.getElement();
189 container.setHtml( '' );
190 container.append( iframe );
191
192 // IE need a redirect on focus to make
193 // the cursor blinking inside iframe. (#5461)
194 if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
195 var focusGrabber = CKEDITOR.dom.element.createFromHtml( '<span tabindex="-1" style="position:absolute" role="presentation"></span>' );
196 focusGrabber.on( 'focus', function() {
197 // Since fixDomain is called in src attribute,
198 // IE needs some slight delay to correctly move focus.
199 setTimeout( function() {
200 iframe.$.contentWindow.focus();
201 } );
202 } );
203 container.append( focusGrabber );
204
205 // Override focus handler on field.
206 this.focus = function() {
207 focusGrabber.focus();
208 this.fire( 'focus' );
209 };
210 }
211
212 this.getInputElement = function() {
213 return iframe;
214 };
215
216 // Force container to scale in IE.
217 if ( CKEDITOR.env.ie ) {
218 container.setStyle( 'display', 'block' );
219 container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
220 }
221 },
222 commit: function() {
223 var editor = this.getDialog().getParentEditor(),
224 body = this.getInputElement().getFrameDocument().getBody(),
225 bogus = body.getBogus(),
226 html;
227 bogus && bogus.remove();
228
229 // Saving the contents so changes until paste is complete will not take place (#7500)
230 html = body.getHtml();
231
232 // Opera needs some time to think about what has happened and what it should do now.
233 setTimeout( function() {
234 editor.fire( 'pasteDialogCommit', {
235 dataValue: html,
236 // Avoid error if there was no paste so lastDataTransfer is null.
237 dataTransfer: lastDataTransfer || clipboard.initPasteDataTransfer()
238 } );
239 }, 0 );
240 }
241 }
242 ]
243 } ]
244 };
245} );
246
247/**
248 * Internal event to pass paste dialog's data to the listeners.
249 *
250 * @private
251 * @event pasteDialogCommit
252 * @member CKEDITOR.editor
253 * @param {CKEDITOR.editor} editor This editor instance.
254 */
diff --git a/sources/plugins/clipboard/icons/copy-rtl.png b/sources/plugins/clipboard/icons/copy-rtl.png
new file mode 100644
index 0000000..ce94fc0
--- /dev/null
+++ b/sources/plugins/clipboard/icons/copy-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/copy.png b/sources/plugins/clipboard/icons/copy.png
new file mode 100644
index 0000000..ce94fc0
--- /dev/null
+++ b/sources/plugins/clipboard/icons/copy.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/cut-rtl.png b/sources/plugins/clipboard/icons/cut-rtl.png
new file mode 100644
index 0000000..8ae48d9
--- /dev/null
+++ b/sources/plugins/clipboard/icons/cut-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/cut.png b/sources/plugins/clipboard/icons/cut.png
new file mode 100644
index 0000000..8ae48d9
--- /dev/null
+++ b/sources/plugins/clipboard/icons/cut.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/copy-rtl.png b/sources/plugins/clipboard/icons/hidpi/copy-rtl.png
new file mode 100644
index 0000000..74c6765
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/copy-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/copy.png b/sources/plugins/clipboard/icons/hidpi/copy.png
new file mode 100644
index 0000000..74c6765
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/copy.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/cut-rtl.png b/sources/plugins/clipboard/icons/hidpi/cut-rtl.png
new file mode 100644
index 0000000..f5a9b0d
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/cut-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/cut.png b/sources/plugins/clipboard/icons/hidpi/cut.png
new file mode 100644
index 0000000..f5a9b0d
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/cut.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/paste-rtl.png b/sources/plugins/clipboard/icons/hidpi/paste-rtl.png
new file mode 100644
index 0000000..12cac92
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/paste-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/paste.png b/sources/plugins/clipboard/icons/hidpi/paste.png
new file mode 100644
index 0000000..12cac92
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/paste.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/paste-rtl.png b/sources/plugins/clipboard/icons/paste-rtl.png
new file mode 100644
index 0000000..7039251
--- /dev/null
+++ b/sources/plugins/clipboard/icons/paste-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/paste.png b/sources/plugins/clipboard/icons/paste.png
new file mode 100644
index 0000000..7039251
--- /dev/null
+++ b/sources/plugins/clipboard/icons/paste.png
Binary files differ
diff --git a/sources/plugins/clipboard/lang/af.js b/sources/plugins/clipboard/lang/af.js
new file mode 100644
index 0000000..f87522f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/af.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'af', {
6 copy: 'Kopiëer',
7 copyError: 'U blaaier se sekuriteitsinstelling belet die kopiëringsaksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+C).',
8 cut: 'Knip',
9 cutError: 'U blaaier se sekuriteitsinstelling belet die outomatiese knip-aksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+X).',
10 paste: 'Plak',
11 pasteArea: 'Plak-area',
12 pasteMsg: 'Plak die teks in die volgende teks-area met die sleutelbordkombinasie (<STRONG>Ctrl/Cmd+V</STRONG>) en druk <STRONG>OK</STRONG>.',
13 securityMsg: 'Weens u blaaier se sekuriteitsinstelling is data op die knipbord nie toeganklik nie. U kan dit eers weer in hierdie venster plak.',
14 title: 'Byvoeg'
15} );
diff --git a/sources/plugins/clipboard/lang/ar.js b/sources/plugins/clipboard/lang/ar.js
new file mode 100644
index 0000000..aa96596
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ar.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ar', {
6 copy: 'نسخ',
7 copyError: 'الإعدادات الأمنية للمتصفح الذي تستخدمه تمنع عمليات النسخ التلقائي. فضلاً إستخدم لوحة المفاتيح لفعل ذلك (Ctrl/Cmd+C).',
8 cut: 'قص',
9 cutError: 'الإعدادات الأمنية للمتصفح الذي تستخدمه تمنع القص التلقائي. فضلاً إستخدم لوحة المفاتيح لفعل ذلك (Ctrl/Cmd+X).',
10 paste: 'لصق',
11 pasteArea: 'منطقة اللصق',
12 pasteMsg: 'الصق داخل الصندوق بإستخدام زرائر (<STRONG>Ctrl/Cmd+V</STRONG>) في لوحة المفاتيح، ثم اضغط زر <STRONG>موافق</STRONG>.',
13 securityMsg: 'نظراً لإعدادات الأمان الخاصة بمتصفحك، لن يتمكن هذا المحرر من الوصول لمحتوى حافظتك، لذلك يجب عليك لصق المحتوى مرة أخرى في هذه النافذة.',
14 title: 'لصق'
15} );
diff --git a/sources/plugins/clipboard/lang/az.js b/sources/plugins/clipboard/lang/az.js
new file mode 100644
index 0000000..1fc1a99
--- /dev/null
+++ b/sources/plugins/clipboard/lang/az.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'az', {
6 copy: 'Köçür',
7 copyError: 'Avtomatik köçürülməsi mümkün deyil. Ctrl+C basın.',
8 cut: 'Kəs',
9 cutError: 'Avtomatik kəsmə mümkün deyil. Ctrl+X basın.',
10 paste: 'Əlavə et',
11 pasteArea: 'Əlavəetmə sahəsi',
12 pasteMsg: 'Bu sahəyə əlavə edin (<strong>Ctrl+V</strong>)',
13 securityMsg: 'Mübadilə buferi açmaq mümkün deyil. Bu pəncərədə yenidən əlavə edin.',
14 title: 'Əlavə et'
15} );
diff --git a/sources/plugins/clipboard/lang/bg.js b/sources/plugins/clipboard/lang/bg.js
new file mode 100644
index 0000000..93a5a9c
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bg.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bg', {
6 copy: 'Копирай',
7 copyError: 'Настройките за сигурност на вашия бразуър не разрешават на редактора да изпълни запаметяването. За целта използвайте клавиатурата (Ctrl/Cmd+C).',
8 cut: 'Отрежи',
9 cutError: 'Настройките за сигурност на Вашия браузър не позволяват на редактора автоматично да изъплни действията за отрязване. Моля ползвайте клавиатурните команди за целта (ctrl+x).',
10 paste: 'Вмъкни',
11 pasteArea: 'Зона за вмъкване',
12 pasteMsg: 'Вмъкнете тук съдъжанието с клавиатуарата (<STRONG>Ctrl/Cmd+V</STRONG>) и натиснете <STRONG>OK</STRONG>.',
13 securityMsg: 'Заради настройките за сигурност на Вашия браузър, редакторът не може да прочете данните от клипборда коректно.',
14 title: 'Вмъкни'
15} );
diff --git a/sources/plugins/clipboard/lang/bn.js b/sources/plugins/clipboard/lang/bn.js
new file mode 100644
index 0000000..f821fa0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bn.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bn', {
6 copy: 'কপি',
7 copyError: 'আপনার ব্রাউজারের নিরাপত্তা সেটিংসমূহ এডিটরকে স্বয়ংক্রিয়ভাবে কপি করার প্রক্রিয়া চালনা করার অনুমতি দেয় না। অনুগ্রহপূর্বক এই কাজের জন্য কিবোর্ড ব্যবহার করুন (Ctrl/Cmd+C)।',
8 cut: 'কাট',
9 cutError: 'আপনার ব্রাউজারের সুরক্ষা সেটিংস এডিটরকে অটোমেটিক কাট করার অনুমতি দেয়নি। দয়া করে এই কাজের জন্য কিবোর্ড ব্যবহার করুন (Ctrl/Cmd+X)।',
10 paste: 'পেস্ট',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'অনুগ্রহ করে নীচের বাক্সে কিবোর্ড ব্যবহার করে (<STRONG>Ctrl/Cmd+V</STRONG>) পেস্ট করুন এবং <STRONG>OK</STRONG> চাপ দিন',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'পেস্ট'
15} );
diff --git a/sources/plugins/clipboard/lang/bs.js b/sources/plugins/clipboard/lang/bs.js
new file mode 100644
index 0000000..1c23a61
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bs.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bs', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosne postavke Vašeg pretraživaèa ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Sigurnosne postavke vašeg pretraživaèa ne dozvoljavaju operacije automatskog rezanja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+X).',
10 paste: 'Zalijepi',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK', // MISSING
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'Zalijepi'
15} );
diff --git a/sources/plugins/clipboard/lang/ca.js b/sources/plugins/clipboard/lang/ca.js
new file mode 100644
index 0000000..52179c1
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ca.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ca', {
6 copy: 'Copiar',
7 copyError: 'La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de copiar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+C).',
8 cut: 'Retallar',
9 cutError: 'La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de retallar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+X).',
10 paste: 'Enganxar',
11 pasteArea: 'Àrea d\'enganxat',
12 pasteMsg: 'Si us plau, enganxi dins del següent camp utilitzant el teclat (<strong>Ctrl/Cmd+V</strong>) i premi OK.',
13 securityMsg: 'A causa de la configuració de seguretat del vostre navegador, l\'editor no pot accedir a les dades del porta-retalls directament. Enganxeu-ho un altre cop en aquesta finestra.',
14 title: 'Enganxar'
15} );
diff --git a/sources/plugins/clipboard/lang/cs.js b/sources/plugins/clipboard/lang/cs.js
new file mode 100644
index 0000000..7cf573e
--- /dev/null
+++ b/sources/plugins/clipboard/lang/cs.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'cs', {
6 copy: 'Kopírovat',
7 copyError: 'Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro kopírování zvoleného textu do schránky. Prosím zkopírujte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+C).',
8 cut: 'Vyjmout',
9 cutError: 'Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro vyjmutí zvoleného textu do schránky. Prosím vyjměte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+X).',
10 paste: 'Vložit',
11 pasteArea: 'Oblast vkládání',
12 pasteMsg: 'Do následujícího pole vložte požadovaný obsah pomocí klávesnice (<STRONG>Ctrl/Cmd+V</STRONG>) a stiskněte <STRONG>OK</STRONG>.',
13 securityMsg: 'Z důvodů nastavení bezpečnosti vašeho prohlížeče nemůže editor přistupovat přímo do schránky. Obsah schránky prosím vložte znovu do tohoto okna.',
14 title: 'Vložit'
15} );
diff --git a/sources/plugins/clipboard/lang/cy.js b/sources/plugins/clipboard/lang/cy.js
new file mode 100644
index 0000000..00c5eeb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/cy.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'cy', {
6 copy: 'Copïo',
7 copyError: '\'Dyw gosodiadau diogelwch eich porwr ddim yn caniatàu\'r golygydd i gynnal \'gweithredoedd copïo\' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+C).',
8 cut: 'Torri',
9 cutError: 'Nid yw gosodiadau diogelwch eich porwr yn caniatàu\'r golygydd i gynnal \'gweithredoedd torri\' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+X).',
10 paste: 'Gludo',
11 pasteArea: 'Ardal Gludo',
12 pasteMsg: 'Gludwch i mewn i\'r blwch canlynol gan ddefnyddio\'r bysellfwrdd (<strong>Ctrl/Cmd+V</strong>) a phwyso <strong>Iawn</strong>.',
13 securityMsg: 'Oherwydd gosodiadau diogelwch eich porwr, \'dyw\'r porwr ddim yn gallu ennill mynediad i\'r data ar y clipfwrdd yn uniongyrchol. Mae angen i chi ei ludo eto i\'r ffenestr hon.',
14 title: 'Gludo'
15} );
diff --git a/sources/plugins/clipboard/lang/da.js b/sources/plugins/clipboard/lang/da.js
new file mode 100644
index 0000000..c029016
--- /dev/null
+++ b/sources/plugins/clipboard/lang/da.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'da', {
6 copy: 'Kopiér',
7 copyError: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at kopiere teksten (Ctrl/Cmd+C).',
8 cut: 'Klip',
9 cutError: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at klippe teksten (Ctrl/Cmd+X).',
10 paste: 'Indsæt',
11 pasteArea: 'Indsæt område',
12 pasteMsg: 'Indsæt i feltet herunder (<STRONG>Ctrl/Cmd+V</STRONG>) og klik på <STRONG>OK</STRONG>.',
13 securityMsg: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Du skal indsætte udklipsholderens indhold i dette vindue igen.',
14 title: 'Indsæt'
15} );
diff --git a/sources/plugins/clipboard/lang/de-ch.js b/sources/plugins/clipboard/lang/de-ch.js
new file mode 100644
index 0000000..325b100
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de-ch.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'de-ch', {
6 copy: 'Kopieren',
7 copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
8 cut: 'Ausschneiden',
9 cutError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).',
10 paste: 'Einfügen',
11 pasteArea: 'Einfügebereich',
12 pasteMsg: 'Bitte fügen Sie den Text in der folgenden Box über die Tastatur (mit <STRONG>Strg+V</STRONG>) ein und bestätigen Sie mit <STRONG>OK</STRONG>.',
13 securityMsg: 'Aufgrund von Sicherheitsbeschränkungen Ihres Browsers kann der Editor nicht direkt auf die Zwischenablage zugreifen. Bitte fügen Sie den Inhalt erneut in diesem Fenster ein.',
14 title: 'Einfügen'
15} );
diff --git a/sources/plugins/clipboard/lang/de.js b/sources/plugins/clipboard/lang/de.js
new file mode 100644
index 0000000..2d6b30b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'de', {
6 copy: 'Kopieren',
7 copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
8 cut: 'Ausschneiden',
9 cutError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).',
10 paste: 'Einfügen',
11 pasteArea: 'Einfügebereich',
12 pasteMsg: 'Bitte fügen Sie den Text in der folgenden Box über die Tastatur (mit <STRONG>Strg+V</STRONG>) ein und bestätigen Sie mit <STRONG>OK</STRONG>.',
13 securityMsg: 'Aufgrund von Sicherheitsbeschränkungen Ihres Browsers kann der Editor nicht direkt auf die Zwischenablage zugreifen. Bitte fügen Sie den Inhalt erneut in diesem Fenster ein.',
14 title: 'Einfügen'
15} );
diff --git a/sources/plugins/clipboard/lang/el.js b/sources/plugins/clipboard/lang/el.js
new file mode 100644
index 0000000..0528840
--- /dev/null
+++ b/sources/plugins/clipboard/lang/el.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'el', {
6 copy: 'Αντιγραφή',
7 copyError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αντιγραφής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+C).',
8 cut: 'Αποκοπή',
9 cutError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αποκοπής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+X).',
10 paste: 'Επικόλληση',
11 pasteArea: 'Περιοχή Επικόλλησης',
12 pasteMsg: 'Παρακαλώ επικολλήστε στο ακόλουθο κουτί χρησιμοποιώντας το πληκτρολόγιο (<strong>Ctrl/Cmd+V</strong>) και πατήστε OK.',
13 securityMsg: 'Λόγων των ρυθμίσεων ασφάλειας του περιηγητή σας, ο επεξεργαστής δεν μπορεί να έχει πρόσβαση στην μνήμη επικόλλησης. Χρειάζεται να επικολλήσετε ξανά σε αυτό το παράθυρο.',
14 title: 'Επικόλληση'
15} );
diff --git a/sources/plugins/clipboard/lang/en-au.js b/sources/plugins/clipboard/lang/en-au.js
new file mode 100644
index 0000000..5c497fb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-au.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-au', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
14 title: 'Paste'
15} );
diff --git a/sources/plugins/clipboard/lang/en-ca.js b/sources/plugins/clipboard/lang/en-ca.js
new file mode 100644
index 0000000..036ebab
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-ca.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-ca', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
14 title: 'Paste'
15} );
diff --git a/sources/plugins/clipboard/lang/en-gb.js b/sources/plugins/clipboard/lang/en-gb.js
new file mode 100644
index 0000000..bb511ce
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-gb.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-gb', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteArea: 'Paste Area',
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
14 title: 'Paste'
15} );
diff --git a/sources/plugins/clipboard/lang/en.js b/sources/plugins/clipboard/lang/en.js
new file mode 100644
index 0000000..4db6960
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteArea: 'Paste Area',
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
14 title: 'Paste'
15} );
diff --git a/sources/plugins/clipboard/lang/eo.js b/sources/plugins/clipboard/lang/eo.js
new file mode 100644
index 0000000..2df4150
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eo.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'eo', {
6 copy: 'Kopii',
7 copyError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras kopiajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-C).',
8 cut: 'Eltondi',
9 cutError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras eltondajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-X).',
10 paste: 'Interglui',
11 pasteArea: 'Intergluoareo',
12 pasteMsg: 'Bonvolu glui la tekston en la jenan areon per uzado de la klavaro (<strong>Ctrl/Cmd+V</strong>) kaj premu OK',
13 securityMsg: 'Pro la sekurecagordo de via TTT-legilo, la redaktilo ne povas rekte atingi viajn datenojn en la poŝo. Bonvolu denove interglui la datenojn en tiun fenestron.',
14 title: 'Interglui'
15} );
diff --git a/sources/plugins/clipboard/lang/es.js b/sources/plugins/clipboard/lang/es.js
new file mode 100644
index 0000000..c455992
--- /dev/null
+++ b/sources/plugins/clipboard/lang/es.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'es', {
6 copy: 'Copiar',
7 copyError: 'La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de copiado.\r\nPor favor use el teclado (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de cortado.\r\nPor favor use el teclado (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteArea: 'Zona de pegado',
12 pasteMsg: 'Por favor pegue dentro del cuadro utilizando el teclado (<STRONG>Ctrl/Cmd+V</STRONG>);\r\nluego presione <STRONG>Aceptar</STRONG>.',
13 securityMsg: 'Debido a la configuración de seguridad de su navegador, el editor no tiene acceso al portapapeles.\r\nEs necesario que lo pegue de nuevo en esta ventana.',
14 title: 'Pegar'
15} );
diff --git a/sources/plugins/clipboard/lang/et.js b/sources/plugins/clipboard/lang/et.js
new file mode 100644
index 0000000..7d86b30
--- /dev/null
+++ b/sources/plugins/clipboard/lang/et.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'et', {
6 copy: 'Kopeeri',
7 copyError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt kopeerida. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+C).',
8 cut: 'Lõika',
9 cutError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt lõigata. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+X).',
10 paste: 'Aseta',
11 pasteArea: 'Asetamise ala',
12 pasteMsg: 'Palun aseta tekst järgnevasse kasti kasutades klaviatuuri klahvikombinatsiooni (<STRONG>Ctrl/Cmd+V</STRONG>) ja vajuta seejärel <STRONG>OK</STRONG>.',
13 securityMsg: 'Sinu veebisirvija turvaseadete tõttu ei oma redaktor otsest ligipääsu lõikelaua andmetele. Sa pead asetama need uuesti siia aknasse.',
14 title: 'Asetamine'
15} );
diff --git a/sources/plugins/clipboard/lang/eu.js b/sources/plugins/clipboard/lang/eu.js
new file mode 100644
index 0000000..93240b5
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eu.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'eu', {
6 copy: 'Kopiatu',
7 copyError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki kopiatzea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+C).',
8 cut: 'Ebaki',
9 cutError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki moztea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+X).',
10 paste: 'Itsatsi',
11 pasteArea: 'Itsasteko area',
12 pasteMsg: 'Mesedez teklatua erabiliz (<strong>Ctrl/Cmd+V</strong>) ondorengo eremuan testua itsatsi eta sakatu <strong>Ados</strong>.',
13 securityMsg: 'Nabigatzailearen segurtasun ezarpenak direla eta, editoreak ezin du arbela zuzenean erabili. Leiho honetan berriro itsatsi behar duzu.',
14 title: 'Itsatsi'
15} );
diff --git a/sources/plugins/clipboard/lang/fa.js b/sources/plugins/clipboard/lang/fa.js
new file mode 100644
index 0000000..8abee21
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fa.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fa', {
6 copy: 'رونوشت',
7 copyError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای کپی کردن را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+C).',
8 cut: 'برش',
9 cutError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای برش را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+X).',
10 paste: 'چسباندن',
11 pasteArea: 'محل چسباندن',
12 pasteMsg: 'لطفا متن را با کلیدهای (<STRONG>Ctrl/Cmd+V</STRONG>) در این جعبهٴ متنی بچسبانید و <STRONG>پذیرش</STRONG> را بزنید.',
13 securityMsg: 'به خاطر تنظیمات امنیتی مرورگر شما، ویرایشگر نمیتواند دسترسی مستقیم به دادههای clipboard داشته باشد. شما باید دوباره آنرا در این پنجره بچسبانید.',
14 title: 'چسباندن'
15} );
diff --git a/sources/plugins/clipboard/lang/fi.js b/sources/plugins/clipboard/lang/fi.js
new file mode 100644
index 0000000..d165fb3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fi.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fi', {
6 copy: 'Kopioi',
7 copyError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa kopioimista. Käytä näppäimistöä kopioimiseen (Ctrl+C).',
8 cut: 'Leikkaa',
9 cutError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa leikkaamista. Käytä näppäimistöä leikkaamiseen (Ctrl+X).',
10 paste: 'Liitä',
11 pasteArea: 'Leikealue',
12 pasteMsg: 'Liitä painamalla (<STRONG>Ctrl+V</STRONG>) ja painamalla <STRONG>OK</STRONG>.',
13 securityMsg: 'Selaimesi turva-asetukset eivät salli editorin käyttää leikepöytää suoraan. Sinun pitää suorittaa liittäminen tässä ikkunassa.',
14 title: 'Liitä'
15} );
diff --git a/sources/plugins/clipboard/lang/fo.js b/sources/plugins/clipboard/lang/fo.js
new file mode 100644
index 0000000..5c1ec8a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fo.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fo', {
6 copy: 'Avrita',
7 copyError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at avrita tekstin. Vinarliga nýt knappaborðið til at avrita tekstin (Ctrl/Cmd+C).',
8 cut: 'Kvett',
9 cutError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at kvetta tekstin. Vinarliga nýt knappaborðið til at kvetta tekstin (Ctrl/Cmd+X).',
10 paste: 'Innrita',
11 pasteArea: 'Avritingarumráði',
12 pasteMsg: 'Vinarliga koyr tekstin í hendan rútin við knappaborðinum (<strong>Ctrl/Cmd+V</strong>) og klikk á <strong>Góðtak</strong>.',
13 securityMsg: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í beinleiðis atgongd til avritingarminnið. Tygum mugu royna aftur í hesum rútinum.',
14 title: 'Innrita'
15} );
diff --git a/sources/plugins/clipboard/lang/fr-ca.js b/sources/plugins/clipboard/lang/fr-ca.js
new file mode 100644
index 0000000..3425f56
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr-ca.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fr-ca', {
6 copy: 'Copier',
7 copyError: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur de copier automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+C).',
8 cut: 'Couper',
9 cutError: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur de couper automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+X).',
10 paste: 'Coller',
11 pasteArea: 'Coller la zone',
12 pasteMsg: 'Veuillez coller dans la zone ci-dessous en utilisant le clavier (<STRONG>Ctrl/Cmd+V</STRONG>) et appuyer sur <STRONG>OK</STRONG>.',
13 securityMsg: 'A cause des paramètres de sécurité de votre navigateur, l\'éditeur ne peut accéder au presse-papier directement. Vous devez coller à nouveau le contenu dans cette fenêtre.',
14 title: 'Coller'
15} );
diff --git a/sources/plugins/clipboard/lang/fr.js b/sources/plugins/clipboard/lang/fr.js
new file mode 100644
index 0000000..bb8349f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fr', {
6 copy: 'Copier',
7 copyError: 'Les paramètres de sécurité de votre navigateur n\'autorisent pas l\'éditeur à exécuter automatiquement l\'opération « Copier ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+C).',
8 cut: 'Couper',
9 cutError: 'Les paramètres de sécurité de votre navigateur n\'autorisent pas l\'éditeur à exécuter automatiquement l\'opération « Couper ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+X).',
10 paste: 'Coller',
11 pasteArea: 'Coller la zone',
12 pasteMsg: 'Veuillez coller le texte dans la zone suivante en utilisant le raccourci clavier (<strong>Ctrl/Cmd+V</strong>) et cliquez sur OK.',
13 securityMsg: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur d\'accéder directement aux données du presse-papier. Vous devez les coller à nouveau dans cette fenêtre.',
14 title: 'Coller'
15} );
diff --git a/sources/plugins/clipboard/lang/gl.js b/sources/plugins/clipboard/lang/gl.js
new file mode 100644
index 0000000..3c89dd0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gl.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'gl', {
6 copy: 'Copiar',
7 copyError: 'Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de copia. Use o teclado para iso (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de corte. Use o teclado para iso (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteArea: 'Zona de pegado',
12 pasteMsg: 'Pegue dentro do seguinte cadro usando o teclado (<STRONG>Ctrl/Cmd+V</STRONG>) e prema en Aceptar',
13 securityMsg: 'Por mor da configuración de seguranza do seu navegador, o editor non ten acceso ao portapapeis. É necesario pegalo novamente nesta xanela.',
14 title: 'Pegar'
15} );
diff --git a/sources/plugins/clipboard/lang/gu.js b/sources/plugins/clipboard/lang/gu.js
new file mode 100644
index 0000000..fcf039a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gu.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'gu', {
6 copy: 'નકલ',
7 copyError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કોપી કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+C) का प्रयोग करें।',
8 cut: 'કાપવું',
9 cutError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કટ કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+X) નો ઉપયોગ કરો.',
10 paste: 'પેસ્ટ',
11 pasteArea: 'પેસ્ટ કરવાની જગ્યા',
12 pasteMsg: 'Ctrl/Cmd+V નો પ્રયોગ કરી પેસ્ટ કરો',
13 securityMsg: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસના કારણે,એડિટર તમારા કિલ્પબોર્ડ ડેટા ને કોપી નથી કરી શકતો. તમારે આ વિન્ડોમાં ફરીથી પેસ્ટ કરવું પડશે.',
14 title: 'પેસ્ટ'
15} );
diff --git a/sources/plugins/clipboard/lang/he.js b/sources/plugins/clipboard/lang/he.js
new file mode 100644
index 0000000..a3726c3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/he.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'he', {
6 copy: 'העתקה',
7 copyError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות העתקה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+C).',
8 cut: 'גזירה',
9 cutError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות גזירה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+X).',
10 paste: 'הדבקה',
11 pasteArea: 'איזור הדבקה',
12 pasteMsg: 'נא להדביק בתוך הקופסה באמצעות (<b>Ctrl/Cmd+V</b>) וללחוץ על <b>אישור</b>.',
13 securityMsg: 'עקב הגדרות אבטחה בדפדפן, לא ניתן לגשת אל לוח הגזירים (Clipboard) בצורה ישירה. נא להדביק שוב בחלון זה.',
14 title: 'הדבקה'
15} );
diff --git a/sources/plugins/clipboard/lang/hi.js b/sources/plugins/clipboard/lang/hi.js
new file mode 100644
index 0000000..738b0b9
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hi.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hi', {
6 copy: 'कॉपी',
7 copyError: 'आपके ब्राआउज़र की सुरक्षा सॅटिन्ग्स ने कॉपी करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+C) का प्रयोग करें।',
8 cut: 'कट',
9 cutError: 'आपके ब्राउज़र की सुरक्षा सॅटिन्ग्स ने कट करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+X) का प्रयोग करें।',
10 paste: 'पेस्ट',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Ctrl/Cmd+V का प्रयोग करके पेस्ट करें और ठीक है करें.',
13 securityMsg: 'आपके ब्राउज़र की सुरक्षा आपके ब्राउज़र की सुरKश सैटिंग के कारण, एडिटर आपके क्लिपबोर्ड डेटा को नहीं पा सकता है. आपको उसे इस विन्डो में दोबारा पेस्ट करना होगा.',
14 title: 'पेस्ट'
15} );
diff --git a/sources/plugins/clipboard/lang/hr.js b/sources/plugins/clipboard/lang/hr.js
new file mode 100644
index 0000000..7366069
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hr.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hr', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog izrezivanja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+X).',
10 paste: 'Zalijepi',
11 pasteArea: 'Prostor za ljepljenje',
12 pasteMsg: 'Molimo zaljepite unutar doljnjeg okvira koristeći tipkovnicu (<STRONG>Ctrl/Cmd+V</STRONG>) i kliknite <STRONG>OK</STRONG>.',
13 securityMsg: 'Zbog sigurnosnih postavki Vašeg pretraživača, editor nema direktan pristup Vašem međuspremniku. Potrebno je ponovno zalijepiti tekst u ovaj prozor.',
14 title: 'Zalijepi'
15} );
diff --git a/sources/plugins/clipboard/lang/hu.js b/sources/plugins/clipboard/lang/hu.js
new file mode 100644
index 0000000..b124e35
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hu.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hu', {
6 copy: 'Másolás',
7 copyError: 'A böngésző biztonsági beállításai nem engedélyezik a szerkesztőnek, hogy végrehajtsa a másolás műveletet. Használja az alábbi billentyűkombinációt (Ctrl/Cmd+X).',
8 cut: 'Kivágás',
9 cutError: 'A böngésző biztonsági beállításai nem engedélyezik a szerkesztőnek, hogy végrehajtsa a kivágás műveletet. Használja az alábbi billentyűkombinációt (Ctrl/Cmd+X).',
10 paste: 'Beillesztés',
11 pasteArea: 'Beszúrás mező',
12 pasteMsg: 'Másolja be az alábbi mezőbe a <STRONG>Ctrl/Cmd+V</STRONG> billentyűk lenyomásával, majd nyomjon <STRONG>Rendben</STRONG>-t.',
13 securityMsg: 'A böngésző biztonsági beállításai miatt a szerkesztő nem képes hozzáférni a vágólap adataihoz. Illeszd be újra ebben az ablakban.',
14 title: 'Beillesztés'
15} );
diff --git a/sources/plugins/clipboard/lang/id.js b/sources/plugins/clipboard/lang/id.js
new file mode 100644
index 0000000..e7b40ad
--- /dev/null
+++ b/sources/plugins/clipboard/lang/id.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'id', {
6 copy: 'Salin',
7 copyError: 'Pengaturan keamanan peramban anda tidak mengizinkan editor untuk mengeksekusi operasi menyalin secara otomatis. Mohon gunakan papan tuts (Ctrl/Cmd+C)',
8 cut: 'Potong',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).', // MISSING
10 paste: 'Tempel',
11 pasteArea: 'Area Tempel',
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK', // MISSING
13 securityMsg: 'Karena pengaturan keamanan peramban anda, editor tida dapat mengakses data clipboard anda secara langsung. Anda harus mem-paste kembali pada halaman ini',
14 title: 'Tempel'
15} );
diff --git a/sources/plugins/clipboard/lang/is.js b/sources/plugins/clipboard/lang/is.js
new file mode 100644
index 0000000..6b36cef
--- /dev/null
+++ b/sources/plugins/clipboard/lang/is.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'is', {
6 copy: 'Afrita',
7 copyError: 'Öryggisstillingar vafrans þíns leyfa ekki afritun texta með músaraðgerð. Notaðu lyklaborðið í afrita (Ctrl/Cmd+C).',
8 cut: 'Klippa',
9 cutError: 'Öryggisstillingar vafrans þíns leyfa ekki klippingu texta með músaraðgerð. Notaðu lyklaborðið í klippa (Ctrl/Cmd+X).',
10 paste: 'Líma',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Límdu í svæðið hér að neðan og (<STRONG>Ctrl/Cmd+V</STRONG>) og smelltu á <STRONG>OK</STRONG>.',
13 securityMsg: 'Vegna öryggisstillinga í vafranum þínum fær ritillinn ekki beinan aðgang að klippuborðinu. Þú verður að líma innihaldið aftur inn í þennan glugga.',
14 title: 'Líma'
15} );
diff --git a/sources/plugins/clipboard/lang/it.js b/sources/plugins/clipboard/lang/it.js
new file mode 100644
index 0000000..21f8815
--- /dev/null
+++ b/sources/plugins/clipboard/lang/it.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'it', {
6 copy: 'Copia',
7 copyError: 'Le impostazioni di sicurezza del browser non permettono di copiare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+C).',
8 cut: 'Taglia',
9 cutError: 'Le impostazioni di sicurezza del browser non permettono di tagliare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+X).',
10 paste: 'Incolla',
11 pasteArea: 'Incolla',
12 pasteMsg: 'Incolla il testo all\'interno dell\'area sottostante usando la scorciatoia di tastiere (<STRONG>Ctrl/Cmd+V</STRONG>) e premi <STRONG>OK</STRONG>.',
13 securityMsg: 'A causa delle impostazioni di sicurezza del browser,l\'editor non è in grado di accedere direttamente agli appunti. E\' pertanto necessario incollarli di nuovo in questa finestra.',
14 title: 'Incolla'
15} );
diff --git a/sources/plugins/clipboard/lang/ja.js b/sources/plugins/clipboard/lang/ja.js
new file mode 100644
index 0000000..f099380
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ja.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ja', {
6 copy: 'コピー',
7 copyError: 'ブラウザーのセキュリティ設定によりエディタのコピー操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+C)を使用してください。',
8 cut: '切り取り',
9 cutError: 'ブラウザーのセキュリティ設定によりエディタの切り取り操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+X)を使用してください。',
10 paste: '貼り付け',
11 pasteArea: '貼り付け場所',
12 pasteMsg: 'キーボード(<STRONG>Ctrl/Cmd+V</STRONG>)を使用して、次の入力エリア内で貼り付けて、<STRONG>OK</STRONG>を押してください。',
13 securityMsg: 'ブラウザのセキュリティ設定により、エディタはクリップボードデータに直接アクセスすることができません。このウィンドウは貼り付け操作を行う度に表示されます。',
14 title: '貼り付け'
15} );
diff --git a/sources/plugins/clipboard/lang/ka.js b/sources/plugins/clipboard/lang/ka.js
new file mode 100644
index 0000000..e1af8cb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ka.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ka', {
6 copy: 'ასლი',
7 copyError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ასლის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+C).',
8 cut: 'ამოჭრა',
9 cutError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ამოჭრის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+X).',
10 paste: 'ჩასმა',
11 pasteArea: 'ჩასმის არე',
12 pasteMsg: 'ჩასვით ამ არის შიგნით კლავიატურის გამოყენებით (<strong>Ctrl/Cmd+V</strong>) და დააჭირეთ OK-ს',
13 securityMsg: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა clipboard-ის მონაცემების წვდომის უფლებას. კიდევ უნდა ჩასვათ ტექსტი ამ ფანჯარაში.',
14 title: 'ჩასმა'
15} );
diff --git a/sources/plugins/clipboard/lang/km.js b/sources/plugins/clipboard/lang/km.js
new file mode 100644
index 0000000..32c30cb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/km.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'km', {
6 copy: 'ចម្លង',
7 copyError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះ​មិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ ចំលងអត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+C)។',
8 cut: 'កាត់យក',
9 cutError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះ​មិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ កាត់អត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+X) ។',
10 paste: 'បិទ​ភ្ជាប់',
11 pasteArea: 'តំបន់​បិទ​ភ្ជាប់',
12 pasteMsg: 'សូមចំលងអត្ថបទទៅដាក់ក្នុងប្រអប់ដូចខាងក្រោមដោយប្រើប្រាស់ ឃី ​(<STRONG>Ctrl/Cmd+V</STRONG>) ហើយចុច <STRONG>OK</STRONG> ។',
13 securityMsg: 'ព្រោះតែ​ការកំណត់​សុវត្ថិភាព ប្រអប់សរសេរ​មិន​អាចចាប់​យកទិន្នន័យពីក្តារតម្បៀតខ្ទាស់​អ្នក​​ដោយផ្ទាល់​បានទេ។ អ្នក​ត្រូវចំលង​ដាក់វាម្តង​ទៀត ក្នុងផ្ទាំងនេះ។',
14 title: 'បិទ​ភ្ជាប់'
15} );
diff --git a/sources/plugins/clipboard/lang/ko.js b/sources/plugins/clipboard/lang/ko.js
new file mode 100644
index 0000000..0a0d1e9
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ko.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ko', {
6 copy: '복사',
7 copyError: '브라우저의 보안설정 때문에 복사할 수 없습니다. 키보드(Ctrl/Cmd+C)를 이용해서 복사하십시오.',
8 cut: '잘라내기',
9 cutError: '브라우저의 보안설정 때문에 잘라내기 기능을 실행할 수 없습니다. 키보드(Ctrl/Cmd+X)를 이용해서 잘라내기 하십시오',
10 paste: '붙여넣기',
11 pasteArea: '붙여넣기 범위',
12 pasteMsg: '키보드(<strong>Ctrl/Cmd+V</strong>)를 이용해서 상자안에 붙여넣고 <strong>확인</strong> 를 누르세요.',
13 securityMsg: '브라우저 보안 설정으로 인해, 클립보드에 직접 접근할 수 없습니다. 이 창에 다시 붙여넣기 하십시오.',
14 title: '붙여넣기'
15} );
diff --git a/sources/plugins/clipboard/lang/ku.js b/sources/plugins/clipboard/lang/ku.js
new file mode 100644
index 0000000..86e1778
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ku.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ku', {
6 copy: 'لەبەرگرتنەوە',
7 copyError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بەسەرنووسەکە لە لکاندنی دەقی خۆکارارنە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+C).',
8 cut: 'بڕین',
9 cutError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بە سەرنووسەکە لەبڕینی خۆکارانە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+X).',
10 paste: 'لکاندن',
11 pasteArea: 'ناوچەی لکاندن',
12 pasteMsg: 'تکایە بیلکێنە لەناوەوەی ئەم سنوقە لەڕێی تەختەکلیلەکەت بە بەکارهێنانی کلیلی (<STRONG>Ctrl/Cmd+V</STRONG>) دووای کلیکی باشە بکە.',
13 securityMsg: 'بەهۆی شێوەپێدانی پارێزی وێبگەڕەکەت، سەرنووسەکه ناتوانێت دەستبگەیەنێت بەهەڵگیراوەکە ڕاستەوخۆ. بۆیه پێویسته دووباره بیلکێنیت لەم پەنجەرەیه.',
14 title: 'لکاندن'
15} );
diff --git a/sources/plugins/clipboard/lang/lt.js b/sources/plugins/clipboard/lang/lt.js
new file mode 100644
index 0000000..86ecbbb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lt.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'lt', {
6 copy: 'Kopijuoti',
7 copyError: 'Jūsų naršyklės saugumo nustatymai neleidžia redaktoriui automatiškai įvykdyti kopijavimo operacijų. Tam prašome naudoti klaviatūrą (Ctrl/Cmd+C).',
8 cut: 'Iškirpti',
9 cutError: 'Jūsų naršyklės saugumo nustatymai neleidžia redaktoriui automatiškai įvykdyti iškirpimo operacijų. Tam prašome naudoti klaviatūrą (Ctrl/Cmd+X).',
10 paste: 'Įdėti',
11 pasteArea: 'Įkelti dalį',
12 pasteMsg: 'Žemiau esančiame įvedimo lauke įdėkite tekstą, naudodami klaviatūrą (<STRONG>Ctrl/Cmd+V</STRONG>) ir paspauskite mygtuką <STRONG>OK</STRONG>.',
13 securityMsg: 'Dėl jūsų naršyklės saugumo nustatymų, redaktorius negali tiesiogiai pasiekti laikinosios atminties. Jums reikia nukopijuoti dar kartą į šį langą.',
14 title: 'Įdėti'
15} );
diff --git a/sources/plugins/clipboard/lang/lv.js b/sources/plugins/clipboard/lang/lv.js
new file mode 100644
index 0000000..c762fc6
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lv.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'lv', {
6 copy: 'Kopēt',
7 copyError: 'Jūsu pārlūkprogrammas drošības iestatījumi nepieļauj redaktoram automātiski veikt kopēšanas darbību. Lūdzu, izmantojiet (Ctrl/Cmd+C), lai veiktu šo darbību.',
8 cut: 'Izgriezt',
9 cutError: 'Jūsu pārlūkprogrammas drošības iestatījumi nepieļauj redaktoram automātiski veikt izgriezšanas darbību. Lūdzu, izmantojiet (Ctrl/Cmd+X), lai veiktu šo darbību.',
10 paste: 'Ielīmēt',
11 pasteArea: 'Ielīmēšanas zona',
12 pasteMsg: 'Lūdzu, ievietojiet tekstu šajā laukumā, izmantojot klaviatūru (<STRONG>Ctrl/Cmd+V</STRONG>) un apstipriniet ar <STRONG>Darīts!</STRONG>.',
13 securityMsg: 'Jūsu pārlūka drošības uzstādījumu dēļ, nav iespējams tieši piekļūt jūsu starpliktuvei. Jums jāielīmē atkārtoti šajā logā.',
14 title: 'Ievietot'
15} );
diff --git a/sources/plugins/clipboard/lang/mk.js b/sources/plugins/clipboard/lang/mk.js
new file mode 100644
index 0000000..eb16066
--- /dev/null
+++ b/sources/plugins/clipboard/lang/mk.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'mk', {
6 copy: 'Копирај (Copy)',
7 copyError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши копирање. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
8 cut: 'Исечи (Cut)',
9 cutError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши сечење. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
10 paste: 'Залепи (Paste)',
11 pasteArea: 'Простор за залепување',
12 pasteMsg: 'Ве молиме да залепите во следниот квадрат користејќи ја тастатурата (<string>Ctrl/Cmd+V</string>) и да притиснете OK',
13 securityMsg: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот директно да пристапи до копираните податоци. Потребно е повторно да се обидете во овој прозорец.',
14 title: 'Залепи (Paste)'
15} );
diff --git a/sources/plugins/clipboard/lang/mn.js b/sources/plugins/clipboard/lang/mn.js
new file mode 100644
index 0000000..5351941
--- /dev/null
+++ b/sources/plugins/clipboard/lang/mn.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'mn', {
6 copy: 'Хуулах',
7 copyError: 'Таны browser-ын хамгаалалтын тохиргоо editor-д автоматаар хуулах үйлдэлийг зөвшөөрөхгүй байна. (Ctrl/Cmd+C) товчны хослолыг ашиглана уу.',
8 cut: 'Хайчлах',
9 cutError: 'Таны browser-ын хамгаалалтын тохиргоо editor-д автоматаар хайчлах үйлдэлийг зөвшөөрөхгүй байна. (Ctrl/Cmd+X) товчны хослолыг ашиглана уу.',
10 paste: 'Буулгах',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: '(<strong>Ctrl/Cmd+V</strong>) товчийг ашиглан paste хийнэ үү. Мөн <strong>OK</strong> дар.',
13 securityMsg: 'Таны үзүүлэгч/browser/-н хамгаалалтын тохиргооноос болоод editor clipboard өгөгдөлрүү шууд хандах боломжгүй. Энэ цонход дахин paste хийхийг оролд.',
14 title: 'Буулгах'
15} );
diff --git a/sources/plugins/clipboard/lang/ms.js b/sources/plugins/clipboard/lang/ms.js
new file mode 100644
index 0000000..3a01be4
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ms.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ms', {
6 copy: 'Salin',
7 copyError: 'Keselamatan perisian browser anda tidak membenarkan operasi salinan text/imej. Sila gunakan papan kekunci (Ctrl/Cmd+C).',
8 cut: 'Potong',
9 cutError: 'Keselamatan perisian browser anda tidak membenarkan operasi suntingan text/imej. Sila gunakan papan kekunci (Ctrl/Cmd+X).',
10 paste: 'Tampal',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK', // MISSING
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'Tampal'
15} );
diff --git a/sources/plugins/clipboard/lang/nb.js b/sources/plugins/clipboard/lang/nb.js
new file mode 100644
index 0000000..5355b8a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/nb.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'nb', {
6 copy: 'Kopier',
7 copyError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk kopiering av tekst. Vennligst bruk tastatursnarveien (Ctrl/Cmd+C).',
8 cut: 'Klipp ut',
9 cutError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk utklipping av tekst. Vennligst bruk tastatursnarveien (Ctrl/Cmd+X).',
10 paste: 'Lim inn',
11 pasteArea: 'Innlimingsområde',
12 pasteMsg: 'Vennligst lim inn i følgende boks med tastaturet (<strong>Ctrl/Cmd+V</strong>) og trykk <strong>OK</strong>.',
13 securityMsg: 'Din nettlesers sikkerhetsinstillinger gir ikke redigeringsverktøyet direkte tilgang til utklippstavlen. Du må derfor lime det inn på nytt i dette vinduet.',
14 title: 'Lim inn'
15} );
diff --git a/sources/plugins/clipboard/lang/nl.js b/sources/plugins/clipboard/lang/nl.js
new file mode 100644
index 0000000..bae806f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/nl.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'nl', {
6 copy: 'Kopiëren',
7 copyError: 'De beveiligingsinstelling van de browser verhinderen het automatisch kopiëren. Gebruik de sneltoets Ctrl/Cmd+C van het toetsenbord.',
8 cut: 'Knippen',
9 cutError: 'De beveiligingsinstelling van de browser verhinderen het automatisch knippen. Gebruik de sneltoets Ctrl/Cmd+X van het toetsenbord.',
10 paste: 'Plakken',
11 pasteArea: 'Plakgebied',
12 pasteMsg: 'Plak de tekst in het volgende vak gebruikmakend van uw toetsenbord (<strong>Ctrl/Cmd+V</strong>) en klik op OK.',
13 securityMsg: 'Door de beveiligingsinstellingen van uw browser is het niet mogelijk om direct vanuit het klembord in de editor te plakken. Middels opnieuw plakken in dit venster kunt u de tekst alsnog plakken in de editor.',
14 title: 'Plakken'
15} );
diff --git a/sources/plugins/clipboard/lang/no.js b/sources/plugins/clipboard/lang/no.js
new file mode 100644
index 0000000..e8c48da
--- /dev/null
+++ b/sources/plugins/clipboard/lang/no.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'no', {
6 copy: 'Kopier',
7 copyError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk kopiering av tekst. Vennligst bruk snarveien (Ctrl/Cmd+C).',
8 cut: 'Klipp ut',
9 cutError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk utklipping av tekst. Vennligst bruk snarveien (Ctrl/Cmd+X).',
10 paste: 'Lim inn',
11 pasteArea: 'Innlimingsområde',
12 pasteMsg: 'Vennligst lim inn i følgende boks med tastaturet (<STRONG>Ctrl/Cmd+V</STRONG>) og trykk <STRONG>OK</STRONG>.',
13 securityMsg: 'Din nettlesers sikkerhetsinstillinger gir ikke redigeringsverktøyet direkte tilgang til utklippstavlen. Du må derfor lime det inn på nytt i dette vinduet.',
14 title: 'Lim inn'
15} );
diff --git a/sources/plugins/clipboard/lang/oc.js b/sources/plugins/clipboard/lang/oc.js
new file mode 100644
index 0000000..e9e78cd
--- /dev/null
+++ b/sources/plugins/clipboard/lang/oc.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'oc', {
6 copy: 'Copiar',
7 copyError: 'Los paramètres de seguretat de vòstre navigador autorizan pas l\'editor a executar automaticament l\'operacion « Copiar ». Utilizatz l\'acorchi de clavièr a aqueste efièit (Ctrl/Cmd+C).',
8 cut: 'Talhar',
9 cutError: 'Los paramètres de seguretat de vòstre navigador autorizan pas l\'editor a executar automaticament l\'operacion « Talhar ». Utilizatz l\'acorchi de clavièr a aqueste efièit (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteArea: 'Pegar la zòna',
12 pasteMsg: 'Pegatz lo tèxte dins la zòna seguenta en utilizant l\'acorchi de clavièr (<strong>Ctrl/Cmd+V</strong>) e clicatz sus D\'acòrdi.',
13 securityMsg: 'Los paramètres de seguretat de vòstre navigador empach l\'editor d\'accedir dirèctament a las donadas del quichapapièr. Las vos cal pegar tornamai dins aquesta fenèstra.',
14 title: 'Pegar'
15} );
diff --git a/sources/plugins/clipboard/lang/pl.js b/sources/plugins/clipboard/lang/pl.js
new file mode 100644
index 0000000..e2ccd16
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pl.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pl', {
6 copy: 'Kopiuj',
7 copyError: 'Ustawienia bezpieczeństwa Twojej przeglądarki nie pozwalają na automatyczne kopiowanie tekstu. Użyj skrótu klawiszowego Ctrl/Cmd+C.',
8 cut: 'Wytnij',
9 cutError: 'Ustawienia bezpieczeństwa Twojej przeglądarki nie pozwalają na automatyczne wycinanie tekstu. Użyj skrótu klawiszowego Ctrl/Cmd+X.',
10 paste: 'Wklej',
11 pasteArea: 'Obszar wklejania',
12 pasteMsg: 'Wklej tekst w poniższym polu, używając skrótu klawiaturowego (<STRONG>Ctrl/Cmd+V</STRONG>), i kliknij <STRONG>OK</STRONG>.',
13 securityMsg: 'Zabezpieczenia przeglądarki uniemożliwiają wklejenie danych bezpośrednio do edytora. Proszę ponownie wkleić dane w tym oknie.',
14 title: 'Wklej'
15} );
diff --git a/sources/plugins/clipboard/lang/pt-br.js b/sources/plugins/clipboard/lang/pt-br.js
new file mode 100644
index 0000000..74608ba
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pt-br.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pt-br', {
6 copy: 'Copiar',
7 copyError: 'As configurações de segurança do seu navegador não permitem que o editor execute operações de copiar automaticamente. Por favor, utilize o teclado para copiar (Ctrl/Cmd+C).',
8 cut: 'Recortar',
9 cutError: 'As configurações de segurança do seu navegador não permitem que o editor execute operações de recortar automaticamente. Por favor, utilize o teclado para recortar (Ctrl/Cmd+X).',
10 paste: 'Colar',
11 pasteArea: 'Área para Colar',
12 pasteMsg: 'Transfira o link usado na caixa usando o teclado com (<STRONG>Ctrl/Cmd+V</STRONG>) e <STRONG>OK</STRONG>.',
13 securityMsg: 'As configurações de segurança do seu navegador não permitem que o editor acesse os dados da área de transferência diretamente. Por favor cole o conteúdo manualmente nesta janela.',
14 title: 'Colar'
15} );
diff --git a/sources/plugins/clipboard/lang/pt.js b/sources/plugins/clipboard/lang/pt.js
new file mode 100644
index 0000000..623ce06
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pt.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pt', {
6 copy: 'Copiar',
7 copyError: 'A configuração de segurança do navegador não permite a execução automática de operações de copiar. Por favor use o teclado (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'A configuração de segurança do navegador não permite a execução automática de operações de cortar. Por favor use o teclado (Ctrl/Cmd+X).',
10 paste: 'Colar',
11 pasteArea: 'Colar área',
12 pasteMsg: 'Por favor, cole dentro da seguinte caixa usando o teclado (<STRONG>Ctrl/Cmd+V</STRONG>) e carregue em <STRONG>OK</STRONG>.',
13 securityMsg: 'Devido ás definições de segurança do teu browser, o editor não pode aceder ao clipboard diretamente. É necessário que voltes a colar as informações nesta janela.',
14 title: 'Colar'
15} );
diff --git a/sources/plugins/clipboard/lang/ro.js b/sources/plugins/clipboard/lang/ro.js
new file mode 100644
index 0000000..1e57798
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ro.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ro', {
6 copy: 'Copiază',
7 copyError: 'Setările de securitate ale navigatorului (browser) pe care îl folosiţi nu permit editorului să execute automat operaţiunea de copiere. Vă rugăm folosiţi tastatura (Ctrl/Cmd+C).',
8 cut: 'Taie',
9 cutError: 'Setările de securitate ale navigatorului (browser) pe care îl folosiţi nu permit editorului să execute automat operaţiunea de tăiere. Vă rugăm folosiţi tastatura (Ctrl/Cmd+X).',
10 paste: 'Adaugă',
11 pasteArea: 'Suprafața de adăugare',
12 pasteMsg: 'Vă rugăm adăugaţi în căsuţa următoare folosind tastatura (<strong>Ctrl/Cmd+V</strong>) şi apăsaţi OK',
13 securityMsg: 'Din cauza setărilor de securitate ale programului dvs. cu care navigaţi pe internet (browser), editorul nu poate accesa direct datele din clipboard. Va trebui să adăugaţi din nou datele în această fereastră.',
14 title: 'Adaugă'
15} );
diff --git a/sources/plugins/clipboard/lang/ru.js b/sources/plugins/clipboard/lang/ru.js
new file mode 100644
index 0000000..d9b4d58
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ru.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ru', {
6 copy: 'Копировать',
7 copyError: 'Настройки безопасности вашего браузера не разрешают редактору выполнять операции по копированию текста. Пожалуйста, используйте для этого клавиатуру (Ctrl/Cmd+C).',
8 cut: 'Вырезать',
9 cutError: 'Настройки безопасности вашего браузера не разрешают редактору выполнять операции по вырезке текста. Пожалуйста, используйте для этого клавиатуру (Ctrl/Cmd+X).',
10 paste: 'Вставить',
11 pasteArea: 'Зона для вставки',
12 pasteMsg: 'Пожалуйста, вставьте текст в зону ниже, используя клавиатуру (<strong>Ctrl/Cmd+V</strong>) и нажмите кнопку "OK".',
13 securityMsg: 'Настройки безопасности вашего браузера не разрешают редактору напрямую обращаться к буферу обмена. Вы должны вставить текст снова в это окно.',
14 title: 'Вставить'
15} );
diff --git a/sources/plugins/clipboard/lang/si.js b/sources/plugins/clipboard/lang/si.js
new file mode 100644
index 0000000..8430d01
--- /dev/null
+++ b/sources/plugins/clipboard/lang/si.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'si', {
6 copy: 'පිටපත් කරන්න',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).', // MISSING
8 cut: 'කපාගන්න',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).', // MISSING
10 paste: 'අලවන්න',
11 pasteArea: 'අලවන ප්‍රදේශ',
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK', // MISSING
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'අලවන්න'
15} );
diff --git a/sources/plugins/clipboard/lang/sk.js b/sources/plugins/clipboard/lang/sk.js
new file mode 100644
index 0000000..6b2b4f4
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sk.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sk', {
6 copy: 'Kopírovať',
7 copyError: 'Bezpečnostné nastavenia vášho prehliadača nedovoľujú editoru automaticky spustiť operáciu kopírovania. Použite na to klávesnicu (Ctrl/Cmd+C).',
8 cut: 'Vystrihnúť',
9 cutError: 'Bezpečnostné nastavenia vášho prehliadača nedovoľujú editoru automaticky spustiť operáciu vystrihnutia. Použite na to klávesnicu (Ctrl/Cmd+X).',
10 paste: 'Vložiť',
11 pasteArea: 'Miesto na vloženie',
12 pasteMsg: 'Použitím klávesnice (<STRONG>Ctrl/Cmd+V</STRONG>) vložte text do rámčeka a stlačte OK.',
13 securityMsg: 'Kvôli bezpečnostným nastaveniam vášho prehliadača editor nemôže pristupovať k schránke na kopírovanie priamo. Vložte to preto do tohto okna.',
14 title: 'Vložiť'
15} );
diff --git a/sources/plugins/clipboard/lang/sl.js b/sources/plugins/clipboard/lang/sl.js
new file mode 100644
index 0000000..3ddc89e
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sl.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sl', {
6 copy: 'Kopiraj',
7 copyError: 'Varnostne nastavitve brskalnika ne dopuščajo samodejnega kopiranja. Uporabite kombinacijo tipk na tipkovnici (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Varnostne nastavitve brskalnika ne dopuščajo samodejnega izrezovanja. Uporabite kombinacijo tipk na tipkovnici (Ctrl/Cmd+X).',
10 paste: 'Prilepi',
11 pasteArea: 'Prilepi območje',
12 pasteMsg: 'Prosimo, prilepite v sleči okvir s pomočjo tipkovnice (<strong>Ctrl/Cmd+V</strong>) in pritisnite V redu.',
13 securityMsg: 'Zaradi varnostnih nastavitev vašega brskalnika urejevalnik ne more neposredno dostopati do odložišča. Vsebino odložišča ponovno prilepite v to okno.',
14 title: 'Prilepi'
15} );
diff --git a/sources/plugins/clipboard/lang/sq.js b/sources/plugins/clipboard/lang/sq.js
new file mode 100644
index 0000000..eda22e7
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sq.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sq', {
6 copy: 'Kopjo',
7 copyError: 'Të dhënat e sigurisë së shfletuesit tuaj nuk lejojnë që redaktuesi automatikisht të kryej veprimin e kopjimit. Ju lutemi shfrytëzoni tastierën për këtë veprim (Ctrl/Cmd+C).',
8 cut: 'Preje',
9 cutError: 'Të dhënat e sigurisë së shfletuesit tuaj nuk lejojnë që redaktuesi automatikisht të kryej veprimin e prerjes. Ju lutemi shfrytëzoni tastierën për këtë veprim (Ctrl/Cmd+X).',
10 paste: 'Hidhe',
11 pasteArea: 'Hapësira Hedhëse',
12 pasteMsg: 'Ju lutemi hidhni brenda kutizës në vijim duke shfrytëzuar tastierën (<strong>Ctrl/Cmd+V</strong>) dhe shtypni Mirë.',
13 securityMsg: 'Për shkak të dhënave të sigurisë së shfletuesit tuaj, redaktuesi nuk është në gjendje të i qaset drejtpërdrejtë të dhanve të tabelës suaj të punës. Ju duhet të hidhni atë përsëri në këtë dritare.',
14 title: 'Hidhe'
15} );
diff --git a/sources/plugins/clipboard/lang/sr-latn.js b/sources/plugins/clipboard/lang/sr-latn.js
new file mode 100644
index 0000000..52102f6
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sr-latn.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sr-latn', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosna podešavanja Vašeg pretraživača ne dozvoljavaju operacije automatskog kopiranja teksta. Molimo Vas da koristite prečicu sa tastature (Ctrl/Cmd+C).',
8 cut: 'Iseci',
9 cutError: 'Sigurnosna podešavanja Vašeg pretraživača ne dozvoljavaju operacije automatskog isecanja teksta. Molimo Vas da koristite prečicu sa tastature (Ctrl/Cmd+X).',
10 paste: 'Zalepi',
11 pasteArea: 'Prostor za lepljenje',
12 pasteMsg: 'Molimo Vas da zalepite unutar donje povrine koristeći tastaturnu prečicu (<STRONG>Ctrl/Cmd+V</STRONG>) i da pritisnete <STRONG>OK</STRONG>.',
13 securityMsg: 'Zbog sigurnosnih postavki vašeg pregledača, editor nije u mogućnosti da direktno pristupi podacima u klipbordu. Potrebno je da zalepite još jednom u ovom prozoru.',
14 title: 'Zalepi'
15} );
diff --git a/sources/plugins/clipboard/lang/sr.js b/sources/plugins/clipboard/lang/sr.js
new file mode 100644
index 0000000..c59ff1f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sr.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sr', {
6 copy: 'Копирај',
7 copyError: 'Сигурносна подешавања Вашег претраживача не дозвољавају операције аутоматског копирања текста. Молимо Вас да користите пречицу са тастатуре (Ctrl/Cmd+C).',
8 cut: 'Исеци',
9 cutError: 'Сигурносна подешавања Вашег претраживача не дозвољавају операције аутоматског исецања текста. Молимо Вас да користите пречицу са тастатуре (Ctrl/Cmd+X).',
10 paste: 'Залепи',
11 pasteArea: 'Залепи зону',
12 pasteMsg: 'Молимо Вас да залепите унутар доње површине користећи тастатурну пречицу (<STRONG>Ctrl/Cmd+V</STRONG>) и да притиснете <STRONG>OK</STRONG>.',
13 securityMsg: 'Због сигурносних подешавања претраживача, едитор не може да приступи оставу. Требате да га поново залепите у овом прозору.',
14 title: 'Залепи'
15} );
diff --git a/sources/plugins/clipboard/lang/sv.js b/sources/plugins/clipboard/lang/sv.js
new file mode 100644
index 0000000..9663daa
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sv.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sv', {
6 copy: 'Kopiera',
7 copyError: 'Säkerhetsinställningar i Er webbläsare tillåter inte åtgärden kopiera. Använd (Ctrl/Cmd+C) istället.',
8 cut: 'Klipp ut',
9 cutError: 'Säkerhetsinställningar i Er webbläsare tillåter inte åtgärden klipp ut. Använd (Ctrl/Cmd+X) istället.',
10 paste: 'Klistra in',
11 pasteArea: 'Paste Area',
12 pasteMsg: 'Var god och klistra in Er text i rutan nedan genom att använda (<strong>Ctrl/Cmd+V</strong>) klicka sen på OK.',
13 securityMsg: 'På grund av din webbläsares säkerhetsinställningar kan verktyget inte få åtkomst till urklippsdatan. Var god och använd detta fönster istället.',
14 title: 'Klistra in'
15} );
diff --git a/sources/plugins/clipboard/lang/th.js b/sources/plugins/clipboard/lang/th.js
new file mode 100644
index 0000000..29664a6
--- /dev/null
+++ b/sources/plugins/clipboard/lang/th.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'th', {
6 copy: 'สำเนา',
7 copyError: 'ไม่สามารถสำเนาข้อความที่เลือกไว้ได้เนื่องจากการกำหนดค่าระดับความปลอดภัย. กรุณาใช้ปุ่มลัดเพื่อวางข้อความแทน (กดปุ่ม Ctrl/Cmd และตัว C พร้อมกัน).',
8 cut: 'ตัด',
9 cutError: 'ไม่สามารถตัดข้อความที่เลือกไว้ได้เนื่องจากการกำหนดค่าระดับความปลอดภัย. กรุณาใช้ปุ่มลัดเพื่อวางข้อความแทน (กดปุ่ม Ctrl/Cmd และตัว X พร้อมกัน).',
10 paste: 'วาง',
11 pasteArea: 'Paste Area', // MISSING
12 pasteMsg: 'กรุณาใช้คีย์บอร์ดเท่านั้น โดยกดปุ๋ม (<strong>Ctrl/Cmd และ V</strong>)พร้อมๆกัน และกด <strong>OK</strong>.',
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'วาง'
15} );
diff --git a/sources/plugins/clipboard/lang/tr.js b/sources/plugins/clipboard/lang/tr.js
new file mode 100644
index 0000000..a60ddc7
--- /dev/null
+++ b/sources/plugins/clipboard/lang/tr.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'tr', {
6 copy: 'Kopyala',
7 copyError: 'Gezgin yazılımınızın güvenlik ayarları düzenleyicinin otomatik kopyalama işlemine izin vermiyor. İşlem için (Ctrl/Cmd+C) tuşlarını kullanın.',
8 cut: 'Kes',
9 cutError: 'Gezgin yazılımınızın güvenlik ayarları düzenleyicinin otomatik kesme işlemine izin vermiyor. İşlem için (Ctrl/Cmd+X) tuşlarını kullanın.',
10 paste: 'Yapıştır',
11 pasteArea: 'Yapıştırma Alanı',
12 pasteMsg: 'Lütfen aşağıdaki kutunun içine yapıştırın. (<STRONG>Ctrl/Cmd+V</STRONG>) ve <STRONG>Tamam</STRONG> butonunu tıklayın.',
13 securityMsg: 'Gezgin yazılımınızın güvenlik ayarları düzenleyicinin direkt olarak panoya erişimine izin vermiyor. Bu pencere içine tekrar yapıştırmalısınız..',
14 title: 'Yapıştır'
15} );
diff --git a/sources/plugins/clipboard/lang/tt.js b/sources/plugins/clipboard/lang/tt.js
new file mode 100644
index 0000000..e4b0537
--- /dev/null
+++ b/sources/plugins/clipboard/lang/tt.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'tt', {
6 copy: 'Күчермәләү',
7 copyError: 'Браузерыгызның иминлек үзлекләре автоматик рәвештә күчермәләү үтәүне тыя. Тиз төймәләрне (Ctrl/Cmd+C) кулланыгыз.',
8 cut: 'Кисеп алу',
9 cutError: 'Браузерыгызның иминлек үзлекләре автоматик рәвештә күчермәләү үтәүне тыя. Тиз төймәләрне (Ctrl/Cmd+C) кулланыгыз.',
10 paste: 'Өстәү',
11 pasteArea: 'Өстәү мәйданы',
12 pasteMsg: 'Please paste inside the following box using the keyboard (<strong>Ctrl/Cmd+V</strong>) and hit OK', // MISSING
13 securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.', // MISSING
14 title: 'Өстәү'
15} );
diff --git a/sources/plugins/clipboard/lang/ug.js b/sources/plugins/clipboard/lang/ug.js
new file mode 100644
index 0000000..dcdf29c
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ug.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ug', {
6 copy: 'كۆچۈر',
7 copyError: 'تور كۆرگۈڭىزنىڭ بىخەتەرلىك تەڭشىكى تەھرىرلىگۈچنىڭ كۆچۈر مەشغۇلاتىنى ئۆزلۈكىدىن ئىجرا قىلىشىغا يول قويمايدۇ، ھەرپتاختا تېز كۇنۇپكا (Ctrl/Cmd+C) ئارقىلىق تاماملاڭ',
8 cut: 'كەس',
9 cutError: 'تور كۆرگۈڭىزنىڭ بىخەتەرلىك تەڭشىكى تەھرىرلىگۈچنىڭ كەس مەشغۇلاتىنى ئۆزلۈكىدىن ئىجرا قىلىشىغا يول قويمايدۇ، ھەرپتاختا تېز كۇنۇپكا (Ctrl/Cmd+X) ئارقىلىق تاماملاڭ',
10 paste: 'چاپلا',
11 pasteArea: 'چاپلاش دائىرىسى',
12 pasteMsg: 'ھەرپتاختا تېز كۇنۇپكا (<STRONG>Ctrl/Cmd+V</STRONG>) نى ئىشلىتىپ مەزمۇننى تۆۋەندىكى رامكىغا كۆچۈرۈڭ، ئاندىن <STRONG>جەزملە</STRONG>نى بېسىڭ',
13 securityMsg: 'توركۆرگۈڭىزنىڭ بىخەتەرلىك تەڭشىكى سەۋەبىدىن بۇ تەھرىرلىگۈچ چاپلاش تاختىسىدىكى مەزمۇننى بىۋاستە زىيارەت قىلالمايدۇ، بۇ كۆزنەكتە قايتا بىر قېتىم چاپلىشىڭىز كېرەك.',
14 title: 'چاپلا'
15} );
diff --git a/sources/plugins/clipboard/lang/uk.js b/sources/plugins/clipboard/lang/uk.js
new file mode 100644
index 0000000..242688f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/uk.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'uk', {
6 copy: 'Копіювати',
7 copyError: 'Налаштування безпеки Вашого браузера не дозволяють редактору автоматично виконувати операції копіювання. Будь ласка, використовуйте клавіатуру для цього (Ctrl/Cmd+C).',
8 cut: 'Вирізати',
9 cutError: 'Налаштування безпеки Вашого браузера не дозволяють редактору автоматично виконувати операції вирізування. Будь ласка, використовуйте клавіатуру для цього (Ctrl/Cmd+X)',
10 paste: 'Вставити',
11 pasteArea: 'Область вставки',
12 pasteMsg: 'Будь ласка, вставте інформацію з буфера обміну в цю область, користуючись комбінацією клавіш (<STRONG>Ctrl/Cmd+V</STRONG>), та натисніть <STRONG>OK</STRONG>.',
13 securityMsg: 'Редактор не може отримати прямий доступ до буферу обміну у зв\'язку з налаштуваннями Вашого браузера. Вам потрібно вставити інформацію в це вікно.',
14 title: 'Вставити'
15} );
diff --git a/sources/plugins/clipboard/lang/vi.js b/sources/plugins/clipboard/lang/vi.js
new file mode 100644
index 0000000..fd36e1f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/vi.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'vi', {
6 copy: 'Sao chép',
7 copyError: 'Các thiết lập bảo mật của trình duyệt không cho phép trình biên tập tự động thực thi lệnh sao chép. Hãy sử dụng bàn phím cho lệnh này (Ctrl/Cmd+C).',
8 cut: 'Cắt',
9 cutError: 'Các thiết lập bảo mật của trình duyệt không cho phép trình biên tập tự động thực thi lệnh cắt. Hãy sử dụng bàn phím cho lệnh này (Ctrl/Cmd+X).',
10 paste: 'Dán',
11 pasteArea: 'Khu vực dán',
12 pasteMsg: 'Hãy dán nội dung vào trong khung bên dưới, sử dụng tổ hợp phím (<STRONG>Ctrl/Cmd+V</STRONG>) và nhấn vào nút <STRONG>Đồng ý</STRONG>.',
13 securityMsg: 'Do thiết lập bảo mật của trình duyệt nên trình biên tập không thể truy cập trực tiếp vào nội dung đã sao chép. Bạn cần phải dán lại nội dung vào cửa sổ này.',
14 title: 'Dán'
15} );
diff --git a/sources/plugins/clipboard/lang/zh-cn.js b/sources/plugins/clipboard/lang/zh-cn.js
new file mode 100644
index 0000000..930f24e
--- /dev/null
+++ b/sources/plugins/clipboard/lang/zh-cn.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'zh-cn', {
6 copy: '复制',
7 copyError: '您的浏览器安全设置不允许编辑器自动执行复制操作,请使用键盘快捷键(Ctrl/Cmd+C)来完成。',
8 cut: '剪切',
9 cutError: '您的浏览器安全设置不允许编辑器自动执行剪切操作,请使用键盘快捷键(Ctrl/Cmd+X)来完成。',
10 paste: '粘贴',
11 pasteArea: '粘贴区域',
12 pasteMsg: '请使用键盘快捷键(<STRONG>Ctrl/Cmd+V</STRONG>)把内容粘贴到下面的方框里,再按 <STRONG>确定</STRONG>',
13 securityMsg: '因为您的浏览器的安全设置原因,本编辑器不能直接访问您的剪贴板内容,你需要在本窗口重新粘贴一次。',
14 title: '粘贴'
15} );
diff --git a/sources/plugins/clipboard/lang/zh.js b/sources/plugins/clipboard/lang/zh.js
new file mode 100644
index 0000000..33a4ef0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/zh.js
@@ -0,0 +1,15 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'zh', {
6 copy: '複製',
7 copyError: '瀏覽器的安全性設定不允許編輯器自動執行複製動作。請使用鍵盤快捷鍵 (Ctrl/Cmd+C) 複製。',
8 cut: '剪下',
9 cutError: '瀏覽器的安全性設定不允許編輯器自動執行剪下動作。請使用鏐盤快捷鍵 (Ctrl/Cmd+X) 剪下。',
10 paste: '貼上',
11 pasteArea: '貼上區',
12 pasteMsg: '請使用鍵盤快捷鍵 (<strong>Ctrl/Cmd+V</strong>) 貼到下方區域中並按下「確定」。',
13 securityMsg: '因為瀏覽器的安全性設定,本編輯器無法直接存取您的剪貼簿資料,請您自行在本視窗進行貼上動作。',
14 title: '貼上'
15} );
diff --git a/sources/plugins/clipboard/plugin.js b/sources/plugins/clipboard/plugin.js
new file mode 100644
index 0000000..5c387b3
--- /dev/null
+++ b/sources/plugins/clipboard/plugin.js
@@ -0,0 +1,2772 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @ignore
8 * File overview: Clipboard support.
9 */
10
11//
12// COPY & PASTE EXECUTION FLOWS:
13// -- CTRL+C
14// * if ( isCustomCopyCutSupported )
15// * dataTransfer.setData( 'text/html', getSelectedHtml )
16// * else
17// * browser's default behavior
18// -- CTRL+X
19// * listen onKey (onkeydown)
20// * fire 'saveSnapshot' on editor
21// * if ( isCustomCopyCutSupported )
22// * dataTransfer.setData( 'text/html', getSelectedHtml )
23// * extractSelectedHtml // remove selected contents
24// * else
25// * browser's default behavior
26// * deferred second 'saveSnapshot' event
27// -- CTRL+V
28// * listen onKey (onkeydown)
29// * simulate 'beforepaste' for non-IEs on editable
30// * listen 'onpaste' on editable ('onbeforepaste' for IE)
31// * fire 'beforePaste' on editor
32// * if ( !canceled && ( htmlInDataTransfer || !external paste) && dataTransfer is not empty ) getClipboardDataByPastebin
33// * fire 'paste' on editor
34// * !canceled && fire 'afterPaste' on editor
35// -- Copy command
36// * tryToCutCopy
37// * execCommand
38// * !success && notification
39// -- Cut command
40// * fixCut
41// * tryToCutCopy
42// * execCommand
43// * !success && notification
44// -- Paste command
45// * fire 'paste' on editable ('beforepaste' for IE)
46// * !canceled && execCommand 'paste'
47// * !success && fire 'pasteDialog' on editor
48// -- Paste from native context menu & menubar
49// (Fx & Webkits are handled in 'paste' default listener.
50// Opera cannot be handled at all because it doesn't fire any events
51// Special treatment is needed for IE, for which is this part of doc)
52// * listen 'onpaste'
53// * cancel native event
54// * fire 'beforePaste' on editor
55// * if ( !canceled && ( htmlInDataTransfer || !external paste) && dataTransfer is not empty ) getClipboardDataByPastebin
56// * execIECommand( 'paste' ) -> this fires another 'paste' event, so cancel it
57// * fire 'paste' on editor
58// * !canceled && fire 'afterPaste' on editor
59//
60//
61// PASTE EVENT - PREPROCESSING:
62// -- Possible dataValue types: auto, text, html.
63// -- Possible dataValue contents:
64// * text (possible \n\r)
65// * htmlified text (text + br,div,p - no presentational markup & attrs - depends on browser)
66// * html
67// -- Possible flags:
68// * htmlified - if true then content is a HTML even if no markup inside. This flag is set
69// for content from editable pastebins, because they 'htmlify' pasted content.
70//
71// -- Type: auto:
72// * content: htmlified text -> filter, unify text markup (brs, ps, divs), set type: text
73// * content: html -> filter, set type: html
74// -- Type: text:
75// * content: htmlified text -> filter, unify text markup
76// * content: html -> filter, strip presentational markup, unify text markup
77// -- Type: html:
78// * content: htmlified text -> filter, unify text markup
79// * content: html -> filter
80//
81// -- Phases:
82// * if dataValue is empty copy data from dataTransfer to dataValue (priority 1)
83// * filtering (priorities 3-5) - e.g. pastefromword filters
84// * content type sniffing (priority 6)
85// * markup transformations for text (priority 6)
86//
87// DRAG & DROP EXECUTION FLOWS:
88// -- Drag
89// * save to the global object:
90// * drag timestamp (with 'cke-' prefix),
91// * selected html,
92// * drag range,
93// * editor instance.
94// * put drag timestamp into event.dataTransfer.text
95// -- Drop
96// * if events text == saved timestamp && editor == saved editor
97// internal drag & drop occurred
98// * getRangeAtDropPosition
99// * create bookmarks for drag and drop ranges starting from the end of the document
100// * dragRange.deleteContents()
101// * fire 'paste' with saved html and drop range
102// * if events text == saved timestamp && editor != saved editor
103// cross editor drag & drop occurred
104// * getRangeAtDropPosition
105// * fire 'paste' with saved html
106// * dragRange.deleteContents()
107// * FF: refreshCursor on afterPaste
108// * if events text != saved timestamp
109// drop form external source occurred
110// * getRangeAtDropPosition
111// * if event contains html data then fire 'paste' with html
112// * else if event contains text data then fire 'paste' with encoded text
113// * FF: refreshCursor on afterPaste
114
115'use strict';
116
117( function() {
118 // Register the plugin.
119 CKEDITOR.plugins.add( 'clipboard', {
120 requires: 'dialog',
121 // jscs:disable maximumLineLength
122 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
123 // jscs:enable maximumLineLength
124 icons: 'copy,copy-rtl,cut,cut-rtl,paste,paste-rtl', // %REMOVE_LINE_CORE%
125 hidpi: true, // %REMOVE_LINE_CORE%
126 init: function( editor ) {
127 var filterType,
128 filtersFactory = filtersFactoryFactory();
129
130 if ( editor.config.forcePasteAsPlainText ) {
131 filterType = 'plain-text';
132 } else if ( editor.config.pasteFilter ) {
133 filterType = editor.config.pasteFilter;
134 }
135 // On Webkit the pasteFilter defaults 'semantic-content' because pasted data is so terrible
136 // that it must be always filtered.
137 else if ( CKEDITOR.env.webkit && !( 'pasteFilter' in editor.config ) ) {
138 filterType = 'semantic-content';
139 }
140
141 editor.pasteFilter = filtersFactory.get( filterType );
142
143 initPasteClipboard( editor );
144 initDragDrop( editor );
145
146 CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );
147
148 // Convert image file (if present) to base64 string for Firefox. Do it as the first
149 // step as the conversion is asynchronous and should hold all further paste processing.
150 if ( CKEDITOR.env.gecko ) {
151 var supportedImageTypes = [ 'image/png', 'image/jpeg', 'image/gif' ],
152 latestId;
153
154 editor.on( 'paste', function( evt ) {
155 var dataObj = evt.data,
156 data = dataObj.dataValue,
157 dataTransfer = dataObj.dataTransfer;
158
159 // If data empty check for image content inside data transfer. #16705
160 if ( !data && dataObj.method == 'paste' && dataTransfer && dataTransfer.getFilesCount() == 1 && latestId != dataTransfer.id ) {
161 var file = dataTransfer.getFile( 0 );
162
163 if ( CKEDITOR.tools.indexOf( supportedImageTypes, file.type ) != -1 ) {
164 var fileReader = new FileReader();
165
166 // Convert image file to img tag with base64 image.
167 fileReader.addEventListener( 'load', function() {
168 evt.data.dataValue = '<img src="' + fileReader.result + '" />';
169 editor.fire( 'paste', evt.data );
170 }, false );
171
172 // Proceed with normal flow if reading file was aborted.
173 fileReader.addEventListener( 'abort', function() {
174 editor.fire( 'paste', evt.data );
175 }, false );
176
177 // Proceed with normal flow if reading file failed.
178 fileReader.addEventListener( 'error', function() {
179 editor.fire( 'paste', evt.data );
180 }, false );
181
182 fileReader.readAsDataURL( file );
183
184 latestId = dataObj.dataTransfer.id;
185
186 evt.stop();
187 }
188 }
189 }, null, null, 1 );
190 }
191
192 editor.on( 'paste', function( evt ) {
193 // Init `dataTransfer` if `paste` event was fired without it, so it will be always available.
194 if ( !evt.data.dataTransfer ) {
195 evt.data.dataTransfer = new CKEDITOR.plugins.clipboard.dataTransfer();
196 }
197
198 // If dataValue is already set (manually or by paste bin), so do not override it.
199 if ( evt.data.dataValue ) {
200 return;
201 }
202
203 var dataTransfer = evt.data.dataTransfer,
204 // IE support only text data and throws exception if we try to get html data.
205 // This html data object may also be empty if we drag content of the textarea.
206 value = dataTransfer.getData( 'text/html' );
207
208 if ( value ) {
209 evt.data.dataValue = value;
210 evt.data.type = 'html';
211 } else {
212 // Try to get text data otherwise.
213 value = dataTransfer.getData( 'text/plain' );
214
215 if ( value ) {
216 evt.data.dataValue = editor.editable().transformPlainTextToHtml( value );
217 evt.data.type = 'text';
218 }
219 }
220 }, null, null, 1 );
221
222 editor.on( 'paste', function( evt ) {
223 var data = evt.data.dataValue,
224 blockElements = CKEDITOR.dtd.$block;
225
226 // Filter webkit garbage.
227 if ( data.indexOf( 'Apple-' ) > -1 ) {
228 // Replace special webkit's &nbsp; with simple space, because webkit
229 // produces them even for normal spaces.
230 data = data.replace( /<span class="Apple-converted-space">&nbsp;<\/span>/gi, ' ' );
231
232 // Strip <span> around white-spaces when not in forced 'html' content type.
233 // This spans are created only when pasting plain text into Webkit,
234 // but for safety reasons remove them always.
235 if ( evt.data.type != 'html' ) {
236 data = data.replace( /<span class="Apple-tab-span"[^>]*>([^<]*)<\/span>/gi, function( all, spaces ) {
237 // Replace tabs with 4 spaces like Fx does.
238 return spaces.replace( /\t/g, '&nbsp;&nbsp; &nbsp;' );
239 } );
240 }
241
242 // This br is produced only when copying & pasting HTML content.
243 if ( data.indexOf( '<br class="Apple-interchange-newline">' ) > -1 ) {
244 evt.data.startsWithEOL = 1;
245 evt.data.preSniffing = 'html'; // Mark as not text.
246 data = data.replace( /<br class="Apple-interchange-newline">/, '' );
247 }
248
249 // Remove all other classes.
250 data = data.replace( /(<[^>]+) class="Apple-[^"]*"/gi, '$1' );
251 }
252
253 // Strip editable that was copied from inside. (#9534)
254 if ( data.match( /^<[^<]+cke_(editable|contents)/i ) ) {
255 var tmp,
256 editable_wrapper,
257 wrapper = new CKEDITOR.dom.element( 'div' );
258
259 wrapper.setHtml( data );
260 // Verify for sure and check for nested editor UI parts. (#9675)
261 while ( wrapper.getChildCount() == 1 &&
262 ( tmp = wrapper.getFirst() ) &&
263 tmp.type == CKEDITOR.NODE_ELEMENT && // Make sure first-child is element.
264 ( tmp.hasClass( 'cke_editable' ) || tmp.hasClass( 'cke_contents' ) ) ) {
265 wrapper = editable_wrapper = tmp;
266 }
267
268 // If editable wrapper was found strip it and bogus <br> (added on FF).
269 if ( editable_wrapper )
270 data = editable_wrapper.getHtml().replace( /<br>$/i, '' );
271 }
272
273 if ( CKEDITOR.env.ie ) {
274 // &nbsp; <p> -> <p> (br.cke-pasted-remove will be removed later)
275 data = data.replace( /^&nbsp;(?: |\r\n)?<(\w+)/g, function( match, elementName ) {
276 if ( elementName.toLowerCase() in blockElements ) {
277 evt.data.preSniffing = 'html'; // Mark as not a text.
278 return '<' + elementName;
279 }
280 return match;
281 } );
282 } else if ( CKEDITOR.env.webkit ) {
283 // </p><div><br></div> -> </p><br>
284 // We don't mark br, because this situation can happen for htmlified text too.
285 data = data.replace( /<\/(\w+)><div><br><\/div>$/, function( match, elementName ) {
286 if ( elementName in blockElements ) {
287 evt.data.endsWithEOL = 1;
288 return '</' + elementName + '>';
289 }
290 return match;
291 } );
292 } else if ( CKEDITOR.env.gecko ) {
293 // Firefox adds bogus <br> when user pasted text followed by space(s).
294 data = data.replace( /(\s)<br>$/, '$1' );
295 }
296
297 evt.data.dataValue = data;
298 }, null, null, 3 );
299
300 editor.on( 'paste', function( evt ) {
301 var dataObj = evt.data,
302 type = dataObj.type,
303 data = dataObj.dataValue,
304 trueType,
305 // Default is 'html'.
306 defaultType = editor.config.clipboard_defaultContentType || 'html',
307 transferType = dataObj.dataTransfer.getTransferType( editor );
308
309 // If forced type is 'html' we don't need to know true data type.
310 if ( type == 'html' || dataObj.preSniffing == 'html' ) {
311 trueType = 'html';
312 } else {
313 trueType = recogniseContentType( data );
314 }
315
316 // Unify text markup.
317 if ( trueType == 'htmlifiedtext' ) {
318 data = htmlifiedTextHtmlification( editor.config, data );
319 }
320
321 // Strip presentational markup & unify text markup.
322 // Forced plain text (dialog or forcePAPT).
323 // Note: we do not check dontFilter option in this case, because forcePAPT was implemented
324 // before pasteFilter and pasteFilter is automatically used on Webkit&Blink since 4.5, so
325 // forcePAPT should have priority as it had before 4.5.
326 if ( type == 'text' && trueType == 'html' ) {
327 data = filterContent( editor, data, filtersFactory.get( 'plain-text' ) );
328 }
329 // External paste and pasteFilter exists and filtering isn't disabled.
330 else if ( transferType == CKEDITOR.DATA_TRANSFER_EXTERNAL && editor.pasteFilter && !dataObj.dontFilter ) {
331 data = filterContent( editor, data, editor.pasteFilter );
332 }
333
334 if ( dataObj.startsWithEOL ) {
335 data = '<br data-cke-eol="1">' + data;
336 }
337 if ( dataObj.endsWithEOL ) {
338 data += '<br data-cke-eol="1">';
339 }
340
341 if ( type == 'auto' ) {
342 type = ( trueType == 'html' || defaultType == 'html' ) ? 'html' : 'text';
343 }
344
345 dataObj.type = type;
346 dataObj.dataValue = data;
347 delete dataObj.preSniffing;
348 delete dataObj.startsWithEOL;
349 delete dataObj.endsWithEOL;
350 }, null, null, 6 );
351
352 // Inserts processed data into the editor at the end of the
353 // events chain.
354 editor.on( 'paste', function( evt ) {
355 var data = evt.data;
356
357 if ( data.dataValue ) {
358 editor.insertHtml( data.dataValue, data.type, data.range );
359
360 // Defer 'afterPaste' so all other listeners for 'paste' will be fired first.
361 // Fire afterPaste only if paste inserted some HTML.
362 setTimeout( function() {
363 editor.fire( 'afterPaste' );
364 }, 0 );
365 }
366 }, null, null, 1000 );
367
368 editor.on( 'pasteDialog', function( evt ) {
369 // TODO it's possible that this setTimeout is not needed any more,
370 // because of changes introduced in the same commit as this comment.
371 // Editor.getClipboardData adds listener to the dialog's events which are
372 // fired after a while (not like 'showDialog').
373 setTimeout( function() {
374 // Open default paste dialog.
375 editor.openDialog( 'paste', evt.data );
376 }, 0 );
377 } );
378 }
379 } );
380
381 function firePasteEvents( editor, data, withBeforePaste ) {
382 if ( !data.type ) {
383 data.type = 'auto';
384 }
385
386 if ( withBeforePaste ) {
387 // Fire 'beforePaste' event so clipboard flavor get customized
388 // by other plugins.
389 if ( editor.fire( 'beforePaste', data ) === false )
390 return false; // Event canceled
391 }
392
393 // Do not fire paste if there is no data (dataValue and dataTranfser are empty).
394 // This check should be done after firing 'beforePaste' because for native paste
395 // 'beforePaste' is by default fired even for empty clipboard.
396 if ( !data.dataValue && data.dataTransfer.isEmpty() ) {
397 return false;
398 }
399
400 if ( !data.dataValue ) {
401 data.dataValue = '';
402 }
403
404 // Because of FF bug we need to use this hack, otherwise cursor is hidden
405 // or it is not possible to move it (#12420).
406 // Also, check that editor.toolbox exists, because the toolbar plugin might not be loaded (#13305).
407 if ( CKEDITOR.env.gecko && data.method == 'drop' && editor.toolbox ) {
408 editor.once( 'afterPaste', function() {
409 editor.toolbox.focus();
410 } );
411 }
412
413 return editor.fire( 'paste', data );
414 }
415
416 function initPasteClipboard( editor ) {
417 var clipboard = CKEDITOR.plugins.clipboard,
418 preventBeforePasteEvent = 0,
419 preventPasteEvent = 0,
420 inReadOnly = 0;
421
422 addListeners();
423 addButtonsCommands();
424
425 /**
426 * Gets clipboard data by directly accessing the clipboard (IE only) or opening the paste dialog window.
427 *
428 * editor.getClipboardData( { title: 'Get my data' }, function( data ) {
429 * if ( data )
430 * alert( data.type + ' ' + data.dataValue );
431 * } );
432 *
433 * @member CKEDITOR.editor
434 * @param {Object} options
435 * @param {String} [options.title] The title of the paste dialog window.
436 * @param {Function} callback A function that will be executed with `data.type` and `data.dataValue`
437 * or `null` if none of the capturing methods succeeded.
438 */
439 editor.getClipboardData = function( options, callback ) {
440 var beforePasteNotCanceled = false,
441 dataType = 'auto',
442 dialogCommited = false;
443
444 // Options are optional - args shift.
445 if ( !callback ) {
446 callback = options;
447 options = null;
448 }
449
450 // Listen with maximum priority to handle content before everyone else.
451 // This callback will handle paste event that will be fired if direct
452 // access to the clipboard succeed in IE.
453 editor.on( 'paste', onPaste, null, null, 0 );
454
455 // Listen at the end of listeners chain to see if event wasn't canceled
456 // and to retrieve modified data.type.
457 editor.on( 'beforePaste', onBeforePaste, null, null, 1000 );
458
459 // getClipboardDataDirectly() will fire 'beforePaste' synchronously, so we can
460 // check if it was canceled and if any listener modified data.type.
461
462 // If command didn't succeed (only IE allows to access clipboard and only if
463 // user agrees) open and handle paste dialog.
464 if ( getClipboardDataDirectly() === false ) {
465 // Direct access to the clipboard wasn't successful so remove listener.
466 editor.removeListener( 'paste', onPaste );
467
468 // If beforePaste was canceled do not open dialog.
469 // Add listeners only if dialog really opened. 'pasteDialog' can be canceled.
470 if ( beforePasteNotCanceled && editor.fire( 'pasteDialog', onDialogOpen ) ) {
471 editor.on( 'pasteDialogCommit', onDialogCommit );
472
473 // 'dialogHide' will be fired after 'pasteDialogCommit'.
474 editor.on( 'dialogHide', function( evt ) {
475 evt.removeListener();
476 evt.data.removeListener( 'pasteDialogCommit', onDialogCommit );
477
478 // Because Opera has to wait a while in pasteDialog we have to wait here.
479 setTimeout( function() {
480 // Notify even if user canceled dialog (clicked 'cancel', ESC, etc).
481 if ( !dialogCommited )
482 callback( null );
483 }, 10 );
484 } );
485 } else {
486 callback( null );
487 }
488 }
489
490 function onPaste( evt ) {
491 evt.removeListener();
492 evt.cancel();
493 callback( evt.data );
494 }
495
496 function onBeforePaste( evt ) {
497 evt.removeListener();
498 beforePasteNotCanceled = true;
499 dataType = evt.data.type;
500 }
501
502 function onDialogCommit( evt ) {
503 evt.removeListener();
504 // Cancel pasteDialogCommit so paste dialog won't automatically fire
505 // 'paste' evt by itself.
506 evt.cancel();
507 dialogCommited = true;
508 callback( {
509 type: dataType,
510 dataValue: evt.data.dataValue,
511 dataTransfer: evt.data.dataTransfer,
512 method: 'paste'
513 } );
514 }
515
516 function onDialogOpen() {
517 this.customTitle = ( options && options.title );
518 }
519 };
520
521 function addButtonsCommands() {
522 addButtonCommand( 'Cut', 'cut', createCutCopyCmd( 'cut' ), 10, 1 );
523 addButtonCommand( 'Copy', 'copy', createCutCopyCmd( 'copy' ), 20, 4 );
524 addButtonCommand( 'Paste', 'paste', createPasteCmd(), 30, 8 );
525
526 function addButtonCommand( buttonName, commandName, command, toolbarOrder, ctxMenuOrder ) {
527 var lang = editor.lang.clipboard[ commandName ];
528
529 editor.addCommand( commandName, command );
530 editor.ui.addButton && editor.ui.addButton( buttonName, {
531 label: lang,
532 command: commandName,
533 toolbar: 'clipboard,' + toolbarOrder
534 } );
535
536 // If the "menu" plugin is loaded, register the menu item.
537 if ( editor.addMenuItems ) {
538 editor.addMenuItem( commandName, {
539 label: lang,
540 command: commandName,
541 group: 'clipboard',
542 order: ctxMenuOrder
543 } );
544 }
545 }
546 }
547
548 function addListeners() {
549 editor.on( 'key', onKey );
550 editor.on( 'contentDom', addPasteListenersToEditable );
551
552 // For improved performance, we're checking the readOnly state on selectionChange instead of hooking a key event for that.
553 editor.on( 'selectionChange', function( evt ) {
554 inReadOnly = evt.data.selection.getRanges()[ 0 ].checkReadOnly();
555 setToolbarStates();
556 } );
557
558 // If the "contextmenu" plugin is loaded, register the listeners.
559 if ( editor.contextMenu ) {
560 editor.contextMenu.addListener( function( element, selection ) {
561 inReadOnly = selection.getRanges()[ 0 ].checkReadOnly();
562 return {
563 cut: stateFromNamedCommand( 'cut' ),
564 copy: stateFromNamedCommand( 'copy' ),
565 paste: stateFromNamedCommand( 'paste' )
566 };
567 } );
568 }
569 }
570
571 // Add events listeners to editable.
572 function addPasteListenersToEditable() {
573 var editable = editor.editable();
574
575 if ( CKEDITOR.plugins.clipboard.isCustomCopyCutSupported ) {
576 var initOnCopyCut = function( evt ) {
577 // If user tries to cut in read-only editor, we must prevent default action. (#13872)
578 if ( !editor.readOnly || evt.name != 'cut' ) {
579 clipboard.initPasteDataTransfer( evt, editor );
580 }
581 evt.data.preventDefault();
582 };
583
584 editable.on( 'copy', initOnCopyCut );
585 editable.on( 'cut', initOnCopyCut );
586
587 // Delete content with the low priority so one can overwrite cut data.
588 editable.on( 'cut', function() {
589 // If user tries to cut in read-only editor, we must prevent default action. (#13872)
590 if ( !editor.readOnly ) {
591 editor.extractSelectedHtml();
592 }
593 }, null, null, 999 );
594 }
595
596 // We'll be catching all pasted content in one line, regardless of whether
597 // it's introduced by a document command execution (e.g. toolbar buttons) or
598 // user paste behaviors (e.g. CTRL+V).
599 editable.on( clipboard.mainPasteEvent, function( evt ) {
600 if ( clipboard.mainPasteEvent == 'beforepaste' && preventBeforePasteEvent ) {
601 return;
602 }
603
604 // If you've just asked yourself why preventPasteEventNow() is not here, but
605 // in listener for CTRL+V and exec method of 'paste' command
606 // you've asked the same question we did.
607 //
608 // THE ANSWER:
609 //
610 // First thing to notice - this answer makes sense only for IE,
611 // because other browsers don't listen for 'paste' event.
612 //
613 // What would happen if we move preventPasteEventNow() here?
614 // For:
615 // * CTRL+V - IE fires 'beforepaste', so we prevent 'paste' and pasteDataFromClipboard(). OK.
616 // * editor.execCommand( 'paste' ) - we fire 'beforepaste', so we prevent
617 // 'paste' and pasteDataFromClipboard() and doc.execCommand( 'Paste' ). OK.
618 // * native context menu - IE fires 'beforepaste', so we prevent 'paste', but unfortunately
619 // on IE we fail with pasteDataFromClipboard() here, because of... we don't know why, but
620 // we just fail, so... we paste nothing. FAIL.
621 // * native menu bar - the same as for native context menu.
622 //
623 // But don't you know any way to distinguish first two cases from last two?
624 // Only one - special flag set in CTRL+V handler and exec method of 'paste'
625 // command. And that's what we did using preventPasteEventNow().
626
627 pasteDataFromClipboard( evt );
628 } );
629
630 // It's not possible to clearly handle all four paste methods (ctrl+v, native menu bar
631 // native context menu, editor's command) in one 'paste/beforepaste' event in IE.
632 //
633 // For ctrl+v & editor's command it's easy to handle pasting in 'beforepaste' listener,
634 // so we do this. For another two methods it's better to use 'paste' event.
635 //
636 // 'paste' is always being fired after 'beforepaste' (except of weird one on opening native
637 // context menu), so for two methods handled in 'beforepaste' we're canceling 'paste'
638 // using preventPasteEvent state.
639 //
640 // 'paste' event in IE is being fired before getClipboardDataByPastebin executes its callback.
641 //
642 // QUESTION: Why didn't you handle all 4 paste methods in handler for 'paste'?
643 // Wouldn't this just be simpler?
644 // ANSWER: Then we would have to evt.data.preventDefault() only for native
645 // context menu and menu bar pastes. The same with execIECommand().
646 // That would force us to mark CTRL+V and editor's paste command with
647 // special flag, other than preventPasteEvent. But we still would have to
648 // have preventPasteEvent for the second event fired by execIECommand.
649 // Code would be longer and not cleaner.
650 if ( clipboard.mainPasteEvent == 'beforepaste' ) {
651 editable.on( 'paste', function( evt ) {
652 if ( preventPasteEvent ) {
653 return;
654 }
655
656 // Cancel next 'paste' event fired by execIECommand( 'paste' )
657 // at the end of this callback.
658 preventPasteEventNow();
659
660 // Prevent native paste.
661 evt.data.preventDefault();
662
663 pasteDataFromClipboard( evt );
664
665 // Force IE to paste content into pastebin so pasteDataFromClipboard will work.
666 if ( !execIECommand( 'paste' ) ) {
667 editor.openDialog( 'paste' );
668 }
669 } );
670
671 // If mainPasteEvent is 'beforePaste' (IE before Edge),
672 // dismiss the (wrong) 'beforepaste' event fired on context/toolbar menu open. (#7953)
673 editable.on( 'contextmenu', preventBeforePasteEventNow, null, null, 0 );
674
675 editable.on( 'beforepaste', function( evt ) {
676 // Do not prevent event on CTRL+V and SHIFT+INS because it blocks paste (#11970).
677 if ( evt.data && !evt.data.$.ctrlKey && !evt.data.$.shiftKey )
678 preventBeforePasteEventNow();
679 }, null, null, 0 );
680 }
681
682 editable.on( 'beforecut', function() {
683 !preventBeforePasteEvent && fixCut( editor );
684 } );
685
686 var mouseupTimeout;
687
688 // Use editor.document instead of editable in non-IEs for observing mouseup
689 // since editable won't fire the event if selection process started within
690 // iframe and ended out of the editor (#9851).
691 editable.attachListener( CKEDITOR.env.ie ? editable : editor.document.getDocumentElement(), 'mouseup', function() {
692 mouseupTimeout = setTimeout( function() {
693 setToolbarStates();
694 }, 0 );
695 } );
696
697 // Make sure that deferred mouseup callback isn't executed after editor instance
698 // had been destroyed. This may happen when editor.destroy() is called in parallel
699 // with mouseup event (i.e. a button with onclick callback) (#10219).
700 editor.on( 'destroy', function() {
701 clearTimeout( mouseupTimeout );
702 } );
703
704 editable.on( 'keyup', setToolbarStates );
705 }
706
707 // Create object representing Cut or Copy commands.
708 function createCutCopyCmd( type ) {
709 return {
710 type: type,
711 canUndo: type == 'cut', // We can't undo copy to clipboard.
712 startDisabled: true,
713 fakeKeystroke: type == 'cut' ? CKEDITOR.CTRL + 88 /*X*/ : CKEDITOR.CTRL + 67 /*C*/,
714 exec: function() {
715 // Attempts to execute the Cut and Copy operations.
716 function tryToCutCopy( type ) {
717 if ( CKEDITOR.env.ie )
718 return execIECommand( type );
719
720 // non-IEs part
721 try {
722 // Other browsers throw an error if the command is disabled.
723 return editor.document.$.execCommand( type, false, null );
724 } catch ( e ) {
725 return false;
726 }
727 }
728
729 this.type == 'cut' && fixCut();
730
731 var success = tryToCutCopy( this.type );
732
733 if ( !success ) {
734 // Show cutError or copyError.
735 editor.showNotification( editor.lang.clipboard[ this.type + 'Error' ] ); // jshint ignore:line
736 }
737
738 return success;
739 }
740 };
741 }
742
743 function createPasteCmd() {
744 return {
745 // Snapshots are done manually by editable.insertXXX methods.
746 canUndo: false,
747 async: true,
748 fakeKeystroke: CKEDITOR.CTRL + 86 /*V*/,
749 exec: function( editor, data ) {
750 var cmd = this,
751 fire = function( data, withBeforePaste ) {
752 data && firePasteEvents( editor, data, !!withBeforePaste );
753
754 editor.fire( 'afterCommandExec', {
755 name: 'paste',
756 command: cmd,
757 returnValue: !!data
758 } );
759 };
760
761 // Check data precisely - don't open dialog on empty string.
762 if ( typeof data == 'string' )
763 fire( {
764 dataValue: data,
765 method: 'paste',
766 dataTransfer: clipboard.initPasteDataTransfer()
767 }, 1 );
768 else
769 editor.getClipboardData( fire );
770 }
771 };
772 }
773
774 function preventPasteEventNow() {
775 preventPasteEvent = 1;
776 // For safety reason we should wait longer than 0/1ms.
777 // We don't know how long execution of quite complex getClipboardData will take
778 // and in for example 'paste' listener execCommand() (which fires 'paste') is called
779 // after getClipboardData finishes.
780 // Luckily, it's impossible to immediately fire another 'paste' event we want to handle,
781 // because we only handle there native context menu and menu bar.
782 setTimeout( function() {
783 preventPasteEvent = 0;
784 }, 100 );
785 }
786
787 function preventBeforePasteEventNow() {
788 preventBeforePasteEvent = 1;
789 setTimeout( function() {
790 preventBeforePasteEvent = 0;
791 }, 10 );
792 }
793
794 // Tries to execute any of the paste, cut or copy commands in IE. Returns a
795 // boolean indicating that the operation succeeded.
796 // @param {String} command *LOWER CASED* name of command ('paste', 'cut', 'copy').
797 function execIECommand( command ) {
798 var doc = editor.document,
799 body = doc.getBody(),
800 enabled = false,
801 onExec = function() {
802 enabled = true;
803 };
804
805 // The following seems to be the only reliable way to detect that
806 // clipboard commands are enabled in IE. It will fire the
807 // onpaste/oncut/oncopy events only if the security settings allowed
808 // the command to execute.
809 body.on( command, onExec );
810
811 // IE7: document.execCommand has problem to paste into positioned element.
812 if ( CKEDITOR.env.version > 7 ) {
813 doc.$.execCommand( command );
814 } else {
815 doc.$.selection.createRange().execCommand( command );
816 }
817
818 body.removeListener( command, onExec );
819
820 return enabled;
821 }
822
823 // Cutting off control type element in IE standards breaks the selection entirely. (#4881)
824 function fixCut() {
825 if ( !CKEDITOR.env.ie || CKEDITOR.env.quirks )
826 return;
827
828 var sel = editor.getSelection(),
829 control, range, dummy;
830
831 if ( ( sel.getType() == CKEDITOR.SELECTION_ELEMENT ) && ( control = sel.getSelectedElement() ) ) {
832 range = sel.getRanges()[ 0 ];
833 dummy = editor.document.createText( '' );
834 dummy.insertBefore( control );
835 range.setStartBefore( dummy );
836 range.setEndAfter( control );
837 sel.selectRanges( [ range ] );
838
839 // Clear up the fix if the paste wasn't succeeded.
840 setTimeout( function() {
841 // Element still online?
842 if ( control.getParent() ) {
843 dummy.remove();
844 sel.selectElement( control );
845 }
846 }, 0 );
847 }
848 }
849
850 // Allow to peek clipboard content by redirecting the
851 // pasting content into a temporary bin and grab the content of it.
852 function getClipboardDataByPastebin( evt, callback ) {
853 var doc = editor.document,
854 editable = editor.editable(),
855 cancel = function( evt ) {
856 evt.cancel();
857 },
858 blurListener;
859
860 // Avoid recursions on 'paste' event or consequent paste too fast. (#5730)
861 if ( doc.getById( 'cke_pastebin' ) )
862 return;
863
864 var sel = editor.getSelection();
865 var bms = sel.createBookmarks();
866
867 // #11384. On IE9+ we use native selectionchange (i.e. editor#selectionCheck) to cache the most
868 // recent selection which we then lock on editable blur. See selection.js for more info.
869 // selectionchange fired before getClipboardDataByPastebin() cached selection
870 // before creating bookmark (cached selection will be invalid, because bookmarks modified the DOM),
871 // so we need to fire selectionchange one more time, to store current seleciton.
872 // Selection will be locked when we focus pastebin.
873 if ( CKEDITOR.env.ie )
874 sel.root.fire( 'selectionchange' );
875
876 // Create container to paste into.
877 // For rich content we prefer to use "body" since it holds
878 // the least possibility to be splitted by pasted content, while this may
879 // breaks the text selection on a frame-less editable, "div" would be
880 // the best one in that case.
881 // In another case on old IEs moving the selection into a "body" paste bin causes error panic.
882 // Body can't be also used for Opera which fills it with <br>
883 // what is indistinguishable from pasted <br> (copying <br> in Opera isn't possible,
884 // but it can be copied from other browser).
885 var pastebin = new CKEDITOR.dom.element(
886 ( CKEDITOR.env.webkit || editable.is( 'body' ) ) && !CKEDITOR.env.ie ? 'body' : 'div', doc );
887
888 pastebin.setAttributes( {
889 id: 'cke_pastebin',
890 'data-cke-temp': '1'
891 } );
892
893 var containerOffset = 0,
894 offsetParent,
895 win = doc.getWindow();
896
897 if ( CKEDITOR.env.webkit ) {
898 // It's better to paste close to the real paste destination, so inherited styles
899 // (which Webkits will try to compensate by styling span) differs less from the destination's one.
900 editable.append( pastebin );
901 // Style pastebin like .cke_editable, to minimize differences between origin and destination. (#9754)
902 pastebin.addClass( 'cke_editable' );
903
904 // Compensate position of offsetParent.
905 if ( !editable.is( 'body' ) ) {
906 // We're not able to get offsetParent from pastebin (body element), so check whether
907 // its parent (editable) is positioned.
908 if ( editable.getComputedStyle( 'position' ) != 'static' )
909 offsetParent = editable;
910 // And if not - safely get offsetParent from editable.
911 else
912 offsetParent = CKEDITOR.dom.element.get( editable.$.offsetParent );
913
914 containerOffset = offsetParent.getDocumentPosition().y;
915 }
916 } else {
917 // Opera and IE doesn't allow to append to html element.
918 editable.getAscendant( CKEDITOR.env.ie ? 'body' : 'html', 1 ).append( pastebin );
919 }
920
921 pastebin.setStyles( {
922 position: 'absolute',
923 // Position the bin at the top (+10 for safety) of viewport to avoid any subsequent document scroll.
924 top: ( win.getScrollPosition().y - containerOffset + 10 ) + 'px',
925 width: '1px',
926 // Caret has to fit in that height, otherwise browsers like Chrome & Opera will scroll window to show it.
927 // Set height equal to viewport's height - 20px (safety gaps), minimum 1px.
928 height: Math.max( 1, win.getViewPaneSize().height - 20 ) + 'px',
929 overflow: 'hidden',
930 // Reset styles that can mess up pastebin position.
931 margin: 0,
932 padding: 0
933 } );
934
935 // Paste fails in Safari when the body tag has 'user-select: none'. (#12506)
936 if ( CKEDITOR.env.safari )
937 pastebin.setStyles( CKEDITOR.tools.cssVendorPrefix( 'user-select', 'text' ) );
938
939 // Check if the paste bin now establishes new editing host.
940 var isEditingHost = pastebin.getParent().isReadOnly();
941
942 if ( isEditingHost ) {
943 // Hide the paste bin.
944 pastebin.setOpacity( 0 );
945 // And make it editable.
946 pastebin.setAttribute( 'contenteditable', true );
947 }
948 // Transparency is not enough since positioned non-editing host always shows
949 // resize handler, pull it off the screen instead.
950 else {
951 pastebin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-10000px' );
952 }
953
954 editor.on( 'selectionChange', cancel, null, null, 0 );
955
956 // Webkit fill fire blur on editable when moving selection to
957 // pastebin (if body is used). Cancel it because it causes incorrect
958 // selection lock in case of inline editor (#10644).
959 // The same seems to apply to Firefox (#10787).
960 if ( CKEDITOR.env.webkit || CKEDITOR.env.gecko )
961 blurListener = editable.once( 'blur', cancel, null, null, -100 );
962
963 // Temporarily move selection to the pastebin.
964 isEditingHost && pastebin.focus();
965 var range = new CKEDITOR.dom.range( pastebin );
966 range.selectNodeContents( pastebin );
967 var selPastebin = range.select();
968
969 // If non-native paste is executed, IE will open security alert and blur editable.
970 // Editable will then lock selection inside itself and after accepting security alert
971 // this selection will be restored. We overwrite stored selection, so it's restored
972 // in pastebin. (#9552)
973 if ( CKEDITOR.env.ie ) {
974 blurListener = editable.once( 'blur', function() {
975 editor.lockSelection( selPastebin );
976 } );
977 }
978
979 var scrollTop = CKEDITOR.document.getWindow().getScrollPosition().y;
980
981 // Wait a while and grab the pasted contents.
982 setTimeout( function() {
983 // Restore main window's scroll position which could have been changed
984 // by browser in cases described in #9771.
985 if ( CKEDITOR.env.webkit )
986 CKEDITOR.document.getBody().$.scrollTop = scrollTop;
987
988 // Blur will be fired only on non-native paste. In other case manually remove listener.
989 blurListener && blurListener.removeListener();
990
991 // Restore properly the document focus. (#8849)
992 if ( CKEDITOR.env.ie )
993 editable.focus();
994
995 // IE7: selection must go before removing pastebin. (#8691)
996 sel.selectBookmarks( bms );
997 pastebin.remove();
998
999 // Grab the HTML contents.
1000 // We need to look for a apple style wrapper on webkit it also adds
1001 // a div wrapper if you copy/paste the body of the editor.
1002 // Remove hidden div and restore selection.
1003 var bogusSpan;
1004 if ( CKEDITOR.env.webkit && ( bogusSpan = pastebin.getFirst() ) && ( bogusSpan.is && bogusSpan.hasClass( 'Apple-style-span' ) ) )
1005 pastebin = bogusSpan;
1006
1007 editor.removeListener( 'selectionChange', cancel );
1008 callback( pastebin.getHtml() );
1009 }, 0 );
1010 }
1011
1012 // Try to get content directly on IE from clipboard, without native event
1013 // being fired before. In other words - synthetically get clipboard data, if it's possible.
1014 // mainPasteEvent will be fired, so if forced native paste:
1015 // * worked, getClipboardDataByPastebin will grab it,
1016 // * didn't work, dataValue and dataTransfer will be empty and editor#paste won't be fired.
1017 // Clipboard data can be accessed directly only on IEs older than Edge.
1018 // On other browsers we should fire beforePaste event and return false.
1019 function getClipboardDataDirectly() {
1020 if ( clipboard.mainPasteEvent == 'paste' ) {
1021 // beforePaste should be fired when dialog open so it can be canceled.
1022 editor.fire( 'beforePaste', { type: 'auto', method: 'paste' } );
1023 return false;
1024 }
1025
1026 // Prevent IE from pasting at the begining of the document.
1027 editor.focus();
1028
1029 // Command will be handled by 'beforepaste', but as
1030 // execIECommand( 'paste' ) will fire also 'paste' event
1031 // we're canceling it.
1032 preventPasteEventNow();
1033
1034 // #9247: Lock focus to prevent IE from hiding toolbar for inline editor.
1035 var focusManager = editor.focusManager;
1036 focusManager.lock();
1037
1038 if ( editor.editable().fire( clipboard.mainPasteEvent ) && !execIECommand( 'paste' ) ) {
1039 focusManager.unlock();
1040 return false;
1041 }
1042 focusManager.unlock();
1043
1044 return true;
1045 }
1046
1047 // Listens for some clipboard related keystrokes, so they get customized.
1048 // Needs to be bind to keydown event.
1049 function onKey( event ) {
1050 if ( editor.mode != 'wysiwyg' )
1051 return;
1052
1053 switch ( event.data.keyCode ) {
1054 // Paste
1055 case CKEDITOR.CTRL + 86: // CTRL+V
1056 case CKEDITOR.SHIFT + 45: // SHIFT+INS
1057 var editable = editor.editable();
1058
1059 // Cancel 'paste' event because ctrl+v is for IE handled
1060 // by 'beforepaste'.
1061 preventPasteEventNow();
1062
1063 // Simulate 'beforepaste' event for all browsers using 'paste' as main event.
1064 if ( clipboard.mainPasteEvent == 'paste' ) {
1065 editable.fire( 'beforepaste' );
1066 }
1067
1068 return;
1069
1070 // Cut
1071 case CKEDITOR.CTRL + 88: // CTRL+X
1072 case CKEDITOR.SHIFT + 46: // SHIFT+DEL
1073 // Save Undo snapshot.
1074 editor.fire( 'saveSnapshot' ); // Save before cut
1075 setTimeout( function() {
1076 editor.fire( 'saveSnapshot' ); // Save after cut
1077 }, 50 ); // OSX is slow (#11416).
1078 }
1079 }
1080
1081 function pasteDataFromClipboard( evt ) {
1082 // Default type is 'auto', but can be changed by beforePaste listeners.
1083 var eventData = {
1084 type: 'auto',
1085 method: 'paste',
1086 dataTransfer: clipboard.initPasteDataTransfer( evt )
1087 };
1088
1089 eventData.dataTransfer.cacheData();
1090
1091 // Fire 'beforePaste' event so clipboard flavor get customized by other plugins.
1092 // If 'beforePaste' is canceled continue executing getClipboardDataByPastebin and then do nothing
1093 // (do not fire 'paste', 'afterPaste' events). This way we can grab all - synthetically
1094 // and natively pasted content and prevent its insertion into editor
1095 // after canceling 'beforePaste' event.
1096 var beforePasteNotCanceled = editor.fire( 'beforePaste', eventData ) !== false;
1097
1098 // Do not use paste bin if the browser let us get HTML or files from dataTranfer.
1099 if ( beforePasteNotCanceled && clipboard.canClipboardApiBeTrusted( eventData.dataTransfer, editor ) ) {
1100 evt.data.preventDefault();
1101 setTimeout( function() {
1102 firePasteEvents( editor, eventData );
1103 }, 0 );
1104 } else {
1105 getClipboardDataByPastebin( evt, function( data ) {
1106 // Clean up.
1107 eventData.dataValue = data.replace( /<span[^>]+data-cke-bookmark[^<]*?<\/span>/ig, '' );
1108
1109 // Fire remaining events (without beforePaste)
1110 beforePasteNotCanceled && firePasteEvents( editor, eventData );
1111 } );
1112 }
1113 }
1114
1115 function setToolbarStates() {
1116 if ( editor.mode != 'wysiwyg' )
1117 return;
1118
1119 var pasteState = stateFromNamedCommand( 'paste' );
1120
1121 editor.getCommand( 'cut' ).setState( stateFromNamedCommand( 'cut' ) );
1122 editor.getCommand( 'copy' ).setState( stateFromNamedCommand( 'copy' ) );
1123 editor.getCommand( 'paste' ).setState( pasteState );
1124 editor.fire( 'pasteState', pasteState );
1125 }
1126
1127 function stateFromNamedCommand( command ) {
1128 if ( inReadOnly && command in { paste: 1, cut: 1 } )
1129 return CKEDITOR.TRISTATE_DISABLED;
1130
1131 if ( command == 'paste' )
1132 return CKEDITOR.TRISTATE_OFF;
1133
1134 // Cut, copy - check if the selection is not empty.
1135 var sel = editor.getSelection(),
1136 ranges = sel.getRanges(),
1137 selectionIsEmpty = sel.getType() == CKEDITOR.SELECTION_NONE || ( ranges.length == 1 && ranges[ 0 ].collapsed );
1138
1139 return selectionIsEmpty ? CKEDITOR.TRISTATE_DISABLED : CKEDITOR.TRISTATE_OFF;
1140 }
1141 }
1142
1143 // Returns:
1144 // * 'htmlifiedtext' if content looks like transformed by browser from plain text.
1145 // See clipboard/paste.html TCs for more info.
1146 // * 'html' if it is not 'htmlifiedtext'.
1147 function recogniseContentType( data ) {
1148 if ( CKEDITOR.env.webkit ) {
1149 // Plain text or ( <div><br></div> and text inside <div> ).
1150 if ( !data.match( /^[^<]*$/g ) && !data.match( /^(<div><br( ?\/)?><\/div>|<div>[^<]*<\/div>)*$/gi ) )
1151 return 'html';
1152 } else if ( CKEDITOR.env.ie ) {
1153 // Text and <br> or ( text and <br> in <p> - paragraphs can be separated by new \r\n ).
1154 if ( !data.match( /^([^<]|<br( ?\/)?>)*$/gi ) && !data.match( /^(<p>([^<]|<br( ?\/)?>)*<\/p>|(\r\n))*$/gi ) )
1155 return 'html';
1156 } else if ( CKEDITOR.env.gecko ) {
1157 // Text or <br>.
1158 if ( !data.match( /^([^<]|<br( ?\/)?>)*$/gi ) )
1159 return 'html';
1160 } else {
1161 return 'html';
1162 }
1163
1164 return 'htmlifiedtext';
1165 }
1166
1167 // This function transforms what browsers produce when
1168 // pasting plain text into editable element (see clipboard/paste.html TCs
1169 // for more info) into correct HTML (similar to that produced by text2Html).
1170 function htmlifiedTextHtmlification( config, data ) {
1171 function repeatParagraphs( repeats ) {
1172 // Repeat blocks floor((n+1)/2) times.
1173 // Even number of repeats - add <br> at the beginning of last <p>.
1174 return CKEDITOR.tools.repeat( '</p><p>', ~~( repeats / 2 ) ) + ( repeats % 2 == 1 ? '<br>' : '' );
1175 }
1176
1177 // Replace adjacent white-spaces (EOLs too - Fx sometimes keeps them) with one space.
1178 data = data.replace( /\s+/g, ' ' )
1179 // Remove spaces from between tags.
1180 .replace( /> +</g, '><' )
1181 // Normalize XHTML syntax and upper cased <br> tags.
1182 .replace( /<br ?\/>/gi, '<br>' );
1183
1184 // IE - lower cased tags.
1185 data = data.replace( /<\/?[A-Z]+>/g, function( match ) {
1186 return match.toLowerCase();
1187 } );
1188
1189 // Don't touch single lines (no <br|p|div>) - nothing to do here.
1190 if ( data.match( /^[^<]$/ ) )
1191 return data;
1192
1193 // Webkit.
1194 if ( CKEDITOR.env.webkit && data.indexOf( '<div>' ) > -1 ) {
1195 // One line break at the beginning - insert <br>
1196 data = data.replace( /^(<div>(<br>|)<\/div>)(?!$|(<div>(<br>|)<\/div>))/g, '<br>' )
1197 // Two or more - reduce number of new lines by one.
1198 .replace( /^(<div>(<br>|)<\/div>){2}(?!$)/g, '<div></div>' );
1199
1200 // Two line breaks create one paragraph in Webkit.
1201 if ( data.match( /<div>(<br>|)<\/div>/ ) ) {
1202 data = '<p>' + data.replace( /(<div>(<br>|)<\/div>)+/g, function( match ) {
1203 return repeatParagraphs( match.split( '</div><div>' ).length + 1 );
1204 } ) + '</p>';
1205 }
1206
1207 // One line break create br.
1208 data = data.replace( /<\/div><div>/g, '<br>' );
1209
1210 // Remove remaining divs.
1211 data = data.replace( /<\/?div>/g, '' );
1212 }
1213
1214 // Opera and Firefox and enterMode != BR.
1215 if ( CKEDITOR.env.gecko && config.enterMode != CKEDITOR.ENTER_BR ) {
1216 // Remove bogus <br> - Fx generates two <brs> for one line break.
1217 // For two line breaks it still produces two <brs>, but it's better to ignore this case than the first one.
1218 if ( CKEDITOR.env.gecko )
1219 data = data.replace( /^<br><br>$/, '<br>' );
1220
1221 // This line satisfy edge case when for Opera we have two line breaks
1222 //data = data.replace( /)
1223
1224 if ( data.indexOf( '<br><br>' ) > -1 ) {
1225 // Two line breaks create one paragraph, three - 2, four - 3, etc.
1226 data = '<p>' + data.replace( /(<br>){2,}/g, function( match ) {
1227 return repeatParagraphs( match.length / 4 );
1228 } ) + '</p>';
1229 }
1230 }
1231
1232 return switchEnterMode( config, data );
1233 }
1234
1235 function filtersFactoryFactory() {
1236 var filters = {};
1237
1238 function setUpTags() {
1239 var tags = {};
1240
1241 for ( var tag in CKEDITOR.dtd ) {
1242 if ( tag.charAt( 0 ) != '$' && tag != 'div' && tag != 'span' ) {
1243 tags[ tag ] = 1;
1244 }
1245 }
1246
1247 return tags;
1248 }
1249
1250 function createSemanticContentFilter() {
1251 var filter = new CKEDITOR.filter();
1252
1253 filter.allow( {
1254 $1: {
1255 elements: setUpTags(),
1256 attributes: true,
1257 styles: false,
1258 classes: false
1259 }
1260 } );
1261
1262 return filter;
1263 }
1264
1265 return {
1266 get: function( type ) {
1267 if ( type == 'plain-text' ) {
1268 // Does this look confusing to you? Did we forget about enter mode?
1269 // It is a trick that let's us creating one filter for edidtor, regardless of its
1270 // activeEnterMode (which as the name indicates can change during runtime).
1271 //
1272 // How does it work?
1273 // The active enter mode is passed to the filter.applyTo method.
1274 // The filter first marks all elements except <br> as disallowed and then tries to remove
1275 // them. However, it cannot remove e.g. a <p> element completely, because it's a basic structural element,
1276 // so it tries to replace it with an element created based on the active enter mode, eventually doing nothing.
1277 //
1278 // Now you can sleep well.
1279 return filters.plainText || ( filters.plainText = new CKEDITOR.filter( 'br' ) );
1280 } else if ( type == 'semantic-content' ) {
1281 return filters.semanticContent || ( filters.semanticContent = createSemanticContentFilter() );
1282 } else if ( type ) {
1283 // Create filter based on rules (string or object).
1284 return new CKEDITOR.filter( type );
1285 }
1286
1287 return null;
1288 }
1289 };
1290 }
1291
1292 function filterContent( editor, data, filter ) {
1293 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data ),
1294 writer = new CKEDITOR.htmlParser.basicWriter();
1295
1296 filter.applyTo( fragment, true, false, editor.activeEnterMode );
1297 fragment.writeHtml( writer );
1298
1299 return writer.getHtml();
1300 }
1301
1302 function switchEnterMode( config, data ) {
1303 if ( config.enterMode == CKEDITOR.ENTER_BR ) {
1304 data = data.replace( /(<\/p><p>)+/g, function( match ) {
1305 return CKEDITOR.tools.repeat( '<br>', match.length / 7 * 2 );
1306 } ).replace( /<\/?p>/g, '' );
1307 } else if ( config.enterMode == CKEDITOR.ENTER_DIV ) {
1308 data = data.replace( /<(\/)?p>/g, '<$1div>' );
1309 }
1310
1311 return data;
1312 }
1313
1314 function preventDefaultSetDropEffectToNone( evt ) {
1315 evt.data.preventDefault();
1316 evt.data.$.dataTransfer.dropEffect = 'none';
1317 }
1318
1319 function initDragDrop( editor ) {
1320 var clipboard = CKEDITOR.plugins.clipboard;
1321
1322 editor.on( 'contentDom', function() {
1323 var editable = editor.editable(),
1324 dropTarget = CKEDITOR.plugins.clipboard.getDropTarget( editor ),
1325 top = editor.ui.space( 'top' ),
1326 bottom = editor.ui.space( 'bottom' );
1327
1328 // -------------- DRAGOVER TOP & BOTTOM --------------
1329
1330 // Not allowing dragging on toolbar and bottom (#12613).
1331 clipboard.preventDefaultDropOnElement( top );
1332 clipboard.preventDefaultDropOnElement( bottom );
1333
1334 // -------------- DRAGSTART --------------
1335 // Listed on dragstart to mark internal and cross-editor drag & drop
1336 // and save range and selected HTML.
1337
1338 editable.attachListener( dropTarget, 'dragstart', fireDragEvent );
1339
1340 // Make sure to reset data transfer (in case dragend was not called or was canceled).
1341 editable.attachListener( editor, 'dragstart', clipboard.resetDragDataTransfer, clipboard, null, 1 );
1342
1343 // Create a dataTransfer object and save it globally.
1344 editable.attachListener( editor, 'dragstart', function( evt ) {
1345 clipboard.initDragDataTransfer( evt, editor );
1346 }, null, null, 2 );
1347
1348 editable.attachListener( editor, 'dragstart', function() {
1349 // Save drag range globally for cross editor D&D.
1350 var dragRange = clipboard.dragRange = editor.getSelection().getRanges()[ 0 ];
1351
1352 // Store number of children, so we can later tell if any text node was split on drop. (#13011, #13447)
1353 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
1354 clipboard.dragStartContainerChildCount = dragRange ? getContainerChildCount( dragRange.startContainer ) : null;
1355 clipboard.dragEndContainerChildCount = dragRange ? getContainerChildCount( dragRange.endContainer ) : null;
1356 }
1357 }, null, null, 100 );
1358
1359 // -------------- DRAGEND --------------
1360 // Clean up on dragend.
1361
1362 editable.attachListener( dropTarget, 'dragend', fireDragEvent );
1363
1364 // Init data transfer if someone wants to use it in dragend.
1365 editable.attachListener( editor, 'dragend', clipboard.initDragDataTransfer, clipboard, null, 1 );
1366
1367 // When drag & drop is done we need to reset dataTransfer so the future
1368 // external drop will be not recognize as internal.
1369 editable.attachListener( editor, 'dragend', clipboard.resetDragDataTransfer, clipboard, null, 100 );
1370
1371 // -------------- DRAGOVER --------------
1372 // We need to call preventDefault on dragover because otherwise if
1373 // we drop image it will overwrite document.
1374
1375 editable.attachListener( dropTarget, 'dragover', function( evt ) {
1376 var target = evt.data.getTarget();
1377
1378 // Prevent reloading page when dragging image on empty document (#12619).
1379 if ( target && target.is && target.is( 'html' ) ) {
1380 evt.data.preventDefault();
1381 return;
1382 }
1383
1384 // If we do not prevent default dragover on IE the file path
1385 // will be loaded and we will lose content. On the other hand
1386 // if we prevent it the cursor will not we shown, so we prevent
1387 // dragover only on IE, on versions which support file API and only
1388 // if the event contains files.
1389 if ( CKEDITOR.env.ie &&
1390 CKEDITOR.plugins.clipboard.isFileApiSupported &&
1391 evt.data.$.dataTransfer.types.contains( 'Files' ) ) {
1392 evt.data.preventDefault();
1393 }
1394 } );
1395
1396 // -------------- DROP --------------
1397
1398 editable.attachListener( dropTarget, 'drop', function( evt ) {
1399 // Do nothing if event was already prevented. (#13879)
1400 if ( evt.data.$.defaultPrevented ) {
1401 return;
1402 }
1403
1404 // Cancel native drop.
1405 evt.data.preventDefault();
1406
1407 var target = evt.data.getTarget(),
1408 readOnly = target.isReadOnly();
1409
1410 // Do nothing if drop on non editable element (#13015).
1411 // The <html> tag isn't editable (body is), but we want to allow drop on it
1412 // (so it is possible to drop below editor contents).
1413 if ( readOnly && !( target.type == CKEDITOR.NODE_ELEMENT && target.is( 'html' ) ) ) {
1414 return;
1415 }
1416
1417 // Getting drop position is one of the most complex parts.
1418 var dropRange = clipboard.getRangeAtDropPosition( evt, editor ),
1419 dragRange = clipboard.dragRange;
1420
1421 // Do nothing if it was not possible to get drop range.
1422 if ( !dropRange ) {
1423 return;
1424 }
1425
1426 // Fire drop.
1427 fireDragEvent( evt, dragRange, dropRange );
1428 }, null, null, 9999 );
1429
1430 // Create dataTransfer or get it, if it was created before.
1431 editable.attachListener( editor, 'drop', clipboard.initDragDataTransfer, clipboard, null, 1 );
1432
1433 // Execute drop action, fire paste.
1434 editable.attachListener( editor, 'drop', function( evt ) {
1435 var data = evt.data;
1436
1437 if ( !data ) {
1438 return;
1439 }
1440
1441 // Let user modify drag and drop range.
1442 var dropRange = data.dropRange,
1443 dragRange = data.dragRange,
1444 dataTransfer = data.dataTransfer;
1445
1446 if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_INTERNAL ) {
1447 // Execute drop with a timeout because otherwise selection, after drop,
1448 // on IE is in the drag position, instead of drop position.
1449 setTimeout( function() {
1450 clipboard.internalDrop( dragRange, dropRange, dataTransfer, editor );
1451 }, 0 );
1452 } else if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) {
1453 crossEditorDrop( dragRange, dropRange, dataTransfer );
1454 } else {
1455 externalDrop( dropRange, dataTransfer );
1456 }
1457 }, null, null, 9999 );
1458
1459 // Cross editor drag and drop (drag in one Editor and drop in the other).
1460 function crossEditorDrop( dragRange, dropRange, dataTransfer ) {
1461 // Paste event should be fired before delete contents because otherwise
1462 // Chrome have a problem with drop range (Chrome split the drop
1463 // range container so the offset is bigger then container length).
1464 dropRange.select();
1465 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
1466
1467 // Remove dragged content and make a snapshot.
1468 dataTransfer.sourceEditor.fire( 'saveSnapshot' );
1469
1470 dataTransfer.sourceEditor.editable().extractHtmlFromRange( dragRange );
1471
1472 // Make some selection before saving snapshot, otherwise error will be thrown, because
1473 // there will be no valid selection after content is removed.
1474 dataTransfer.sourceEditor.getSelection().selectRanges( [ dragRange ] );
1475 dataTransfer.sourceEditor.fire( 'saveSnapshot' );
1476 }
1477
1478 // Drop from external source.
1479 function externalDrop( dropRange, dataTransfer ) {
1480 // Paste content into the drop position.
1481 dropRange.select();
1482
1483 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
1484
1485 // Usually we reset DataTranfer on dragend,
1486 // but dragend is called on the same element as dragstart
1487 // so it will not be called on on external drop.
1488 clipboard.resetDragDataTransfer();
1489 }
1490
1491 // Fire drag/drop events (dragstart, dragend, drop).
1492 function fireDragEvent( evt, dragRange, dropRange ) {
1493 var eventData = {
1494 $: evt.data.$,
1495 target: evt.data.getTarget()
1496 };
1497
1498 if ( dragRange ) {
1499 eventData.dragRange = dragRange;
1500 }
1501 if ( dropRange ) {
1502 eventData.dropRange = dropRange;
1503 }
1504
1505 if ( editor.fire( evt.name, eventData ) === false ) {
1506 evt.data.preventDefault();
1507 }
1508 }
1509
1510 function getContainerChildCount( container ) {
1511 if ( container.type != CKEDITOR.NODE_ELEMENT ) {
1512 container = container.getParent();
1513 }
1514
1515 return container.getChildCount();
1516 }
1517 } );
1518 }
1519
1520 /**
1521 * @singleton
1522 * @class CKEDITOR.plugins.clipboard
1523 */
1524 CKEDITOR.plugins.clipboard = {
1525 /**
1526 * True if the environment allows to set data on copy or cut manually. This value is false in IE, because this browser
1527 * shows the security dialog window when the script tries to set clipboard data and on iOS, because custom data is
1528 * not saved to clipboard there.
1529 *
1530 * @since 4.5
1531 * @readonly
1532 * @property {Boolean}
1533 */
1534 isCustomCopyCutSupported: !CKEDITOR.env.ie && !CKEDITOR.env.iOS,
1535
1536 /**
1537 * True if the environment supports MIME types and custom data types in dataTransfer/cliboardData getData/setData methods.
1538 *
1539 * @since 4.5
1540 * @readonly
1541 * @property {Boolean}
1542 */
1543 isCustomDataTypesSupported: !CKEDITOR.env.ie,
1544
1545 /**
1546 * True if the environment supports File API.
1547 *
1548 * @since 4.5
1549 * @readonly
1550 * @property {Boolean}
1551 */
1552 isFileApiSupported: !CKEDITOR.env.ie || CKEDITOR.env.version > 9,
1553
1554 /**
1555 * Main native paste event editable should listen to.
1556 *
1557 * **Note:** Safari does not like the {@link CKEDITOR.editor#beforePaste} event &mdash; it sometimes does not
1558 * handle <kbd>Ctrl+C</kbd> properly. This is probably caused by some race condition between events.
1559 * Chrome, Firefox and Edge work well with both events, so it is better to use {@link CKEDITOR.editor#paste}
1560 * which will handle pasting from e.g. browsers' menu bars.
1561 * IE7/8 does not like the {@link CKEDITOR.editor#paste} event for which it is throwing random errors.
1562 *
1563 * @since 4.5
1564 * @readonly
1565 * @property {String}
1566 */
1567 mainPasteEvent: ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ? 'beforepaste' : 'paste',
1568
1569 /**
1570 * Returns `true` if it is expected that a browser provides HTML data through the Clipboard API.
1571 * If not, this method returns `false` and as a result CKEditor will use the paste bin. Read more in
1572 * the [Clipboard Integration](http://docs.ckeditor.com/#!/guide/dev_clipboard-section-clipboard-api) guide.
1573 *
1574 * @since 4.5.2
1575 * @returns {Boolean}
1576 */
1577 canClipboardApiBeTrusted: function( dataTransfer, editor ) {
1578 // If it's an internal or cross-editor data transfer, then it means that custom cut/copy/paste support works
1579 // and that the data were put manually on the data transfer so we can be sure that it's available.
1580 if ( dataTransfer.getTransferType( editor ) != CKEDITOR.DATA_TRANSFER_EXTERNAL ) {
1581 return true;
1582 }
1583
1584 // In Chrome we can trust Clipboard API, with the exception of Chrome on Android (in both - mobile and desktop modes), where
1585 // clipboard API is not available so we need to check it (#13187).
1586 if ( CKEDITOR.env.chrome && !dataTransfer.isEmpty() ) {
1587 return true;
1588 }
1589
1590 // Because of a Firefox bug HTML data are not available in some cases (e.g. paste from Word), in such cases we
1591 // need to use the pastebin (#13528, https://bugzilla.mozilla.org/show_bug.cgi?id=1183686).
1592 if ( CKEDITOR.env.gecko && ( dataTransfer.getData( 'text/html' ) || dataTransfer.getFilesCount() ) ) {
1593 return true;
1594 }
1595
1596 // In Safari and IE HTML data is not available though the Clipboard API.
1597 // In Edge things are a bit messy at the moment -
1598 // https://connect.microsoft.com/IE/feedback/details/1572456/edge-clipboard-api-text-html-content-messed-up-in-event-clipboarddata
1599 // It is safer to use the paste bin in unknown cases.
1600 return false;
1601 },
1602
1603 /**
1604 * Returns the element that should be used as the target for the drop event.
1605 *
1606 * @since 4.5
1607 * @param {CKEDITOR.editor} editor The editor instance.
1608 * @returns {CKEDITOR.dom.domObject} the element that should be used as the target for the drop event.
1609 */
1610 getDropTarget: function( editor ) {
1611 var editable = editor.editable();
1612
1613 // #11123 Firefox needs to listen on document, because otherwise event won't be fired.
1614 // #11086 IE8 cannot listen on document.
1615 if ( ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) || editable.isInline() ) {
1616 return editable;
1617 } else {
1618 return editor.document;
1619 }
1620 },
1621
1622 /**
1623 * IE 8 & 9 split text node on drop so the first node contains the
1624 * text before the drop position and the second contains the rest. If you
1625 * drag the content from the same node you will be not be able to get
1626 * it (the range becomes invalid), so you need to join them back.
1627 *
1628 * Note that the first node in IE 8 & 9 is the original node object
1629 * but with shortened content.
1630 *
1631 * Before:
1632 * --- Text Node A ----------------------------------
1633 * /\
1634 * Drag position
1635 *
1636 * After (IE 8 & 9):
1637 * --- Text Node A ----- --- Text Node B -----------
1638 * /\ /\
1639 * Drop position Drag position
1640 * (invalid)
1641 *
1642 * After (other browsers):
1643 * --- Text Node A ----------------------------------
1644 * /\ /\
1645 * Drop position Drag position
1646 *
1647 * **Note:** This function is in the public scope for tests usage only.
1648 *
1649 * @since 4.5
1650 * @private
1651 * @param {CKEDITOR.dom.range} dragRange The drag range.
1652 * @param {CKEDITOR.dom.range} dropRange The drop range.
1653 * @param {Number} preDragStartContainerChildCount The number of children of the drag range start container before the drop.
1654 * @param {Number} preDragEndContainerChildCount The number of children of the drag range end container before the drop.
1655 */
1656 fixSplitNodesAfterDrop: function( dragRange, dropRange, preDragStartContainerChildCount, preDragEndContainerChildCount ) {
1657 var dropContainer = dropRange.startContainer;
1658
1659 if (
1660 typeof preDragEndContainerChildCount != 'number' ||
1661 typeof preDragStartContainerChildCount != 'number'
1662 ) {
1663 return;
1664 }
1665
1666 // We are only concerned about ranges anchored in elements.
1667 if ( dropContainer.type != CKEDITOR.NODE_ELEMENT ) {
1668 return;
1669 }
1670
1671 if ( handleContainer( dragRange.startContainer, dropContainer, preDragStartContainerChildCount ) ) {
1672 return;
1673 }
1674
1675 if ( handleContainer( dragRange.endContainer, dropContainer, preDragEndContainerChildCount ) ) {
1676 return;
1677 }
1678
1679 function handleContainer( dragContainer, dropContainer, preChildCount ) {
1680 var dragElement = dragContainer;
1681 if ( dragElement.type == CKEDITOR.NODE_TEXT ) {
1682 dragElement = dragContainer.getParent();
1683 }
1684
1685 if ( dragElement.equals( dropContainer ) && preChildCount != dropContainer.getChildCount() ) {
1686 applyFix( dropRange );
1687 return true;
1688 }
1689 }
1690
1691 function applyFix( dropRange ) {
1692 var nodeBefore = dropRange.startContainer.getChild( dropRange.startOffset - 1 ),
1693 nodeAfter = dropRange.startContainer.getChild( dropRange.startOffset );
1694
1695 if (
1696 nodeBefore && nodeBefore.type == CKEDITOR.NODE_TEXT &&
1697 nodeAfter && nodeAfter.type == CKEDITOR.NODE_TEXT
1698 ) {
1699 var offset = nodeBefore.getLength();
1700
1701 nodeBefore.setText( nodeBefore.getText() + nodeAfter.getText() );
1702 nodeAfter.remove();
1703
1704 dropRange.setStart( nodeBefore, offset );
1705 dropRange.collapse( true );
1706 }
1707 }
1708 },
1709
1710 /**
1711 * Checks whether turning the drag range into bookmarks will invalidate the drop range.
1712 * This usually happens when the drop range shares the container with the drag range and is
1713 * located after the drag range, but there are countless edge cases.
1714 *
1715 * This function is stricly related to {@link #internalDrop} which toggles
1716 * order in which it creates bookmarks for both ranges based on a value returned
1717 * by this method. In some cases this method returns a value which is not necessarily
1718 * true in terms of what it was meant to check, but it is convenient, because
1719 * we know how it is interpreted in {@link #internalDrop}, so the correct
1720 * behavior of the entire algorithm is assured.
1721 *
1722 * **Note:** This function is in the public scope for tests usage only.
1723 *
1724 * @since 4.5
1725 * @private
1726 * @param {CKEDITOR.dom.range} dragRange The first range to compare.
1727 * @param {CKEDITOR.dom.range} dropRange The second range to compare.
1728 * @returns {Boolean} `true` if the first range is before the second range.
1729 */
1730 isDropRangeAffectedByDragRange: function( dragRange, dropRange ) {
1731 var dropContainer = dropRange.startContainer,
1732 dropOffset = dropRange.endOffset;
1733
1734 // Both containers are the same and drop offset is at the same position or later.
1735 // " A L] A " " M A "
1736 // ^ ^
1737 if ( dragRange.endContainer.equals( dropContainer ) && dragRange.endOffset <= dropOffset ) {
1738 return true;
1739 }
1740
1741 // Bookmark for drag start container will mess up with offsets.
1742 // " O [L A " " M A "
1743 // ^ ^
1744 if (
1745 dragRange.startContainer.getParent().equals( dropContainer ) &&
1746 dragRange.startContainer.getIndex() < dropOffset
1747 ) {
1748 return true;
1749 }
1750
1751 // Bookmark for drag end container will mess up with offsets.
1752 // " O] L A " " M A "
1753 // ^ ^
1754 if (
1755 dragRange.endContainer.getParent().equals( dropContainer ) &&
1756 dragRange.endContainer.getIndex() < dropOffset
1757 ) {
1758 return true;
1759 }
1760
1761 return false;
1762 },
1763
1764 /**
1765 * Internal drag and drop (drag and drop in the same editor instance).
1766 *
1767 * **Note:** This function is in the public scope for tests usage only.
1768 *
1769 * @since 4.5
1770 * @private
1771 * @param {CKEDITOR.dom.range} dragRange The first range to compare.
1772 * @param {CKEDITOR.dom.range} dropRange The second range to compare.
1773 * @param {CKEDITOR.plugins.clipboard.dataTransfer} dataTransfer
1774 * @param {CKEDITOR.editor} editor
1775 */
1776 internalDrop: function( dragRange, dropRange, dataTransfer, editor ) {
1777 var clipboard = CKEDITOR.plugins.clipboard,
1778 editable = editor.editable(),
1779 dragBookmark, dropBookmark, isDropRangeAffected;
1780
1781 // Save and lock snapshot so there will be only
1782 // one snapshot for both remove and insert content.
1783 editor.fire( 'saveSnapshot' );
1784 editor.fire( 'lockSnapshot', { dontUpdate: 1 } );
1785
1786 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
1787 this.fixSplitNodesAfterDrop(
1788 dragRange,
1789 dropRange,
1790 clipboard.dragStartContainerChildCount,
1791 clipboard.dragEndContainerChildCount
1792 );
1793 }
1794
1795 // Because we manipulate multiple ranges we need to do it carefully,
1796 // changing one range (event creating a bookmark) may make other invalid.
1797 // We need to change ranges into bookmarks so we can manipulate them easily in the future.
1798 // We can change the range which is later in the text before we change the preceding range.
1799 // We call isDropRangeAffectedByDragRange to test the order of ranges.
1800 isDropRangeAffected = this.isDropRangeAffectedByDragRange( dragRange, dropRange );
1801 if ( !isDropRangeAffected ) {
1802 dragBookmark = dragRange.createBookmark( false );
1803 }
1804 dropBookmark = dropRange.clone().createBookmark( false );
1805 if ( isDropRangeAffected ) {
1806 dragBookmark = dragRange.createBookmark( false );
1807 }
1808
1809 // Check if drop range is inside range.
1810 // This is an edge case when we drop something on editable's margin/padding.
1811 // That space is not treated as a part of the range we drag, so it is possible to drop there.
1812 // When we drop, browser tries to find closest drop position and it finds it inside drag range. (#13453)
1813 var startNode = dragBookmark.startNode,
1814 endNode = dragBookmark.endNode,
1815 dropNode = dropBookmark.startNode,
1816 dropInsideDragRange =
1817 // Must check endNode because dragRange could be collapsed in some edge cases (simulated DnD).
1818 endNode &&
1819 ( startNode.getPosition( dropNode ) & CKEDITOR.POSITION_PRECEDING ) &&
1820 ( endNode.getPosition( dropNode ) & CKEDITOR.POSITION_FOLLOWING );
1821
1822 // If the drop range happens to be inside drag range change it's position to the beginning of the drag range.
1823 if ( dropInsideDragRange ) {
1824 // We only change position of bookmark span that is connected with dropBookmark.
1825 // dropRange will be overwritten and set to the dropBookmark later.
1826 dropNode.insertBefore( startNode );
1827 }
1828
1829 // No we can safely delete content for the drag range...
1830 dragRange = editor.createRange();
1831 dragRange.moveToBookmark( dragBookmark );
1832 editable.extractHtmlFromRange( dragRange, 1 );
1833
1834 // ...and paste content into the drop position.
1835 dropRange = editor.createRange();
1836 dropRange.moveToBookmark( dropBookmark );
1837
1838 // We do not select drop range, because of may be in the place we can not set the selection
1839 // (e.g. between blocks, in case of block widget D&D). We put range to the paste event instead.
1840 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop', range: dropRange }, 1 );
1841
1842 editor.fire( 'unlockSnapshot' );
1843 },
1844
1845 /**
1846 * Gets the range from the `drop` event.
1847 *
1848 * @since 4.5
1849 * @param {Object} domEvent A native DOM drop event object.
1850 * @param {CKEDITOR.editor} editor The source editor instance.
1851 * @returns {CKEDITOR.dom.range} range at drop position.
1852 */
1853 getRangeAtDropPosition: function( dropEvt, editor ) {
1854 var $evt = dropEvt.data.$,
1855 x = $evt.clientX,
1856 y = $evt.clientY,
1857 $range,
1858 defaultRange = editor.getSelection( true ).getRanges()[ 0 ],
1859 range = editor.createRange();
1860
1861 // Make testing possible.
1862 if ( dropEvt.data.testRange )
1863 return dropEvt.data.testRange;
1864
1865 // Webkits.
1866 if ( document.caretRangeFromPoint ) {
1867 $range = editor.document.$.caretRangeFromPoint( x, y );
1868 range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );
1869 range.collapse( true );
1870 }
1871 // FF.
1872 else if ( $evt.rangeParent ) {
1873 range.setStart( CKEDITOR.dom.node( $evt.rangeParent ), $evt.rangeOffset );
1874 range.collapse( true );
1875 }
1876 // IEs 9+.
1877 // We check if editable is focused to make sure that it's an internal DnD. External DnD must use the second
1878 // mechanism because of http://dev.ckeditor.com/ticket/13472#comment:6.
1879 else if ( CKEDITOR.env.ie && CKEDITOR.env.version > 8 && defaultRange && editor.editable().hasFocus ) {
1880 // On IE 9+ range by default is where we expected it.
1881 // defaultRange may be undefined if dragover was canceled (file drop).
1882 return defaultRange;
1883 }
1884 // IE 8 and all IEs if !defaultRange or external DnD.
1885 else if ( document.body.createTextRange ) {
1886 // To use this method we need a focus (which may be somewhere else in case of external drop).
1887 editor.focus();
1888
1889 $range = editor.document.getBody().$.createTextRange();
1890 try {
1891 var sucess = false;
1892
1893 // If user drop between text line IEs moveToPoint throws exception:
1894 //
1895 // Lorem ipsum pulvinar purus et euismod
1896 //
1897 // dolor sit amet,| consectetur adipiscing
1898 // *
1899 // vestibulum tincidunt augue eget tempus.
1900 //
1901 // * - drop position
1902 // | - expected cursor position
1903 //
1904 // So we try to call moveToPoint with +-1px up to +-20px above or
1905 // below original drop position to find nearest good drop position.
1906 for ( var i = 0; i < 20 && !sucess; i++ ) {
1907 if ( !sucess ) {
1908 try {
1909 $range.moveToPoint( x, y - i );
1910 sucess = true;
1911 } catch ( err ) {
1912 }
1913 }
1914 if ( !sucess ) {
1915 try {
1916 $range.moveToPoint( x, y + i );
1917 sucess = true;
1918 } catch ( err ) {
1919 }
1920 }
1921 }
1922
1923 if ( sucess ) {
1924 var id = 'cke-temp-' + ( new Date() ).getTime();
1925 $range.pasteHTML( '<span id="' + id + '">\u200b</span>' );
1926
1927 var span = editor.document.getById( id );
1928 range.moveToPosition( span, CKEDITOR.POSITION_BEFORE_START );
1929 span.remove();
1930 } else {
1931 // If the fist method does not succeed we might be next to
1932 // the short element (like header):
1933 //
1934 // Lorem ipsum pulvinar purus et euismod.
1935 //
1936 //
1937 // SOME HEADER| *
1938 //
1939 //
1940 // vestibulum tincidunt augue eget tempus.
1941 //
1942 // * - drop position
1943 // | - expected cursor position
1944 //
1945 // In such situation elementFromPoint returns proper element. Using getClientRect
1946 // it is possible to check if the cursor should be at the beginning or at the end
1947 // of paragraph.
1948 var $element = editor.document.$.elementFromPoint( x, y ),
1949 element = new CKEDITOR.dom.element( $element ),
1950 rect;
1951
1952 if ( !element.equals( editor.editable() ) && element.getName() != 'html' ) {
1953 rect = element.getClientRect();
1954
1955 if ( x < rect.left ) {
1956 range.setStartAt( element, CKEDITOR.POSITION_AFTER_START );
1957 range.collapse( true );
1958 } else {
1959 range.setStartAt( element, CKEDITOR.POSITION_BEFORE_END );
1960 range.collapse( true );
1961 }
1962 }
1963 // If drop happens on no element elementFromPoint returns html or body.
1964 //
1965 // * |Lorem ipsum pulvinar purus et euismod.
1966 //
1967 // vestibulum tincidunt augue eget tempus.
1968 //
1969 // * - drop position
1970 // | - expected cursor position
1971 //
1972 // In such case we can try to use default selection. If startContainer is not
1973 // 'editable' element it is probably proper selection.
1974 else if ( defaultRange && defaultRange.startContainer &&
1975 !defaultRange.startContainer.equals( editor.editable() ) ) {
1976 return defaultRange;
1977
1978 // Otherwise we can not find any drop position and we have to return null
1979 // and cancel drop event.
1980 } else {
1981 return null;
1982 }
1983
1984 }
1985 } catch ( err ) {
1986 return null;
1987 }
1988 } else {
1989 return null;
1990 }
1991
1992 return range;
1993 },
1994
1995 /**
1996 * This function tries to link the `evt.data.dataTransfer` property of the {@link CKEDITOR.editor#dragstart},
1997 * {@link CKEDITOR.editor#dragend} and {@link CKEDITOR.editor#drop} events to a single
1998 * {@link CKEDITOR.plugins.clipboard.dataTransfer} object.
1999 *
2000 * This method is automatically used by the core of the drag and drop functionality and
2001 * usually does not have to be called manually when using the drag and drop events.
2002 *
2003 * This method behaves differently depending on whether the drag and drop events were fired
2004 * artificially (to represent a non-native drag and drop) or whether they were caused by the native drag and drop.
2005 *
2006 * If the native event is not available, then it will create a new {@link CKEDITOR.plugins.clipboard.dataTransfer}
2007 * instance (if it does not exist already) and will link it to this and all following event objects until
2008 * the {@link #resetDragDataTransfer} method is called. It means that all three drag and drop events must be fired
2009 * in order to ensure that the data transfer is bound correctly.
2010 *
2011 * If the native event is available, then the {@link CKEDITOR.plugins.clipboard.dataTransfer} is identified
2012 * by its ID and a new instance is assigned to the `evt.data.dataTransfer` only if the ID changed or
2013 * the {@link #resetDragDataTransfer} method was called.
2014 *
2015 * @since 4.5
2016 * @param {CKEDITOR.dom.event} [evt] A drop event object.
2017 * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
2018 */
2019 initDragDataTransfer: function( evt, sourceEditor ) {
2020 // Create a new dataTransfer object based on the drop event.
2021 // If this event was used on dragstart to create dataTransfer
2022 // both dataTransfer objects will have the same id.
2023 var nativeDataTransfer = evt.data.$ ? evt.data.$.dataTransfer : null,
2024 dataTransfer = new this.dataTransfer( nativeDataTransfer, sourceEditor );
2025
2026 if ( !nativeDataTransfer ) {
2027 // No native event.
2028 if ( this.dragData ) {
2029 dataTransfer = this.dragData;
2030 } else {
2031 this.dragData = dataTransfer;
2032 }
2033 } else {
2034 // Native event. If there is the same id we will replace dataTransfer with the one
2035 // created on drag, because it contains drag editor, drag content and so on.
2036 // Otherwise (in case of drag from external source) we save new object to
2037 // the global clipboard.dragData.
2038 if ( this.dragData && dataTransfer.id == this.dragData.id ) {
2039 dataTransfer = this.dragData;
2040 } else {
2041 this.dragData = dataTransfer;
2042 }
2043 }
2044
2045 evt.data.dataTransfer = dataTransfer;
2046 },
2047
2048 /**
2049 * Removes the global {@link #dragData} so the next call to {@link #initDragDataTransfer}
2050 * always creates a new instance of {@link CKEDITOR.plugins.clipboard.dataTransfer}.
2051 *
2052 * @since 4.5
2053 */
2054 resetDragDataTransfer: function() {
2055 this.dragData = null;
2056 },
2057
2058 /**
2059 * Global object storing the data transfer of the current drag and drop operation.
2060 * Do not use it directly, use {@link #initDragDataTransfer} and {@link #resetDragDataTransfer}.
2061 *
2062 * Note: This object is global (meaning that it is not related to a single editor instance)
2063 * in order to handle drag and drop from one editor into another.
2064 *
2065 * @since 4.5
2066 * @private
2067 * @property {CKEDITOR.plugins.clipboard.dataTransfer} dragData
2068 */
2069
2070 /**
2071 * Range object to save the drag range and remove its content after the drop.
2072 *
2073 * @since 4.5
2074 * @private
2075 * @property {CKEDITOR.dom.range} dragRange
2076 */
2077
2078 /**
2079 * Initializes and links data transfer objects based on the paste event. If the data
2080 * transfer object was already initialized on this event, the function will
2081 * return that object. In IE it is not possible to link copy/cut and paste events
2082 * so the method always returns a new object. The same happens if there is no paste event
2083 * passed to the method.
2084 *
2085 * @since 4.5
2086 * @param {CKEDITOR.dom.event} [evt] A paste event object.
2087 * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
2088 * @returns {CKEDITOR.plugins.clipboard.dataTransfer} The data transfer object.
2089 */
2090 initPasteDataTransfer: function( evt, sourceEditor ) {
2091 if ( !this.isCustomCopyCutSupported ) {
2092 // Edge does not support custom copy/cut, but it have some useful data in the clipboardData (#13755).
2093 return new this.dataTransfer( ( CKEDITOR.env.edge && evt && evt.data.$ && evt.data.$.clipboardData ) || null, sourceEditor );
2094 } else if ( evt && evt.data && evt.data.$ ) {
2095 var dataTransfer = new this.dataTransfer( evt.data.$.clipboardData, sourceEditor );
2096
2097 if ( this.copyCutData && dataTransfer.id == this.copyCutData.id ) {
2098 dataTransfer = this.copyCutData;
2099 dataTransfer.$ = evt.data.$.clipboardData;
2100 } else {
2101 this.copyCutData = dataTransfer;
2102 }
2103
2104 return dataTransfer;
2105 } else {
2106 return new this.dataTransfer( null, sourceEditor );
2107 }
2108 },
2109
2110 /**
2111 * Prevents dropping on the specified element.
2112 *
2113 * @since 4.5
2114 * @param {CKEDITOR.dom.element} element The element on which dropping should be disabled.
2115 */
2116 preventDefaultDropOnElement: function( element ) {
2117 element && element.on( 'dragover', preventDefaultSetDropEffectToNone );
2118 }
2119 };
2120
2121 // Data type used to link drag and drop events.
2122 //
2123 // In IE URL data type is buggie and there is no way to mark drag & drop without
2124 // modifying text data (which would be displayed if user drop content to the textarea)
2125 // so we just read dragged text.
2126 //
2127 // In Chrome and Firefox we can use custom data types.
2128 var clipboardIdDataType = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ? 'cke/id' : 'Text';
2129 /**
2130 * Facade for the native `dataTransfer`/`clipboadData` object to hide all differences
2131 * between browsers.
2132 *
2133 * @since 4.5
2134 * @class CKEDITOR.plugins.clipboard.dataTransfer
2135 * @constructor Creates a class instance.
2136 * @param {Object} [nativeDataTransfer] A native data transfer object.
2137 * @param {CKEDITOR.editor} [editor] The source editor instance. If the editor is defined, dataValue will
2138 * be created based on the editor content and the type will be 'html'.
2139 */
2140 CKEDITOR.plugins.clipboard.dataTransfer = function( nativeDataTransfer, editor ) {
2141 if ( nativeDataTransfer ) {
2142 this.$ = nativeDataTransfer;
2143 }
2144
2145 this._ = {
2146 metaRegExp: /^<meta.*?>/i,
2147 bodyRegExp: /<body(?:[\s\S]*?)>([\s\S]*)<\/body>/i,
2148 fragmentRegExp: /<!--(?:Start|End)Fragment-->/g,
2149
2150 data: {},
2151 files: [],
2152
2153 normalizeType: function( type ) {
2154 type = type.toLowerCase();
2155
2156 if ( type == 'text' || type == 'text/plain' ) {
2157 return 'Text'; // IE support only Text and URL;
2158 } else if ( type == 'url' ) {
2159 return 'URL'; // IE support only Text and URL;
2160 } else {
2161 return type;
2162 }
2163 }
2164 };
2165
2166 // Check if ID is already created.
2167 this.id = this.getData( clipboardIdDataType );
2168
2169 // If there is no ID we need to create it. Different browsers needs different ID.
2170 if ( !this.id ) {
2171 if ( clipboardIdDataType == 'Text' ) {
2172 // For IE10+ only Text data type is supported and we have to compare dragged
2173 // and dropped text. If the ID is not set it means that empty string was dragged
2174 // (ex. image with no alt). We change null to empty string.
2175 this.id = '';
2176 } else {
2177 // String for custom data type.
2178 this.id = 'cke-' + CKEDITOR.tools.getUniqueId();
2179 }
2180 }
2181
2182 // In IE10+ we can not use any data type besides text, so we do not call setData.
2183 if ( clipboardIdDataType != 'Text' ) {
2184 // Try to set ID so it will be passed from the drag to the drop event.
2185 // On some browsers with some event it is not possible to setData so we
2186 // need to catch exceptions.
2187 try {
2188 this.$.setData( clipboardIdDataType, this.id );
2189 } catch ( err ) {}
2190 }
2191
2192 if ( editor ) {
2193 this.sourceEditor = editor;
2194
2195 this.setData( 'text/html', editor.getSelectedHtml( 1 ) );
2196
2197 // Without setData( 'text', ... ) on dragstart there is no drop event in Safari.
2198 // Also 'text' data is empty as drop to the textarea does not work if we do not put there text.
2199 if ( clipboardIdDataType != 'Text' && !this.getData( 'text/plain' ) ) {
2200 this.setData( 'text/plain', editor.getSelection().getSelectedText() );
2201 }
2202 }
2203
2204 /**
2205 * Data transfer ID used to bind all dataTransfer
2206 * objects based on the same event (e.g. in drag and drop events).
2207 *
2208 * @readonly
2209 * @property {String} id
2210 */
2211
2212 /**
2213 * A native DOM event object.
2214 *
2215 * @readonly
2216 * @property {Object} $
2217 */
2218
2219 /**
2220 * Source editor &mdash; the editor where the drag starts.
2221 * Might be undefined if the drag starts outside the editor (e.g. when dropping files to the editor).
2222 *
2223 * @readonly
2224 * @property {CKEDITOR.editor} sourceEditor
2225 */
2226
2227 /**
2228 * Private properties and methods.
2229 *
2230 * @private
2231 * @property {Object} _
2232 */
2233 };
2234
2235 /**
2236 * Data transfer operation (drag and drop or copy and paste) started and ended in the same
2237 * editor instance.
2238 *
2239 * @since 4.5
2240 * @readonly
2241 * @property {Number} [=1]
2242 * @member CKEDITOR
2243 */
2244 CKEDITOR.DATA_TRANSFER_INTERNAL = 1;
2245
2246 /**
2247 * Data transfer operation (drag and drop or copy and paste) started in one editor
2248 * instance and ended in another.
2249 *
2250 * @since 4.5
2251 * @readonly
2252 * @property {Number} [=2]
2253 * @member CKEDITOR
2254 */
2255 CKEDITOR.DATA_TRANSFER_CROSS_EDITORS = 2;
2256
2257 /**
2258 * Data transfer operation (drag and drop or copy and paste) started outside of the editor.
2259 * The source of the data may be a textarea, HTML, another application, etc.
2260 *
2261 * @since 4.5
2262 * @readonly
2263 * @property {Number} [=3]
2264 * @member CKEDITOR
2265 */
2266 CKEDITOR.DATA_TRANSFER_EXTERNAL = 3;
2267
2268 CKEDITOR.plugins.clipboard.dataTransfer.prototype = {
2269 /**
2270 * Facade for the native `getData` method.
2271 *
2272 * @param {String} type The type of data to retrieve.
2273 * @returns {String} type Stored data for the given type or an empty string if the data for that type does not exist.
2274 */
2275 getData: function( type ) {
2276 function isEmpty( data ) {
2277 return data === undefined || data === null || data === '';
2278 }
2279
2280 type = this._.normalizeType( type );
2281
2282 var data = this._.data[ type ],
2283 result;
2284
2285 if ( isEmpty( data ) ) {
2286 try {
2287 data = this.$.getData( type );
2288 } catch ( e ) {}
2289 }
2290
2291 if ( isEmpty( data ) ) {
2292 data = '';
2293 }
2294
2295 // Some browsers add <meta http-equiv="content-type" content="text/html; charset=utf-8"> at the begging of the HTML data
2296 // or surround it with <html><head>...</head><body>(some content)<!--StartFragment--> and <!--EndFragment-->(some content)</body></html>
2297 // This code removes meta tags and returns only the contents of the <body> element if found. Note that
2298 // some significant content may be placed outside Start/EndFragment comments so it's kept.
2299 //
2300 // See #13583 for more details.
2301 if ( type == 'text/html' ) {
2302 data = data.replace( this._.metaRegExp, '' );
2303
2304 // Keep only contents of the <body> element
2305 result = this._.bodyRegExp.exec( data );
2306 if ( result && result.length ) {
2307 data = result[ 1 ];
2308
2309 // Remove also comments.
2310 data = data.replace( this._.fragmentRegExp, '' );
2311 }
2312 }
2313 // Firefox on Linux put files paths as a text/plain data if there are files
2314 // in the dataTransfer object. We need to hide it, because files should be
2315 // handled on paste only if dataValue is empty.
2316 else if ( type == 'Text' && CKEDITOR.env.gecko && this.getFilesCount() &&
2317 data.substring( 0, 7 ) == 'file://' ) {
2318 data = '';
2319 }
2320
2321 return data;
2322 },
2323
2324 /**
2325 * Facade for the native `setData` method.
2326 *
2327 * @param {String} type The type of data to retrieve.
2328 * @param {String} value The data to add.
2329 */
2330 setData: function( type, value ) {
2331 type = this._.normalizeType( type );
2332
2333 this._.data[ type ] = value;
2334
2335 // There is "Unexpected call to method or property access." error if you try
2336 // to set data of unsupported type on IE.
2337 if ( !CKEDITOR.plugins.clipboard.isCustomDataTypesSupported && type != 'URL' && type != 'Text' ) {
2338 return;
2339 }
2340
2341 // If we use the text type to bind the ID, then if someone tries to set the text, we must also
2342 // update ID accordingly. #13468.
2343 if ( clipboardIdDataType == 'Text' && type == 'Text' ) {
2344 this.id = value;
2345 }
2346
2347 try {
2348 this.$.setData( type, value );
2349 } catch ( e ) {}
2350 },
2351
2352 /**
2353 * Gets the data transfer type.
2354 *
2355 * @param {CKEDITOR.editor} targetEditor The drop/paste target editor instance.
2356 * @returns {Number} Possible values: {@link CKEDITOR#DATA_TRANSFER_INTERNAL},
2357 * {@link CKEDITOR#DATA_TRANSFER_CROSS_EDITORS}, {@link CKEDITOR#DATA_TRANSFER_EXTERNAL}.
2358 */
2359 getTransferType: function( targetEditor ) {
2360 if ( !this.sourceEditor ) {
2361 return CKEDITOR.DATA_TRANSFER_EXTERNAL;
2362 } else if ( this.sourceEditor == targetEditor ) {
2363 return CKEDITOR.DATA_TRANSFER_INTERNAL;
2364 } else {
2365 return CKEDITOR.DATA_TRANSFER_CROSS_EDITORS;
2366 }
2367 },
2368
2369 /**
2370 * Copies the data from the native data transfer to a private cache.
2371 * This function is needed because the data from the native data transfer
2372 * is available only synchronously to the event listener. It is not possible
2373 * to get the data asynchronously, after a timeout, and the {@link CKEDITOR.editor#paste}
2374 * event is fired asynchronously &mdash; hence the need for caching the data.
2375 */
2376 cacheData: function() {
2377 if ( !this.$ ) {
2378 return;
2379 }
2380
2381 var that = this,
2382 i, file;
2383
2384 function getAndSetData( type ) {
2385 type = that._.normalizeType( type );
2386
2387 var data = that.getData( type );
2388 if ( data ) {
2389 that._.data[ type ] = data;
2390 }
2391 }
2392
2393 // Copy data.
2394 if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
2395 if ( this.$.types ) {
2396 for ( i = 0; i < this.$.types.length; i++ ) {
2397 getAndSetData( this.$.types[ i ] );
2398 }
2399 }
2400 } else {
2401 getAndSetData( 'Text' );
2402 getAndSetData( 'URL' );
2403 }
2404
2405 // Copy files references.
2406 file = this._getImageFromClipboard();
2407 if ( ( this.$ && this.$.files ) || file ) {
2408 this._.files = [];
2409
2410 // Edge have empty files property with no length (#13755).
2411 if ( this.$.files && this.$.files.length ) {
2412 for ( i = 0; i < this.$.files.length; i++ ) {
2413 this._.files.push( this.$.files[ i ] );
2414 }
2415 }
2416
2417 // Don't include $.items if both $.files and $.items contains files, because,
2418 // according to spec and browsers behavior, they contain the same files.
2419 if ( this._.files.length === 0 && file ) {
2420 this._.files.push( file );
2421 }
2422 }
2423 },
2424
2425 /**
2426 * Gets the number of files in the dataTransfer object.
2427 *
2428 * @returns {Number} The number of files.
2429 */
2430 getFilesCount: function() {
2431 if ( this._.files.length ) {
2432 return this._.files.length;
2433 }
2434
2435 if ( this.$ && this.$.files && this.$.files.length ) {
2436 return this.$.files.length;
2437 }
2438
2439 return this._getImageFromClipboard() ? 1 : 0;
2440 },
2441
2442 /**
2443 * Gets the file at the index given.
2444 *
2445 * @param {Number} i Index.
2446 * @returns {File} File instance.
2447 */
2448 getFile: function( i ) {
2449 if ( this._.files.length ) {
2450 return this._.files[ i ];
2451 }
2452
2453 if ( this.$ && this.$.files && this.$.files.length ) {
2454 return this.$.files[ i ];
2455 }
2456
2457 // File or null if the file was not found.
2458 return i === 0 ? this._getImageFromClipboard() : undefined;
2459 },
2460
2461 /**
2462 * Checks if the data transfer contains any data.
2463 *
2464 * @returns {Boolean} `true` if the object contains no data.
2465 */
2466 isEmpty: function() {
2467 var typesToCheck = {},
2468 type;
2469
2470 // If dataTransfer contains files it is not empty.
2471 if ( this.getFilesCount() ) {
2472 return false;
2473 }
2474
2475 // Add custom types.
2476 for ( type in this._.data ) {
2477 typesToCheck[ type ] = 1;
2478 }
2479
2480 // Add native types.
2481 if ( this.$ ) {
2482 if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
2483 if ( this.$.types ) {
2484 for ( var i = 0; i < this.$.types.length; i++ ) {
2485 typesToCheck[ this.$.types[ i ] ] = 1;
2486 }
2487 }
2488 } else {
2489 typesToCheck.Text = 1;
2490 typesToCheck.URL = 1;
2491 }
2492 }
2493
2494 // Remove ID.
2495 if ( clipboardIdDataType != 'Text' ) {
2496 typesToCheck[ clipboardIdDataType ] = 0;
2497 }
2498
2499 for ( type in typesToCheck ) {
2500 if ( typesToCheck[ type ] && this.getData( type ) !== '' ) {
2501 return false;
2502 }
2503 }
2504
2505 return true;
2506 },
2507
2508 /**
2509 * When the content of the clipboard is pasted in Chrome, the clipboard data object has an empty `files` property,
2510 * but it is possible to get the file as `items[0].getAsFile();` (#12961).
2511 *
2512 * @private
2513 * @returns {File} File instance or `null` if not found.
2514 */
2515 _getImageFromClipboard: function() {
2516 var file;
2517
2518 if ( this.$ && this.$.items && this.$.items[ 0 ] ) {
2519 try {
2520 file = this.$.items[ 0 ].getAsFile();
2521 // Duck typing
2522 if ( file && file.type ) {
2523 return file;
2524 }
2525 } catch ( err ) {
2526 // noop
2527 }
2528 }
2529
2530 return undefined;
2531 }
2532 };
2533} )();
2534
2535/**
2536 * The default content type that is used when pasted data cannot be clearly recognized as HTML or text.
2537 *
2538 * For example: `'foo'` may come from a plain text editor or a website. It is not possible to recognize the content
2539 * type in this case, so the default type will be used. At the same time it is clear that `'<b>example</b> text'` is
2540 * HTML and its origin is a web page, email or another rich text editor.
2541 *
2542 * **Note:** If content type is text, then styles of the paste context are preserved.
2543 *
2544 * CKEDITOR.config.clipboard_defaultContentType = 'text';
2545 *
2546 * See also the {@link CKEDITOR.editor#paste} event and read more about the integration with clipboard
2547 * in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2548 *
2549 * @since 4.0
2550 * @cfg {'html'/'text'} [clipboard_defaultContentType='html']
2551 * @member CKEDITOR.config
2552 */
2553
2554/**
2555 * Fired after the user initiated a paste action, but before the data is inserted into the editor.
2556 * The listeners to this event are able to process the content before its insertion into the document.
2557 *
2558 * Read more about the integration with clipboard in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2559 *
2560 * See also:
2561 *
2562 * * the {@link CKEDITOR.config#pasteFilter} option,
2563 * * the {@link CKEDITOR.editor#drop} event,
2564 * * the {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2565 *
2566 * @since 3.1
2567 * @event paste
2568 * @member CKEDITOR.editor
2569 * @param {CKEDITOR.editor} editor This editor instance.
2570 * @param data
2571 * @param {String} data.type The type of data in `data.dataValue`. Usually `'html'` or `'text'`, but for listeners
2572 * with a priority smaller than `6` it may also be `'auto'` which means that the content type has not been recognised yet
2573 * (this will be done by the content type sniffer that listens with priority `6`).
2574 * @param {String} data.dataValue HTML to be pasted.
2575 * @param {String} data.method Indicates the data transfer method. It could be drag and drop or copy and paste.
2576 * Possible values: `'drop'`, `'paste'`. Introduced in CKEditor 4.5.
2577 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer Facade for the native dataTransfer object
2578 * which provides access to various data types and files, and passes some data between linked events
2579 * (like drag and drop). Introduced in CKEditor 4.5.
2580 * @param {Boolean} [data.dontFilter=false] Whether the {@link CKEDITOR.editor#pasteFilter paste filter} should not
2581 * be applied to data. This option has no effect when `data.type` equals `'text'` which means that for instance
2582 * {@link CKEDITOR.config#forcePasteAsPlainText} has a higher priority. Introduced in CKEditor 4.5.
2583 */
2584
2585/**
2586 * Fired before the {@link #paste} event. Allows to preset data type.
2587 *
2588 * **Note:** This event is deprecated. Add a `0` priority listener for the
2589 * {@link #paste} event instead.
2590 *
2591 * @deprecated
2592 * @event beforePaste
2593 * @member CKEDITOR.editor
2594 */
2595
2596 /**
2597 * Fired after the {@link #paste} event if content was modified. Note that if the paste
2598 * event does not insert any data, the `afterPaste` event will not be fired.
2599 *
2600 * @event afterPaste
2601 * @member CKEDITOR.editor
2602 */
2603
2604/**
2605 * Internal event to open the Paste dialog window.
2606 *
2607 * @private
2608 * @event pasteDialog
2609 * @member CKEDITOR.editor
2610 * @param {CKEDITOR.editor} editor This editor instance.
2611 * @param {Function} [data] Callback that will be passed to {@link CKEDITOR.editor#openDialog}.
2612 */
2613
2614/**
2615 * Facade for the native `drop` event. Fired when the native `drop` event occurs.
2616 *
2617 * **Note:** To manipulate dropped data, use the {@link CKEDITOR.editor#paste} event.
2618 * Use the `drop` event only to control drag and drop operations (e.g. to prevent the ability to drop some content).
2619 *
2620 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2621 *
2622 * See also:
2623 *
2624 * * The {@link CKEDITOR.editor#paste} event,
2625 * * The {@link CKEDITOR.editor#dragstart} and {@link CKEDITOR.editor#dragend} events,
2626 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2627 *
2628 * @since 4.5
2629 * @event drop
2630 * @member CKEDITOR.editor
2631 * @param {CKEDITOR.editor} editor This editor instance.
2632 * @param data
2633 * @param {Object} data.$ Native drop event.
2634 * @param {CKEDITOR.dom.node} data.target Drop target.
2635 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2636 * @param {CKEDITOR.dom.range} data.dragRange Drag range, lets you manipulate the drag range.
2637 * Note that dragged HTML is saved as `text/html` data on `dragstart` so if you change the drag range
2638 * on drop, dropped HTML will not change. You need to change it manually using
2639 * {@link CKEDITOR.plugins.clipboard.dataTransfer#setData dataTransfer.setData}.
2640 * @param {CKEDITOR.dom.range} data.dropRange Drop range, lets you manipulate the drop range.
2641 */
2642
2643/**
2644 * Facade for the native `dragstart` event. Fired when the native `dragstart` event occurs.
2645 *
2646 * This event can be canceled in order to block the drag start operation. It can also be fired to mimic the start of the drag and drop
2647 * operation. For instance, the `widget` plugin uses this option to integrate its custom block widget drag and drop with
2648 * the entire system.
2649 *
2650 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2651 *
2652 * See also:
2653 *
2654 * * The {@link CKEDITOR.editor#paste} event,
2655 * * The {@link CKEDITOR.editor#drop} and {@link CKEDITOR.editor#dragend} events,
2656 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2657 *
2658 * @since 4.5
2659 * @event dragstart
2660 * @member CKEDITOR.editor
2661 * @param {CKEDITOR.editor} editor This editor instance.
2662 * @param data
2663 * @param {Object} data.$ Native dragstart event.
2664 * @param {CKEDITOR.dom.node} data.target Drag target.
2665 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2666 */
2667
2668/**
2669 * Facade for the native `dragend` event. Fired when the native `dragend` event occurs.
2670 *
2671 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2672 *
2673 * See also:
2674 *
2675 * * The {@link CKEDITOR.editor#paste} event,
2676 * * The {@link CKEDITOR.editor#drop} and {@link CKEDITOR.editor#dragend} events,
2677 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2678 *
2679 * @since 4.5
2680 * @event dragend
2681 * @member CKEDITOR.editor
2682 * @param {CKEDITOR.editor} editor This editor instance.
2683 * @param data
2684 * @param {Object} data.$ Native dragend event.
2685 * @param {CKEDITOR.dom.node} data.target Drag target.
2686 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2687 */
2688
2689/**
2690 * Defines a filter which is applied to external data pasted or dropped into the editor. Possible values are:
2691 *
2692 * * `'plain-text'` &ndash; Content will be pasted as a plain text.
2693 * * `'semantic-content'` &ndash; Known tags (except `div`, `span`) with all attributes (except
2694 * `style` and `class`) will be kept.
2695 * * `'h1 h2 p div'` &ndash; Custom rules compatible with {@link CKEDITOR.filter}.
2696 * * `null` &ndash; Content will not be filtered by the paste filter (but it still may be filtered
2697 * by [Advanced Content Filter](#!/guide/dev_advanced_content_filter)). This value can be used to
2698 * disable the paste filter in Chrome and Safari, where this option defaults to `'semantic-content'`.
2699 *
2700 * Example:
2701 *
2702 * config.pasteFilter = 'plain-text';
2703 *
2704 * Custom setting:
2705 *
2706 * config.pasteFilter = 'h1 h2 p ul ol li; img[!src, alt]; a[!href]';
2707 *
2708 * Based on this configuration option, a proper {@link CKEDITOR.filter} instance will be defined and assigned to the editor
2709 * as a {@link CKEDITOR.editor#pasteFilter}. You can tweak the paste filter settings on the fly on this object
2710 * as well as delete or replace it.
2711 *
2712 * var editor = CKEDITOR.replace( 'editor', {
2713 * pasteFilter: 'semantic-content'
2714 * } );
2715 *
2716 * editor.on( 'instanceReady', function() {
2717 * // The result of this will be that all semantic content will be preserved
2718 * // except tables.
2719 * editor.pasteFilter.disallow( 'table' );
2720 * } );
2721 *
2722 * Note that the paste filter is applied only to **external** data. There are three data sources:
2723 *
2724 * * copied and pasted in the same editor (internal),
2725 * * copied from one editor and pasted into another (cross-editor),
2726 * * coming from all other sources like websites, MS Word, etc. (external).
2727 *
2728 * If {@link CKEDITOR.config#allowedContent Advanced Content Filter} is not disabled, then
2729 * it will also be applied to pasted and dropped data. The paste filter job is to "normalize"
2730 * external data which often needs to be handled differently than content produced by the editor.
2731 *
2732 * This setting defaults to `'semantic-content'` in Chrome, Opera and Safari (all Blink and Webkit based browsers)
2733 * due to messy HTML which these browsers keep in the clipboard. In other browsers it defaults to `null`.
2734 *
2735 * @since 4.5
2736 * @cfg {String} [pasteFilter='semantic-content' in Chrome and Safari and `null` in other browsers]
2737 * @member CKEDITOR.config
2738 */
2739
2740/**
2741 * {@link CKEDITOR.filter Content filter} which is used when external data is pasted or dropped into the editor
2742 * or a forced paste as plain text occurs.
2743 *
2744 * This object might be used on the fly to define rules for pasted external content.
2745 * This object is available and used if the {@link CKEDITOR.plugins.clipboard clipboard} plugin is enabled and
2746 * {@link CKEDITOR.config#pasteFilter} or {@link CKEDITOR.config#forcePasteAsPlainText} was defined.
2747 *
2748 * To enable the filter:
2749 *
2750 * var editor = CKEDITOR.replace( 'editor', {
2751 * pasteFilter: 'plain-text'
2752 * } );
2753 *
2754 * You can also modify the filter on the fly later on:
2755 *
2756 * editor.pasteFilter = new CKEDITOR.filter( 'p h1 h2; a[!href]' );
2757 *
2758 * Note that the paste filter is only applied to **external** data. There are three data sources:
2759 *
2760 * * copied and pasted in the same editor (internal),
2761 * * copied from one editor and pasted into another (cross-editor),
2762 * * coming from all other sources like websites, MS Word, etc. (external).
2763 *
2764 * If {@link CKEDITOR.config#allowedContent Advanced Content Filter} is not disabled, then
2765 * it will also be applied to pasted and dropped data. The paste filter job is to "normalize"
2766 * external data which often needs to be handled differently than content produced by the editor.
2767 *
2768 * @since 4.5
2769 * @readonly
2770 * @property {CKEDITOR.filter} [pasteFilter]
2771 * @member CKEDITOR.editor
2772 */
diff --git a/sources/plugins/contextmenu/lang/af.js b/sources/plugins/contextmenu/lang/af.js
new file mode 100644
index 0000000..76b5b96
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/af.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'af', {
6 options: 'Konteks Spyskaart-opsies'
7} );
diff --git a/sources/plugins/contextmenu/lang/ar.js b/sources/plugins/contextmenu/lang/ar.js
new file mode 100644
index 0000000..c81b063
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ar.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ar', {
6 options: 'خصائص قائمة السياق'
7} );
diff --git a/sources/plugins/contextmenu/lang/az.js b/sources/plugins/contextmenu/lang/az.js
new file mode 100644
index 0000000..651f2f8
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/az.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'az', {
6 options: 'Əlavə əməliyyatlar'
7} );
diff --git a/sources/plugins/contextmenu/lang/bg.js b/sources/plugins/contextmenu/lang/bg.js
new file mode 100644
index 0000000..6bb7a40
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/bg.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'bg', {
6 options: 'Опции на контекстното меню'
7} );
diff --git a/sources/plugins/contextmenu/lang/bn.js b/sources/plugins/contextmenu/lang/bn.js
new file mode 100644
index 0000000..fe93ec8
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/bn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'bn', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/bs.js b/sources/plugins/contextmenu/lang/bs.js
new file mode 100644
index 0000000..9354351
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/bs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'bs', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/ca.js b/sources/plugins/contextmenu/lang/ca.js
new file mode 100644
index 0000000..91c7ec8
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ca', {
6 options: 'Opcions del menú contextual'
7} );
diff --git a/sources/plugins/contextmenu/lang/cs.js b/sources/plugins/contextmenu/lang/cs.js
new file mode 100644
index 0000000..e53a0f5
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/cs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'cs', {
6 options: 'Nastavení kontextové nabídky'
7} );
diff --git a/sources/plugins/contextmenu/lang/cy.js b/sources/plugins/contextmenu/lang/cy.js
new file mode 100644
index 0000000..1816b84
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/cy.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'cy', {
6 options: 'Opsiynau Dewislen Cyd-destun'
7} );
diff --git a/sources/plugins/contextmenu/lang/da.js b/sources/plugins/contextmenu/lang/da.js
new file mode 100644
index 0000000..10043a5
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/da.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'da', {
6 options: 'Muligheder for hjælpemenu'
7} );
diff --git a/sources/plugins/contextmenu/lang/de-ch.js b/sources/plugins/contextmenu/lang/de-ch.js
new file mode 100644
index 0000000..216cd18
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/de-ch.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'de-ch', {
6 options: 'Kontextmenüoptionen'
7} );
diff --git a/sources/plugins/contextmenu/lang/de.js b/sources/plugins/contextmenu/lang/de.js
new file mode 100644
index 0000000..aa0c098
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/de.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'de', {
6 options: 'Kontextmenüoptionen'
7} );
diff --git a/sources/plugins/contextmenu/lang/el.js b/sources/plugins/contextmenu/lang/el.js
new file mode 100644
index 0000000..bdad720
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/el.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'el', {
6 options: 'Επιλογές Αναδυόμενου Μενού'
7} );
diff --git a/sources/plugins/contextmenu/lang/en-au.js b/sources/plugins/contextmenu/lang/en-au.js
new file mode 100644
index 0000000..cd6b202
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/en-au.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'en-au', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/en-ca.js b/sources/plugins/contextmenu/lang/en-ca.js
new file mode 100644
index 0000000..25950c9
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/en-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'en-ca', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/en-gb.js b/sources/plugins/contextmenu/lang/en-gb.js
new file mode 100644
index 0000000..62f08d5
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/en-gb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'en-gb', {
6 options: 'Context Menu Options'
7} );
diff --git a/sources/plugins/contextmenu/lang/en.js b/sources/plugins/contextmenu/lang/en.js
new file mode 100644
index 0000000..10b5f47
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/en.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'en', {
6 options: 'Context Menu Options'
7} );
diff --git a/sources/plugins/contextmenu/lang/eo.js b/sources/plugins/contextmenu/lang/eo.js
new file mode 100644
index 0000000..6a9760c
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/eo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'eo', {
6 options: 'Opcioj de Kunteksta Menuo'
7} );
diff --git a/sources/plugins/contextmenu/lang/es.js b/sources/plugins/contextmenu/lang/es.js
new file mode 100644
index 0000000..1e8e06d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/es.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'es', {
6 options: 'Opciones del menú contextual'
7} );
diff --git a/sources/plugins/contextmenu/lang/et.js b/sources/plugins/contextmenu/lang/et.js
new file mode 100644
index 0000000..d7ece9a
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/et.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'et', {
6 options: 'Kontekstimenüü valikud'
7} );
diff --git a/sources/plugins/contextmenu/lang/eu.js b/sources/plugins/contextmenu/lang/eu.js
new file mode 100644
index 0000000..32018e0
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/eu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'eu', {
6 options: 'Testuinguru-menuaren aukerak'
7} );
diff --git a/sources/plugins/contextmenu/lang/fa.js b/sources/plugins/contextmenu/lang/fa.js
new file mode 100644
index 0000000..233d30d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/fa.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'fa', {
6 options: 'گزینه​های منوی زمینه'
7} );
diff --git a/sources/plugins/contextmenu/lang/fi.js b/sources/plugins/contextmenu/lang/fi.js
new file mode 100644
index 0000000..5c11832
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/fi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'fi', {
6 options: 'Pikavalikon ominaisuudet'
7} );
diff --git a/sources/plugins/contextmenu/lang/fo.js b/sources/plugins/contextmenu/lang/fo.js
new file mode 100644
index 0000000..6069a48
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/fo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'fo', {
6 options: 'Context Menu Options'
7} );
diff --git a/sources/plugins/contextmenu/lang/fr-ca.js b/sources/plugins/contextmenu/lang/fr-ca.js
new file mode 100644
index 0000000..d7aca5c
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/fr-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'fr-ca', {
6 options: 'Options du menu contextuel'
7} );
diff --git a/sources/plugins/contextmenu/lang/fr.js b/sources/plugins/contextmenu/lang/fr.js
new file mode 100644
index 0000000..7af3f33
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/fr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'fr', {
6 options: 'Options du menu contextuel'
7} );
diff --git a/sources/plugins/contextmenu/lang/gl.js b/sources/plugins/contextmenu/lang/gl.js
new file mode 100644
index 0000000..de69eae
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/gl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'gl', {
6 options: 'Opcións do menú contextual'
7} );
diff --git a/sources/plugins/contextmenu/lang/gu.js b/sources/plugins/contextmenu/lang/gu.js
new file mode 100644
index 0000000..d9a83da
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/gu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'gu', {
6 options: 'કોન્તેક્ષ્ત્ મેનુના વિકલ્પો'
7} );
diff --git a/sources/plugins/contextmenu/lang/he.js b/sources/plugins/contextmenu/lang/he.js
new file mode 100644
index 0000000..a276534
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/he.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'he', {
6 options: 'אפשרויות תפריט ההקשר'
7} );
diff --git a/sources/plugins/contextmenu/lang/hi.js b/sources/plugins/contextmenu/lang/hi.js
new file mode 100644
index 0000000..a3f501d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/hi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'hi', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/hr.js b/sources/plugins/contextmenu/lang/hr.js
new file mode 100644
index 0000000..149c1eb
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/hr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'hr', {
6 options: 'Opcije izbornika'
7} );
diff --git a/sources/plugins/contextmenu/lang/hu.js b/sources/plugins/contextmenu/lang/hu.js
new file mode 100644
index 0000000..60bb66c
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/hu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'hu', {
6 options: 'Helyi menü opciók'
7} );
diff --git a/sources/plugins/contextmenu/lang/id.js b/sources/plugins/contextmenu/lang/id.js
new file mode 100644
index 0000000..8d19e50
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/id.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'id', {
6 options: 'Opsi Konteks Pilihan'
7} );
diff --git a/sources/plugins/contextmenu/lang/is.js b/sources/plugins/contextmenu/lang/is.js
new file mode 100644
index 0000000..4404c99
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/is.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'is', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/it.js b/sources/plugins/contextmenu/lang/it.js
new file mode 100644
index 0000000..0453e18
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/it.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'it', {
6 options: 'Opzioni del menù contestuale'
7} );
diff --git a/sources/plugins/contextmenu/lang/ja.js b/sources/plugins/contextmenu/lang/ja.js
new file mode 100644
index 0000000..5887847
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ja.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ja', {
6 options: 'コンテキストメニューオプション'
7} );
diff --git a/sources/plugins/contextmenu/lang/ka.js b/sources/plugins/contextmenu/lang/ka.js
new file mode 100644
index 0000000..f279b0a
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ka.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ka', {
6 options: 'კონტექსტური მენიუს პარამეტრები'
7} );
diff --git a/sources/plugins/contextmenu/lang/km.js b/sources/plugins/contextmenu/lang/km.js
new file mode 100644
index 0000000..9f5d965
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/km.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'km', {
6 options: 'ជម្រើស​ម៉ឺនុយ​បរិបទ'
7} );
diff --git a/sources/plugins/contextmenu/lang/ko.js b/sources/plugins/contextmenu/lang/ko.js
new file mode 100644
index 0000000..45273b5
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ko.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ko', {
6 options: '컨텍스트 메뉴 옵션'
7} );
diff --git a/sources/plugins/contextmenu/lang/ku.js b/sources/plugins/contextmenu/lang/ku.js
new file mode 100644
index 0000000..c183cb2
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ku.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ku', {
6 options: 'هەڵبژاردەی لیستەی کلیکی دەستی ڕاست'
7} );
diff --git a/sources/plugins/contextmenu/lang/lt.js b/sources/plugins/contextmenu/lang/lt.js
new file mode 100644
index 0000000..e16597a
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/lt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'lt', {
6 options: 'Kontekstinio meniu parametrai'
7} );
diff --git a/sources/plugins/contextmenu/lang/lv.js b/sources/plugins/contextmenu/lang/lv.js
new file mode 100644
index 0000000..b14f0eb
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/lv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'lv', {
6 options: 'Uznirstošās izvēlnes uzstādījumi'
7} );
diff --git a/sources/plugins/contextmenu/lang/mk.js b/sources/plugins/contextmenu/lang/mk.js
new file mode 100644
index 0000000..1d7c4c7
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/mk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'mk', {
6 options: 'Контекст-мени опции'
7} );
diff --git a/sources/plugins/contextmenu/lang/mn.js b/sources/plugins/contextmenu/lang/mn.js
new file mode 100644
index 0000000..5076f18
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/mn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'mn', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/ms.js b/sources/plugins/contextmenu/lang/ms.js
new file mode 100644
index 0000000..019ba76
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ms.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ms', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/nb.js b/sources/plugins/contextmenu/lang/nb.js
new file mode 100644
index 0000000..c7c41b0
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/nb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'nb', {
6 options: 'Alternativer for høyreklikkmeny'
7} );
diff --git a/sources/plugins/contextmenu/lang/nl.js b/sources/plugins/contextmenu/lang/nl.js
new file mode 100644
index 0000000..0ceb7cb
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/nl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'nl', {
6 options: 'Contextmenu opties'
7} );
diff --git a/sources/plugins/contextmenu/lang/no.js b/sources/plugins/contextmenu/lang/no.js
new file mode 100644
index 0000000..ee283cf
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/no.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'no', {
6 options: 'Alternativer for høyreklikkmeny'
7} );
diff --git a/sources/plugins/contextmenu/lang/oc.js b/sources/plugins/contextmenu/lang/oc.js
new file mode 100644
index 0000000..8fab98f
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/oc.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'oc', {
6 options: 'Opcions del menú contextual'
7} );
diff --git a/sources/plugins/contextmenu/lang/pl.js b/sources/plugins/contextmenu/lang/pl.js
new file mode 100644
index 0000000..99ef5d9
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/pl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'pl', {
6 options: 'Opcje menu kontekstowego'
7} );
diff --git a/sources/plugins/contextmenu/lang/pt-br.js b/sources/plugins/contextmenu/lang/pt-br.js
new file mode 100644
index 0000000..ec91513
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/pt-br.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'pt-br', {
6 options: 'Opções Menu de Contexto'
7} );
diff --git a/sources/plugins/contextmenu/lang/pt.js b/sources/plugins/contextmenu/lang/pt.js
new file mode 100644
index 0000000..c2c969d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/pt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'pt', {
6 options: 'Menu de opções de contexto'
7} );
diff --git a/sources/plugins/contextmenu/lang/ro.js b/sources/plugins/contextmenu/lang/ro.js
new file mode 100644
index 0000000..928c4b3
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ro.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ro', {
6 options: 'Opțiuni Meniu Contextual'
7} );
diff --git a/sources/plugins/contextmenu/lang/ru.js b/sources/plugins/contextmenu/lang/ru.js
new file mode 100644
index 0000000..f671b6a
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ru.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ru', {
6 options: 'Параметры контекстного меню'
7} );
diff --git a/sources/plugins/contextmenu/lang/si.js b/sources/plugins/contextmenu/lang/si.js
new file mode 100644
index 0000000..ec603a3
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/si.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'si', {
6 options: 'අනතර්ග ලේඛණ විකල්ප'
7} );
diff --git a/sources/plugins/contextmenu/lang/sk.js b/sources/plugins/contextmenu/lang/sk.js
new file mode 100644
index 0000000..fda2b3d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sk', {
6 options: 'Možnosti kontextového menu'
7} );
diff --git a/sources/plugins/contextmenu/lang/sl.js b/sources/plugins/contextmenu/lang/sl.js
new file mode 100644
index 0000000..9c7fc29
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sl', {
6 options: 'Možnosti kontekstnega menija'
7} );
diff --git a/sources/plugins/contextmenu/lang/sq.js b/sources/plugins/contextmenu/lang/sq.js
new file mode 100644
index 0000000..698ca2d
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sq.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sq', {
6 options: 'Mundësitë e Menysë së Kontekstit'
7} );
diff --git a/sources/plugins/contextmenu/lang/sr-latn.js b/sources/plugins/contextmenu/lang/sr-latn.js
new file mode 100644
index 0000000..d550e84
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sr-latn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sr-latn', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/sr.js b/sources/plugins/contextmenu/lang/sr.js
new file mode 100644
index 0000000..2f7ba14
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sr', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/sv.js b/sources/plugins/contextmenu/lang/sv.js
new file mode 100644
index 0000000..a3b043f
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/sv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'sv', {
6 options: 'Context Menu Options'
7} );
diff --git a/sources/plugins/contextmenu/lang/th.js b/sources/plugins/contextmenu/lang/th.js
new file mode 100644
index 0000000..ce77065
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/th.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'th', {
6 options: 'Context Menu Options' // MISSING
7} );
diff --git a/sources/plugins/contextmenu/lang/tr.js b/sources/plugins/contextmenu/lang/tr.js
new file mode 100644
index 0000000..4d5a550
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/tr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'tr', {
6 options: 'İçerik Menüsü Seçenekleri'
7} );
diff --git a/sources/plugins/contextmenu/lang/tt.js b/sources/plugins/contextmenu/lang/tt.js
new file mode 100644
index 0000000..0531370
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/tt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'tt', {
6 options: 'Контекст меню үзлекләре'
7} );
diff --git a/sources/plugins/contextmenu/lang/ug.js b/sources/plugins/contextmenu/lang/ug.js
new file mode 100644
index 0000000..95a9d0a
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/ug.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'ug', {
6 options: 'قىسقا يول تىزىملىك تاللانمىسى'
7} );
diff --git a/sources/plugins/contextmenu/lang/uk.js b/sources/plugins/contextmenu/lang/uk.js
new file mode 100644
index 0000000..0a4ffb9
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/uk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'uk', {
6 options: 'Опції контекстного меню'
7} );
diff --git a/sources/plugins/contextmenu/lang/vi.js b/sources/plugins/contextmenu/lang/vi.js
new file mode 100644
index 0000000..42c39b0
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/vi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'vi', {
6 options: 'Tùy chọn menu bổ xung'
7} );
diff --git a/sources/plugins/contextmenu/lang/zh-cn.js b/sources/plugins/contextmenu/lang/zh-cn.js
new file mode 100644
index 0000000..56879ee
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/zh-cn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'zh-cn', {
6 options: '快捷菜单选项'
7} );
diff --git a/sources/plugins/contextmenu/lang/zh.js b/sources/plugins/contextmenu/lang/zh.js
new file mode 100644
index 0000000..c8d8b93
--- /dev/null
+++ b/sources/plugins/contextmenu/lang/zh.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'contextmenu', 'zh', {
6 options: '內容功能表選項'
7} );
diff --git a/sources/plugins/contextmenu/plugin.js b/sources/plugins/contextmenu/plugin.js
new file mode 100644
index 0000000..6cd3935
--- /dev/null
+++ b/sources/plugins/contextmenu/plugin.js
@@ -0,0 +1,159 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'contextmenu', {
7 requires: 'menu',
8
9 // jscs:disable maximumLineLength
10 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
11 // jscs:enable maximumLineLength
12
13 // Make sure the base class (CKEDITOR.menu) is loaded before it (#3318).
14 onLoad: function() {
15 /**
16 * Class replacing the non-configurable native context menu with a configurable CKEditor's equivalent.
17 *
18 * @class
19 * @extends CKEDITOR.menu
20 */
21 CKEDITOR.plugins.contextMenu = CKEDITOR.tools.createClass( {
22 base: CKEDITOR.menu,
23
24 /**
25 * Creates the CKEDITOR.plugins.contextMenu class instance.
26 *
27 * @constructor
28 * @param {CKEDITOR.editor} editor
29 */
30 $: function( editor ) {
31 this.base.call( this, editor, {
32 panel: {
33 className: 'cke_menu_panel',
34 attributes: {
35 'aria-label': editor.lang.contextmenu.options
36 }
37 }
38 } );
39 },
40
41 proto: {
42 /**
43 * Starts watching on native context menu triggers (<kbd>Option</kbd> key, right click) on the given element.
44 *
45 * @param {CKEDITOR.dom.element} element
46 * @param {Boolean} [nativeContextMenuOnCtrl] Whether to open native context menu if the
47 * <kbd>Ctrl</kbd> key is held on opening the context menu. See {@link CKEDITOR.config#browserContextMenuOnCtrl}.
48 */
49 addTarget: function( element, nativeContextMenuOnCtrl ) {
50 element.on( 'contextmenu', function( event ) {
51 var domEvent = event.data,
52 isCtrlKeyDown =
53 // Safari on Windows always show 'ctrlKey' as true in 'contextmenu' event,
54 // which make this property unreliable. (#4826)
55 ( CKEDITOR.env.webkit ? holdCtrlKey : ( CKEDITOR.env.mac ? domEvent.$.metaKey : domEvent.$.ctrlKey ) );
56
57 if ( nativeContextMenuOnCtrl && isCtrlKeyDown )
58 return;
59
60 // Cancel the browser context menu.
61 domEvent.preventDefault();
62
63 // Fix selection when non-editable element in Webkit/Blink (Mac) (#11306).
64 if ( CKEDITOR.env.mac && CKEDITOR.env.webkit ) {
65 var editor = this.editor,
66 contentEditableParent = new CKEDITOR.dom.elementPath( domEvent.getTarget(), editor.editable() ).contains( function( el ) {
67 // Return when non-editable or nested editable element is found.
68 return el.hasAttribute( 'contenteditable' );
69 }, true ); // Exclude editor's editable.
70
71 // Fake selection for non-editables only (to exclude nested editables).
72 if ( contentEditableParent && contentEditableParent.getAttribute( 'contenteditable' ) == 'false' )
73 editor.getSelection().fake( contentEditableParent );
74 }
75
76 var doc = domEvent.getTarget().getDocument(),
77 offsetParent = domEvent.getTarget().getDocument().getDocumentElement(),
78 fromFrame = !doc.equals( CKEDITOR.document ),
79 scroll = doc.getWindow().getScrollPosition(),
80 offsetX = fromFrame ? domEvent.$.clientX : domEvent.$.pageX || scroll.x + domEvent.$.clientX,
81 offsetY = fromFrame ? domEvent.$.clientY : domEvent.$.pageY || scroll.y + domEvent.$.clientY;
82
83 CKEDITOR.tools.setTimeout( function() {
84 this.open( offsetParent, null, offsetX, offsetY );
85
86 // IE needs a short while to allow selection change before opening menu. (#7908)
87 }, CKEDITOR.env.ie ? 200 : 0, this );
88 }, this );
89
90 if ( CKEDITOR.env.webkit ) {
91 var holdCtrlKey,
92 onKeyDown = function( event ) {
93 holdCtrlKey = CKEDITOR.env.mac ? event.data.$.metaKey : event.data.$.ctrlKey;
94 },
95 resetOnKeyUp = function() {
96 holdCtrlKey = 0;
97 };
98
99 element.on( 'keydown', onKeyDown );
100 element.on( 'keyup', resetOnKeyUp );
101 element.on( 'contextmenu', resetOnKeyUp );
102 }
103 },
104
105 /**
106 * Opens the context menu in the given location. See the {@link CKEDITOR.menu#show} method.
107 *
108 * @param {CKEDITOR.dom.element} offsetParent
109 * @param {Number} [corner]
110 * @param {Number} [offsetX]
111 * @param {Number} [offsetY]
112 */
113 open: function( offsetParent, corner, offsetX, offsetY ) {
114 this.editor.focus();
115 offsetParent = offsetParent || CKEDITOR.document.getDocumentElement();
116
117 // #9362: Force selection check to update commands' states in the new context.
118 this.editor.selectionChange( 1 );
119
120 this.show( offsetParent, corner, offsetX, offsetY );
121 }
122 }
123 } );
124 },
125
126 beforeInit: function( editor ) {
127 /**
128 * @readonly
129 * @property {CKEDITOR.plugins.contextMenu} contextMenu
130 * @member CKEDITOR.editor
131 */
132 var contextMenu = editor.contextMenu = new CKEDITOR.plugins.contextMenu( editor );
133
134 editor.on( 'contentDom', function() {
135 contextMenu.addTarget( editor.editable(), editor.config.browserContextMenuOnCtrl !== false );
136 } );
137
138 editor.addCommand( 'contextMenu', {
139 exec: function() {
140 editor.contextMenu.open( editor.document.getBody() );
141 }
142 } );
143
144 editor.setKeystroke( CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu' );
145 editor.setKeystroke( CKEDITOR.CTRL + CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu' );
146 }
147} );
148
149/**
150 * Whether to show the browser native context menu when the <kbd>Ctrl</kbd> or
151 * <kbd>Meta</kbd> (Mac) key is pressed on opening the context menu with the
152 * right mouse button click or the <kbd>Menu</kbd> key.
153 *
154 * config.browserContextMenuOnCtrl = false;
155 *
156 * @since 3.0.2
157 * @cfg {Boolean} [browserContextMenuOnCtrl=true]
158 * @member CKEDITOR.config
159 */
diff --git a/sources/plugins/dialog/dialogDefinition.js b/sources/plugins/dialog/dialogDefinition.js
new file mode 100644
index 0000000..6ecb491
--- /dev/null
+++ b/sources/plugins/dialog/dialogDefinition.js
@@ -0,0 +1,1032 @@
1// jscs:disable disallowMixedSpacesAndTabs
2/**
3 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4 * For licensing, see LICENSE.md or http://ckeditor.com/license
5 */
6
7/**
8 * @fileOverview Defines the "virtual" dialog, dialog content and dialog button
9 * definition classes.
10 */
11
12/**
13 * The definition of a dialog window.
14 *
15 * This class is not really part of the API. It just illustrates the properties
16 * that developers can use to define and create dialogs.
17 *
18 * // There is no constructor for this class, the user just has to define an
19 * // object with the appropriate properties.
20 *
21 * CKEDITOR.dialog.add( 'testOnly', function( editor ) {
22 * return {
23 * title: 'Test Dialog',
24 * resizable: CKEDITOR.DIALOG_RESIZE_BOTH,
25 * minWidth: 500,
26 * minHeight: 400,
27 * contents: [
28 * {
29 * id: 'tab1',
30 * label: 'First Tab',
31 * title: 'First Tab Title',
32 * accessKey: 'Q',
33 * elements: [
34 * {
35 * type: 'text',
36 * label: 'Test Text 1',
37 * id: 'testText1',
38 * 'default': 'hello world!'
39 * }
40 * ]
41 * }
42 * ]
43 * };
44 * } );
45 *
46 * @class CKEDITOR.dialog.definition
47 */
48
49/**
50 * The dialog title, displayed in the dialog's header. Required.
51 *
52 * @property {String} title
53 */
54
55/**
56 * How the dialog can be resized, must be one of the four contents defined below.
57 *
58 * * {@link CKEDITOR#DIALOG_RESIZE_NONE}
59 * * {@link CKEDITOR#DIALOG_RESIZE_WIDTH}
60 * * {@link CKEDITOR#DIALOG_RESIZE_HEIGHT}
61 * * {@link CKEDITOR#DIALOG_RESIZE_BOTH}
62 *
63 * @property {Number} [resizable=CKEDITOR.DIALOG_RESIZE_NONE]
64 */
65
66/**
67 * The minimum width of the dialog, in pixels.
68 *
69 * @property {Number} [minWidth=600]
70 */
71
72/**
73 * The minimum height of the dialog, in pixels.
74 *
75 * @property {Number} [minHeight=400]
76 */
77
78
79/**
80 * The initial width of the dialog, in pixels.
81 *
82 * @since 3.5.3
83 * @property {Number} [width=CKEDITOR.dialog.definition#minWidth]
84 */
85
86/**
87 * The initial height of the dialog, in pixels.
88 *
89 * @since 3.5.3
90 * @property {Number} [height=CKEDITOR.dialog.definition.minHeight]
91 */
92
93/**
94 * The buttons in the dialog, defined as an array of
95 * {@link CKEDITOR.dialog.definition.button} objects.
96 *
97 * @property {Array} [buttons=[ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]]
98 */
99
100/**
101 * The contents in the dialog, defined as an array of
102 * {@link CKEDITOR.dialog.definition.content} objects. Required.
103 *
104 * @property {Array} contents
105 */
106
107/**
108 * The function to execute when OK is pressed.
109 *
110 * @property {Function} onOk
111 */
112
113/**
114 * The function to execute when Cancel is pressed.
115 *
116 * @property {Function} onCancel
117 */
118
119/**
120 * The function to execute when the dialog is displayed for the first time.
121 *
122 * @property {Function} onLoad
123 */
124
125/**
126 * The function to execute when the dialog is loaded (executed every time the dialog is opened).
127 *
128 * @property {Function} onShow
129 */
130
131/**
132 * This class is not really part of the API. It just illustrates the properties
133 * that developers can use to define and create dialog content pages.
134 *
135 * @class CKEDITOR.dialog.definition.content.
136 */
137
138/**
139 * The id of the content page.
140 *
141 * @property {String} id
142 */
143
144/**
145 * The tab label of the content page.
146 *
147 * @property {String} label
148 */
149
150/**
151 * The popup message of the tab label.
152 *
153 * @property {String} title
154 */
155
156/**
157 * The CTRL hotkey for switching to the tab.
158 *
159 * contentDefinition.accessKey = 'Q'; // Switch to this page when CTRL-Q is pressed.
160 *
161 * @property {String} accessKey
162 */
163
164/**
165 * The UI elements contained in this content page, defined as an array of
166 * {@link CKEDITOR.dialog.definition.uiElement} objects.
167 *
168 * @property {Array} elements
169 */
170
171/**
172 * The definition of user interface element (textarea, radio etc).
173 *
174 * This class is not really part of the API. It just illustrates the properties
175 * that developers can use to define and create dialog UI elements.
176 *
177 * @class CKEDITOR.dialog.definition.uiElement
178 * @see CKEDITOR.ui.dialog.uiElement
179 */
180
181/**
182 * The id of the UI element.
183 *
184 * @property {String} id
185 */
186
187/**
188 * The type of the UI element. Required.
189 *
190 * @property {String} type
191 */
192
193/**
194 * The popup label of the UI element.
195 *
196 * @property {String} title
197 */
198
199/**
200 * The content that needs to be allowed to enable this UI element.
201 * All formats accepted by {@link CKEDITOR.filter#check} may be used.
202 *
203 * When all UI elements in a tab are disabled, this tab will be disabled automatically.
204 *
205 * @property {String/Object/CKEDITOR.style} requiredContent
206 */
207
208/**
209 * CSS class names to append to the UI element.
210 *
211 * @property {String} className
212 */
213
214/**
215 * Inline CSS classes to append to the UI element.
216 *
217 * @property {String} style
218 */
219
220/**
221 * Horizontal alignment (in container) of the UI element.
222 *
223 * @property {String} align
224 */
225
226/**
227 * Function to execute the first time the UI element is displayed.
228 *
229 * @property {Function} onLoad
230 */
231
232/**
233 * Function to execute whenever the UI element's parent dialog is displayed.
234 *
235 * @property {Function} onShow
236 */
237
238/**
239 * Function to execute whenever the UI element's parent dialog is closed.
240 *
241 * @property {Function} onHide
242 */
243
244/**
245 * Function to execute whenever the UI element's parent
246 * dialog's {@link CKEDITOR.dialog#setupContent} method is executed.
247 * It usually takes care of the respective UI element as a standalone element.
248 *
249 * @property {Function} setup
250 */
251
252/**
253 * Function to execute whenever the UI element's parent
254 * dialog's {@link CKEDITOR.dialog#commitContent} method is executed.
255 * It usually takes care of the respective UI element as a standalone element.
256 *
257 * @property {Function} commit
258 */
259
260// ----- hbox -----------------------------------------------------------------
261
262/**
263 * Horizontal layout box for dialog UI elements, auto-expends to available width of container.
264 *
265 * This class is not really part of the API. It just illustrates the properties
266 * that developers can use to define and create horizontal layouts.
267 *
268 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.hbox} object and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
269 *
270 * // There is no constructor for this class, the user just has to define an
271 * // object with the appropriate properties.
272 *
273 * // Example:
274 * {
275 * type: 'hbox',
276 * widths: [ '25%', '25%', '50%' ],
277 * children: [
278 * {
279 * type: 'text',
280 * id: 'id1',
281 * width: '40px',
282 * },
283 * {
284 * type: 'text',
285 * id: 'id2',
286 * width: '40px',
287 * },
288 * {
289 * type: 'text',
290 * id: 'id3'
291 * }
292 * ]
293 * }
294 *
295 * @class CKEDITOR.dialog.definition.hbox
296 * @extends CKEDITOR.dialog.definition.uiElement
297 */
298
299/**
300 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
301 *
302 * @property {Array} children
303 */
304
305/**
306 * (Optional) The widths of child cells.
307 *
308 * @property {Array} widths
309 */
310
311/**
312 * (Optional) The height of the layout.
313 *
314 * @property {Number} height
315 */
316
317/**
318 * The CSS styles to apply to this element.
319 *
320 * @property {String} styles
321 */
322
323/**
324 * (Optional) The padding width inside child cells. Example: 0, 1.
325 *
326 * @property {Number} padding
327 */
328
329/**
330 * (Optional) The alignment of the whole layout. Example: center, top.
331 *
332 * @property {String} align
333 */
334
335// ----- vbox -----------------------------------------------------------------
336
337/**
338 * Vertical layout box for dialog UI elements.
339 *
340 * This class is not really part of the API. It just illustrates the properties
341 * that developers can use to define and create vertical layouts.
342 *
343 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.vbox} object and can
344 * be accessed with {@link CKEDITOR.dialog#getContentElement}.
345 *
346 * // There is no constructor for this class, the user just has to define an
347 * // object with the appropriate properties.
348 *
349 * // Example:
350 * {
351 * type: 'vbox',
352 * align: 'right',
353 * width: '200px',
354 * children: [
355 * {
356 * type: 'text',
357 * id: 'age',
358 * label: 'Age'
359 * },
360 * {
361 * type: 'text',
362 * id: 'sex',
363 * label: 'Sex'
364 * },
365 * {
366 * type: 'text',
367 * id: 'nationality',
368 * label: 'Nationality'
369 * }
370 * ]
371 * }
372 *
373 * @class CKEDITOR.dialog.definition.vbox
374 * @extends CKEDITOR.dialog.definition.uiElement
375 */
376
377/**
378 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
379 *
380 * @property {Array} children
381 */
382
383/**
384 * (Optional) The width of the layout.
385 *
386 * @property {Array} width
387 */
388
389/**
390 * (Optional) The heights of individual cells.
391 *
392 * @property {Number} heights
393 */
394
395/**
396 * The CSS styles to apply to this element.
397 *
398 * @property {String} styles
399 */
400
401/**
402 * (Optional) The padding width inside child cells. Example: 0, 1.
403 *
404 * @property {Number} padding
405 */
406
407/**
408 * (Optional) The alignment of the whole layout. Example: center, top.
409 *
410 * @property {String} align
411 */
412
413/**
414 * (Optional) Whether the layout should expand vertically to fill its container.
415 *
416 * @property {Boolean} expand
417 */
418
419// ----- labeled element ------------------------------------------------------
420
421/**
422 * The definition of labeled user interface element (textarea, textInput etc).
423 *
424 * This class is not really part of the API. It just illustrates the properties
425 * that developers can use to define and create dialog UI elements.
426 *
427 * @class CKEDITOR.dialog.definition.labeledElement
428 * @extends CKEDITOR.dialog.definition.uiElement
429 * @see CKEDITOR.ui.dialog.labeledElement
430 */
431
432/**
433 * The label of the UI element.
434 *
435 * {
436 * type: 'text',
437 * label: 'My Label'
438 * }
439 *
440 * @property {String} label
441 */
442
443/**
444 * (Optional) Specify the layout of the label. Set to `'horizontal'` for horizontal layout.
445 * The default layout is vertical.
446 *
447 * {
448 * type: 'text',
449 * label: 'My Label',
450 * labelLayout: 'horizontal'
451 * }
452 *
453 * @property {String} labelLayout
454 */
455
456/**
457 * (Optional) Applies only to horizontal layouts: a two elements array of lengths to specify the widths of the
458 * label and the content element. See also {@link CKEDITOR.dialog.definition.labeledElement#labelLayout}.
459 *
460 * {
461 * type: 'text',
462 * label: 'My Label',
463 * labelLayout: 'horizontal',
464 * widths: [100, 200]
465 * }
466 *
467 * @property {Array} widths
468 */
469
470/**
471 * Specify the inline style of the uiElement label.
472 *
473 * {
474 * type: 'text',
475 * label: 'My Label',
476 * labelStyle: 'color: red'
477 * }
478 *
479 * @property {String} labelStyle
480 */
481
482
483/**
484 * Specify the inline style of the input element.
485 *
486 * {
487 * type: 'text',
488 * label: 'My Label',
489 * inputStyle: 'text-align: center'
490 * }
491 *
492 * @since 3.6.1
493 * @property {String} inputStyle
494 */
495
496/**
497 * Specify the inline style of the input element container.
498 *
499 * {
500 * type: 'text',
501 * label: 'My Label',
502 * controlStyle: 'width: 3em'
503 * }
504 *
505 * @since 3.6.1
506 * @property {String} controlStyle
507 */
508
509// ----- button ---------------------------------------------------------------
510
511/**
512 * The definition of a button.
513 *
514 * This class is not really part of the API. It just illustrates the properties
515 * that developers can use to define and create buttons.
516 *
517 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.button} object
518 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
519 *
520 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
521 *
522 * // There is no constructor for this class, the user just has to define an
523 * // object with the appropriate properties.
524 *
525 * // Example:
526 * {
527 * type: 'button',
528 * id: 'buttonId',
529 * label: 'Click me',
530 * title: 'My title',
531 * onClick: function() {
532 * // this = CKEDITOR.ui.dialog.button
533 * alert( 'Clicked: ' + this.id );
534 * }
535 * }
536 *
537 * @class CKEDITOR.dialog.definition.button
538 * @extends CKEDITOR.dialog.definition.uiElement
539 */
540
541/**
542 * Whether the button is disabled.
543 *
544 * @property {Boolean} disabled
545 */
546
547/**
548 * The label of the UI element.
549 *
550 * @property {String} label
551 */
552
553// ----- checkbox ------
554/**
555 * The definition of a checkbox element.
556 *
557 * This class is not really part of the API. It just illustrates the properties
558 * that developers can use to define and create groups of checkbox buttons.
559 *
560 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.checkbox} object
561 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
562 *
563 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
564 *
565 * // There is no constructor for this class, the user just has to define an
566 * // object with the appropriate properties.
567 *
568 * // Example:
569 * {
570 * type: 'checkbox',
571 * id: 'agree',
572 * label: 'I agree',
573 * 'default': 'checked',
574 * onClick: function() {
575 * // this = CKEDITOR.ui.dialog.checkbox
576 * alert( 'Checked: ' + this.getValue() );
577 * }
578 * }
579 *
580 * @class CKEDITOR.dialog.definition.checkbox
581 * @extends CKEDITOR.dialog.definition.uiElement
582 */
583
584/**
585 * (Optional) The validation function.
586 *
587 * @property {Function} validate
588 */
589
590/**
591 * The label of the UI element.
592 *
593 * @property {String} label
594 */
595
596/**
597 * The default state.
598 *
599 * @property {String} [default='' (unchecked)]
600 */
601
602// ----- file -----------------------------------------------------------------
603
604/**
605 * The definition of a file upload input.
606 *
607 * This class is not really part of the API. It just illustrates the properties
608 * that developers can use to define and create file upload elements.
609 *
610 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.file} object
611 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
612 *
613 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
614 *
615 * // There is no constructor for this class, the user just has to define an
616 * // object with the appropriate properties.
617 *
618 * // Example:
619 * {
620 * type: 'file',
621 * id: 'upload',
622 * label: 'Select file from your computer',
623 * size: 38
624 * },
625 * {
626 * type: 'fileButton',
627 * id: 'fileId',
628 * label: 'Upload file',
629 * 'for': [ 'tab1', 'upload' ],
630 * filebrowser: {
631 * onSelect: function( fileUrl, data ) {
632 * alert( 'Successfully uploaded: ' + fileUrl );
633 * }
634 * }
635 * }
636 *
637 * @class CKEDITOR.dialog.definition.file
638 * @extends CKEDITOR.dialog.definition.labeledElement
639 */
640
641/**
642 * (Optional) The validation function.
643 *
644 * @property {Function} validate
645 */
646
647/**
648 * (Optional) The action attribute of the form element associated with this file upload input.
649 * If empty, CKEditor will use path to server connector for currently opened folder.
650 *
651 * @property {String} action
652 */
653
654/**
655 * The size of the UI element.
656 *
657 * @property {Number} size
658 */
659
660// ----- fileButton -----------------------------------------------------------
661
662/**
663 * The definition of a button for submitting the file in a file upload input.
664 *
665 * This class is not really part of the API. It just illustrates the properties
666 * that developers can use to define and create a button for submitting the file in a file upload input.
667 *
668 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.fileButton} object
669 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
670 *
671 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
672 *
673 * @class CKEDITOR.dialog.definition.fileButton
674 * @extends CKEDITOR.dialog.definition.uiElement
675 */
676
677/**
678 * (Optional) The validation function.
679 *
680 * @property {Function} validate
681 */
682
683/**
684 * The label of the UI element.
685 *
686 * @property {String} label
687 */
688
689/**
690 * The instruction for CKEditor how to deal with file upload.
691 * By default, the file and fileButton elements will not work "as expected" if this attribute is not set.
692 *
693 * // Update field with id 'txtUrl' in the 'tab1' tab when file is uploaded.
694 * filebrowser: 'tab1:txtUrl'
695 *
696 * // Call custom onSelect function when file is successfully uploaded.
697 * filebrowser: {
698 * onSelect: function( fileUrl, data ) {
699 * alert( 'Successfully uploaded: ' + fileUrl );
700 * }
701 * }
702 *
703 * @property {String} filebrowser/Object
704 */
705
706/**
707 * An array that contains pageId and elementId of the file upload input element for which this button is created.
708 *
709 * [ pageId, elementId ]
710 *
711 * @property {String} for
712 */
713
714// ----- html -----------------------------------------------------------------
715
716/**
717 * The definition of a raw HTML element.
718 *
719 * This class is not really part of the API. It just illustrates the properties
720 * that developers can use to define and create elements made from raw HTML code.
721 *
722 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.html} object
723 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
724 *
725 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
726 * To access HTML elements use {@link CKEDITOR.dom.document#getById}.
727 *
728 * // There is no constructor for this class, the user just has to define an
729 * // object with the appropriate properties.
730 *
731 * // Example 1:
732 * {
733 * type: 'html',
734 * html: '<h3>This is some sample HTML content.</h3>'
735 * }
736 *
737 * // Example 2:
738 * // Complete sample with document.getById() call when the "Ok" button is clicked.
739 * var dialogDefinition = {
740 * title: 'Sample dialog',
741 * minWidth: 300,
742 * minHeight: 200,
743 * onOk: function() {
744 * // "this" is now a CKEDITOR.dialog object.
745 * var document = this.getElement().getDocument();
746 * // document = CKEDITOR.dom.document
747 * var element = <b>document.getById( 'myDiv' );</b>
748 * if ( element )
749 * alert( element.getHtml() );
750 * },
751 * contents: [
752 * {
753 * id: 'tab1',
754 * label: '',
755 * title: '',
756 * elements: [
757 * {
758 * type: 'html',
759 * html: '<div id="myDiv">Sample <b>text</b>.</div><div id="otherId">Another div.</div>'
760 * }
761 * ]
762 * }
763 * ],
764 * buttons: [ CKEDITOR.dialog.cancelButton, CKEDITOR.dialog.okButton ]
765 * };
766 *
767 * @class CKEDITOR.dialog.definition.html
768 * @extends CKEDITOR.dialog.definition.uiElement
769 */
770
771/**
772 * (Required) HTML code of this element.
773 *
774 * @property {String} html
775 */
776
777// ----- radio ----------------------------------------------------------------
778
779/**
780 * The definition of a radio group.
781 *
782 * This class is not really part of the API. It just illustrates the properties
783 * that developers can use to define and create groups of radio buttons.
784 *
785 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.radio} object
786 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
787 *
788 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
789 *
790 * // There is no constructor for this class, the user just has to define an
791 * // object with the appropriate properties.
792 *
793 * // Example:
794 * {
795 * type: 'radio',
796 * id: 'country',
797 * label: 'Which country is bigger',
798 * items: [ [ 'France', 'FR' ], [ 'Germany', 'DE' ] ],
799 * style: 'color: green',
800 * 'default': 'DE',
801 * onClick: function() {
802 * // this = CKEDITOR.ui.dialog.radio
803 * alert( 'Current value: ' + this.getValue() );
804 * }
805 * }
806 *
807 * @class CKEDITOR.dialog.definition.radio
808 * @extends CKEDITOR.dialog.definition.labeledElement
809 */
810
811/**
812 * The default value.
813 *
814 * @property {String} default
815 */
816
817/**
818 * (Optional) The validation function.
819 *
820 * @property {Function} validate
821 */
822
823/**
824 * An array of options. Each option is a 1- or 2-item array of format `[ 'Description', 'Value' ]`.
825 * If `'Value'` is missing, then the value would be assumed to be the same as the description.
826 *
827 * @property {Array} items
828 */
829
830// ----- selectElement --------------------------------------------------------
831
832/**
833 * The definition of a select element.
834 *
835 * This class is not really part of the API. It just illustrates the properties
836 * that developers can use to define and create select elements.
837 *
838 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.select} object
839 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
840 *
841 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
842 *
843 * // There is no constructor for this class, the user just has to define an
844 * // object with the appropriate properties.
845 *
846 * // Example:
847 * {
848 * type: 'select',
849 * id: 'sport',
850 * label: 'Select your favourite sport',
851 * items: [ [ 'Basketball' ], [ 'Baseball' ], [ 'Hockey' ], [ 'Football' ] ],
852 * 'default': 'Football',
853 * onChange: function( api ) {
854 * // this = CKEDITOR.ui.dialog.select
855 * alert( 'Current value: ' + this.getValue() );
856 * }
857 * }
858 *
859 * @class CKEDITOR.dialog.definition.select
860 * @extends CKEDITOR.dialog.definition.labeledElement
861 */
862
863/**
864 * The default value.
865 *
866 * @property {String} default
867 */
868
869/**
870 * (Optional) The validation function.
871 *
872 * @property {Function} validate
873 */
874
875/**
876 * An array of options. Each option is a 1- or 2-item array of format `[ 'Description', 'Value' ]`.
877 * If `'Value'` is missing, then the value would be assumed to be the same as the description.
878 *
879 * @property {Array} items
880 */
881
882/**
883 * (Optional) Set this to true if you'd like to have a multiple-choice select box.
884 *
885 * @property {Boolean} [multiple=false]
886 */
887
888/**
889 * (Optional) The number of items to display in the select box.
890 *
891 * @property {Number} size
892 */
893
894// ----- textInput ------------------------------------------------------------
895
896/**
897 * The definition of a text field (single line).
898 *
899 * This class is not really part of the API. It just illustrates the properties
900 * that developers can use to define and create text fields.
901 *
902 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.textInput} object
903 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
904 *
905 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
906 *
907 * // There is no constructor for this class, the user just has to define an
908 * // object with the appropriate properties.
909 *
910 * {
911 * type: 'text',
912 * id: 'name',
913 * label: 'Your name',
914 * 'default': '',
915 * validate: function() {
916 * if ( !this.getValue() ) {
917 * api.openMsgDialog( '', 'Name cannot be empty.' );
918 * return false;
919 * }
920 * }
921 * }
922 *
923 * @class CKEDITOR.dialog.definition.textInput
924 * @extends CKEDITOR.dialog.definition.labeledElement
925 */
926
927/**
928 * The default value.
929 *
930 * @property {String} default
931 */
932
933/**
934 * (Optional) The maximum length.
935 *
936 * @property {Number} maxLength
937 */
938
939/**
940 * (Optional) The size of the input field.
941 *
942 * @property {Number} size
943 */
944
945/**
946 * (Optional) The validation function.
947 *
948 * @property {Function} validate
949 */
950
951/**
952 * @property bidi
953 * @inheritdoc CKEDITOR.dialog.definition.textarea#bidi
954 */
955
956// ----- textarea -------------------------------------------------------------
957
958/**
959 * The definition of a text field (multiple lines).
960 *
961 * This class is not really part of the API. It just illustrates the properties
962 * that developers can use to define and create textarea.
963 *
964 * Once the dialog is opened, the created element becomes a {@link CKEDITOR.ui.dialog.textarea} object
965 * and can be accessed with {@link CKEDITOR.dialog#getContentElement}.
966 *
967 * For a complete example of dialog definition, please check {@link CKEDITOR.dialog#add}.
968 *
969* // There is no constructor for this class, the user just has to define an
970* // object with the appropriate properties.
971*
972* // Example:
973* {
974* type: 'textarea',
975* id: 'message',
976* label: 'Your comment',
977* 'default': '',
978* validate: function() {
979* if ( this.getValue().length < 5 ) {
980* api.openMsgDialog( 'The comment is too short.' );
981* return false;
982* }
983* }
984* }
985 *
986 * @class CKEDITOR.dialog.definition.textarea
987 * @extends CKEDITOR.dialog.definition.labeledElement
988 */
989
990/**
991 * The number of rows.
992 *
993 * @property {Number} rows
994 */
995
996/**
997 * The number of columns.
998 *
999 * @property {Number} cols
1000 */
1001
1002/**
1003 * (Optional) The validation function.
1004 *
1005 * @property {Function} validate
1006 */
1007
1008/**
1009 * The default value.
1010 *
1011 * @property {String} default
1012 */
1013
1014/**
1015 * Whether the text direction of this input should be togglable using the following keystrokes:
1016 *
1017 * * *Shift+Alt+End* &ndash; switch to Right-To-Left,
1018 * * *Shift+Alt+Home* &ndash; switch to Left-To-Right.
1019 *
1020 * By default the input will be loaded without any text direction set, which means that
1021 * the direction will be inherited from the editor's text direction.
1022 *
1023 * If the direction was set, a marker will be prepended to every non-empty value of this input:
1024 *
1025 * * [`\u202A`](http://unicode.org/cldr/utility/character.jsp?a=202A) &ndash; for Right-To-Left,
1026 * * [`\u202B`](http://unicode.org/cldr/utility/character.jsp?a=202B) &ndash; for Left-To-Right.
1027 *
1028 * This marker allows for restoring the same text direction upon the next dialog opening.
1029 *
1030 * @since 4.5
1031 * @property {Boolean} bidi
1032 */
diff --git a/sources/plugins/dialog/plugin.js b/sources/plugins/dialog/plugin.js
new file mode 100644
index 0000000..d6af6a2
--- /dev/null
+++ b/sources/plugins/dialog/plugin.js
@@ -0,0 +1,3399 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The floating dialog plugin.
8 */
9
10/**
11 * No resize for this dialog.
12 *
13 * @readonly
14 * @property {Number} [=0]
15 * @member CKEDITOR
16 */
17CKEDITOR.DIALOG_RESIZE_NONE = 0;
18
19/**
20 * Only allow horizontal resizing for this dialog, disable vertical resizing.
21 *
22 * @readonly
23 * @property {Number} [=1]
24 * @member CKEDITOR
25 */
26CKEDITOR.DIALOG_RESIZE_WIDTH = 1;
27
28/**
29 * Only allow vertical resizing for this dialog, disable horizontal resizing.
30 *
31 * @readonly
32 * @property {Number} [=2]
33 * @member CKEDITOR
34 */
35CKEDITOR.DIALOG_RESIZE_HEIGHT = 2;
36
37/**
38 * Allow the dialog to be resized in both directions.
39 *
40 * @readonly
41 * @property {Number} [=3]
42 * @member CKEDITOR
43 */
44CKEDITOR.DIALOG_RESIZE_BOTH = 3;
45
46/**
47 * Dialog state when idle.
48 *
49 * @readonly
50 * @property {Number} [=1]
51 * @member CKEDITOR
52 */
53CKEDITOR.DIALOG_STATE_IDLE = 1;
54
55/**
56 * Dialog state when busy.
57 *
58 * @readonly
59 * @property {Number} [=2]
60 * @member CKEDITOR
61 */
62CKEDITOR.DIALOG_STATE_BUSY = 2;
63
64( function() {
65 var cssLength = CKEDITOR.tools.cssLength;
66
67 function isTabVisible( tabId ) {
68 return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight;
69 }
70
71 function getPreviousVisibleTab() {
72 var tabId = this._.currentTabId,
73 length = this._.tabIdList.length,
74 tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length;
75
76 for ( var i = tabIndex - 1; i > tabIndex - length; i-- ) {
77 if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
78 return this._.tabIdList[ i % length ];
79 }
80
81 return null;
82 }
83
84 function getNextVisibleTab() {
85 var tabId = this._.currentTabId,
86 length = this._.tabIdList.length,
87 tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId );
88
89 for ( var i = tabIndex + 1; i < tabIndex + length; i++ ) {
90 if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
91 return this._.tabIdList[ i % length ];
92 }
93
94 return null;
95 }
96
97
98 function clearOrRecoverTextInputValue( container, isRecover ) {
99 var inputs = container.$.getElementsByTagName( 'input' );
100 for ( var i = 0, length = inputs.length; i < length; i++ ) {
101 var item = new CKEDITOR.dom.element( inputs[ i ] );
102
103 if ( item.getAttribute( 'type' ).toLowerCase() == 'text' ) {
104 if ( isRecover ) {
105 item.setAttribute( 'value', item.getCustomData( 'fake_value' ) || '' );
106 item.removeCustomData( 'fake_value' );
107 } else {
108 item.setCustomData( 'fake_value', item.getAttribute( 'value' ) );
109 item.setAttribute( 'value', '' );
110 }
111 }
112 }
113 }
114
115 // Handle dialog element validation state UI changes.
116 function handleFieldValidated( isValid, msg ) {
117 var input = this.getInputElement();
118 if ( input )
119 isValid ? input.removeAttribute( 'aria-invalid' ) : input.setAttribute( 'aria-invalid', true );
120
121 if ( !isValid ) {
122 if ( this.select )
123 this.select();
124 else
125 this.focus();
126 }
127
128 msg && alert( msg ); // jshint ignore:line
129
130 this.fire( 'validated', { valid: isValid, msg: msg } );
131 }
132
133 function resetField() {
134 var input = this.getInputElement();
135 input && input.removeAttribute( 'aria-invalid' );
136 }
137
138 var templateSource = '<div class="cke_reset_all {editorId} {editorDialogClass} {hidpi}' +
139 '" dir="{langDir}"' +
140 ' lang="{langCode}"' +
141 ' role="dialog"' +
142 ' aria-labelledby="cke_dialog_title_{id}"' +
143 '>' +
144 '<table class="cke_dialog ' + CKEDITOR.env.cssClass + ' cke_{langDir}"' +
145 ' style="position:absolute" role="presentation">' +
146 '<tr><td role="presentation">' +
147 '<div class="cke_dialog_body" role="presentation">' +
148 '<div id="cke_dialog_title_{id}" class="cke_dialog_title" role="presentation"></div>' +
149 '<a id="cke_dialog_close_button_{id}" class="cke_dialog_close_button" href="javascript:void(0)" title="{closeTitle}" role="button"><span class="cke_label">X</span></a>' +
150 '<div id="cke_dialog_tabs_{id}" class="cke_dialog_tabs" role="tablist"></div>' +
151 '<table class="cke_dialog_contents" role="presentation">' +
152 '<tr>' +
153 '<td id="cke_dialog_contents_{id}" class="cke_dialog_contents_body" role="presentation"></td>' +
154 '</tr>' +
155 '<tr>' +
156 '<td id="cke_dialog_footer_{id}" class="cke_dialog_footer" role="presentation"></td>' +
157 '</tr>' +
158 '</table>' +
159 '</div>' +
160 '</td></tr>' +
161 '</table>' +
162 '</div>';
163
164 function buildDialog( editor ) {
165 var element = CKEDITOR.dom.element.createFromHtml( CKEDITOR.addTemplate( 'dialog', templateSource ).output( {
166 id: CKEDITOR.tools.getNextNumber(),
167 editorId: editor.id,
168 langDir: editor.lang.dir,
169 langCode: editor.langCode,
170 editorDialogClass: 'cke_editor_' + editor.name.replace( /\./g, '\\.' ) + '_dialog',
171 closeTitle: editor.lang.common.close,
172 hidpi: CKEDITOR.env.hidpi ? 'cke_hidpi' : ''
173 } ) );
174
175 // TODO: Change this to getById(), so it'll support custom templates.
176 var body = element.getChild( [ 0, 0, 0, 0, 0 ] ),
177 title = body.getChild( 0 ),
178 close = body.getChild( 1 );
179
180 // Don't allow dragging on dialog (#13184).
181 editor.plugins.clipboard && CKEDITOR.plugins.clipboard.preventDefaultDropOnElement( body );
182
183 // IFrame shim for dialog that masks activeX in IE. (#7619)
184 if ( CKEDITOR.env.ie && !CKEDITOR.env.quirks && !CKEDITOR.env.edge ) {
185 var src = 'javascript:void(function(){' + encodeURIComponent( 'document.open();(' + CKEDITOR.tools.fixDomain + ')();document.close();' ) + '}())', // jshint ignore:line
186 iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' +
187 ' frameBorder="0"' +
188 ' class="cke_iframe_shim"' +
189 ' src="' + src + '"' +
190 ' tabIndex="-1"' +
191 '></iframe>' );
192 iframe.appendTo( body.getParent() );
193 }
194
195 // Make the Title and Close Button unselectable.
196 title.unselectable();
197 close.unselectable();
198
199 return {
200 element: element,
201 parts: {
202 dialog: element.getChild( 0 ),
203 title: title,
204 close: close,
205 tabs: body.getChild( 2 ),
206 contents: body.getChild( [ 3, 0, 0, 0 ] ),
207 footer: body.getChild( [ 3, 0, 1, 0 ] )
208 }
209 };
210 }
211
212 /**
213 * This is the base class for runtime dialog objects. An instance of this
214 * class represents a single named dialog for a single editor instance.
215 *
216 * var dialogObj = new CKEDITOR.dialog( editor, 'smiley' );
217 *
218 * @class
219 * @constructor Creates a dialog class instance.
220 * @param {Object} editor The editor which created the dialog.
221 * @param {String} dialogName The dialog's registered name.
222 */
223 CKEDITOR.dialog = function( editor, dialogName ) {
224 // Load the dialog definition.
225 var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],
226 defaultDefinition = CKEDITOR.tools.clone( defaultDialogDefinition ),
227 buttonsOrder = editor.config.dialog_buttonsOrder || 'OS',
228 dir = editor.lang.dir,
229 tabsToRemove = {},
230 i, processed, stopPropagation;
231
232 if ( ( buttonsOrder == 'OS' && CKEDITOR.env.mac ) || // The buttons in MacOS Apps are in reverse order (#4750)
233 ( buttonsOrder == 'rtl' && dir == 'ltr' ) || ( buttonsOrder == 'ltr' && dir == 'rtl' ) )
234 defaultDefinition.buttons.reverse();
235
236
237 // Completes the definition with the default values.
238 definition = CKEDITOR.tools.extend( definition( editor ), defaultDefinition );
239
240 // Clone a functionally independent copy for this dialog.
241 definition = CKEDITOR.tools.clone( definition );
242
243 // Create a complex definition object, extending it with the API
244 // functions.
245 definition = new definitionObject( this, definition );
246
247 var themeBuilt = buildDialog( editor );
248
249 // Initialize some basic parameters.
250 this._ = {
251 editor: editor,
252 element: themeBuilt.element,
253 name: dialogName,
254 contentSize: { width: 0, height: 0 },
255 size: { width: 0, height: 0 },
256 contents: {},
257 buttons: {},
258 accessKeyMap: {},
259
260 // Initialize the tab and page map.
261 tabs: {},
262 tabIdList: [],
263 currentTabId: null,
264 currentTabIndex: null,
265 pageCount: 0,
266 lastTab: null,
267 tabBarMode: false,
268
269 // Initialize the tab order array for input widgets.
270 focusList: [],
271 currentFocusIndex: 0,
272 hasFocus: false
273 };
274
275 this.parts = themeBuilt.parts;
276
277 CKEDITOR.tools.setTimeout( function() {
278 editor.fire( 'ariaWidget', this.parts.contents );
279 }, 0, this );
280
281 // Set the startup styles for the dialog, avoiding it enlarging the
282 // page size on the dialog creation.
283 var startStyles = {
284 position: CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed',
285 top: 0,
286 visibility: 'hidden'
287 };
288
289 startStyles[ dir == 'rtl' ? 'right' : 'left' ] = 0;
290 this.parts.dialog.setStyles( startStyles );
291
292
293 // Call the CKEDITOR.event constructor to initialize this instance.
294 CKEDITOR.event.call( this );
295
296 // Fire the "dialogDefinition" event, making it possible to customize
297 // the dialog definition.
298 this.definition = definition = CKEDITOR.fire( 'dialogDefinition', {
299 name: dialogName,
300 definition: definition
301 }, editor ).definition;
302
303 // Cache tabs that should be removed.
304 if ( !( 'removeDialogTabs' in editor._ ) && editor.config.removeDialogTabs ) {
305 var removeContents = editor.config.removeDialogTabs.split( ';' );
306
307 for ( i = 0; i < removeContents.length; i++ ) {
308 var parts = removeContents[ i ].split( ':' );
309 if ( parts.length == 2 ) {
310 var removeDialogName = parts[ 0 ];
311 if ( !tabsToRemove[ removeDialogName ] )
312 tabsToRemove[ removeDialogName ] = [];
313 tabsToRemove[ removeDialogName ].push( parts[ 1 ] );
314 }
315 }
316 editor._.removeDialogTabs = tabsToRemove;
317 }
318
319 // Remove tabs of this dialog.
320 if ( editor._.removeDialogTabs && ( tabsToRemove = editor._.removeDialogTabs[ dialogName ] ) ) {
321 for ( i = 0; i < tabsToRemove.length; i++ )
322 definition.removeContents( tabsToRemove[ i ] );
323 }
324
325 // Initialize load, show, hide, ok and cancel events.
326 if ( definition.onLoad )
327 this.on( 'load', definition.onLoad );
328
329 if ( definition.onShow )
330 this.on( 'show', definition.onShow );
331
332 if ( definition.onHide )
333 this.on( 'hide', definition.onHide );
334
335 if ( definition.onOk ) {
336 this.on( 'ok', function( evt ) {
337 // Dialog confirm might probably introduce content changes (#5415).
338 editor.fire( 'saveSnapshot' );
339 setTimeout( function() {
340 editor.fire( 'saveSnapshot' );
341 }, 0 );
342 if ( definition.onOk.call( this, evt ) === false )
343 evt.data.hide = false;
344 } );
345 }
346
347 // Set default dialog state.
348 this.state = CKEDITOR.DIALOG_STATE_IDLE;
349
350 if ( definition.onCancel ) {
351 this.on( 'cancel', function( evt ) {
352 if ( definition.onCancel.call( this, evt ) === false )
353 evt.data.hide = false;
354 } );
355 }
356
357 var me = this;
358
359 // Iterates over all items inside all content in the dialog, calling a
360 // function for each of them.
361 var iterContents = function( func ) {
362 var contents = me._.contents,
363 stop = false;
364
365 for ( var i in contents ) {
366 for ( var j in contents[ i ] ) {
367 stop = func.call( this, contents[ i ][ j ] );
368 if ( stop )
369 return;
370 }
371 }
372 };
373
374 this.on( 'ok', function( evt ) {
375 iterContents( function( item ) {
376 if ( item.validate ) {
377 var retval = item.validate( this ),
378 invalid = ( typeof retval == 'string' ) || retval === false;
379
380 if ( invalid ) {
381 evt.data.hide = false;
382 evt.stop();
383 }
384
385 handleFieldValidated.call( item, !invalid, typeof retval == 'string' ? retval : undefined );
386 return invalid;
387 }
388 } );
389 }, this, null, 0 );
390
391 this.on( 'cancel', function( evt ) {
392 iterContents( function( item ) {
393 if ( item.isChanged() ) {
394 if ( !editor.config.dialog_noConfirmCancel && !confirm( editor.lang.common.confirmCancel ) ) // jshint ignore:line
395 evt.data.hide = false;
396 return true;
397 }
398 } );
399 }, this, null, 0 );
400
401 this.parts.close.on( 'click', function( evt ) {
402 if ( this.fire( 'cancel', { hide: true } ).hide !== false )
403 this.hide();
404 evt.data.preventDefault();
405 }, this );
406
407 // Sort focus list according to tab order definitions.
408 function setupFocus() {
409 var focusList = me._.focusList;
410 focusList.sort( function( a, b ) {
411 // Mimics browser tab order logics;
412 if ( a.tabIndex != b.tabIndex )
413 return b.tabIndex - a.tabIndex;
414 // Sort is not stable in some browsers,
415 // fall-back the comparator to 'focusIndex';
416 else
417 return a.focusIndex - b.focusIndex;
418 } );
419
420 var size = focusList.length;
421 for ( var i = 0; i < size; i++ )
422 focusList[ i ].focusIndex = i;
423 }
424
425 // Expects 1 or -1 as an offset, meaning direction of the offset change.
426 function changeFocus( offset ) {
427 var focusList = me._.focusList;
428 offset = offset || 0;
429
430 if ( focusList.length < 1 )
431 return;
432
433 var startIndex = me._.currentFocusIndex;
434
435 if ( me._.tabBarMode && offset < 0 ) {
436 // If we are in tab mode, we need to mimic that we started tabbing back from the first
437 // focusList (so it will go to the last one).
438 startIndex = 0;
439 }
440
441 // Trigger the 'blur' event of any input element before anything,
442 // since certain UI updates may depend on it.
443 try {
444 focusList[ startIndex ].getInputElement().$.blur();
445 } catch ( e ) {}
446
447 var currentIndex = startIndex,
448 hasTabs = me._.pageCount > 1;
449
450 do {
451 currentIndex = currentIndex + offset;
452
453 if ( hasTabs && !me._.tabBarMode && ( currentIndex == focusList.length || currentIndex == -1 ) ) {
454 // If the dialog was not in tab mode, then focus the first tab (#13027).
455 me._.tabBarMode = true;
456 me._.tabs[ me._.currentTabId ][ 0 ].focus();
457 me._.currentFocusIndex = -1;
458
459 // Early return, in order to avoid accessing focusList[ -1 ].
460 return;
461 }
462
463 currentIndex = ( currentIndex + focusList.length ) % focusList.length;
464
465 if ( currentIndex == startIndex ) {
466 break;
467 }
468 } while ( offset && !focusList[ currentIndex ].isFocusable() );
469
470 focusList[ currentIndex ].focus();
471
472 // Select whole field content.
473 if ( focusList[ currentIndex ].type == 'text' )
474 focusList[ currentIndex ].select();
475 }
476
477 this.changeFocus = changeFocus;
478
479
480 function keydownHandler( evt ) {
481 // If I'm not the top dialog, ignore.
482 if ( me != CKEDITOR.dialog._.currentTop )
483 return;
484
485 var keystroke = evt.data.getKeystroke(),
486 rtl = editor.lang.dir == 'rtl',
487 arrowKeys = [ 37, 38, 39, 40 ],
488 button;
489
490 processed = stopPropagation = 0;
491
492 if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 ) {
493 var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 );
494 changeFocus( shiftPressed ? -1 : 1 );
495 processed = 1;
496 } else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 ) {
497 // Alt-F10 puts focus into the current tab item in the tab bar.
498 me._.tabBarMode = true;
499 me._.tabs[ me._.currentTabId ][ 0 ].focus();
500 me._.currentFocusIndex = -1;
501 processed = 1;
502 } else if ( CKEDITOR.tools.indexOf( arrowKeys, keystroke ) != -1 && me._.tabBarMode ) {
503 // Array with key codes that activate previous tab.
504 var prevKeyCodes = [
505 // Depending on the lang dir: right or left key
506 rtl ? 39 : 37,
507 // Top/bot arrow: actually for both cases it's the same.
508 38
509 ],
510 nextId = CKEDITOR.tools.indexOf( prevKeyCodes, keystroke ) != -1 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me );
511
512 me.selectPage( nextId );
513 me._.tabs[ nextId ][ 0 ].focus();
514 processed = 1;
515 } else if ( ( keystroke == 13 || keystroke == 32 ) && me._.tabBarMode ) {
516 this.selectPage( this._.currentTabId );
517 this._.tabBarMode = false;
518 this._.currentFocusIndex = -1;
519 changeFocus( 1 );
520 processed = 1;
521 }
522 // If user presses enter key in a text box, it implies clicking OK for the dialog.
523 else if ( keystroke == 13 /*ENTER*/ ) {
524 // Don't do that for a target that handles ENTER.
525 var target = evt.data.getTarget();
526 if ( !target.is( 'a', 'button', 'select', 'textarea' ) && ( !target.is( 'input' ) || target.$.type != 'button' ) ) {
527 button = this.getButton( 'ok' );
528 button && CKEDITOR.tools.setTimeout( button.click, 0, button );
529 processed = 1;
530 }
531 stopPropagation = 1; // Always block the propagation (#4269)
532 } else if ( keystroke == 27 /*ESC*/ ) {
533 button = this.getButton( 'cancel' );
534
535 // If there's a Cancel button, click it, else just fire the cancel event and hide the dialog.
536 if ( button )
537 CKEDITOR.tools.setTimeout( button.click, 0, button );
538 else {
539 if ( this.fire( 'cancel', { hide: true } ).hide !== false )
540 this.hide();
541 }
542 stopPropagation = 1; // Always block the propagation (#4269)
543 } else {
544 return;
545 }
546
547 keypressHandler( evt );
548 }
549
550 function keypressHandler( evt ) {
551 if ( processed )
552 evt.data.preventDefault( 1 );
553 else if ( stopPropagation )
554 evt.data.stopPropagation();
555 }
556
557 var dialogElement = this._.element;
558
559 editor.focusManager.add( dialogElement, 1 );
560
561 // Add the dialog keyboard handlers.
562 this.on( 'show', function() {
563 dialogElement.on( 'keydown', keydownHandler, this );
564
565 // Some browsers instead, don't cancel key events in the keydown, but in the
566 // keypress. So we must do a longer trip in those cases. (#4531,#8985)
567 if ( CKEDITOR.env.gecko )
568 dialogElement.on( 'keypress', keypressHandler, this );
569
570 } );
571 this.on( 'hide', function() {
572 dialogElement.removeListener( 'keydown', keydownHandler );
573 if ( CKEDITOR.env.gecko )
574 dialogElement.removeListener( 'keypress', keypressHandler );
575
576 // Reset fields state when closing dialog.
577 iterContents( function( item ) {
578 resetField.apply( item );
579 } );
580 } );
581 this.on( 'iframeAdded', function( evt ) {
582 var doc = new CKEDITOR.dom.document( evt.data.iframe.$.contentWindow.document );
583 doc.on( 'keydown', keydownHandler, this, null, 0 );
584 } );
585
586 // Auto-focus logic in dialog.
587 this.on( 'show', function() {
588 // Setup tabIndex on showing the dialog instead of on loading
589 // to allow dynamic tab order happen in dialog definition.
590 setupFocus();
591
592 var hasTabs = me._.pageCount > 1;
593
594 if ( editor.config.dialog_startupFocusTab && hasTabs ) {
595 me._.tabBarMode = true;
596 me._.tabs[ me._.currentTabId ][ 0 ].focus();
597 me._.currentFocusIndex = -1;
598 } else if ( !this._.hasFocus ) {
599 // http://dev.ckeditor.com/ticket/13114#comment:4.
600 this._.currentFocusIndex = hasTabs ? -1 : this._.focusList.length - 1;
601
602 // Decide where to put the initial focus.
603 if ( definition.onFocus ) {
604 var initialFocus = definition.onFocus.call( this );
605 // Focus the field that the user specified.
606 initialFocus && initialFocus.focus();
607 }
608 // Focus the first field in layout order.
609 else {
610 changeFocus( 1 );
611 }
612 }
613 }, this, null, 0xffffffff );
614
615 // IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661).
616 // This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken.
617 if ( CKEDITOR.env.ie6Compat ) {
618 this.on( 'load', function() {
619 var outer = this.getElement(),
620 inner = outer.getFirst();
621 inner.remove();
622 inner.appendTo( outer );
623 }, this );
624 }
625
626 initDragAndDrop( this );
627 initResizeHandles( this );
628
629 // Insert the title.
630 ( new CKEDITOR.dom.text( definition.title, CKEDITOR.document ) ).appendTo( this.parts.title );
631
632 // Insert the tabs and contents.
633 for ( i = 0; i < definition.contents.length; i++ ) {
634 var page = definition.contents[ i ];
635 page && this.addPage( page );
636 }
637
638 this.parts.tabs.on( 'click', function( evt ) {
639 var target = evt.data.getTarget();
640 // If we aren't inside a tab, bail out.
641 if ( target.hasClass( 'cke_dialog_tab' ) ) {
642 // Get the ID of the tab, without the 'cke_' prefix and the unique number suffix.
643 var id = target.$.id;
644 this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) );
645
646 if ( this._.tabBarMode ) {
647 this._.tabBarMode = false;
648 this._.currentFocusIndex = -1;
649 changeFocus( 1 );
650 }
651 evt.data.preventDefault();
652 }
653 }, this );
654
655 // Insert buttons.
656 var buttonsHtml = [],
657 buttons = CKEDITOR.dialog._.uiElementBuilders.hbox.build( this, {
658 type: 'hbox',
659 className: 'cke_dialog_footer_buttons',
660 widths: [],
661 children: definition.buttons
662 }, buttonsHtml ).getChild();
663 this.parts.footer.setHtml( buttonsHtml.join( '' ) );
664
665 for ( i = 0; i < buttons.length; i++ )
666 this._.buttons[ buttons[ i ].id ] = buttons[ i ];
667
668 /**
669 * Current state of the dialog. Use the {@link #setState} method to update it.
670 * See the {@link #event-state} event to know more.
671 *
672 * @readonly
673 * @property {Number} [state=CKEDITOR.DIALOG_STATE_IDLE]
674 */
675 };
676
677 // Focusable interface. Use it via dialog.addFocusable.
678 function Focusable( dialog, element, index ) {
679 this.element = element;
680 this.focusIndex = index;
681 // TODO: support tabIndex for focusables.
682 this.tabIndex = 0;
683 this.isFocusable = function() {
684 return !element.getAttribute( 'disabled' ) && element.isVisible();
685 };
686 this.focus = function() {
687 dialog._.currentFocusIndex = this.focusIndex;
688 this.element.focus();
689 };
690 // Bind events
691 element.on( 'keydown', function( e ) {
692 if ( e.data.getKeystroke() in { 32: 1, 13: 1 } )
693 this.fire( 'click' );
694 } );
695 element.on( 'focus', function() {
696 this.fire( 'mouseover' );
697 } );
698 element.on( 'blur', function() {
699 this.fire( 'mouseout' );
700 } );
701 }
702
703 // Re-layout the dialog on window resize.
704 function resizeWithWindow( dialog ) {
705 var win = CKEDITOR.document.getWindow();
706 function resizeHandler() {
707 dialog.layout();
708 }
709 win.on( 'resize', resizeHandler );
710 dialog.on( 'hide', function() {
711 win.removeListener( 'resize', resizeHandler );
712 } );
713 }
714
715 CKEDITOR.dialog.prototype = {
716 destroy: function() {
717 this.hide();
718 this._.element.remove();
719 },
720
721 /**
722 * Resizes the dialog.
723 *
724 * dialogObj.resize( 800, 640 );
725 *
726 * @method
727 * @param {Number} width The width of the dialog in pixels.
728 * @param {Number} height The height of the dialog in pixels.
729 */
730 resize: ( function() {
731 return function( width, height ) {
732 if ( this._.contentSize && this._.contentSize.width == width && this._.contentSize.height == height )
733 return;
734
735 CKEDITOR.dialog.fire( 'resize', {
736 dialog: this,
737 width: width,
738 height: height
739 }, this._.editor );
740
741 this.fire( 'resize', {
742 width: width,
743 height: height
744 }, this._.editor );
745
746 var contents = this.parts.contents;
747 contents.setStyles( {
748 width: width + 'px',
749 height: height + 'px'
750 } );
751
752 // Update dialog position when dimension get changed in RTL.
753 if ( this._.editor.lang.dir == 'rtl' && this._.position )
754 this._.position.x = CKEDITOR.document.getWindow().getViewPaneSize().width - this._.contentSize.width - parseInt( this._.element.getFirst().getStyle( 'right' ), 10 );
755
756 this._.contentSize = { width: width, height: height };
757 };
758 } )(),
759
760 /**
761 * Gets the current size of the dialog in pixels.
762 *
763 * var width = dialogObj.getSize().width;
764 *
765 * @returns {Object}
766 * @returns {Number} return.width
767 * @returns {Number} return.height
768 */
769 getSize: function() {
770 var element = this._.element.getFirst();
771 return { width: element.$.offsetWidth || 0, height: element.$.offsetHeight || 0 };
772 },
773
774 /**
775 * Moves the dialog to an `(x, y)` coordinate relative to the window.
776 *
777 * dialogObj.move( 10, 40 );
778 *
779 * @method
780 * @param {Number} x The target x-coordinate.
781 * @param {Number} y The target y-coordinate.
782 * @param {Boolean} save Flag indicate whether the dialog position should be remembered on next open up.
783 */
784 move: function( x, y, save ) {
785
786 // The dialog may be fixed positioned or absolute positioned. Ask the
787 // browser what is the current situation first.
788 var element = this._.element.getFirst(), rtl = this._.editor.lang.dir == 'rtl';
789 var isFixed = element.getComputedStyle( 'position' ) == 'fixed';
790
791 // (#8888) In some cases of a very small viewport, dialog is incorrectly
792 // positioned in IE7. It also happens that it remains sticky and user cannot
793 // scroll down/up to reveal dialog's content below/above the viewport; this is
794 // cumbersome.
795 // The only way to fix this is to move mouse out of the browser and
796 // go back to see that dialog position is automagically fixed. No events,
797 // no style change - pure magic. This is a IE7 rendering issue, which can be
798 // fixed with dummy style redraw on each move.
799 if ( CKEDITOR.env.ie )
800 element.setStyle( 'zoom', '100%' );
801
802 if ( isFixed && this._.position && this._.position.x == x && this._.position.y == y )
803 return;
804
805 // Save the current position.
806 this._.position = { x: x, y: y };
807
808 // If not fixed positioned, add scroll position to the coordinates.
809 if ( !isFixed ) {
810 var scrollPosition = CKEDITOR.document.getWindow().getScrollPosition();
811 x += scrollPosition.x;
812 y += scrollPosition.y;
813 }
814
815 // Translate coordinate for RTL.
816 if ( rtl ) {
817 var dialogSize = this.getSize(), viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize();
818 x = viewPaneSize.width - dialogSize.width - x;
819 }
820
821 var styles = { 'top': ( y > 0 ? y : 0 ) + 'px' };
822 styles[ rtl ? 'right' : 'left' ] = ( x > 0 ? x : 0 ) + 'px';
823
824 element.setStyles( styles );
825
826 save && ( this._.moved = 1 );
827 },
828
829 /**
830 * Gets the dialog's position in the window.
831 *
832 * var dialogX = dialogObj.getPosition().x;
833 *
834 * @returns {Object}
835 * @returns {Number} return.x
836 * @returns {Number} return.y
837 */
838 getPosition: function() {
839 return CKEDITOR.tools.extend( {}, this._.position );
840 },
841
842 /**
843 * Shows the dialog box.
844 *
845 * dialogObj.show();
846 */
847 show: function() {
848 // Insert the dialog's element to the root document.
849 var element = this._.element;
850 var definition = this.definition;
851 if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) )
852 element.appendTo( CKEDITOR.document.getBody() );
853 else
854 element.setStyle( 'display', 'block' );
855
856 // First, set the dialog to an appropriate size.
857 this.resize(
858 this._.contentSize && this._.contentSize.width || definition.width || definition.minWidth,
859 this._.contentSize && this._.contentSize.height || definition.height || definition.minHeight
860 );
861
862 // Reset all inputs back to their default value.
863 this.reset();
864
865 // Select the first tab by default.
866 this.selectPage( this.definition.contents[ 0 ].id );
867
868 // Set z-index.
869 if ( CKEDITOR.dialog._.currentZIndex === null )
870 CKEDITOR.dialog._.currentZIndex = this._.editor.config.baseFloatZIndex;
871 this._.element.getFirst().setStyle( 'z-index', CKEDITOR.dialog._.currentZIndex += 10 );
872
873 // Maintain the dialog ordering and dialog cover.
874 if ( CKEDITOR.dialog._.currentTop === null ) {
875 CKEDITOR.dialog._.currentTop = this;
876 this._.parentDialog = null;
877 showCover( this._.editor );
878
879 } else {
880 this._.parentDialog = CKEDITOR.dialog._.currentTop;
881 var parentElement = this._.parentDialog.getElement().getFirst();
882 parentElement.$.style.zIndex -= Math.floor( this._.editor.config.baseFloatZIndex / 2 );
883 CKEDITOR.dialog._.currentTop = this;
884 }
885
886 element.on( 'keydown', accessKeyDownHandler );
887 element.on( 'keyup', accessKeyUpHandler );
888
889 // Reset the hasFocus state.
890 this._.hasFocus = false;
891
892 for ( var i in definition.contents ) {
893 if ( !definition.contents[ i ] )
894 continue;
895
896 var content = definition.contents[ i ],
897 tab = this._.tabs[ content.id ],
898 requiredContent = content.requiredContent,
899 enableElements = 0;
900
901 if ( !tab )
902 continue;
903
904 for ( var j in this._.contents[ content.id ] ) {
905 var elem = this._.contents[ content.id ][ j ];
906
907 if ( elem.type == 'hbox' || elem.type == 'vbox' || !elem.getInputElement() )
908 continue;
909
910 if ( elem.requiredContent && !this._.editor.activeFilter.check( elem.requiredContent ) )
911 elem.disable();
912 else {
913 elem.enable();
914 enableElements++;
915 }
916 }
917
918 if ( !enableElements || ( requiredContent && !this._.editor.activeFilter.check( requiredContent ) ) )
919 tab[ 0 ].addClass( 'cke_dialog_tab_disabled' );
920 else
921 tab[ 0 ].removeClass( 'cke_dialog_tab_disabled' );
922 }
923
924 CKEDITOR.tools.setTimeout( function() {
925 this.layout();
926 resizeWithWindow( this );
927
928 this.parts.dialog.setStyle( 'visibility', '' );
929
930 // Execute onLoad for the first show.
931 this.fireOnce( 'load', {} );
932 CKEDITOR.ui.fire( 'ready', this );
933
934 this.fire( 'show', {} );
935 this._.editor.fire( 'dialogShow', this );
936
937 if ( !this._.parentDialog )
938 this._.editor.focusManager.lock();
939
940 // Save the initial values of the dialog.
941 this.foreach( function( contentObj ) {
942 contentObj.setInitValue && contentObj.setInitValue();
943 } );
944
945 }, 100, this );
946 },
947
948 /**
949 * Rearrange the dialog to its previous position or the middle of the window.
950 *
951 * @since 3.5
952 */
953 layout: function() {
954 var el = this.parts.dialog;
955 var dialogSize = this.getSize();
956 var win = CKEDITOR.document.getWindow(),
957 viewSize = win.getViewPaneSize();
958
959 var posX = ( viewSize.width - dialogSize.width ) / 2,
960 posY = ( viewSize.height - dialogSize.height ) / 2;
961
962 // Switch to absolute position when viewport is smaller than dialog size.
963 if ( !CKEDITOR.env.ie6Compat ) {
964 if ( dialogSize.height + ( posY > 0 ? posY : 0 ) > viewSize.height || dialogSize.width + ( posX > 0 ? posX : 0 ) > viewSize.width ) {
965 el.setStyle( 'position', 'absolute' );
966 } else {
967 el.setStyle( 'position', 'fixed' );
968 }
969 }
970
971 this.move( this._.moved ? this._.position.x : posX, this._.moved ? this._.position.y : posY );
972 },
973
974 /**
975 * Executes a function for each UI element.
976 *
977 * @param {Function} fn Function to execute for each UI element.
978 * @returns {CKEDITOR.dialog} The current dialog object.
979 */
980 foreach: function( fn ) {
981 for ( var i in this._.contents ) {
982 for ( var j in this._.contents[ i ] ) {
983 fn.call( this, this._.contents[i][j] );
984 }
985 }
986
987 return this;
988 },
989
990 /**
991 * Resets all input values in the dialog.
992 *
993 * dialogObj.reset();
994 *
995 * @method
996 * @chainable
997 */
998 reset: ( function() {
999 var fn = function( widget ) {
1000 if ( widget.reset )
1001 widget.reset( 1 );
1002 };
1003 return function() {
1004 this.foreach( fn );
1005 return this;
1006 };
1007 } )(),
1008
1009
1010 /**
1011 * Calls the {@link CKEDITOR.dialog.definition.uiElement#setup} method of each
1012 * of the UI elements, with the arguments passed through it.
1013 * It is usually being called when the dialog is opened, to put the initial value inside the field.
1014 *
1015 * dialogObj.setupContent();
1016 *
1017 * var timestamp = ( new Date() ).valueOf();
1018 * dialogObj.setupContent( timestamp );
1019 */
1020 setupContent: function() {
1021 var args = arguments;
1022 this.foreach( function( widget ) {
1023 if ( widget.setup )
1024 widget.setup.apply( widget, args );
1025 } );
1026 },
1027
1028 /**
1029 * Calls the {@link CKEDITOR.dialog.definition.uiElement#commit} method of each
1030 * of the UI elements, with the arguments passed through it.
1031 * It is usually being called when the user confirms the dialog, to process the values.
1032 *
1033 * dialogObj.commitContent();
1034 *
1035 * var timestamp = ( new Date() ).valueOf();
1036 * dialogObj.commitContent( timestamp );
1037 */
1038 commitContent: function() {
1039 var args = arguments;
1040 this.foreach( function( widget ) {
1041 // Make sure IE triggers "change" event on last focused input before closing the dialog. (#7915)
1042 if ( CKEDITOR.env.ie && this._.currentFocusIndex == widget.focusIndex )
1043 widget.getInputElement().$.blur();
1044
1045 if ( widget.commit )
1046 widget.commit.apply( widget, args );
1047 } );
1048 },
1049
1050 /**
1051 * Hides the dialog box.
1052 *
1053 * dialogObj.hide();
1054 */
1055 hide: function() {
1056 if ( !this.parts.dialog.isVisible() )
1057 return;
1058
1059 this.fire( 'hide', {} );
1060 this._.editor.fire( 'dialogHide', this );
1061 // Reset the tab page.
1062 this.selectPage( this._.tabIdList[ 0 ] );
1063 var element = this._.element;
1064 element.setStyle( 'display', 'none' );
1065 this.parts.dialog.setStyle( 'visibility', 'hidden' );
1066 // Unregister all access keys associated with this dialog.
1067 unregisterAccessKey( this );
1068
1069 // Close any child(top) dialogs first.
1070 while ( CKEDITOR.dialog._.currentTop != this )
1071 CKEDITOR.dialog._.currentTop.hide();
1072
1073 // Maintain dialog ordering and remove cover if needed.
1074 if ( !this._.parentDialog )
1075 hideCover( this._.editor );
1076 else {
1077 var parentElement = this._.parentDialog.getElement().getFirst();
1078 parentElement.setStyle( 'z-index', parseInt( parentElement.$.style.zIndex, 10 ) + Math.floor( this._.editor.config.baseFloatZIndex / 2 ) );
1079 }
1080 CKEDITOR.dialog._.currentTop = this._.parentDialog;
1081
1082 // Deduct or clear the z-index.
1083 if ( !this._.parentDialog ) {
1084 CKEDITOR.dialog._.currentZIndex = null;
1085
1086 // Remove access key handlers.
1087 element.removeListener( 'keydown', accessKeyDownHandler );
1088 element.removeListener( 'keyup', accessKeyUpHandler );
1089
1090 var editor = this._.editor;
1091 editor.focus();
1092
1093 // Give a while before unlock, waiting for focus to return to the editable. (#172)
1094 setTimeout( function() {
1095 editor.focusManager.unlock();
1096
1097 // Fixed iOS focus issue (#12381).
1098 // Keep in mind that editor.focus() does not work in this case.
1099 if ( CKEDITOR.env.iOS ) {
1100 editor.window.focus();
1101 }
1102 }, 0 );
1103
1104 } else {
1105 CKEDITOR.dialog._.currentZIndex -= 10;
1106 }
1107
1108 delete this._.parentDialog;
1109 // Reset the initial values of the dialog.
1110 this.foreach( function( contentObj ) {
1111 contentObj.resetInitValue && contentObj.resetInitValue();
1112 } );
1113
1114 // Reset dialog state back to IDLE, if busy (#13213).
1115 this.setState( CKEDITOR.DIALOG_STATE_IDLE );
1116 },
1117
1118 /**
1119 * Adds a tabbed page into the dialog.
1120 *
1121 * @param {Object} contents Content definition.
1122 */
1123 addPage: function( contents ) {
1124 if ( contents.requiredContent && !this._.editor.filter.check( contents.requiredContent ) )
1125 return;
1126
1127 var pageHtml = [],
1128 titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '',
1129 vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this, {
1130 type: 'vbox',
1131 className: 'cke_dialog_page_contents',
1132 children: contents.elements,
1133 expand: !!contents.expand,
1134 padding: contents.padding,
1135 style: contents.style || 'width: 100%;'
1136 }, pageHtml );
1137
1138 var contentMap = this._.contents[ contents.id ] = {},
1139 cursor,
1140 children = vbox.getChild(),
1141 enabledFields = 0;
1142
1143 while ( ( cursor = children.shift() ) ) {
1144 // Count all allowed fields.
1145 if ( !cursor.notAllowed && cursor.type != 'hbox' && cursor.type != 'vbox' )
1146 enabledFields++;
1147
1148 contentMap[ cursor.id ] = cursor;
1149 if ( typeof cursor.getChild == 'function' )
1150 children.push.apply( children, cursor.getChild() );
1151 }
1152
1153 // If all fields are disabled (because they are not allowed) hide this tab.
1154 if ( !enabledFields )
1155 contents.hidden = true;
1156
1157 // Create the HTML for the tab and the content block.
1158 var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );
1159 page.setAttribute( 'role', 'tabpanel' );
1160
1161 var env = CKEDITOR.env;
1162 var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(),
1163 tab = CKEDITOR.dom.element.createFromHtml( [
1164 '<a class="cke_dialog_tab"',
1165 ( this._.pageCount > 0 ? ' cke_last' : 'cke_first' ),
1166 titleHtml,
1167 ( !!contents.hidden ? ' style="display:none"' : '' ),
1168 ' id="', tabId, '"',
1169 env.gecko && !env.hc ? '' : ' href="javascript:void(0)"',
1170 ' tabIndex="-1"',
1171 ' hidefocus="true"',
1172 ' role="tab">',
1173 contents.label,
1174 '</a>'
1175 ].join( '' ) );
1176
1177 page.setAttribute( 'aria-labelledby', tabId );
1178
1179 // Take records for the tabs and elements created.
1180 this._.tabs[ contents.id ] = [ tab, page ];
1181 this._.tabIdList.push( contents.id );
1182 !contents.hidden && this._.pageCount++;
1183 this._.lastTab = tab;
1184 this.updateStyle();
1185
1186 // Attach the DOM nodes.
1187
1188 page.setAttribute( 'name', contents.id );
1189 page.appendTo( this.parts.contents );
1190
1191 tab.unselectable();
1192 this.parts.tabs.append( tab );
1193
1194 // Add access key handlers if access key is defined.
1195 if ( contents.accessKey ) {
1196 registerAccessKey( this, this, 'CTRL+' + contents.accessKey, tabAccessKeyDown, tabAccessKeyUp );
1197 this._.accessKeyMap[ 'CTRL+' + contents.accessKey ] = contents.id;
1198 }
1199 },
1200
1201 /**
1202 * Activates a tab page in the dialog by its id.
1203 *
1204 * dialogObj.selectPage( 'tab_1' );
1205 *
1206 * @param {String} id The id of the dialog tab to be activated.
1207 */
1208 selectPage: function( id ) {
1209 if ( this._.currentTabId == id )
1210 return;
1211
1212 if ( this._.tabs[ id ][ 0 ].hasClass( 'cke_dialog_tab_disabled' ) )
1213 return;
1214
1215 // If event was canceled - do nothing.
1216 if ( this.fire( 'selectPage', { page: id, currentPage: this._.currentTabId } ) === false )
1217 return;
1218
1219 // Hide the non-selected tabs and pages.
1220 for ( var i in this._.tabs ) {
1221 var tab = this._.tabs[ i ][ 0 ],
1222 page = this._.tabs[ i ][ 1 ];
1223 if ( i != id ) {
1224 tab.removeClass( 'cke_dialog_tab_selected' );
1225 page.hide();
1226 }
1227 page.setAttribute( 'aria-hidden', i != id );
1228 }
1229
1230 var selected = this._.tabs[ id ];
1231 selected[ 0 ].addClass( 'cke_dialog_tab_selected' );
1232
1233 // [IE] an invisible input[type='text'] will enlarge it's width
1234 // if it's value is long when it shows, so we clear it's value
1235 // before it shows and then recover it (#5649)
1236 if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat ) {
1237 clearOrRecoverTextInputValue( selected[ 1 ] );
1238 selected[ 1 ].show();
1239 setTimeout( function() {
1240 clearOrRecoverTextInputValue( selected[ 1 ], 1 );
1241 }, 0 );
1242 } else {
1243 selected[ 1 ].show();
1244 }
1245
1246 this._.currentTabId = id;
1247 this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );
1248 },
1249
1250 /**
1251 * Dialog state-specific style updates.
1252 */
1253 updateStyle: function() {
1254 // If only a single page shown, a different style is used in the central pane.
1255 this.parts.dialog[ ( this._.pageCount === 1 ? 'add' : 'remove' ) + 'Class' ]( 'cke_single_page' );
1256 },
1257
1258 /**
1259 * Hides a page's tab away from the dialog.
1260 *
1261 * dialog.hidePage( 'tab_3' );
1262 *
1263 * @param {String} id The page's Id.
1264 */
1265 hidePage: function( id ) {
1266 var tab = this._.tabs[ id ] && this._.tabs[ id ][ 0 ];
1267 if ( !tab || this._.pageCount == 1 || !tab.isVisible() )
1268 return;
1269 // Switch to other tab first when we're hiding the active tab.
1270 else if ( id == this._.currentTabId )
1271 this.selectPage( getPreviousVisibleTab.call( this ) );
1272
1273 tab.hide();
1274 this._.pageCount--;
1275 this.updateStyle();
1276 },
1277
1278 /**
1279 * Unhides a page's tab.
1280 *
1281 * dialog.showPage( 'tab_2' );
1282 *
1283 * @param {String} id The page's Id.
1284 */
1285 showPage: function( id ) {
1286 var tab = this._.tabs[ id ] && this._.tabs[ id ][ 0 ];
1287 if ( !tab )
1288 return;
1289 tab.show();
1290 this._.pageCount++;
1291 this.updateStyle();
1292 },
1293
1294 /**
1295 * Gets the root DOM element of the dialog.
1296 *
1297 * var dialogElement = dialogObj.getElement().getFirst();
1298 * dialogElement.setStyle( 'padding', '5px' );
1299 *
1300 * @returns {CKEDITOR.dom.element} The `<span>` element containing this dialog.
1301 */
1302 getElement: function() {
1303 return this._.element;
1304 },
1305
1306 /**
1307 * Gets the name of the dialog.
1308 *
1309 * var dialogName = dialogObj.getName();
1310 *
1311 * @returns {String} The name of this dialog.
1312 */
1313 getName: function() {
1314 return this._.name;
1315 },
1316
1317 /**
1318 * Gets a dialog UI element object from a dialog page.
1319 *
1320 * dialogObj.getContentElement( 'tabId', 'elementId' ).setValue( 'Example' );
1321 *
1322 * @param {String} pageId id of dialog page.
1323 * @param {String} elementId id of UI element.
1324 * @returns {CKEDITOR.ui.dialog.uiElement} The dialog UI element.
1325 */
1326 getContentElement: function( pageId, elementId ) {
1327 var page = this._.contents[ pageId ];
1328 return page && page[ elementId ];
1329 },
1330
1331 /**
1332 * Gets the value of a dialog UI element.
1333 *
1334 * alert( dialogObj.getValueOf( 'tabId', 'elementId' ) );
1335 *
1336 * @param {String} pageId id of dialog page.
1337 * @param {String} elementId id of UI element.
1338 * @returns {Object} The value of the UI element.
1339 */
1340 getValueOf: function( pageId, elementId ) {
1341 return this.getContentElement( pageId, elementId ).getValue();
1342 },
1343
1344 /**
1345 * Sets the value of a dialog UI element.
1346 *
1347 * dialogObj.setValueOf( 'tabId', 'elementId', 'Example' );
1348 *
1349 * @param {String} pageId id of the dialog page.
1350 * @param {String} elementId id of the UI element.
1351 * @param {Object} value The new value of the UI element.
1352 */
1353 setValueOf: function( pageId, elementId, value ) {
1354 return this.getContentElement( pageId, elementId ).setValue( value );
1355 },
1356
1357 /**
1358 * Gets the UI element of a button in the dialog's button row.
1359 *
1360 * @returns {CKEDITOR.ui.dialog.button} The button object.
1361 *
1362 * @param {String} id The id of the button.
1363 */
1364 getButton: function( id ) {
1365 return this._.buttons[ id ];
1366 },
1367
1368 /**
1369 * Simulates a click to a dialog button in the dialog's button row.
1370 *
1371 * @returns The return value of the dialog's `click` event.
1372 *
1373 * @param {String} id The id of the button.
1374 */
1375 click: function( id ) {
1376 return this._.buttons[ id ].click();
1377 },
1378
1379 /**
1380 * Disables a dialog button.
1381 *
1382 * @param {String} id The id of the button.
1383 */
1384 disableButton: function( id ) {
1385 return this._.buttons[ id ].disable();
1386 },
1387
1388 /**
1389 * Enables a dialog button.
1390 *
1391 * @param {String} id The id of the button.
1392 */
1393 enableButton: function( id ) {
1394 return this._.buttons[ id ].enable();
1395 },
1396
1397 /**
1398 * Gets the number of pages in the dialog.
1399 *
1400 * @returns {Number} Page count.
1401 */
1402 getPageCount: function() {
1403 return this._.pageCount;
1404 },
1405
1406 /**
1407 * Gets the editor instance which opened this dialog.
1408 *
1409 * @returns {CKEDITOR.editor} Parent editor instances.
1410 */
1411 getParentEditor: function() {
1412 return this._.editor;
1413 },
1414
1415 /**
1416 * Gets the element that was selected when opening the dialog, if any.
1417 *
1418 * @returns {CKEDITOR.dom.element} The element that was selected, or `null`.
1419 */
1420 getSelectedElement: function() {
1421 return this.getParentEditor().getSelection().getSelectedElement();
1422 },
1423
1424 /**
1425 * Adds element to dialog's focusable list.
1426 *
1427 * @param {CKEDITOR.dom.element} element
1428 * @param {Number} [index]
1429 */
1430 addFocusable: function( element, index ) {
1431 if ( typeof index == 'undefined' ) {
1432 index = this._.focusList.length;
1433 this._.focusList.push( new Focusable( this, element, index ) );
1434 } else {
1435 this._.focusList.splice( index, 0, new Focusable( this, element, index ) );
1436 for ( var i = index + 1; i < this._.focusList.length; i++ )
1437 this._.focusList[ i ].focusIndex++;
1438 }
1439 },
1440
1441 /**
1442 * Sets the dialog {@link #property-state}.
1443 *
1444 * @since 4.5
1445 * @param {Number} state Either {@link CKEDITOR#DIALOG_STATE_IDLE} or {@link CKEDITOR#DIALOG_STATE_BUSY}.
1446 */
1447 setState: function( state ) {
1448 var oldState = this.state;
1449
1450 if ( oldState == state ) {
1451 return;
1452 }
1453
1454 this.state = state;
1455
1456 if ( state == CKEDITOR.DIALOG_STATE_BUSY ) {
1457 // Insert the spinner on demand.
1458 if ( !this.parts.spinner ) {
1459 var dir = this.getParentEditor().lang.dir,
1460 spinnerDef = {
1461 attributes: {
1462 'class': 'cke_dialog_spinner'
1463 },
1464 styles: {
1465 'float': dir == 'rtl' ? 'right' : 'left'
1466 }
1467 };
1468
1469 spinnerDef.styles[ 'margin-' + ( dir == 'rtl' ? 'left' : 'right' ) ] = '8px';
1470
1471 this.parts.spinner = CKEDITOR.document.createElement( 'div', spinnerDef );
1472
1473 this.parts.spinner.setHtml( '&#8987;' );
1474 this.parts.spinner.appendTo( this.parts.title, 1 );
1475 }
1476
1477 // Finally, show the spinner.
1478 this.parts.spinner.show();
1479
1480 this.getButton( 'ok' ).disable();
1481 } else if ( state == CKEDITOR.DIALOG_STATE_IDLE ) {
1482 // Hide the spinner. But don't do anything if there is no spinner yet.
1483 this.parts.spinner && this.parts.spinner.hide();
1484
1485 this.getButton( 'ok' ).enable();
1486 }
1487
1488 this.fire( 'state', state );
1489 }
1490 };
1491
1492 CKEDITOR.tools.extend( CKEDITOR.dialog, {
1493 /**
1494 * Registers a dialog.
1495 *
1496 * // Full sample plugin, which does not only register a dialog window but also adds an item to the context menu.
1497 * // To open the dialog window, choose "Open dialog" in the context menu.
1498 * CKEDITOR.plugins.add( 'myplugin', {
1499 * init: function( editor ) {
1500 * editor.addCommand( 'mydialog',new CKEDITOR.dialogCommand( 'mydialog' ) );
1501 *
1502 * if ( editor.contextMenu ) {
1503 * editor.addMenuGroup( 'mygroup', 10 );
1504 * editor.addMenuItem( 'My Dialog', {
1505 * label: 'Open dialog',
1506 * command: 'mydialog',
1507 * group: 'mygroup'
1508 * } );
1509 * editor.contextMenu.addListener( function( element ) {
1510 * return { 'My Dialog': CKEDITOR.TRISTATE_OFF };
1511 * } );
1512 * }
1513 *
1514 * CKEDITOR.dialog.add( 'mydialog', function( api ) {
1515 * // CKEDITOR.dialog.definition
1516 * var dialogDefinition = {
1517 * title: 'Sample dialog',
1518 * minWidth: 390,
1519 * minHeight: 130,
1520 * contents: [
1521 * {
1522 * id: 'tab1',
1523 * label: 'Label',
1524 * title: 'Title',
1525 * expand: true,
1526 * padding: 0,
1527 * elements: [
1528 * {
1529 * type: 'html',
1530 * html: '<p>This is some sample HTML content.</p>'
1531 * },
1532 * {
1533 * type: 'textarea',
1534 * id: 'textareaId',
1535 * rows: 4,
1536 * cols: 40
1537 * }
1538 * ]
1539 * }
1540 * ],
1541 * buttons: [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ],
1542 * onOk: function() {
1543 * // "this" is now a CKEDITOR.dialog object.
1544 * // Accessing dialog elements:
1545 * var textareaObj = this.getContentElement( 'tab1', 'textareaId' );
1546 * alert( "You have entered: " + textareaObj.getValue() );
1547 * }
1548 * };
1549 *
1550 * return dialogDefinition;
1551 * } );
1552 * }
1553 * } );
1554 *
1555 * CKEDITOR.replace( 'editor1', { extraPlugins: 'myplugin' } );
1556 *
1557 * @static
1558 * @param {String} name The dialog's name.
1559 * @param {Function/String} dialogDefinition
1560 * A function returning the dialog's definition, or the URL to the `.js` file holding the function.
1561 * The function should accept an argument `editor` which is the current editor instance, and
1562 * return an object conforming to {@link CKEDITOR.dialog.definition}.
1563 * @see CKEDITOR.dialog.definition
1564 */
1565 add: function( name, dialogDefinition ) {
1566 // Avoid path registration from multiple instances override definition.
1567 if ( !this._.dialogDefinitions[ name ] || typeof dialogDefinition == 'function' )
1568 this._.dialogDefinitions[ name ] = dialogDefinition;
1569 },
1570
1571 /**
1572 * @static
1573 * @todo
1574 */
1575 exists: function( name ) {
1576 return !!this._.dialogDefinitions[ name ];
1577 },
1578
1579 /**
1580 * @static
1581 * @todo
1582 */
1583 getCurrent: function() {
1584 return CKEDITOR.dialog._.currentTop;
1585 },
1586
1587 /**
1588 * Check whether tab wasn't removed by {@link CKEDITOR.config#removeDialogTabs}.
1589 *
1590 * @since 4.1
1591 * @static
1592 * @param {CKEDITOR.editor} editor
1593 * @param {String} dialogName
1594 * @param {String} tabName
1595 * @returns {Boolean}
1596 */
1597 isTabEnabled: function( editor, dialogName, tabName ) {
1598 var cfg = editor.config.removeDialogTabs;
1599
1600 return !( cfg && cfg.match( new RegExp( '(?:^|;)' + dialogName + ':' + tabName + '(?:$|;)', 'i' ) ) );
1601 },
1602
1603 /**
1604 * The default OK button for dialogs. Fires the `ok` event and closes the dialog if the event succeeds.
1605 *
1606 * @static
1607 * @method
1608 */
1609 okButton: ( function() {
1610 var retval = function( editor, override ) {
1611 override = override || {};
1612 return CKEDITOR.tools.extend( {
1613 id: 'ok',
1614 type: 'button',
1615 label: editor.lang.common.ok,
1616 'class': 'cke_dialog_ui_button_ok',
1617 onClick: function( evt ) {
1618 var dialog = evt.data.dialog;
1619 if ( dialog.fire( 'ok', { hide: true } ).hide !== false )
1620 dialog.hide();
1621 }
1622 }, override, true );
1623 };
1624 retval.type = 'button';
1625 retval.override = function( override ) {
1626 return CKEDITOR.tools.extend( function( editor ) {
1627 return retval( editor, override );
1628 }, { type: 'button' }, true );
1629 };
1630 return retval;
1631 } )(),
1632
1633 /**
1634 * The default cancel button for dialogs. Fires the `cancel` event and
1635 * closes the dialog if no UI element value changed.
1636 *
1637 * @static
1638 * @method
1639 */
1640 cancelButton: ( function() {
1641 var retval = function( editor, override ) {
1642 override = override || {};
1643 return CKEDITOR.tools.extend( {
1644 id: 'cancel',
1645 type: 'button',
1646 label: editor.lang.common.cancel,
1647 'class': 'cke_dialog_ui_button_cancel',
1648 onClick: function( evt ) {
1649 var dialog = evt.data.dialog;
1650 if ( dialog.fire( 'cancel', { hide: true } ).hide !== false )
1651 dialog.hide();
1652 }
1653 }, override, true );
1654 };
1655 retval.type = 'button';
1656 retval.override = function( override ) {
1657 return CKEDITOR.tools.extend( function( editor ) {
1658 return retval( editor, override );
1659 }, { type: 'button' }, true );
1660 };
1661 return retval;
1662 } )(),
1663
1664 /**
1665 * Registers a dialog UI element.
1666 *
1667 * @static
1668 * @param {String} typeName The name of the UI element.
1669 * @param {Function} builder The function to build the UI element.
1670 */
1671 addUIElement: function( typeName, builder ) {
1672 this._.uiElementBuilders[ typeName ] = builder;
1673 }
1674 } );
1675
1676 CKEDITOR.dialog._ = {
1677 uiElementBuilders: {},
1678
1679 dialogDefinitions: {},
1680
1681 currentTop: null,
1682
1683 currentZIndex: null
1684 };
1685
1686 // "Inherit" (copy actually) from CKEDITOR.event.
1687 CKEDITOR.event.implementOn( CKEDITOR.dialog );
1688 CKEDITOR.event.implementOn( CKEDITOR.dialog.prototype );
1689
1690 var defaultDialogDefinition = {
1691 resizable: CKEDITOR.DIALOG_RESIZE_BOTH,
1692 minWidth: 600,
1693 minHeight: 400,
1694 buttons: [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]
1695 };
1696
1697 // Tool function used to return an item from an array based on its id
1698 // property.
1699 var getById = function( array, id, recurse ) {
1700 for ( var i = 0, item;
1701 ( item = array[ i ] ); i++ ) {
1702 if ( item.id == id )
1703 return item;
1704 if ( recurse && item[ recurse ] ) {
1705 var retval = getById( item[ recurse ], id, recurse );
1706 if ( retval )
1707 return retval;
1708 }
1709 }
1710 return null;
1711 };
1712
1713 // Tool function used to add an item into an array.
1714 var addById = function( array, newItem, nextSiblingId, recurse, nullIfNotFound ) {
1715 if ( nextSiblingId ) {
1716 for ( var i = 0, item;
1717 ( item = array[ i ] ); i++ ) {
1718 if ( item.id == nextSiblingId ) {
1719 array.splice( i, 0, newItem );
1720 return newItem;
1721 }
1722
1723 if ( recurse && item[ recurse ] ) {
1724 var retval = addById( item[ recurse ], newItem, nextSiblingId, recurse, true );
1725 if ( retval )
1726 return retval;
1727 }
1728 }
1729
1730 if ( nullIfNotFound )
1731 return null;
1732 }
1733
1734 array.push( newItem );
1735 return newItem;
1736 };
1737
1738 // Tool function used to remove an item from an array based on its id.
1739 var removeById = function( array, id, recurse ) {
1740 for ( var i = 0, item;
1741 ( item = array[ i ] ); i++ ) {
1742 if ( item.id == id )
1743 return array.splice( i, 1 );
1744 if ( recurse && item[ recurse ] ) {
1745 var retval = removeById( item[ recurse ], id, recurse );
1746 if ( retval )
1747 return retval;
1748 }
1749 }
1750 return null;
1751 };
1752
1753 /**
1754 * This class is not really part of the API. It is the `definition` property value
1755 * passed to `dialogDefinition` event handlers.
1756 *
1757 * CKEDITOR.on( 'dialogDefinition', function( evt ) {
1758 * var definition = evt.data.definition;
1759 * var content = definition.getContents( 'page1' );
1760 * // ...
1761 * } );
1762 *
1763 * @private
1764 * @class CKEDITOR.dialog.definitionObject
1765 * @extends CKEDITOR.dialog.definition
1766 * @constructor Creates a definitionObject class instance.
1767 */
1768 var definitionObject = function( dialog, dialogDefinition ) {
1769 // TODO : Check if needed.
1770 this.dialog = dialog;
1771
1772 // Transform the contents entries in contentObjects.
1773 var contents = dialogDefinition.contents;
1774 for ( var i = 0, content;
1775 ( content = contents[ i ] ); i++ )
1776 contents[ i ] = content && new contentObject( dialog, content );
1777
1778 CKEDITOR.tools.extend( this, dialogDefinition );
1779 };
1780
1781 definitionObject.prototype = {
1782 /**
1783 * Gets a content definition.
1784 *
1785 * @param {String} id The id of the content definition.
1786 * @returns {CKEDITOR.dialog.definition.content} The content definition matching id.
1787 */
1788 getContents: function( id ) {
1789 return getById( this.contents, id );
1790 },
1791
1792 /**
1793 * Gets a button definition.
1794 *
1795 * @param {String} id The id of the button definition.
1796 * @returns {CKEDITOR.dialog.definition.button} The button definition matching id.
1797 */
1798 getButton: function( id ) {
1799 return getById( this.buttons, id );
1800 },
1801
1802 /**
1803 * Adds a content definition object under this dialog definition.
1804 *
1805 * @param {CKEDITOR.dialog.definition.content} contentDefinition The
1806 * content definition.
1807 * @param {String} [nextSiblingId] The id of an existing content
1808 * definition which the new content definition will be inserted
1809 * before. Omit if the new content definition is to be inserted as
1810 * the last item.
1811 * @returns {CKEDITOR.dialog.definition.content} The inserted content definition.
1812 */
1813 addContents: function( contentDefinition, nextSiblingId ) {
1814 return addById( this.contents, contentDefinition, nextSiblingId );
1815 },
1816
1817 /**
1818 * Adds a button definition object under this dialog definition.
1819 *
1820 * @param {CKEDITOR.dialog.definition.button} buttonDefinition The
1821 * button definition.
1822 * @param {String} [nextSiblingId] The id of an existing button
1823 * definition which the new button definition will be inserted
1824 * before. Omit if the new button definition is to be inserted as
1825 * the last item.
1826 * @returns {CKEDITOR.dialog.definition.button} The inserted button definition.
1827 */
1828 addButton: function( buttonDefinition, nextSiblingId ) {
1829 return addById( this.buttons, buttonDefinition, nextSiblingId );
1830 },
1831
1832 /**
1833 * Removes a content definition from this dialog definition.
1834 *
1835 * @param {String} id The id of the content definition to be removed.
1836 * @returns {CKEDITOR.dialog.definition.content} The removed content definition.
1837 */
1838 removeContents: function( id ) {
1839 removeById( this.contents, id );
1840 },
1841
1842 /**
1843 * Removes a button definition from the dialog definition.
1844 *
1845 * @param {String} id The id of the button definition to be removed.
1846 * @returns {CKEDITOR.dialog.definition.button} The removed button definition.
1847 */
1848 removeButton: function( id ) {
1849 removeById( this.buttons, id );
1850 }
1851 };
1852
1853 /**
1854 * This class is not really part of the API. It is the template of the
1855 * objects representing content pages inside the
1856 * CKEDITOR.dialog.definitionObject.
1857 *
1858 * CKEDITOR.on( 'dialogDefinition', function( evt ) {
1859 * var definition = evt.data.definition;
1860 * var content = definition.getContents( 'page1' );
1861 * content.remove( 'textInput1' );
1862 * // ...
1863 * } );
1864 *
1865 * @private
1866 * @class CKEDITOR.dialog.definition.contentObject
1867 * @constructor Creates a contentObject class instance.
1868 */
1869 function contentObject( dialog, contentDefinition ) {
1870 this._ = {
1871 dialog: dialog
1872 };
1873
1874 CKEDITOR.tools.extend( this, contentDefinition );
1875 }
1876
1877 contentObject.prototype = {
1878 /**
1879 * Gets a UI element definition under the content definition.
1880 *
1881 * @param {String} id The id of the UI element definition.
1882 * @returns {CKEDITOR.dialog.definition.uiElement}
1883 */
1884 get: function( id ) {
1885 return getById( this.elements, id, 'children' );
1886 },
1887
1888 /**
1889 * Adds a UI element definition to the content definition.
1890 *
1891 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition The
1892 * UI elemnet definition to be added.
1893 * @param {String} nextSiblingId The id of an existing UI element
1894 * definition which the new UI element definition will be inserted
1895 * before. Omit if the new button definition is to be inserted as
1896 * the last item.
1897 * @returns {CKEDITOR.dialog.definition.uiElement} The element definition inserted.
1898 */
1899 add: function( elementDefinition, nextSiblingId ) {
1900 return addById( this.elements, elementDefinition, nextSiblingId, 'children' );
1901 },
1902
1903 /**
1904 * Removes a UI element definition from the content definition.
1905 *
1906 * @param {String} id The id of the UI element definition to be removed.
1907 * @returns {CKEDITOR.dialog.definition.uiElement} The element definition removed.
1908 */
1909 remove: function( id ) {
1910 removeById( this.elements, id, 'children' );
1911 }
1912 };
1913
1914 function initDragAndDrop( dialog ) {
1915 var lastCoords = null,
1916 abstractDialogCoords = null,
1917 editor = dialog.getParentEditor(),
1918 magnetDistance = editor.config.dialog_magnetDistance,
1919 margins = CKEDITOR.skin.margins || [ 0, 0, 0, 0 ];
1920
1921 if ( typeof magnetDistance == 'undefined' )
1922 magnetDistance = 20;
1923
1924 function mouseMoveHandler( evt ) {
1925 var dialogSize = dialog.getSize(),
1926 viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(),
1927 x = evt.data.$.screenX,
1928 y = evt.data.$.screenY,
1929 dx = x - lastCoords.x,
1930 dy = y - lastCoords.y,
1931 realX, realY;
1932
1933 lastCoords = { x: x, y: y };
1934 abstractDialogCoords.x += dx;
1935 abstractDialogCoords.y += dy;
1936
1937 if ( abstractDialogCoords.x + margins[ 3 ] < magnetDistance )
1938 realX = -margins[ 3 ];
1939 else if ( abstractDialogCoords.x - margins[ 1 ] > viewPaneSize.width - dialogSize.width - magnetDistance )
1940 realX = viewPaneSize.width - dialogSize.width + ( editor.lang.dir == 'rtl' ? 0 : margins[ 1 ] );
1941 else
1942 realX = abstractDialogCoords.x;
1943
1944 if ( abstractDialogCoords.y + margins[ 0 ] < magnetDistance )
1945 realY = -margins[ 0 ];
1946 else if ( abstractDialogCoords.y - margins[ 2 ] > viewPaneSize.height - dialogSize.height - magnetDistance )
1947 realY = viewPaneSize.height - dialogSize.height + margins[ 2 ];
1948 else
1949 realY = abstractDialogCoords.y;
1950
1951 dialog.move( realX, realY, 1 );
1952
1953 evt.data.preventDefault();
1954 }
1955
1956 function mouseUpHandler() {
1957 CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );
1958 CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );
1959
1960 if ( CKEDITOR.env.ie6Compat ) {
1961 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1962 coverDoc.removeListener( 'mousemove', mouseMoveHandler );
1963 coverDoc.removeListener( 'mouseup', mouseUpHandler );
1964 }
1965 }
1966
1967 dialog.parts.title.on( 'mousedown', function( evt ) {
1968 lastCoords = { x: evt.data.$.screenX, y: evt.data.$.screenY };
1969
1970 CKEDITOR.document.on( 'mousemove', mouseMoveHandler );
1971 CKEDITOR.document.on( 'mouseup', mouseUpHandler );
1972 abstractDialogCoords = dialog.getPosition();
1973
1974 if ( CKEDITOR.env.ie6Compat ) {
1975 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
1976 coverDoc.on( 'mousemove', mouseMoveHandler );
1977 coverDoc.on( 'mouseup', mouseUpHandler );
1978 }
1979
1980 evt.data.preventDefault();
1981 }, dialog );
1982 }
1983
1984 function initResizeHandles( dialog ) {
1985 var def = dialog.definition,
1986 resizable = def.resizable;
1987
1988 if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE )
1989 return;
1990
1991 var editor = dialog.getParentEditor();
1992 var wrapperWidth, wrapperHeight, viewSize, origin, startSize, dialogCover;
1993
1994 var mouseDownFn = CKEDITOR.tools.addFunction( function( $event ) {
1995 startSize = dialog.getSize();
1996
1997 var content = dialog.parts.contents,
1998 iframeDialog = content.$.getElementsByTagName( 'iframe' ).length;
1999
2000 // Shim to help capturing "mousemove" over iframe.
2001 if ( iframeDialog ) {
2002 dialogCover = CKEDITOR.dom.element.createFromHtml( '<div class="cke_dialog_resize_cover" style="height: 100%; position: absolute; width: 100%;"></div>' );
2003 content.append( dialogCover );
2004 }
2005
2006 // Calculate the offset between content and chrome size.
2007 wrapperHeight = startSize.height - dialog.parts.contents.getSize( 'height', !( CKEDITOR.env.gecko || CKEDITOR.env.ie && CKEDITOR.env.quirks ) );
2008 wrapperWidth = startSize.width - dialog.parts.contents.getSize( 'width', 1 );
2009
2010 origin = { x: $event.screenX, y: $event.screenY };
2011
2012 viewSize = CKEDITOR.document.getWindow().getViewPaneSize();
2013
2014 CKEDITOR.document.on( 'mousemove', mouseMoveHandler );
2015 CKEDITOR.document.on( 'mouseup', mouseUpHandler );
2016
2017 if ( CKEDITOR.env.ie6Compat ) {
2018 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
2019 coverDoc.on( 'mousemove', mouseMoveHandler );
2020 coverDoc.on( 'mouseup', mouseUpHandler );
2021 }
2022
2023 $event.preventDefault && $event.preventDefault();
2024 } );
2025
2026 // Prepend the grip to the dialog.
2027 dialog.on( 'load', function() {
2028 var direction = '';
2029 if ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH )
2030 direction = ' cke_resizer_horizontal';
2031 else if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT )
2032 direction = ' cke_resizer_vertical';
2033 var resizer = CKEDITOR.dom.element.createFromHtml(
2034 '<div' +
2035 ' class="cke_resizer' + direction + ' cke_resizer_' + editor.lang.dir + '"' +
2036 ' title="' + CKEDITOR.tools.htmlEncode( editor.lang.common.resize ) + '"' +
2037 ' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event )">' +
2038 // BLACK LOWER RIGHT TRIANGLE (ltr)
2039 // BLACK LOWER LEFT TRIANGLE (rtl)
2040 ( editor.lang.dir == 'ltr' ? '\u25E2' : '\u25E3' ) +
2041 '</div>' );
2042 dialog.parts.footer.append( resizer, 1 );
2043 } );
2044 editor.on( 'destroy', function() {
2045 CKEDITOR.tools.removeFunction( mouseDownFn );
2046 } );
2047
2048 function mouseMoveHandler( evt ) {
2049 var rtl = editor.lang.dir == 'rtl',
2050 dx = ( evt.data.$.screenX - origin.x ) * ( rtl ? -1 : 1 ),
2051 dy = evt.data.$.screenY - origin.y,
2052 width = startSize.width,
2053 height = startSize.height,
2054 internalWidth = width + dx * ( dialog._.moved ? 1 : 2 ),
2055 internalHeight = height + dy * ( dialog._.moved ? 1 : 2 ),
2056 element = dialog._.element.getFirst(),
2057 right = rtl && element.getComputedStyle( 'right' ),
2058 position = dialog.getPosition();
2059
2060 if ( position.y + internalHeight > viewSize.height )
2061 internalHeight = viewSize.height - position.y;
2062
2063 if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width )
2064 internalWidth = viewSize.width - ( rtl ? right : position.x );
2065
2066 // Make sure the dialog will not be resized to the wrong side when it's in the leftmost position for RTL.
2067 if ( ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) )
2068 width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth );
2069
2070 if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH )
2071 height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight );
2072
2073 dialog.resize( width, height );
2074
2075 if ( !dialog._.moved )
2076 dialog.layout();
2077
2078 evt.data.preventDefault();
2079 }
2080
2081 function mouseUpHandler() {
2082 CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );
2083 CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );
2084
2085 if ( dialogCover ) {
2086 dialogCover.remove();
2087 dialogCover = null;
2088 }
2089
2090 if ( CKEDITOR.env.ie6Compat ) {
2091 var coverDoc = currentCover.getChild( 0 ).getFrameDocument();
2092 coverDoc.removeListener( 'mouseup', mouseUpHandler );
2093 coverDoc.removeListener( 'mousemove', mouseMoveHandler );
2094 }
2095 }
2096 }
2097
2098 var resizeCover;
2099 // Caching resuable covers and allowing only one cover
2100 // on screen.
2101 var covers = {},
2102 currentCover;
2103
2104 function cancelEvent( ev ) {
2105 ev.data.preventDefault( 1 );
2106 }
2107
2108 function showCover( editor ) {
2109 var win = CKEDITOR.document.getWindow(),
2110 config = editor.config,
2111 skinName = ( CKEDITOR.skinName || editor.config.skin ),
2112 backgroundColorStyle = config.dialog_backgroundCoverColor || ( skinName == 'moono-lisa' ? 'black' : 'white' ),
2113 backgroundCoverOpacity = config.dialog_backgroundCoverOpacity,
2114 baseFloatZIndex = config.baseFloatZIndex,
2115 coverKey = CKEDITOR.tools.genKey( backgroundColorStyle, backgroundCoverOpacity, baseFloatZIndex ),
2116 coverElement = covers[ coverKey ];
2117
2118 if ( !coverElement ) {
2119 var html = [
2120 '<div tabIndex="-1" style="position: ', ( CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed' ),
2121 '; z-index: ', baseFloatZIndex,
2122 '; top: 0px; left: 0px; ',
2123 ( !CKEDITOR.env.ie6Compat ? 'background-color: ' + backgroundColorStyle : '' ),
2124 '" class="cke_dialog_background_cover">'
2125 ];
2126
2127 if ( CKEDITOR.env.ie6Compat ) {
2128 // Support for custom document.domain in IE.
2129 var iframeHtml = '<html><body style=\\\'background-color:' + backgroundColorStyle + ';\\\'></body></html>';
2130
2131 html.push( '<iframe' +
2132 ' hidefocus="true"' +
2133 ' frameborder="0"' +
2134 ' id="cke_dialog_background_iframe"' +
2135 ' src="javascript:' );
2136
2137 html.push( 'void((function(){' + encodeURIComponent(
2138 'document.open();' +
2139 // Support for custom document.domain in IE.
2140 '(' + CKEDITOR.tools.fixDomain + ')();' +
2141 'document.write( \'' + iframeHtml + '\' );' +
2142 'document.close();'
2143 ) + '})())' );
2144
2145 html.push( '"' +
2146 ' style="' +
2147 'position:absolute;' +
2148 'left:0;' +
2149 'top:0;' +
2150 'width:100%;' +
2151 'height: 100%;' +
2152 'filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0)">' +
2153 '</iframe>' );
2154 }
2155
2156 html.push( '</div>' );
2157
2158 coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) );
2159 coverElement.setOpacity( backgroundCoverOpacity !== undefined ? backgroundCoverOpacity : 0.5 );
2160
2161 coverElement.on( 'keydown', cancelEvent );
2162 coverElement.on( 'keypress', cancelEvent );
2163 coverElement.on( 'keyup', cancelEvent );
2164
2165 coverElement.appendTo( CKEDITOR.document.getBody() );
2166 covers[ coverKey ] = coverElement;
2167 } else {
2168 coverElement.show();
2169 }
2170
2171 // Makes the dialog cover a focus holder as well.
2172 editor.focusManager.add( coverElement );
2173
2174 currentCover = coverElement;
2175 var resizeFunc = function() {
2176 var size = win.getViewPaneSize();
2177 coverElement.setStyles( {
2178 width: size.width + 'px',
2179 height: size.height + 'px'
2180 } );
2181 };
2182
2183 var scrollFunc = function() {
2184 var pos = win.getScrollPosition(),
2185 cursor = CKEDITOR.dialog._.currentTop;
2186 coverElement.setStyles( {
2187 left: pos.x + 'px',
2188 top: pos.y + 'px'
2189 } );
2190
2191 if ( cursor ) {
2192 do {
2193 var dialogPos = cursor.getPosition();
2194 cursor.move( dialogPos.x, dialogPos.y );
2195 } while ( ( cursor = cursor._.parentDialog ) );
2196 }
2197 };
2198
2199 resizeCover = resizeFunc;
2200 win.on( 'resize', resizeFunc );
2201 resizeFunc();
2202 // Using Safari/Mac, focus must be kept where it is (#7027)
2203 if ( !( CKEDITOR.env.mac && CKEDITOR.env.webkit ) )
2204 coverElement.focus();
2205
2206 if ( CKEDITOR.env.ie6Compat ) {
2207 // IE BUG: win.$.onscroll assignment doesn't work.. it must be window.onscroll.
2208 // So we need to invent a really funny way to make it work.
2209 var myScrollHandler = function() {
2210 scrollFunc();
2211 arguments.callee.prevScrollHandler.apply( this, arguments );
2212 };
2213 win.$.setTimeout( function() {
2214 myScrollHandler.prevScrollHandler = window.onscroll ||
2215 function() {};
2216 window.onscroll = myScrollHandler;
2217 }, 0 );
2218 scrollFunc();
2219 }
2220 }
2221
2222 function hideCover( editor ) {
2223 if ( !currentCover )
2224 return;
2225
2226 editor.focusManager.remove( currentCover );
2227 var win = CKEDITOR.document.getWindow();
2228 currentCover.hide();
2229 win.removeListener( 'resize', resizeCover );
2230
2231 if ( CKEDITOR.env.ie6Compat ) {
2232 win.$.setTimeout( function() {
2233 var prevScrollHandler = window.onscroll && window.onscroll.prevScrollHandler;
2234 window.onscroll = prevScrollHandler || null;
2235 }, 0 );
2236 }
2237 resizeCover = null;
2238 }
2239
2240 function removeCovers() {
2241 for ( var coverId in covers )
2242 covers[ coverId ].remove();
2243 covers = {};
2244 }
2245
2246 var accessKeyProcessors = {};
2247
2248 var accessKeyDownHandler = function( evt ) {
2249 var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,
2250 alt = evt.data.$.altKey,
2251 shift = evt.data.$.shiftKey,
2252 key = String.fromCharCode( evt.data.$.keyCode ),
2253 keyProcessor = accessKeyProcessors[ ( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '' ) + ( shift ? 'SHIFT+' : '' ) + key ];
2254
2255 if ( !keyProcessor || !keyProcessor.length )
2256 return;
2257
2258 keyProcessor = keyProcessor[ keyProcessor.length - 1 ];
2259 keyProcessor.keydown && keyProcessor.keydown.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );
2260 evt.data.preventDefault();
2261 };
2262
2263 var accessKeyUpHandler = function( evt ) {
2264 var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,
2265 alt = evt.data.$.altKey,
2266 shift = evt.data.$.shiftKey,
2267 key = String.fromCharCode( evt.data.$.keyCode ),
2268 keyProcessor = accessKeyProcessors[ ( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '' ) + ( shift ? 'SHIFT+' : '' ) + key ];
2269
2270 if ( !keyProcessor || !keyProcessor.length )
2271 return;
2272
2273 keyProcessor = keyProcessor[ keyProcessor.length - 1 ];
2274 if ( keyProcessor.keyup ) {
2275 keyProcessor.keyup.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );
2276 evt.data.preventDefault();
2277 }
2278 };
2279
2280 var registerAccessKey = function( uiElement, dialog, key, downFunc, upFunc ) {
2281 var procList = accessKeyProcessors[ key ] || ( accessKeyProcessors[ key ] = [] );
2282 procList.push( {
2283 uiElement: uiElement,
2284 dialog: dialog,
2285 key: key,
2286 keyup: upFunc || uiElement.accessKeyUp,
2287 keydown: downFunc || uiElement.accessKeyDown
2288 } );
2289 };
2290
2291 var unregisterAccessKey = function( obj ) {
2292 for ( var i in accessKeyProcessors ) {
2293 var list = accessKeyProcessors[ i ];
2294 for ( var j = list.length - 1; j >= 0; j-- ) {
2295 if ( list[ j ].dialog == obj || list[ j ].uiElement == obj )
2296 list.splice( j, 1 );
2297 }
2298 if ( list.length === 0 )
2299 delete accessKeyProcessors[ i ];
2300 }
2301 };
2302
2303 var tabAccessKeyUp = function( dialog, key ) {
2304 if ( dialog._.accessKeyMap[ key ] )
2305 dialog.selectPage( dialog._.accessKeyMap[ key ] );
2306 };
2307
2308 var tabAccessKeyDown = function() {};
2309
2310 ( function() {
2311 CKEDITOR.ui.dialog = {
2312 /**
2313 * The base class of all dialog UI elements.
2314 *
2315 * @class CKEDITOR.ui.dialog.uiElement
2316 * @constructor Creates a uiElement class instance.
2317 * @param {CKEDITOR.dialog} dialog Parent dialog object.
2318 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition Element
2319 * definition.
2320 *
2321 * Accepted fields:
2322 *
2323 * * `id` (Required) The id of the UI element. See {@link CKEDITOR.dialog#getContentElement}.
2324 * * `type` (Required) The type of the UI element. The
2325 * value to this field specifies which UI element class will be used to
2326 * generate the final widget.
2327 * * `title` (Optional) The popup tooltip for the UI
2328 * element.
2329 * * `hidden` (Optional) A flag that tells if the element
2330 * should be initially visible.
2331 * * `className` (Optional) Additional CSS class names
2332 * to add to the UI element. Separated by space.
2333 * * `style` (Optional) Additional CSS inline styles
2334 * to add to the UI element. A semicolon (;) is required after the last
2335 * style declaration.
2336 * * `accessKey` (Optional) The alphanumeric access key
2337 * for this element. Access keys are automatically prefixed by CTRL.
2338 * * `on*` (Optional) Any UI element definition field that
2339 * starts with `on` followed immediately by a capital letter and
2340 * probably more letters is an event handler. Event handlers may be further
2341 * divided into registered event handlers and DOM event handlers. Please
2342 * refer to {@link CKEDITOR.ui.dialog.uiElement#registerEvents} and
2343 * {@link CKEDITOR.ui.dialog.uiElement#eventProcessors} for more information.
2344 *
2345 * @param {Array} htmlList
2346 * List of HTML code to be added to the dialog's content area.
2347 * @param {Function/String} [nodeNameArg='div']
2348 * A function returning a string, or a simple string for the node name for
2349 * the root DOM node.
2350 * @param {Function/Object} [stylesArg={}]
2351 * A function returning an object, or a simple object for CSS styles applied
2352 * to the DOM node.
2353 * @param {Function/Object} [attributesArg={}]
2354 * A fucntion returning an object, or a simple object for attributes applied
2355 * to the DOM node.
2356 * @param {Function/String} [contentsArg='']
2357 * A function returning a string, or a simple string for the HTML code inside
2358 * the root DOM node. Default is empty string.
2359 */
2360 uiElement: function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg ) {
2361 if ( arguments.length < 4 )
2362 return;
2363
2364 var nodeName = ( nodeNameArg.call ? nodeNameArg( elementDefinition ) : nodeNameArg ) || 'div',
2365 html = [ '<', nodeName, ' ' ],
2366 styles = ( stylesArg && stylesArg.call ? stylesArg( elementDefinition ) : stylesArg ) || {},
2367 attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {},
2368 innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '',
2369 domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement',
2370 i;
2371
2372 if ( elementDefinition.requiredContent && !dialog.getParentEditor().filter.check( elementDefinition.requiredContent ) ) {
2373 styles.display = 'none';
2374 this.notAllowed = true;
2375 }
2376
2377 // Set the id, a unique id is required for getElement() to work.
2378 attributes.id = domId;
2379
2380 // Set the type and definition CSS class names.
2381 var classes = {};
2382 if ( elementDefinition.type )
2383 classes[ 'cke_dialog_ui_' + elementDefinition.type ] = 1;
2384 if ( elementDefinition.className )
2385 classes[ elementDefinition.className ] = 1;
2386 if ( elementDefinition.disabled )
2387 classes.cke_disabled = 1;
2388
2389 var attributeClasses = ( attributes[ 'class' ] && attributes[ 'class' ].split ) ? attributes[ 'class' ].split( ' ' ) : [];
2390 for ( i = 0; i < attributeClasses.length; i++ ) {
2391 if ( attributeClasses[ i ] )
2392 classes[ attributeClasses[ i ] ] = 1;
2393 }
2394 var finalClasses = [];
2395 for ( i in classes )
2396 finalClasses.push( i );
2397 attributes[ 'class' ] = finalClasses.join( ' ' );
2398
2399 // Set the popup tooltop.
2400 if ( elementDefinition.title )
2401 attributes.title = elementDefinition.title;
2402
2403 // Write the inline CSS styles.
2404 var styleStr = ( elementDefinition.style || '' ).split( ';' );
2405
2406 // Element alignment support.
2407 if ( elementDefinition.align ) {
2408 var align = elementDefinition.align;
2409 styles[ 'margin-left' ] = align == 'left' ? 0 : 'auto';
2410 styles[ 'margin-right' ] = align == 'right' ? 0 : 'auto';
2411 }
2412
2413 for ( i in styles )
2414 styleStr.push( i + ':' + styles[ i ] );
2415 if ( elementDefinition.hidden )
2416 styleStr.push( 'display:none' );
2417 for ( i = styleStr.length - 1; i >= 0; i-- ) {
2418 if ( styleStr[ i ] === '' )
2419 styleStr.splice( i, 1 );
2420 }
2421 if ( styleStr.length > 0 )
2422 attributes.style = ( attributes.style ? ( attributes.style + '; ' ) : '' ) + styleStr.join( '; ' );
2423
2424 // Write the attributes.
2425 for ( i in attributes )
2426 html.push( i + '="' + CKEDITOR.tools.htmlEncode( attributes[ i ] ) + '" ' );
2427
2428 // Write the content HTML.
2429 html.push( '>', innerHTML, '</', nodeName, '>' );
2430
2431 // Add contents to the parent HTML array.
2432 htmlList.push( html.join( '' ) );
2433
2434 ( this._ || ( this._ = {} ) ).dialog = dialog;
2435
2436 // Override isChanged if it is defined in element definition.
2437 if ( typeof elementDefinition.isChanged == 'boolean' )
2438 this.isChanged = function() {
2439 return elementDefinition.isChanged;
2440 };
2441 if ( typeof elementDefinition.isChanged == 'function' )
2442 this.isChanged = elementDefinition.isChanged;
2443
2444 // Overload 'get(set)Value' on definition.
2445 if ( typeof elementDefinition.setValue == 'function' ) {
2446 this.setValue = CKEDITOR.tools.override( this.setValue, function( org ) {
2447 return function( val ) {
2448 org.call( this, elementDefinition.setValue.call( this, val ) );
2449 };
2450 } );
2451 }
2452
2453 if ( typeof elementDefinition.getValue == 'function' ) {
2454 this.getValue = CKEDITOR.tools.override( this.getValue, function( org ) {
2455 return function() {
2456 return elementDefinition.getValue.call( this, org.call( this ) );
2457 };
2458 } );
2459 }
2460
2461 // Add events.
2462 CKEDITOR.event.implementOn( this );
2463
2464 this.registerEvents( elementDefinition );
2465 if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey )
2466 registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey );
2467
2468 var me = this;
2469 dialog.on( 'load', function() {
2470 var input = me.getInputElement();
2471 if ( input ) {
2472 var focusClass = me.type in { 'checkbox': 1, 'ratio': 1 } && CKEDITOR.env.ie && CKEDITOR.env.version < 8 ? 'cke_dialog_ui_focused' : '';
2473 input.on( 'focus', function() {
2474 dialog._.tabBarMode = false;
2475 dialog._.hasFocus = true;
2476 me.fire( 'focus' );
2477 focusClass && this.addClass( focusClass );
2478
2479 } );
2480
2481 input.on( 'blur', function() {
2482 me.fire( 'blur' );
2483 focusClass && this.removeClass( focusClass );
2484 } );
2485 }
2486 } );
2487
2488 // Completes this object with everything we have in the
2489 // definition.
2490 CKEDITOR.tools.extend( this, elementDefinition );
2491
2492 // Register the object as a tab focus if it can be included.
2493 if ( this.keyboardFocusable ) {
2494 this.tabIndex = elementDefinition.tabIndex || 0;
2495
2496 this.focusIndex = dialog._.focusList.push( this ) - 1;
2497 this.on( 'focus', function() {
2498 dialog._.currentFocusIndex = me.focusIndex;
2499 } );
2500 }
2501 },
2502
2503 /**
2504 * Horizontal layout box for dialog UI elements, auto-expends to available width of container.
2505 *
2506 * @class CKEDITOR.ui.dialog.hbox
2507 * @extends CKEDITOR.ui.dialog.uiElement
2508 * @constructor Creates a hbox class instance.
2509 * @param {CKEDITOR.dialog} dialog Parent dialog object.
2510 * @param {Array} childObjList
2511 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
2512 * @param {Array} childHtmlList
2513 * Array of HTML code that correspond to the HTML output of all the
2514 * objects in childObjList.
2515 * @param {Array} htmlList
2516 * Array of HTML code that this element will output to.
2517 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
2518 * The element definition. Accepted fields:
2519 *
2520 * * `widths` (Optional) The widths of child cells.
2521 * * `height` (Optional) The height of the layout.
2522 * * `padding` (Optional) The padding width inside child cells.
2523 * * `align` (Optional) The alignment of the whole layout.
2524 */
2525 hbox: function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) {
2526 if ( arguments.length < 4 )
2527 return;
2528
2529 this._ || ( this._ = {} );
2530
2531 var children = this._.children = childObjList,
2532 widths = elementDefinition && elementDefinition.widths || null,
2533 height = elementDefinition && elementDefinition.height || null,
2534 styles = {},
2535 i;
2536 /** @ignore */
2537 var innerHTML = function() {
2538 var html = [ '<tbody><tr class="cke_dialog_ui_hbox">' ];
2539 for ( i = 0; i < childHtmlList.length; i++ ) {
2540 var className = 'cke_dialog_ui_hbox_child',
2541 styles = [];
2542 if ( i === 0 ) {
2543 className = 'cke_dialog_ui_hbox_first';
2544 }
2545 if ( i == childHtmlList.length - 1 ) {
2546 className = 'cke_dialog_ui_hbox_last';
2547 }
2548
2549 html.push( '<td class="', className, '" role="presentation" ' );
2550 if ( widths ) {
2551 if ( widths[ i ] ) {
2552 styles.push( 'width:' + cssLength( widths[i] ) );
2553 }
2554 } else {
2555 styles.push( 'width:' + Math.floor( 100 / childHtmlList.length ) + '%' );
2556 }
2557 if ( height ) {
2558 styles.push( 'height:' + cssLength( height ) );
2559 }
2560 if ( elementDefinition && elementDefinition.padding !== undefined ) {
2561 styles.push( 'padding:' + cssLength( elementDefinition.padding ) );
2562 }
2563 // In IE Quirks alignment has to be done on table cells. (#7324)
2564 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align ) {
2565 styles.push( 'text-align:' + children[ i ].align );
2566 }
2567 if ( styles.length > 0 ) {
2568 html.push( 'style="' + styles.join( '; ' ) + '" ' );
2569 }
2570 html.push( '>', childHtmlList[ i ], '</td>' );
2571 }
2572 html.push( '</tr></tbody>' );
2573 return html.join( '' );
2574 };
2575
2576 var attribs = { role: 'presentation' };
2577 elementDefinition && elementDefinition.align && ( attribs.align = elementDefinition.align );
2578
2579 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type: 'hbox' }, htmlList, 'table', styles, attribs, innerHTML );
2580 },
2581
2582 /**
2583 * Vertical layout box for dialog UI elements.
2584 *
2585 * @class CKEDITOR.ui.dialog.vbox
2586 * @extends CKEDITOR.ui.dialog.hbox
2587 * @constructor Creates a vbox class instance.
2588 * @param {CKEDITOR.dialog} dialog Parent dialog object.
2589 * @param {Array} childObjList
2590 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
2591 * @param {Array} childHtmlList
2592 * Array of HTML code that correspond to the HTML output of all the
2593 * objects in childObjList.
2594 * @param {Array} htmlList Array of HTML code that this element will output to.
2595 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
2596 * The element definition. Accepted fields:
2597 *
2598 * * `width` (Optional) The width of the layout.
2599 * * `heights` (Optional) The heights of individual cells.
2600 * * `align` (Optional) The alignment of the layout.
2601 * * `padding` (Optional) The padding width inside child cells.
2602 * * `expand` (Optional) Whether the layout should expand
2603 * vertically to fill its container.
2604 */
2605 vbox: function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) {
2606 if ( arguments.length < 3 )
2607 return;
2608
2609 this._ || ( this._ = {} );
2610
2611 var children = this._.children = childObjList,
2612 width = elementDefinition && elementDefinition.width || null,
2613 heights = elementDefinition && elementDefinition.heights || null;
2614 /** @ignore */
2615 var innerHTML = function() {
2616 var html = [ '<table role="presentation" cellspacing="0" border="0" ' ];
2617 html.push( 'style="' );
2618 if ( elementDefinition && elementDefinition.expand )
2619 html.push( 'height:100%;' );
2620 html.push( 'width:' + cssLength( width || '100%' ), ';' );
2621
2622 // (#10123) Temp fix for dialog broken layout in latest webkit.
2623 if ( CKEDITOR.env.webkit )
2624 html.push( 'float:none;' );
2625
2626 html.push( '"' );
2627 html.push( 'align="', CKEDITOR.tools.htmlEncode(
2628 ( elementDefinition && elementDefinition.align ) || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' ) ), '" ' );
2629
2630 html.push( '><tbody>' );
2631 for ( var i = 0; i < childHtmlList.length; i++ ) {
2632 var styles = [];
2633 html.push( '<tr><td role="presentation" ' );
2634 if ( width )
2635 styles.push( 'width:' + cssLength( width || '100%' ) );
2636 if ( heights )
2637 styles.push( 'height:' + cssLength( heights[ i ] ) );
2638 else if ( elementDefinition && elementDefinition.expand )
2639 styles.push( 'height:' + Math.floor( 100 / childHtmlList.length ) + '%' );
2640 if ( elementDefinition && elementDefinition.padding !== undefined )
2641 styles.push( 'padding:' + cssLength( elementDefinition.padding ) );
2642 // In IE Quirks alignment has to be done on table cells. (#7324)
2643 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align )
2644 styles.push( 'text-align:' + children[ i ].align );
2645 if ( styles.length > 0 )
2646 html.push( 'style="', styles.join( '; ' ), '" ' );
2647 html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[ i ], '</td></tr>' );
2648 }
2649 html.push( '</tbody></table>' );
2650 return html.join( '' );
2651 };
2652 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type: 'vbox' }, htmlList, 'div', null, { role: 'presentation' }, innerHTML );
2653 }
2654 };
2655 } )();
2656
2657 /** @class CKEDITOR.ui.dialog.uiElement */
2658 CKEDITOR.ui.dialog.uiElement.prototype = {
2659 /**
2660 * Gets the root DOM element of this dialog UI object.
2661 *
2662 * uiElement.getElement().hide();
2663 *
2664 * @returns {CKEDITOR.dom.element} Root DOM element of UI object.
2665 */
2666 getElement: function() {
2667 return CKEDITOR.document.getById( this.domId );
2668 },
2669
2670 /**
2671 * Gets the DOM element that the user inputs values.
2672 *
2673 * This function is used by {@link #setValue}, {@link #getValue} and {@link #focus}. It should
2674 * be overrided in child classes where the input element isn't the root
2675 * element.
2676 *
2677 * var rawValue = textInput.getInputElement().$.value;
2678 *
2679 * @returns {CKEDITOR.dom.element} The element where the user input values.
2680 */
2681 getInputElement: function() {
2682 return this.getElement();
2683 },
2684
2685 /**
2686 * Gets the parent dialog object containing this UI element.
2687 *
2688 * var dialog = uiElement.getDialog();
2689 *
2690 * @returns {CKEDITOR.dialog} Parent dialog object.
2691 */
2692 getDialog: function() {
2693 return this._.dialog;
2694 },
2695
2696 /**
2697 * Sets the value of this dialog UI object.
2698 *
2699 * uiElement.setValue( 'Dingo' );
2700 *
2701 * @chainable
2702 * @param {Object} value The new value.
2703 * @param {Boolean} noChangeEvent Internal commit, to supress `change` event on this element.
2704 */
2705 setValue: function( value, noChangeEvent ) {
2706 this.getInputElement().setValue( value );
2707 !noChangeEvent && this.fire( 'change', { value: value } );
2708 return this;
2709 },
2710
2711 /**
2712 * Gets the current value of this dialog UI object.
2713 *
2714 * var myValue = uiElement.getValue();
2715 *
2716 * @returns {Object} The current value.
2717 */
2718 getValue: function() {
2719 return this.getInputElement().getValue();
2720 },
2721
2722 /**
2723 * Tells whether the UI object's value has changed.
2724 *
2725 * if ( uiElement.isChanged() )
2726 * confirm( 'Value changed! Continue?' );
2727 *
2728 * @returns {Boolean} `true` if changed, `false` if not changed.
2729 */
2730 isChanged: function() {
2731 // Override in input classes.
2732 return false;
2733 },
2734
2735 /**
2736 * Selects the parent tab of this element. Usually called by focus() or overridden focus() methods.
2737 *
2738 * focus : function() {
2739 * this.selectParentTab();
2740 * // do something else.
2741 * }
2742 *
2743 * @chainable
2744 */
2745 selectParentTab: function() {
2746 var element = this.getInputElement(),
2747 cursor = element,
2748 tabId;
2749 while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 ) {
2750
2751 }
2752
2753 // Some widgets don't have parent tabs (e.g. OK and Cancel buttons).
2754 if ( !cursor )
2755 return this;
2756
2757 tabId = cursor.getAttribute( 'name' );
2758 // Avoid duplicate select.
2759 if ( this._.dialog._.currentTabId != tabId )
2760 this._.dialog.selectPage( tabId );
2761 return this;
2762 },
2763
2764 /**
2765 * Puts the focus to the UI object. Switches tabs if the UI object isn't in the active tab page.
2766 *
2767 * uiElement.focus();
2768 *
2769 * @chainable
2770 */
2771 focus: function() {
2772 this.selectParentTab().getInputElement().focus();
2773 return this;
2774 },
2775
2776 /**
2777 * Registers the `on*` event handlers defined in the element definition.
2778 *
2779 * The default behavior of this function is:
2780 *
2781 * 1. If the on* event is defined in the class's eventProcesors list,
2782 * then the registration is delegated to the corresponding function
2783 * in the eventProcessors list.
2784 * 2. If the on* event is not defined in the eventProcessors list, then
2785 * register the event handler under the corresponding DOM event of
2786 * the UI element's input DOM element (as defined by the return value
2787 * of {@link #getInputElement}).
2788 *
2789 * This function is only called at UI element instantiation, but can
2790 * be overridded in child classes if they require more flexibility.
2791 *
2792 * @chainable
2793 * @param {CKEDITOR.dialog.definition.uiElement} definition The UI element
2794 * definition.
2795 */
2796 registerEvents: function( definition ) {
2797 var regex = /^on([A-Z]\w+)/,
2798 match;
2799
2800 var registerDomEvent = function( uiElement, dialog, eventName, func ) {
2801 dialog.on( 'load', function() {
2802 uiElement.getInputElement().on( eventName, func, uiElement );
2803 } );
2804 };
2805
2806 for ( var i in definition ) {
2807 if ( !( match = i.match( regex ) ) )
2808 continue;
2809 if ( this.eventProcessors[ i ] )
2810 this.eventProcessors[ i ].call( this, this._.dialog, definition[ i ] );
2811 else
2812 registerDomEvent( this, this._.dialog, match[ 1 ].toLowerCase(), definition[ i ] );
2813 }
2814
2815 return this;
2816 },
2817
2818 /**
2819 * The event processor list used by
2820 * {@link CKEDITOR.ui.dialog.uiElement#getInputElement} at UI element
2821 * instantiation. The default list defines three `on*` events:
2822 *
2823 * 1. `onLoad` - Called when the element's parent dialog opens for the
2824 * first time.
2825 * 2. `onShow` - Called whenever the element's parent dialog opens.
2826 * 3. `onHide` - Called whenever the element's parent dialog closes.
2827 *
2828 * // This connects the 'click' event in CKEDITOR.ui.dialog.button to onClick
2829 * // handlers in the UI element's definitions.
2830 * CKEDITOR.ui.dialog.button.eventProcessors = CKEDITOR.tools.extend( {},
2831 * CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,
2832 * { onClick : function( dialog, func ) { this.on( 'click', func ); } },
2833 * true
2834 * );
2835 *
2836 * @property {Object}
2837 */
2838 eventProcessors: {
2839 onLoad: function( dialog, func ) {
2840 dialog.on( 'load', func, this );
2841 },
2842
2843 onShow: function( dialog, func ) {
2844 dialog.on( 'show', func, this );
2845 },
2846
2847 onHide: function( dialog, func ) {
2848 dialog.on( 'hide', func, this );
2849 }
2850 },
2851
2852 /**
2853 * The default handler for a UI element's access key down event, which
2854 * tries to put focus to the UI element.
2855 *
2856 * Can be overridded in child classes for more sophisticaed behavior.
2857 *
2858 * @param {CKEDITOR.dialog} dialog The parent dialog object.
2859 * @param {String} key The key combination pressed. Since access keys
2860 * are defined to always include the `CTRL` key, its value should always
2861 * include a `'CTRL+'` prefix.
2862 */
2863 accessKeyDown: function() {
2864 this.focus();
2865 },
2866
2867 /**
2868 * The default handler for a UI element's access key up event, which
2869 * does nothing.
2870 *
2871 * Can be overridded in child classes for more sophisticated behavior.
2872 *
2873 * @param {CKEDITOR.dialog} dialog The parent dialog object.
2874 * @param {String} key The key combination pressed. Since access keys
2875 * are defined to always include the `CTRL` key, its value should always
2876 * include a `'CTRL+'` prefix.
2877 */
2878 accessKeyUp: function() {},
2879
2880 /**
2881 * Disables a UI element.
2882 */
2883 disable: function() {
2884 var element = this.getElement(),
2885 input = this.getInputElement();
2886 input.setAttribute( 'disabled', 'true' );
2887 element.addClass( 'cke_disabled' );
2888 },
2889
2890 /**
2891 * Enables a UI element.
2892 */
2893 enable: function() {
2894 var element = this.getElement(),
2895 input = this.getInputElement();
2896 input.removeAttribute( 'disabled' );
2897 element.removeClass( 'cke_disabled' );
2898 },
2899
2900 /**
2901 * Determines whether an UI element is enabled or not.
2902 *
2903 * @returns {Boolean} Whether the UI element is enabled.
2904 */
2905 isEnabled: function() {
2906 return !this.getElement().hasClass( 'cke_disabled' );
2907 },
2908
2909 /**
2910 * Determines whether an UI element is visible or not.
2911 *
2912 * @returns {Boolean} Whether the UI element is visible.
2913 */
2914 isVisible: function() {
2915 return this.getInputElement().isVisible();
2916 },
2917
2918 /**
2919 * Determines whether an UI element is focus-able or not.
2920 * Focus-able is defined as being both visible and enabled.
2921 *
2922 * @returns {Boolean} Whether the UI element can be focused.
2923 */
2924 isFocusable: function() {
2925 if ( !this.isEnabled() || !this.isVisible() )
2926 return false;
2927 return true;
2928 }
2929 };
2930
2931 /** @class CKEDITOR.ui.dialog.hbox */
2932 CKEDITOR.ui.dialog.hbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
2933 /**
2934 * Gets a child UI element inside this container.
2935 *
2936 * var checkbox = hbox.getChild( [0,1] );
2937 * checkbox.setValue( true );
2938 *
2939 * @param {Array/Number} indices An array or a single number to indicate the child's
2940 * position in the container's descendant tree. Omit to get all the children in an array.
2941 * @returns {Array/CKEDITOR.ui.dialog.uiElement} Array of all UI elements in the container
2942 * if no argument given, or the specified UI element if indices is given.
2943 */
2944 getChild: function( indices ) {
2945 // If no arguments, return a clone of the children array.
2946 if ( arguments.length < 1 )
2947 return this._.children.concat();
2948
2949 // If indices isn't array, make it one.
2950 if ( !indices.splice )
2951 indices = [ indices ];
2952
2953 // Retrieve the child element according to tree position.
2954 if ( indices.length < 2 )
2955 return this._.children[ indices[ 0 ] ];
2956 else
2957 return ( this._.children[ indices[ 0 ] ] && this._.children[ indices[ 0 ] ].getChild ) ? this._.children[ indices[ 0 ] ].getChild( indices.slice( 1, indices.length ) ) : null;
2958 }
2959 }, true );
2960
2961 CKEDITOR.ui.dialog.vbox.prototype = new CKEDITOR.ui.dialog.hbox();
2962
2963 ( function() {
2964 var commonBuilder = {
2965 build: function( dialog, elementDefinition, output ) {
2966 var children = elementDefinition.children,
2967 child,
2968 childHtmlList = [],
2969 childObjList = [];
2970 for ( var i = 0;
2971 ( i < children.length && ( child = children[ i ] ) ); i++ ) {
2972 var childHtml = [];
2973 childHtmlList.push( childHtml );
2974 childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
2975 }
2976 return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
2977 }
2978 };
2979
2980 CKEDITOR.dialog.addUIElement( 'hbox', commonBuilder );
2981 CKEDITOR.dialog.addUIElement( 'vbox', commonBuilder );
2982 } )();
2983
2984 /**
2985 * Generic dialog command. It opens a specific dialog when executed.
2986 *
2987 * // Register the "link" command, which opens the "link" dialog.
2988 * editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) );
2989 *
2990 * @class
2991 * @constructor Creates a dialogCommand class instance.
2992 * @extends CKEDITOR.commandDefinition
2993 * @param {String} dialogName The name of the dialog to open when executing
2994 * this command.
2995 * @param {Object} [ext] Additional command definition's properties.
2996 */
2997 CKEDITOR.dialogCommand = function( dialogName, ext ) {
2998 this.dialogName = dialogName;
2999 CKEDITOR.tools.extend( this, ext, true );
3000 };
3001
3002 CKEDITOR.dialogCommand.prototype = {
3003 exec: function( editor ) {
3004 editor.openDialog( this.dialogName );
3005 },
3006
3007 // Dialog commands just open a dialog ui, thus require no undo logic,
3008 // undo support should dedicate to specific dialog implementation.
3009 canUndo: false,
3010
3011 editorFocus: 1
3012 };
3013
3014 ( function() {
3015 var notEmptyRegex = /^([a]|[^a])+$/,
3016 integerRegex = /^\d*$/,
3017 numberRegex = /^\d*(?:\.\d+)?$/,
3018 htmlLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|\%)?)?$/,
3019 cssLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|em|ex|in|cm|mm|pt|pc|\%)?)?$/i,
3020 inlineStyleRegex = /^(\s*[\w-]+\s*:\s*[^:;]+(?:;|$))*$/;
3021
3022 CKEDITOR.VALIDATE_OR = 1;
3023 CKEDITOR.VALIDATE_AND = 2;
3024
3025 CKEDITOR.dialog.validate = {
3026 functions: function() {
3027 var args = arguments;
3028 return function() {
3029 /**
3030 * It's important for validate functions to be able to accept the value
3031 * as argument in addition to this.getValue(), so that it is possible to
3032 * combine validate functions together to make more sophisticated
3033 * validators.
3034 */
3035 var value = this && this.getValue ? this.getValue() : args[ 0 ];
3036
3037 var msg,
3038 relation = CKEDITOR.VALIDATE_AND,
3039 functions = [],
3040 i;
3041
3042 for ( i = 0; i < args.length; i++ ) {
3043 if ( typeof args[ i ] == 'function' )
3044 functions.push( args[ i ] );
3045 else
3046 break;
3047 }
3048
3049 if ( i < args.length && typeof args[ i ] == 'string' ) {
3050 msg = args[ i ];
3051 i++;
3052 }
3053
3054 if ( i < args.length && typeof args[ i ] == 'number' )
3055 relation = args[ i ];
3056
3057 var passed = ( relation == CKEDITOR.VALIDATE_AND ? true : false );
3058 for ( i = 0; i < functions.length; i++ ) {
3059 if ( relation == CKEDITOR.VALIDATE_AND )
3060 passed = passed && functions[ i ]( value );
3061 else
3062 passed = passed || functions[ i ]( value );
3063 }
3064
3065 return !passed ? msg : true;
3066 };
3067 },
3068
3069 regex: function( regex, msg ) {
3070 /*
3071 * Can be greatly shortened by deriving from functions validator if code size
3072 * turns out to be more important than performance.
3073 */
3074 return function() {
3075 var value = this && this.getValue ? this.getValue() : arguments[ 0 ];
3076 return !regex.test( value ) ? msg : true;
3077 };
3078 },
3079
3080 notEmpty: function( msg ) {
3081 return this.regex( notEmptyRegex, msg );
3082 },
3083
3084 integer: function( msg ) {
3085 return this.regex( integerRegex, msg );
3086 },
3087
3088 'number': function( msg ) {
3089 return this.regex( numberRegex, msg );
3090 },
3091
3092 'cssLength': function( msg ) {
3093 return this.functions( function( val ) {
3094 return cssLengthRegex.test( CKEDITOR.tools.trim( val ) );
3095 }, msg );
3096 },
3097
3098 'htmlLength': function( msg ) {
3099 return this.functions( function( val ) {
3100 return htmlLengthRegex.test( CKEDITOR.tools.trim( val ) );
3101 }, msg );
3102 },
3103
3104 'inlineStyle': function( msg ) {
3105 return this.functions( function( val ) {
3106 return inlineStyleRegex.test( CKEDITOR.tools.trim( val ) );
3107 }, msg );
3108 },
3109
3110 equals: function( value, msg ) {
3111 return this.functions( function( val ) {
3112 return val == value;
3113 }, msg );
3114 },
3115
3116 notEqual: function( value, msg ) {
3117 return this.functions( function( val ) {
3118 return val != value;
3119 }, msg );
3120 }
3121 };
3122
3123 CKEDITOR.on( 'instanceDestroyed', function( evt ) {
3124 // Remove dialog cover on last instance destroy.
3125 if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) ) {
3126 var currentTopDialog;
3127 while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) )
3128 currentTopDialog.hide();
3129 removeCovers();
3130 }
3131
3132 var dialogs = evt.editor._.storedDialogs;
3133 for ( var name in dialogs )
3134 dialogs[ name ].destroy();
3135
3136 } );
3137
3138 } )();
3139
3140 // Extend the CKEDITOR.editor class with dialog specific functions.
3141 CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
3142 /**
3143 * Loads and opens a registered dialog.
3144 *
3145 * CKEDITOR.instances.editor1.openDialog( 'smiley' );
3146 *
3147 * @member CKEDITOR.editor
3148 * @param {String} dialogName The registered name of the dialog.
3149 * @param {Function} callback The function to be invoked after dialog instance created.
3150 * @returns {CKEDITOR.dialog} The dialog object corresponding to the dialog displayed.
3151 * `null` if the dialog name is not registered.
3152 * @see CKEDITOR.dialog#add
3153 */
3154 openDialog: function( dialogName, callback ) {
3155 var dialog = null, dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];
3156
3157 if ( CKEDITOR.dialog._.currentTop === null )
3158 showCover( this );
3159
3160 // If the dialogDefinition is already loaded, open it immediately.
3161 if ( typeof dialogDefinitions == 'function' ) {
3162 var storedDialogs = this._.storedDialogs || ( this._.storedDialogs = {} );
3163
3164 dialog = storedDialogs[ dialogName ] || ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) );
3165
3166 callback && callback.call( dialog, dialog );
3167 dialog.show();
3168
3169 } else if ( dialogDefinitions == 'failed' ) {
3170 hideCover( this );
3171 throw new Error( '[CKEDITOR.dialog.openDialog] Dialog "' + dialogName + '" failed when loading definition.' );
3172 } else if ( typeof dialogDefinitions == 'string' ) {
3173
3174 CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ),
3175 function() {
3176 var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];
3177 // In case of plugin error, mark it as loading failed.
3178 if ( typeof dialogDefinition != 'function' )
3179 CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed';
3180
3181 this.openDialog( dialogName, callback );
3182 }, this, 0, 1 );
3183 }
3184
3185 CKEDITOR.skin.loadPart( 'dialog' );
3186
3187 return dialog;
3188 }
3189 } );
3190} )();
3191
3192CKEDITOR.plugins.add( 'dialog', {
3193 requires: 'dialogui',
3194 init: function( editor ) {
3195 editor.on( 'doubleclick', function( evt ) {
3196 if ( evt.data.dialog )
3197 editor.openDialog( evt.data.dialog );
3198 }, null, null, 999 );
3199 }
3200} );
3201
3202// Dialog related configurations.
3203
3204/**
3205 * The color of the dialog background cover. It should be a valid CSS color string.
3206 *
3207 * config.dialog_backgroundCoverColor = 'rgb(255, 254, 253)';
3208 *
3209 * @cfg {String} [dialog_backgroundCoverColor='white']
3210 * @member CKEDITOR.config
3211 */
3212
3213/**
3214 * The opacity of the dialog background cover. It should be a number within the
3215 * range `[0.0, 1.0]`.
3216 *
3217 * config.dialog_backgroundCoverOpacity = 0.7;
3218 *
3219 * @cfg {Number} [dialog_backgroundCoverOpacity=0.5]
3220 * @member CKEDITOR.config
3221 */
3222
3223/**
3224 * If the dialog has more than one tab, put focus into the first tab as soon as dialog is opened.
3225 *
3226 * config.dialog_startupFocusTab = true;
3227 *
3228 * @cfg {Boolean} [dialog_startupFocusTab=false]
3229 * @member CKEDITOR.config
3230 */
3231
3232/**
3233 * The distance of magnetic borders used in moving and resizing dialogs,
3234 * measured in pixels.
3235 *
3236 * config.dialog_magnetDistance = 30;
3237 *
3238 * @cfg {Number} [dialog_magnetDistance=20]
3239 * @member CKEDITOR.config
3240 */
3241
3242/**
3243 * The guideline to follow when generating the dialog buttons. There are 3 possible options:
3244 *
3245 * * `'OS'` - the buttons will be displayed in the default order of the user's OS;
3246 * * `'ltr'` - for Left-To-Right order;
3247 * * `'rtl'` - for Right-To-Left order.
3248 *
3249 * Example:
3250 *
3251 * config.dialog_buttonsOrder = 'rtl';
3252 *
3253 * @since 3.5
3254 * @cfg {String} [dialog_buttonsOrder='OS']
3255 * @member CKEDITOR.config
3256 */
3257
3258/**
3259 * The dialog contents to removed. It's a string composed by dialog name and tab name with a colon between them.
3260 *
3261 * Separate each pair with semicolon (see example).
3262 *
3263 * **Note:** All names are case-sensitive.
3264 *
3265 * **Note:** Be cautious when specifying dialog tabs that are mandatory,
3266 * like `'info'`, dialog functionality might be broken because of this!
3267 *
3268 * config.removeDialogTabs = 'flash:advanced;image:Link';
3269 *
3270 * @since 3.5
3271 * @cfg {String} [removeDialogTabs='']
3272 * @member CKEDITOR.config
3273 */
3274
3275/**
3276 * Tells if user should not be asked to confirm close, if any dialog field was modified.
3277 * By default it is set to `false` meaning that the confirmation dialog will be shown.
3278 *
3279 * config.dialog_noConfirmCancel = true;
3280 *
3281 * @since 4.3
3282 * @cfg {Boolean} [dialog_noConfirmCancel=false]
3283 * @member CKEDITOR.config
3284 */
3285
3286/**
3287 * Event fired when a dialog definition is about to be used to create a dialog into
3288 * an editor instance. This event makes it possible to customize the definition
3289 * before creating it.
3290 *
3291 * Note that this event is called only the first time a specific dialog is
3292 * opened. Successive openings will use the cached dialog, and this event will
3293 * not get fired.
3294 *
3295 * @event dialogDefinition
3296 * @member CKEDITOR
3297 * @param {CKEDITOR.dialog.definition} data The dialog defination that
3298 * is being loaded.
3299 * @param {CKEDITOR.editor} editor The editor instance that will use the dialog.
3300 */
3301
3302/**
3303 * Event fired when a tab is going to be selected in a dialog.
3304 *
3305 * @event selectPage
3306 * @member CKEDITOR.dialog
3307 * @param data
3308 * @param {String} data.page The id of the page that it's gonna be selected.
3309 * @param {String} data.currentPage The id of the current page.
3310 */
3311
3312/**
3313 * Event fired when the user tries to dismiss a dialog.
3314 *
3315 * @event cancel
3316 * @member CKEDITOR.dialog
3317 * @param data
3318 * @param {Boolean} data.hide Whether the event should proceed or not.
3319 */
3320
3321/**
3322 * Event fired when the user tries to confirm a dialog.
3323 *
3324 * @event ok
3325 * @member CKEDITOR.dialog
3326 * @param data
3327 * @param {Boolean} data.hide Whether the event should proceed or not.
3328 */
3329
3330/**
3331 * Event fired when a dialog is shown.
3332 *
3333 * @event show
3334 * @member CKEDITOR.dialog
3335 */
3336
3337/**
3338 * Event fired when a dialog is shown.
3339 *
3340 * @event dialogShow
3341 * @member CKEDITOR.editor
3342 * @param {CKEDITOR.editor} editor This editor instance.
3343 * @param {CKEDITOR.dialog} data The opened dialog instance.
3344 */
3345
3346/**
3347 * Event fired when a dialog is hidden.
3348 *
3349 * @event hide
3350 * @member CKEDITOR.dialog
3351 */
3352
3353/**
3354 * Event fired when a dialog is hidden.
3355 *
3356 * @event dialogHide
3357 * @member CKEDITOR.editor
3358 * @param {CKEDITOR.editor} editor This editor instance.
3359 * @param {CKEDITOR.dialog} data The hidden dialog instance.
3360 */
3361
3362/**
3363 * Event fired when a dialog is being resized. The event is fired on
3364 * both the {@link CKEDITOR.dialog} object and the dialog instance
3365 * since 3.5.3, previously it was only available in the global object.
3366 *
3367 * @static
3368 * @event resize
3369 * @member CKEDITOR.dialog
3370 * @param data
3371 * @param {CKEDITOR.dialog} data.dialog The dialog being resized (if
3372 * it is fired on the dialog itself, this parameter is not sent).
3373 * @param {String} data.skin The skin name.
3374 * @param {Number} data.width The new width.
3375 * @param {Number} data.height The new height.
3376 */
3377
3378/**
3379 * Event fired when a dialog is being resized. The event is fired on
3380 * both the {@link CKEDITOR.dialog} object and the dialog instance
3381 * since 3.5.3, previously it was only available in the global object.
3382 *
3383 * @since 3.5
3384 * @event resize
3385 * @member CKEDITOR.dialog
3386 * @param data
3387 * @param {Number} data.width The new width.
3388 * @param {Number} data.height The new height.
3389 */
3390
3391/**
3392 * Event fired when the dialog state changes, usually by {@link CKEDITOR.dialog#setState}.
3393 *
3394 * @since 4.5
3395 * @event state
3396 * @member CKEDITOR.dialog
3397 * @param data
3398 * @param {Number} data The new state. Either {@link CKEDITOR#DIALOG_STATE_IDLE} or {@link CKEDITOR#DIALOG_STATE_BUSY}.
3399 */
diff --git a/sources/plugins/dialog/samples/assets/my_dialog.js b/sources/plugins/dialog/samples/assets/my_dialog.js
new file mode 100644
index 0000000..6239dea
--- /dev/null
+++ b/sources/plugins/dialog/samples/assets/my_dialog.js
@@ -0,0 +1,49 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.dialog.add( 'myDialog', function() {
7 return {
8 title: 'My Dialog',
9 minWidth: 400,
10 minHeight: 200,
11 contents: [
12 {
13 id: 'tab1',
14 label: 'First Tab',
15 title: 'First Tab',
16 elements: [
17 {
18 id: 'input1',
19 type: 'text',
20 label: 'Text Field'
21 },
22 {
23 id: 'select1',
24 type: 'select',
25 label: 'Select Field',
26 items: [
27 [ 'option1', 'value1' ],
28 [ 'option2', 'value2' ]
29 ]
30 }
31 ]
32 },
33 {
34 id: 'tab2',
35 label: 'Second Tab',
36 title: 'Second Tab',
37 elements: [
38 {
39 id: 'button1',
40 type: 'button',
41 label: 'Button Field'
42 }
43 ]
44 }
45 ]
46 };
47} );
48
49// %LEAVE_UNMINIFIED% %REMOVE_LINE%
diff --git a/sources/plugins/dialog/samples/dialog.html b/sources/plugins/dialog/samples/dialog.html
new file mode 100644
index 0000000..0f22a1a
--- /dev/null
+++ b/sources/plugins/dialog/samples/dialog.html
@@ -0,0 +1,190 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Using API to Customize Dialog Windows &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link rel="stylesheet" href="../../../samples/old/sample.css">
12 <meta name="ckeditor-sample-name" content="Using the JavaScript API to customize dialog windows">
13 <meta name="ckeditor-sample-group" content="Advanced Samples">
14 <meta name="ckeditor-sample-description" content="Using the dialog windows API to customize dialog windows without changing the original editor code.">
15 <style>
16
17 .cke_button__mybutton_icon
18 {
19 display: none !important;
20 }
21
22 .cke_button__mybutton_label
23 {
24 display: inline !important;
25 }
26
27 </style>
28 <script>
29
30 CKEDITOR.on( 'instanceCreated', function( ev ){
31 var editor = ev.editor;
32
33 // Listen for the "pluginsLoaded" event, so we are sure that the
34 // "dialog" plugin has been loaded and we are able to do our
35 // customizations.
36 editor.on( 'pluginsLoaded', function() {
37
38 // If our custom dialog has not been registered, do that now.
39 if ( !CKEDITOR.dialog.exists( 'myDialog' ) ) {
40 // We need to do the following trick to find out the dialog
41 // definition file URL path. In the real world, you would simply
42 // point to an absolute path directly, like "/mydir/mydialog.js".
43 var href = document.location.href.split( '/' );
44 href.pop();
45 href.push( 'assets/my_dialog.js' );
46 href = href.join( '/' );
47
48 // Finally, register the dialog.
49 CKEDITOR.dialog.add( 'myDialog', href );
50 }
51
52 // Register the command used to open the dialog.
53 editor.addCommand( 'myDialogCmd', new CKEDITOR.dialogCommand( 'myDialog' ) );
54
55 // Add the a custom toolbar buttons, which fires the above
56 // command..
57 editor.ui.add( 'MyButton', CKEDITOR.UI_BUTTON, {
58 label: 'My Dialog',
59 command: 'myDialogCmd'
60 });
61 });
62 });
63
64 // When opening a dialog, its "definition" is created for it, for
65 // each editor instance. The "dialogDefinition" event is then
66 // fired. We should use this event to make customizations to the
67 // definition of existing dialogs.
68 CKEDITOR.on( 'dialogDefinition', function( ev ) {
69 // Take the dialog name and its definition from the event data.
70 var dialogName = ev.data.name;
71 var dialogDefinition = ev.data.definition;
72
73 // Check if the definition is from the dialog we're
74 // interested on (the "Link" dialog).
75 if ( dialogName == 'myDialog' && ev.editor.name == 'editor2' ) {
76 // Get a reference to the "Link Info" tab.
77 var infoTab = dialogDefinition.getContents( 'tab1' );
78
79 // Add a new text field to the "tab1" tab page.
80 infoTab.add( {
81 type: 'text',
82 label: 'My Custom Field',
83 id: 'customField',
84 'default': 'Sample!',
85 validate: function() {
86 if ( ( /\d/ ).test( this.getValue() ) )
87 return 'My Custom Field must not contain digits';
88 }
89 });
90
91 // Remove the "select1" field from the "tab1" tab.
92 infoTab.remove( 'select1' );
93
94 // Set the default value for "input1" field.
95 var input1 = infoTab.get( 'input1' );
96 input1[ 'default' ] = 'www.example.com';
97
98 // Remove the "tab2" tab page.
99 dialogDefinition.removeContents( 'tab2' );
100
101 // Add a new tab to the "Link" dialog.
102 dialogDefinition.addContents( {
103 id: 'customTab',
104 label: 'My Tab',
105 accessKey: 'M',
106 elements: [
107 {
108 id: 'myField1',
109 type: 'text',
110 label: 'My Text Field'
111 },
112 {
113 id: 'myField2',
114 type: 'text',
115 label: 'Another Text Field'
116 }
117 ]
118 });
119
120 // Provide the focus handler to start initial focus in "customField" field.
121 dialogDefinition.onFocus = function() {
122 var urlField = this.getContentElement( 'tab1', 'customField' );
123 urlField.select();
124 };
125 }
126 });
127
128 var config = {
129 extraPlugins: 'dialog',
130 toolbar: [ [ 'MyButton' ] ]
131 };
132
133 </script>
134</head>
135<body>
136 <h1 class="samples">
137 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Using CKEditor Dialog API
138 </h1>
139 <div class="warning deprecated">
140 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
141 </div>
142 <div class="description">
143 <p>
144 This sample shows how to use the
145 <a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.dialog">CKEditor Dialog API</a>
146 to customize CKEditor dialog windows without changing the original editor code.
147 The following customizations are being done in the example below:
148 </p>
149 <p>
150 For details on how to create this setup check the source code of this sample page.
151 </p>
152 </div>
153 <p>A custom dialog is added to the editors using the <code>pluginsLoaded</code> event, from an external <a target="_blank" href="assets/my_dialog.js">dialog definition file</a>:</p>
154 <ol>
155 <li><strong>Creating a custom dialog window</strong> &ndash; "My Dialog" dialog window opened with the "My Dialog" toolbar button.</li>
156 <li><strong>Creating a custom button</strong> &ndash; Add button to open the dialog with "My Dialog" toolbar button.</li>
157 </ol>
158 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
159 <script>
160 // Replace the <textarea id="editor1"> with an CKEditor instance.
161 CKEDITOR.replace( 'editor1', config );
162 </script>
163 <p>The below editor modify the dialog definition of the above added dialog using the <code>dialogDefinition</code> event:</p>
164 <ol>
165 <li><strong>Adding dialog tab</strong> &ndash; Add new tab "My Tab" to dialog window.</li>
166 <li><strong>Removing a dialog window tab</strong> &ndash; Remove "Second Tab" page from the dialog window.</li>
167 <li><strong>Adding dialog window fields</strong> &ndash; Add "My Custom Field" to the dialog window.</li>
168 <li><strong>Removing dialog window field</strong> &ndash; Remove "Select Field" selection field from the dialog window.</li>
169 <li><strong>Setting default values for dialog window fields</strong> &ndash; Set default value of "Text Field" text field. </li>
170 <li><strong>Setup initial focus for dialog window</strong> &ndash; Put initial focus on "My Custom Field" text field. </li>
171 </ol>
172 <textarea cols="80" id="editor2" name="editor2" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
173 <script>
174
175 // Replace the <textarea id="editor1"> with an CKEditor instance.
176 CKEDITOR.replace( 'editor2', config );
177
178 </script>
179 <div id="footer">
180 <hr>
181 <p>
182 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
183 </p>
184 <p id="copy">
185 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
186 Knabben. All rights reserved.
187 </p>
188 </div>
189</body>
190</html>
diff --git a/sources/plugins/dialogadvtab/plugin.js b/sources/plugins/dialogadvtab/plugin.js
new file mode 100644
index 0000000..460b534
--- /dev/null
+++ b/sources/plugins/dialogadvtab/plugin.js
@@ -0,0 +1,196 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7
8 function setupAdvParams( element ) {
9 var attrName = this.att;
10
11 var value = element && element.hasAttribute( attrName ) && element.getAttribute( attrName ) || '';
12
13 if ( value !== undefined )
14 this.setValue( value );
15 }
16
17 function commitAdvParams() {
18 // Dialogs may use different parameters in the commit list, so, by
19 // definition, we take the first CKEDITOR.dom.element available.
20 var element;
21
22 for ( var i = 0; i < arguments.length; i++ ) {
23 if ( arguments[ i ] instanceof CKEDITOR.dom.element ) {
24 element = arguments[ i ];
25 break;
26 }
27 }
28
29 if ( element ) {
30 var attrName = this.att,
31 value = this.getValue();
32
33 if ( value )
34 element.setAttribute( attrName, value );
35 else
36 element.removeAttribute( attrName, value );
37 }
38 }
39
40 var defaultTabConfig = { id: 1, dir: 1, classes: 1, styles: 1 };
41
42 CKEDITOR.plugins.add( 'dialogadvtab', {
43 requires: 'dialog',
44
45 // Returns allowed content rule for the content created by this plugin.
46 allowedContent: function( tabConfig ) {
47 if ( !tabConfig )
48 tabConfig = defaultTabConfig;
49
50 var allowedAttrs = [];
51 if ( tabConfig.id )
52 allowedAttrs.push( 'id' );
53 if ( tabConfig.dir )
54 allowedAttrs.push( 'dir' );
55
56 var allowed = '';
57
58 if ( allowedAttrs.length )
59 allowed += '[' + allowedAttrs.join( ',' ) + ']';
60
61 if ( tabConfig.classes )
62 allowed += '(*)';
63 if ( tabConfig.styles )
64 allowed += '{*}';
65
66 return allowed;
67 },
68
69 // @param tabConfig
70 // id, dir, classes, styles
71 createAdvancedTab: function( editor, tabConfig, element ) {
72 if ( !tabConfig )
73 tabConfig = defaultTabConfig;
74
75 var lang = editor.lang.common;
76
77 var result = {
78 id: 'advanced',
79 label: lang.advancedTab,
80 title: lang.advancedTab,
81 elements: [ {
82 type: 'vbox',
83 padding: 1,
84 children: []
85 } ]
86 };
87
88 var contents = [];
89
90 if ( tabConfig.id || tabConfig.dir ) {
91 if ( tabConfig.id ) {
92 contents.push( {
93 id: 'advId',
94 att: 'id',
95 type: 'text',
96 requiredContent: element ? element + '[id]' : null,
97 label: lang.id,
98 setup: setupAdvParams,
99 commit: commitAdvParams
100 } );
101 }
102
103 if ( tabConfig.dir ) {
104 contents.push( {
105 id: 'advLangDir',
106 att: 'dir',
107 type: 'select',
108 requiredContent: element ? element + '[dir]' : null,
109 label: lang.langDir,
110 'default': '',
111 style: 'width:100%',
112 items: [
113 [ lang.notSet, '' ],
114 [ lang.langDirLTR, 'ltr' ],
115 [ lang.langDirRTL, 'rtl' ]
116 ],
117 setup: setupAdvParams,
118 commit: commitAdvParams
119 } );
120 }
121
122 result.elements[ 0 ].children.push( {
123 type: 'hbox',
124 widths: [ '50%', '50%' ],
125 children: [].concat( contents )
126 } );
127 }
128
129 if ( tabConfig.styles || tabConfig.classes ) {
130 contents = [];
131
132 if ( tabConfig.styles ) {
133 contents.push( {
134 id: 'advStyles',
135 att: 'style',
136 type: 'text',
137 requiredContent: element ? element + '{cke-xyz}' : null,
138 label: lang.styles,
139 'default': '',
140
141 validate: CKEDITOR.dialog.validate.inlineStyle( lang.invalidInlineStyle ),
142 onChange: function() {},
143
144 getStyle: function( name, defaultValue ) {
145 var match = this.getValue().match( new RegExp( '(?:^|;)\\s*' + name + '\\s*:\\s*([^;]*)', 'i' ) );
146 return match ? match[ 1 ] : defaultValue;
147 },
148
149 updateStyle: function( name, value ) {
150 var styles = this.getValue();
151
152 var tmp = editor.document.createElement( 'span' );
153 tmp.setAttribute( 'style', styles );
154 tmp.setStyle( name, value );
155 styles = CKEDITOR.tools.normalizeCssText( tmp.getAttribute( 'style' ) );
156
157 this.setValue( styles, 1 );
158 },
159
160 setup: setupAdvParams,
161
162 commit: commitAdvParams
163
164 } );
165 }
166
167 if ( tabConfig.classes ) {
168 contents.push( {
169 type: 'hbox',
170 widths: [ '45%', '55%' ],
171 children: [ {
172 id: 'advCSSClasses',
173 att: 'class',
174 type: 'text',
175 requiredContent: element ? element + '(cke-xyz)' : null,
176 label: lang.cssClasses,
177 'default': '',
178 setup: setupAdvParams,
179 commit: commitAdvParams
180
181 } ]
182 } );
183 }
184
185 result.elements[ 0 ].children.push( {
186 type: 'hbox',
187 widths: [ '50%', '50%' ],
188 children: [].concat( contents )
189 } );
190 }
191
192 return result;
193 }
194 } );
195
196} )();
diff --git a/sources/plugins/dialogui/plugin.js b/sources/plugins/dialogui/plugin.js
new file mode 100644
index 0000000..cf91407
--- /dev/null
+++ b/sources/plugins/dialogui/plugin.js
@@ -0,0 +1,1530 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The Dialog User Interface plugin.
8 */
9
10CKEDITOR.plugins.add( 'dialogui', {
11 onLoad: function() {
12
13 var initPrivateObject = function( elementDefinition ) {
14 this._ || ( this._ = {} );
15 this._[ 'default' ] = this._.initValue = elementDefinition[ 'default' ] || '';
16 this._.required = elementDefinition.required || false;
17 var args = [ this._ ];
18 for ( var i = 1; i < arguments.length; i++ )
19 args.push( arguments[ i ] );
20 args.push( true );
21 CKEDITOR.tools.extend.apply( CKEDITOR.tools, args );
22 return this._;
23 },
24 textBuilder = {
25 build: function( dialog, elementDefinition, output ) {
26 return new CKEDITOR.ui.dialog.textInput( dialog, elementDefinition, output );
27 }
28 },
29 commonBuilder = {
30 build: function( dialog, elementDefinition, output ) {
31 return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, elementDefinition, output );
32 }
33 },
34 containerBuilder = {
35 build: function( dialog, elementDefinition, output ) {
36 var children = elementDefinition.children,
37 child,
38 childHtmlList = [],
39 childObjList = [];
40 for ( var i = 0;
41 ( i < children.length && ( child = children[ i ] ) ); i++ ) {
42 var childHtml = [];
43 childHtmlList.push( childHtml );
44 childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
45 }
46 return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
47 }
48 },
49 commonPrototype = {
50 isChanged: function() {
51 return this.getValue() != this.getInitValue();
52 },
53
54 reset: function( noChangeEvent ) {
55 this.setValue( this.getInitValue(), noChangeEvent );
56 },
57
58 setInitValue: function() {
59 this._.initValue = this.getValue();
60 },
61
62 resetInitValue: function() {
63 this._.initValue = this._[ 'default' ];
64 },
65
66 getInitValue: function() {
67 return this._.initValue;
68 }
69 },
70 commonEventProcessors = CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors, {
71 onChange: function( dialog, func ) {
72 if ( !this._.domOnChangeRegistered ) {
73 dialog.on( 'load', function() {
74 this.getInputElement().on( 'change', function() {
75 // Make sure 'onchange' doesn't get fired after dialog closed. (#5719)
76 if ( !dialog.parts.dialog.isVisible() )
77 return;
78
79 this.fire( 'change', { value: this.getValue() } );
80 }, this );
81 }, this );
82 this._.domOnChangeRegistered = true;
83 }
84
85 this.on( 'change', func );
86 }
87 }, true ),
88 eventRegex = /^on([A-Z]\w+)/,
89 cleanInnerDefinition = function( def ) {
90 // An inner UI element should not have the parent's type, title or events.
91 for ( var i in def ) {
92 if ( eventRegex.test( i ) || i == 'title' || i == 'type' )
93 delete def[ i ];
94 }
95 return def;
96 },
97 // @context {CKEDITOR.dialog.uiElement} UI element (textarea or textInput)
98 // @param {CKEDITOR.dom.event} evt
99 toggleBidiKeyUpHandler = function( evt ) {
100 var keystroke = evt.data.getKeystroke();
101
102 // ALT + SHIFT + Home for LTR direction.
103 if ( keystroke == CKEDITOR.SHIFT + CKEDITOR.ALT + 36 )
104 this.setDirectionMarker( 'ltr' );
105
106 // ALT + SHIFT + End for RTL direction.
107 else if ( keystroke == CKEDITOR.SHIFT + CKEDITOR.ALT + 35 )
108 this.setDirectionMarker( 'rtl' );
109 };
110
111 CKEDITOR.tools.extend( CKEDITOR.ui.dialog, {
112 /**
113 * Base class for all dialog window elements with a textual label on the left.
114 *
115 * @class CKEDITOR.ui.dialog.labeledElement
116 * @extends CKEDITOR.ui.dialog.uiElement
117 * @constructor Creates a labeledElement class instance.
118 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
119 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
120 * The element definition. Accepted fields:
121 *
122 * * `label` (Required) The label string.
123 * * `labelLayout` (Optional) Put 'horizontal' here if the
124 * label element is to be laid out horizontally. Otherwise a vertical
125 * layout will be used.
126 * * `widths` (Optional) This applies only to horizontal
127 * layouts &mdash; a two-element array of lengths to specify the widths of the
128 * label and the content element.
129 * * `role` (Optional) Value for the `role` attribute.
130 * * `includeLabel` (Optional) If set to `true`, the `aria-labelledby` attribute
131 * will be included.
132 *
133 * @param {Array} htmlList The list of HTML code to output to.
134 * @param {Function} contentHtml
135 * A function returning the HTML code string to be added inside the content
136 * cell.
137 */
138 labeledElement: function( dialog, elementDefinition, htmlList, contentHtml ) {
139 if ( arguments.length < 4 )
140 return;
141
142 var _ = initPrivateObject.call( this, elementDefinition );
143 _.labelId = CKEDITOR.tools.getNextId() + '_label';
144 this._.children = [];
145
146 var innerHTML = function() {
147 var html = [],
148 requiredClass = elementDefinition.required ? ' cke_required' : '';
149 if ( elementDefinition.labelLayout != 'horizontal' ) {
150 html.push(
151 '<label class="cke_dialog_ui_labeled_label' + requiredClass + '" ', ' id="' + _.labelId + '"',
152 ( _.inputId ? ' for="' + _.inputId + '"' : '' ),
153 ( elementDefinition.labelStyle ? ' style="' + elementDefinition.labelStyle + '"' : '' ) + '>',
154 elementDefinition.label,
155 '</label>',
156 '<div class="cke_dialog_ui_labeled_content"',
157 ( elementDefinition.controlStyle ? ' style="' + elementDefinition.controlStyle + '"' : '' ),
158 ' role="presentation">',
159 contentHtml.call( this, dialog, elementDefinition ),
160 '</div>' );
161 } else {
162 var hboxDefinition = {
163 type: 'hbox',
164 widths: elementDefinition.widths,
165 padding: 0,
166 children: [ {
167 type: 'html',
168 html: '<label class="cke_dialog_ui_labeled_label' + requiredClass + '"' +
169 ' id="' + _.labelId + '"' +
170 ' for="' + _.inputId + '"' +
171 ( elementDefinition.labelStyle ? ' style="' + elementDefinition.labelStyle + '"' : '' ) + '>' +
172 CKEDITOR.tools.htmlEncode( elementDefinition.label ) +
173 '</label>'
174 },
175 {
176 type: 'html',
177 html: '<span class="cke_dialog_ui_labeled_content"' + ( elementDefinition.controlStyle ? ' style="' + elementDefinition.controlStyle + '"' : '' ) + '>' +
178 contentHtml.call( this, dialog, elementDefinition ) +
179 '</span>'
180 } ]
181 };
182 CKEDITOR.dialog._.uiElementBuilders.hbox.build( dialog, hboxDefinition, html );
183 }
184 return html.join( '' );
185 };
186 var attributes = { role: elementDefinition.role || 'presentation' };
187
188 if ( elementDefinition.includeLabel )
189 attributes[ 'aria-labelledby' ] = _.labelId;
190
191 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'div', null, attributes, innerHTML );
192 },
193
194 /**
195 * A text input with a label. This UI element class represents both the
196 * single-line text inputs and password inputs in dialog boxes.
197 *
198 * @class CKEDITOR.ui.dialog.textInput
199 * @extends CKEDITOR.ui.dialog.labeledElement
200 * @constructor Creates a textInput class instance.
201 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
202 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
203 * The element definition. Accepted fields:
204 *
205 * * `default` (Optional) The default value.
206 * * `validate` (Optional) The validation function.
207 * * `maxLength` (Optional) The maximum length of text box contents.
208 * * `size` (Optional) The size of the text box. This is
209 * usually overridden by the size defined by the skin, though.
210 *
211 * @param {Array} htmlList List of HTML code to output to.
212 */
213 textInput: function( dialog, elementDefinition, htmlList ) {
214 if ( arguments.length < 3 )
215 return;
216
217 initPrivateObject.call( this, elementDefinition );
218 var domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textInput',
219 attributes = { 'class': 'cke_dialog_ui_input_' + elementDefinition.type, id: domId, type: elementDefinition.type };
220
221 // Set the validator, if any.
222 if ( elementDefinition.validate )
223 this.validate = elementDefinition.validate;
224
225 // Set the max length and size.
226 if ( elementDefinition.maxLength )
227 attributes.maxlength = elementDefinition.maxLength;
228 if ( elementDefinition.size )
229 attributes.size = elementDefinition.size;
230
231 if ( elementDefinition.inputStyle )
232 attributes.style = elementDefinition.inputStyle;
233
234 // If user presses Enter in a text box, it implies clicking OK for the dialog.
235 var me = this,
236 keyPressedOnMe = false;
237 dialog.on( 'load', function() {
238 me.getInputElement().on( 'keydown', function( evt ) {
239 if ( evt.data.getKeystroke() == 13 )
240 keyPressedOnMe = true;
241 } );
242
243 // Lower the priority this 'keyup' since 'ok' will close the dialog.(#3749)
244 me.getInputElement().on( 'keyup', function( evt ) {
245 if ( evt.data.getKeystroke() == 13 && keyPressedOnMe ) {
246 dialog.getButton( 'ok' ) && setTimeout( function() {
247 dialog.getButton( 'ok' ).click();
248 }, 0 );
249 keyPressedOnMe = false;
250 }
251
252 if ( me.bidi )
253 toggleBidiKeyUpHandler.call( me, evt );
254 }, null, null, 1000 );
255 } );
256
257 var innerHTML = function() {
258 // IE BUG: Text input fields in IE at 100% would exceed a <td> or inline
259 // container's width, so need to wrap it inside a <div>.
260 var html = [ '<div class="cke_dialog_ui_input_', elementDefinition.type, '" role="presentation"' ];
261
262 if ( elementDefinition.width )
263 html.push( 'style="width:' + elementDefinition.width + '" ' );
264
265 html.push( '><input ' );
266
267 attributes[ 'aria-labelledby' ] = this._.labelId;
268 this._.required && ( attributes[ 'aria-required' ] = this._.required );
269 for ( var i in attributes )
270 html.push( i + '="' + attributes[ i ] + '" ' );
271 html.push( ' /></div>' );
272 return html.join( '' );
273 };
274 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
275 },
276
277 /**
278 * A text area with a label at the top or on the left.
279 *
280 * @class CKEDITOR.ui.dialog.textarea
281 * @extends CKEDITOR.ui.dialog.labeledElement
282 * @constructor Creates a textarea class instance.
283 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
284 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
285 *
286 * The element definition. Accepted fields:
287 *
288 * * `rows` (Optional) The number of rows displayed.
289 * Defaults to 5 if not defined.
290 * * `cols` (Optional) The number of cols displayed.
291 * Defaults to 20 if not defined. Usually overridden by skins.
292 * * `default` (Optional) The default value.
293 * * `validate` (Optional) The validation function.
294 *
295 * @param {Array} htmlList List of HTML code to output to.
296 */
297 textarea: function( dialog, elementDefinition, htmlList ) {
298 if ( arguments.length < 3 )
299 return;
300
301 initPrivateObject.call( this, elementDefinition );
302 var me = this,
303 domId = this._.inputId = CKEDITOR.tools.getNextId() + '_textarea',
304 attributes = {};
305
306 if ( elementDefinition.validate )
307 this.validate = elementDefinition.validate;
308
309 // Generates the essential attributes for the textarea tag.
310 attributes.rows = elementDefinition.rows || 5;
311 attributes.cols = elementDefinition.cols || 20;
312
313 attributes[ 'class' ] = 'cke_dialog_ui_input_textarea ' + ( elementDefinition[ 'class' ] || '' );
314
315 if ( typeof elementDefinition.inputStyle != 'undefined' )
316 attributes.style = elementDefinition.inputStyle;
317
318 if ( elementDefinition.dir )
319 attributes.dir = elementDefinition.dir;
320
321 if ( me.bidi ) {
322 dialog.on( 'load', function() {
323 me.getInputElement().on( 'keyup', toggleBidiKeyUpHandler );
324 }, me );
325 }
326
327 var innerHTML = function() {
328 attributes[ 'aria-labelledby' ] = this._.labelId;
329 this._.required && ( attributes[ 'aria-required' ] = this._.required );
330 var html = [ '<div class="cke_dialog_ui_input_textarea" role="presentation"><textarea id="', domId, '" ' ];
331 for ( var i in attributes )
332 html.push( i + '="' + CKEDITOR.tools.htmlEncode( attributes[ i ] ) + '" ' );
333 html.push( '>', CKEDITOR.tools.htmlEncode( me._[ 'default' ] ), '</textarea></div>' );
334 return html.join( '' );
335 };
336 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
337 },
338
339 /**
340 * A single checkbox with a label on the right.
341 *
342 * @class CKEDITOR.ui.dialog.checkbox
343 * @extends CKEDITOR.ui.dialog.uiElement
344 * @constructor Creates a checkbox class instance.
345 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
346 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
347 * The element definition. Accepted fields:
348 *
349 * * `checked` (Optional) Whether the checkbox is checked
350 * on instantiation. Defaults to `false`.
351 * * `validate` (Optional) The validation function.
352 * * `label` (Optional) The checkbox label.
353 *
354 * @param {Array} htmlList List of HTML code to output to.
355 */
356 checkbox: function( dialog, elementDefinition, htmlList ) {
357 if ( arguments.length < 3 )
358 return;
359
360 var _ = initPrivateObject.call( this, elementDefinition, { 'default': !!elementDefinition[ 'default' ] } );
361
362 if ( elementDefinition.validate )
363 this.validate = elementDefinition.validate;
364
365 var innerHTML = function() {
366 var myDefinition = CKEDITOR.tools.extend(
367 {},
368 elementDefinition,
369 {
370 id: elementDefinition.id ? elementDefinition.id + '_checkbox' : CKEDITOR.tools.getNextId() + '_checkbox'
371 },
372 true
373 ),
374 html = [];
375
376 var labelId = CKEDITOR.tools.getNextId() + '_label';
377 var attributes = { 'class': 'cke_dialog_ui_checkbox_input', type: 'checkbox', 'aria-labelledby': labelId };
378 cleanInnerDefinition( myDefinition );
379 if ( elementDefinition[ 'default' ] )
380 attributes.checked = 'checked';
381
382 if ( typeof myDefinition.inputStyle != 'undefined' )
383 myDefinition.style = myDefinition.inputStyle;
384
385 _.checkbox = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'input', null, attributes );
386 html.push(
387 ' <label id="',
388 labelId,
389 '" for="',
390 attributes.id,
391 '"' + ( elementDefinition.labelStyle ? ' style="' + elementDefinition.labelStyle + '"' : '' ) + '>',
392 CKEDITOR.tools.htmlEncode( elementDefinition.label ),
393 '</label>'
394 );
395 return html.join( '' );
396 };
397
398 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'span', null, null, innerHTML );
399 },
400
401 /**
402 * A group of radio buttons.
403 *
404 * @class CKEDITOR.ui.dialog.radio
405 * @extends CKEDITOR.ui.dialog.labeledElement
406 * @constructor Creates a radio class instance.
407 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
408 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
409 * The element definition. Accepted fields:
410 *
411 * * `default` (Required) The default value.
412 * * `validate` (Optional) The validation function.
413 * * `items` (Required) An array of options. Each option
414 * is a one- or two-item array of format `[ 'Description', 'Value' ]`. If `'Value'`
415 * is missing, then the value would be assumed to be the same as the description.
416 *
417 * @param {Array} htmlList List of HTML code to output to.
418 */
419 radio: function( dialog, elementDefinition, htmlList ) {
420 if ( arguments.length < 3 )
421 return;
422
423 initPrivateObject.call( this, elementDefinition );
424
425 if ( !this._[ 'default' ] )
426 this._[ 'default' ] = this._.initValue = elementDefinition.items[ 0 ][ 1 ];
427
428 if ( elementDefinition.validate )
429 this.validate = elementDefinition.validate;
430
431 var children = [],
432 me = this;
433
434 var innerHTML = function() {
435 var inputHtmlList = [],
436 html = [],
437 commonName = ( elementDefinition.id ? elementDefinition.id : CKEDITOR.tools.getNextId() ) + '_radio';
438
439 for ( var i = 0; i < elementDefinition.items.length; i++ ) {
440 var item = elementDefinition.items[ i ],
441 title = item[ 2 ] !== undefined ? item[ 2 ] : item[ 0 ],
442 value = item[ 1 ] !== undefined ? item[ 1 ] : item[ 0 ],
443 inputId = CKEDITOR.tools.getNextId() + '_radio_input',
444 labelId = inputId + '_label',
445
446 inputDefinition = CKEDITOR.tools.extend( {}, elementDefinition, {
447 id: inputId,
448 title: null,
449 type: null
450 }, true ),
451
452 labelDefinition = CKEDITOR.tools.extend( {}, inputDefinition, {
453 title: title
454 }, true ),
455
456 inputAttributes = {
457 type: 'radio',
458 'class': 'cke_dialog_ui_radio_input',
459 name: commonName,
460 value: value,
461 'aria-labelledby': labelId
462 },
463
464 inputHtml = [];
465
466 if ( me._[ 'default' ] == value )
467 inputAttributes.checked = 'checked';
468
469 cleanInnerDefinition( inputDefinition );
470 cleanInnerDefinition( labelDefinition );
471
472 if ( typeof inputDefinition.inputStyle != 'undefined' )
473 inputDefinition.style = inputDefinition.inputStyle;
474
475 // Make inputs of radio type focusable (#10866).
476 inputDefinition.keyboardFocusable = true;
477
478 children.push( new CKEDITOR.ui.dialog.uiElement( dialog, inputDefinition, inputHtml, 'input', null, inputAttributes ) );
479
480 inputHtml.push( ' ' );
481
482 new CKEDITOR.ui.dialog.uiElement( dialog, labelDefinition, inputHtml, 'label', null, {
483 id: labelId,
484 'for': inputAttributes.id
485 }, item[ 0 ] );
486
487 inputHtmlList.push( inputHtml.join( '' ) );
488 }
489
490 new CKEDITOR.ui.dialog.hbox( dialog, children, inputHtmlList, html );
491
492 return html.join( '' );
493 };
494
495 // Adding a role="radiogroup" to definition used for wrapper.
496 elementDefinition.role = 'radiogroup';
497 elementDefinition.includeLabel = true;
498
499 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
500 this._.children = children;
501 },
502
503 /**
504 * A button with a label inside.
505 *
506 * @class CKEDITOR.ui.dialog.button
507 * @extends CKEDITOR.ui.dialog.uiElement
508 * @constructor Creates a button class instance.
509 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
510 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
511 * The element definition. Accepted fields:
512 *
513 * * `label` (Required) The button label.
514 * * `disabled` (Optional) Set to `true` if you want the
515 * button to appear in the disabled state.
516 *
517 * @param {Array} htmlList List of HTML code to output to.
518 */
519 button: function( dialog, elementDefinition, htmlList ) {
520 if ( !arguments.length )
521 return;
522
523 if ( typeof elementDefinition == 'function' )
524 elementDefinition = elementDefinition( dialog.getParentEditor() );
525
526 initPrivateObject.call( this, elementDefinition, { disabled: elementDefinition.disabled || false } );
527
528 // Add OnClick event to this input.
529 CKEDITOR.event.implementOn( this );
530
531 var me = this;
532
533 // Register an event handler for processing button clicks.
534 dialog.on( 'load', function() {
535 var element = this.getElement();
536
537 ( function() {
538 element.on( 'click', function( evt ) {
539 me.click();
540 // #9958
541 evt.data.preventDefault();
542 } );
543
544 element.on( 'keydown', function( evt ) {
545 if ( evt.data.getKeystroke() in { 32: 1 } ) {
546 me.click();
547 evt.data.preventDefault();
548 }
549 } );
550 } )();
551
552 element.unselectable();
553 }, this );
554
555 var outerDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
556 delete outerDefinition.style;
557
558 var labelId = CKEDITOR.tools.getNextId() + '_label';
559 CKEDITOR.ui.dialog.uiElement.call( this, dialog, outerDefinition, htmlList, 'a', null, {
560 style: elementDefinition.style,
561 href: 'javascript:void(0)', // jshint ignore:line
562 title: elementDefinition.label,
563 hidefocus: 'true',
564 'class': elementDefinition[ 'class' ],
565 role: 'button',
566 'aria-labelledby': labelId
567 }, '<span id="' + labelId + '" class="cke_dialog_ui_button">' +
568 CKEDITOR.tools.htmlEncode( elementDefinition.label ) +
569 '</span>' );
570 },
571
572 /**
573 * A select box.
574 *
575 * @class CKEDITOR.ui.dialog.select
576 * @extends CKEDITOR.ui.dialog.uiElement
577 * @constructor Creates a button class instance.
578 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
579 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
580 * The element definition. Accepted fields:
581 *
582 * * `default` (Required) The default value.
583 * * `validate` (Optional) The validation function.
584 * * `items` (Required) An array of options. Each option
585 * is a one- or two-item array of format `[ 'Description', 'Value' ]`. If `'Value'`
586 * is missing, then the value would be assumed to be the same as the
587 * description.
588 * * `multiple` (Optional) Set this to `true` if you would like
589 * to have a multiple-choice select box.
590 * * `size` (Optional) The number of items to display in
591 * the select box.
592 *
593 * @param {Array} htmlList List of HTML code to output to.
594 */
595 select: function( dialog, elementDefinition, htmlList ) {
596 if ( arguments.length < 3 )
597 return;
598
599 var _ = initPrivateObject.call( this, elementDefinition );
600
601 if ( elementDefinition.validate )
602 this.validate = elementDefinition.validate;
603
604 _.inputId = CKEDITOR.tools.getNextId() + '_select';
605
606 var innerHTML = function() {
607 var myDefinition = CKEDITOR.tools.extend(
608 {},
609 elementDefinition,
610 {
611 id: ( elementDefinition.id ? elementDefinition.id + '_select' : CKEDITOR.tools.getNextId() + '_select' )
612 },
613 true
614 ),
615 html = [],
616 innerHTML = [],
617 attributes = { 'id': _.inputId, 'class': 'cke_dialog_ui_input_select', 'aria-labelledby': this._.labelId };
618
619 html.push( '<div class="cke_dialog_ui_input_', elementDefinition.type, '" role="presentation"' );
620 if ( elementDefinition.width )
621 html.push( 'style="width:' + elementDefinition.width + '" ' );
622 html.push( '>' );
623
624 // Add multiple and size attributes from element definition.
625 if ( elementDefinition.size !== undefined )
626 attributes.size = elementDefinition.size;
627 if ( elementDefinition.multiple !== undefined )
628 attributes.multiple = elementDefinition.multiple;
629
630 cleanInnerDefinition( myDefinition );
631 for ( var i = 0, item; i < elementDefinition.items.length && ( item = elementDefinition.items[ i ] ); i++ ) {
632 innerHTML.push( '<option value="', CKEDITOR.tools.htmlEncode( item[ 1 ] !== undefined ? item[ 1 ] : item[ 0 ] ).replace( /"/g, '&quot;' ), '" /> ', CKEDITOR.tools.htmlEncode( item[ 0 ] ) );
633 }
634
635 if ( typeof myDefinition.inputStyle != 'undefined' )
636 myDefinition.style = myDefinition.inputStyle;
637
638 _.select = new CKEDITOR.ui.dialog.uiElement( dialog, myDefinition, html, 'select', null, attributes, innerHTML.join( '' ) );
639
640 html.push( '</div>' );
641
642 return html.join( '' );
643 };
644
645 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
646 },
647
648 /**
649 * A file upload input.
650 *
651 * @class CKEDITOR.ui.dialog.file
652 * @extends CKEDITOR.ui.dialog.labeledElement
653 * @constructor Creates a file class instance.
654 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
655 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
656 * The element definition. Accepted fields:
657 *
658 * * `validate` (Optional) The validation function.
659 *
660 * @param {Array} htmlList List of HTML code to output to.
661 */
662 file: function( dialog, elementDefinition, htmlList ) {
663 if ( arguments.length < 3 )
664 return;
665
666 if ( elementDefinition[ 'default' ] === undefined )
667 elementDefinition[ 'default' ] = '';
668
669 var _ = CKEDITOR.tools.extend( initPrivateObject.call( this, elementDefinition ), { definition: elementDefinition, buttons: [] } );
670
671 if ( elementDefinition.validate )
672 this.validate = elementDefinition.validate;
673
674 /** @ignore */
675 var innerHTML = function() {
676 _.frameId = CKEDITOR.tools.getNextId() + '_fileInput';
677
678 var html = [
679 '<iframe' +
680 ' frameborder="0"' +
681 ' allowtransparency="0"' +
682 ' class="cke_dialog_ui_input_file"' +
683 ' role="presentation"' +
684 ' id="', _.frameId, '"' +
685 ' title="', elementDefinition.label, '"' +
686 ' src="javascript:void('
687 ];
688
689 // Support for custom document.domain on IE. (#10165)
690 html.push( CKEDITOR.env.ie ?
691 '(function(){' + encodeURIComponent(
692 'document.open();' +
693 '(' + CKEDITOR.tools.fixDomain + ')();' +
694 'document.close();'
695 ) + '})()'
696 :
697 '0'
698 );
699
700 html.push( ')"></iframe>' );
701
702 return html.join( '' );
703 };
704
705 // IE BUG: Parent container does not resize to contain the iframe automatically.
706 dialog.on( 'load', function() {
707 var iframe = CKEDITOR.document.getById( _.frameId ),
708 contentDiv = iframe.getParent();
709 contentDiv.addClass( 'cke_dialog_ui_input_file' );
710 } );
711
712 CKEDITOR.ui.dialog.labeledElement.call( this, dialog, elementDefinition, htmlList, innerHTML );
713 },
714
715 /**
716 * A button for submitting the file in a file upload input.
717 *
718 * @class CKEDITOR.ui.dialog.fileButton
719 * @extends CKEDITOR.ui.dialog.button
720 * @constructor Creates a fileButton class instance.
721 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
722 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
723 * The element definition. Accepted fields:
724 *
725 * * `for` (Required) The file input's page and element ID
726 * to associate with, in a two-item array format: `[ 'page_id', 'element_id' ]`.
727 * * `validate` (Optional) The validation function.
728 *
729 * @param {Array} htmlList List of HTML code to output to.
730 */
731 fileButton: function( dialog, elementDefinition, htmlList ) {
732 var me = this;
733 if ( arguments.length < 3 )
734 return;
735
736 initPrivateObject.call( this, elementDefinition );
737
738 if ( elementDefinition.validate )
739 this.validate = elementDefinition.validate;
740
741 var myDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
742 var onClick = myDefinition.onClick;
743 myDefinition.className = ( myDefinition.className ? myDefinition.className + ' ' : '' ) + 'cke_dialog_ui_button';
744 myDefinition.onClick = function( evt ) {
745 var target = elementDefinition[ 'for' ]; // [ pageId, elementId ]
746 if ( !onClick || onClick.call( this, evt ) !== false ) {
747 dialog.getContentElement( target[ 0 ], target[ 1 ] ).submit();
748 this.disable();
749 }
750 };
751
752 dialog.on( 'load', function() {
753 dialog.getContentElement( elementDefinition[ 'for' ][ 0 ], elementDefinition[ 'for' ][ 1 ] )._.buttons.push( me );
754 } );
755
756 CKEDITOR.ui.dialog.button.call( this, dialog, myDefinition, htmlList );
757 },
758
759 html: ( function() {
760 var myHtmlRe = /^\s*<[\w:]+\s+([^>]*)?>/,
761 theirHtmlRe = /^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,
762 emptyTagRe = /\/$/;
763 /**
764 * A dialog window element made from raw HTML code.
765 *
766 * @class CKEDITOR.ui.dialog.html
767 * @extends CKEDITOR.ui.dialog.uiElement
768 * @constructor Creates a html class instance.
769 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
770 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition Element definition.
771 * Accepted fields:
772 *
773 * * `html` (Required) HTML code of this element.
774 *
775 * @param {Array} htmlList List of HTML code to be added to the dialog's content area.
776 */
777 return function( dialog, elementDefinition, htmlList ) {
778 if ( arguments.length < 3 )
779 return;
780
781 var myHtmlList = [],
782 myHtml,
783 theirHtml = elementDefinition.html,
784 myMatch, theirMatch;
785
786 // If the HTML input doesn't contain any tags at the beginning, add a <span> tag around it.
787 if ( theirHtml.charAt( 0 ) != '<' )
788 theirHtml = '<span>' + theirHtml + '</span>';
789
790 // Look for focus function in definition.
791 var focus = elementDefinition.focus;
792 if ( focus ) {
793 var oldFocus = this.focus;
794 this.focus = function() {
795 ( typeof focus == 'function' ? focus : oldFocus ).call( this );
796 this.fire( 'focus' );
797 };
798 if ( elementDefinition.isFocusable ) {
799 var oldIsFocusable = this.isFocusable;
800 this.isFocusable = oldIsFocusable;
801 }
802 this.keyboardFocusable = true;
803 }
804
805 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, myHtmlList, 'span', null, null, '' );
806
807 // Append the attributes created by the uiElement call to the real HTML.
808 myHtml = myHtmlList.join( '' );
809 myMatch = myHtml.match( myHtmlRe );
810 theirMatch = theirHtml.match( theirHtmlRe ) || [ '', '', '' ];
811
812 if ( emptyTagRe.test( theirMatch[ 1 ] ) ) {
813 theirMatch[ 1 ] = theirMatch[ 1 ].slice( 0, -1 );
814 theirMatch[ 2 ] = '/' + theirMatch[ 2 ];
815 }
816
817 htmlList.push( [ theirMatch[ 1 ], ' ', myMatch[ 1 ] || '', theirMatch[ 2 ] ].join( '' ) );
818 };
819 } )(),
820
821 /**
822 * Form fieldset for grouping dialog UI elements.
823 *
824 * @class CKEDITOR.ui.dialog.fieldset
825 * @extends CKEDITOR.ui.dialog.uiElement
826 * @constructor Creates a fieldset class instance.
827 * @param {CKEDITOR.dialog} dialog Parent dialog window object.
828 * @param {Array} childObjList
829 * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
830 * @param {Array} childHtmlList Array of HTML code that corresponds to the HTML output of all the
831 * objects in childObjList.
832 * @param {Array} htmlList Array of HTML code that this element will output to.
833 * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
834 * The element definition. Accepted fields:
835 *
836 * * `label` (Optional) The legend of the this fieldset.
837 * * `children` (Required) An array of dialog window field definitions which will be grouped inside this fieldset.
838 *
839 */
840 fieldset: function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) {
841 var legendLabel = elementDefinition.label;
842 /** @ignore */
843 var innerHTML = function() {
844 var html = [];
845 legendLabel && html.push( '<legend' +
846 ( elementDefinition.labelStyle ? ' style="' + elementDefinition.labelStyle + '"' : '' ) +
847 '>' + legendLabel + '</legend>' );
848 for ( var i = 0; i < childHtmlList.length; i++ )
849 html.push( childHtmlList[ i ] );
850 return html.join( '' );
851 };
852
853 this._ = { children: childObjList };
854 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'fieldset', null, null, innerHTML );
855 }
856
857 }, true );
858
859 CKEDITOR.ui.dialog.html.prototype = new CKEDITOR.ui.dialog.uiElement();
860
861 /** @class CKEDITOR.ui.dialog.labeledElement */
862 CKEDITOR.ui.dialog.labeledElement.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
863 /**
864 * Sets the label text of the element.
865 *
866 * @param {String} label The new label text.
867 * @returns {CKEDITOR.ui.dialog.labeledElement} The current labeled element.
868 */
869 setLabel: function( label ) {
870 var node = CKEDITOR.document.getById( this._.labelId );
871 if ( node.getChildCount() < 1 )
872 ( new CKEDITOR.dom.text( label, CKEDITOR.document ) ).appendTo( node );
873 else
874 node.getChild( 0 ).$.nodeValue = label;
875 return this;
876 },
877
878 /**
879 * Retrieves the current label text of the elment.
880 *
881 * @returns {String} The current label text.
882 */
883 getLabel: function() {
884 var node = CKEDITOR.document.getById( this._.labelId );
885 if ( !node || node.getChildCount() < 1 )
886 return '';
887 else
888 return node.getChild( 0 ).getText();
889 },
890
891 /**
892 * Defines the `onChange` event for UI element definitions.
893 * @property {Object}
894 */
895 eventProcessors: commonEventProcessors
896 }, true );
897
898 /** @class CKEDITOR.ui.dialog.button */
899 CKEDITOR.ui.dialog.button.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
900 /**
901 * Simulates a click to the button.
902 *
903 * @returns {Object} Return value of the `click` event.
904 */
905 click: function() {
906 if ( !this._.disabled )
907 return this.fire( 'click', { dialog: this._.dialog } );
908 return false;
909 },
910
911 /**
912 * Enables the button.
913 */
914 enable: function() {
915 this._.disabled = false;
916 var element = this.getElement();
917 element && element.removeClass( 'cke_disabled' );
918 },
919
920 /**
921 * Disables the button.
922 */
923 disable: function() {
924 this._.disabled = true;
925 this.getElement().addClass( 'cke_disabled' );
926 },
927
928 /**
929 * Checks whether a field is visible.
930 *
931 * @returns {Boolean}
932 */
933 isVisible: function() {
934 return this.getElement().getFirst().isVisible();
935 },
936
937 /**
938 * Checks whether a field is enabled. Fields can be disabled by using the
939 * {@link #disable} method and enabled by using the {@link #enable} method.
940 *
941 * @returns {Boolean}
942 */
943 isEnabled: function() {
944 return !this._.disabled;
945 },
946
947 /**
948 * Defines the `onChange` event and `onClick` for button element definitions.
949 *
950 * @property {Object}
951 */
952 eventProcessors: CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors, {
953 onClick: function( dialog, func ) {
954 this.on( 'click', function() {
955 func.apply( this, arguments );
956 } );
957 }
958 }, true ),
959
960 /**
961 * Handler for the element's access key up event. Simulates a click to
962 * the button.
963 */
964 accessKeyUp: function() {
965 this.click();
966 },
967
968 /**
969 * Handler for the element's access key down event. Simulates a mouse
970 * down to the button.
971 */
972 accessKeyDown: function() {
973 this.focus();
974 },
975
976 keyboardFocusable: true
977 }, true );
978
979 /** @class CKEDITOR.ui.dialog.textInput */
980 CKEDITOR.ui.dialog.textInput.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement(), {
981 /**
982 * Gets the text input DOM element under this UI object.
983 *
984 * @returns {CKEDITOR.dom.element} The DOM element of the text input.
985 */
986 getInputElement: function() {
987 return CKEDITOR.document.getById( this._.inputId );
988 },
989
990 /**
991 * Puts focus into the text input.
992 */
993 focus: function() {
994 var me = this.selectParentTab();
995
996 // GECKO BUG: setTimeout() is needed to workaround invisible selections.
997 setTimeout( function() {
998 var element = me.getInputElement();
999 element && element.$.focus();
1000 }, 0 );
1001 },
1002
1003 /**
1004 * Selects all the text in the text input.
1005 */
1006 select: function() {
1007 var me = this.selectParentTab();
1008
1009 // GECKO BUG: setTimeout() is needed to workaround invisible selections.
1010 setTimeout( function() {
1011 var e = me.getInputElement();
1012 if ( e ) {
1013 e.$.focus();
1014 e.$.select();
1015 }
1016 }, 0 );
1017 },
1018
1019 /**
1020 * Handler for the text input's access key up event. Makes a `select()`
1021 * call to the text input.
1022 */
1023 accessKeyUp: function() {
1024 this.select();
1025 },
1026
1027 /**
1028 * Sets the value of this text input object.
1029 *
1030 * uiElement.setValue( 'Blamo' );
1031 *
1032 * @param {Object} value The new value.
1033 * @returns {CKEDITOR.ui.dialog.textInput} The current UI element.
1034 */
1035 setValue: function( value ) {
1036 if ( this.bidi ) {
1037 var marker = value && value.charAt( 0 ),
1038 dir = ( marker == '\u202A' ? 'ltr' : marker == '\u202B' ? 'rtl' : null );
1039
1040 if ( dir ) {
1041 value = value.slice( 1 );
1042 }
1043
1044 // Set the marker or reset it (if dir==null).
1045 this.setDirectionMarker( dir );
1046 }
1047
1048 if ( !value ) {
1049 value = '';
1050 }
1051
1052 return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply( this, arguments );
1053 },
1054
1055 /**
1056 * Gets the value of this text input object.
1057 *
1058 * @returns {String} The value.
1059 */
1060 getValue: function() {
1061 var value = CKEDITOR.ui.dialog.uiElement.prototype.getValue.call( this );
1062
1063 if ( this.bidi && value ) {
1064 var dir = this.getDirectionMarker();
1065 if ( dir ) {
1066 value = ( dir == 'ltr' ? '\u202A' : '\u202B' ) + value;
1067 }
1068 }
1069
1070 return value;
1071 },
1072
1073 /**
1074 * Sets the text direction marker and the `dir` attribute of the input element.
1075 *
1076 * @since 4.5
1077 * @param {String} dir The text direction. Pass `null` to reset.
1078 */
1079 setDirectionMarker: function( dir ) {
1080 var inputElement = this.getInputElement();
1081
1082 if ( dir ) {
1083 inputElement.setAttributes( {
1084 dir: dir,
1085 'data-cke-dir-marker': dir
1086 } );
1087 // Don't remove the dir attribute if this field hasn't got the marker,
1088 // because the dir attribute could be set independently.
1089 } else if ( this.getDirectionMarker() ) {
1090 inputElement.removeAttributes( [ 'dir', 'data-cke-dir-marker' ] );
1091 }
1092 },
1093
1094 /**
1095 * Gets the value of the text direction marker.
1096 *
1097 * @since 4.5
1098 * @returns {String} `'ltr'`, `'rtl'` or `null` if the marker is not set.
1099 */
1100 getDirectionMarker: function() {
1101 return this.getInputElement().data( 'cke-dir-marker' );
1102 },
1103
1104 keyboardFocusable: true
1105 }, commonPrototype, true );
1106
1107 CKEDITOR.ui.dialog.textarea.prototype = new CKEDITOR.ui.dialog.textInput();
1108
1109 /** @class CKEDITOR.ui.dialog.select */
1110 CKEDITOR.ui.dialog.select.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement(), {
1111 /**
1112 * Gets the DOM element of the select box.
1113 *
1114 * @returns {CKEDITOR.dom.element} The `<select>` element of this UI element.
1115 */
1116 getInputElement: function() {
1117 return this._.select.getElement();
1118 },
1119
1120 /**
1121 * Adds an option to the select box.
1122 *
1123 * @param {String} label Option label.
1124 * @param {String} value (Optional) Option value, if not defined it will be
1125 * assumed to be the same as the label.
1126 * @param {Number} index (Optional) Position of the option to be inserted
1127 * to. If not defined, the new option will be inserted to the end of list.
1128 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1129 */
1130 add: function( label, value, index ) {
1131 var option = new CKEDITOR.dom.element( 'option', this.getDialog().getParentEditor().document ),
1132 selectElement = this.getInputElement().$;
1133 option.$.text = label;
1134 option.$.value = ( value === undefined || value === null ) ? label : value;
1135 if ( index === undefined || index === null ) {
1136 if ( CKEDITOR.env.ie ) {
1137 selectElement.add( option.$ );
1138 } else {
1139 selectElement.add( option.$, null );
1140 }
1141 } else {
1142 selectElement.add( option.$, index );
1143 }
1144 return this;
1145 },
1146
1147 /**
1148 * Removes an option from the selection list.
1149 *
1150 * @param {Number} index Index of the option to be removed.
1151 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1152 */
1153 remove: function( index ) {
1154 var selectElement = this.getInputElement().$;
1155 selectElement.remove( index );
1156 return this;
1157 },
1158
1159 /**
1160 * Clears all options out of the selection list.
1161 *
1162 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
1163 */
1164 clear: function() {
1165 var selectElement = this.getInputElement().$;
1166 while ( selectElement.length > 0 )
1167 selectElement.remove( 0 );
1168 return this;
1169 },
1170
1171 keyboardFocusable: true
1172 }, commonPrototype, true );
1173
1174 /** @class CKEDITOR.ui.dialog.checkbox */
1175 CKEDITOR.ui.dialog.checkbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
1176 /**
1177 * Gets the checkbox DOM element.
1178 *
1179 * @returns {CKEDITOR.dom.element} The DOM element of the checkbox.
1180 */
1181 getInputElement: function() {
1182 return this._.checkbox.getElement();
1183 },
1184
1185 /**
1186 * Sets the state of the checkbox.
1187 *
1188 * @param {Boolean} checked `true` to tick the checkbox, `false` to untick it.
1189 * @param {Boolean} noChangeEvent Internal commit, to supress `change` event on this element.
1190 */
1191 setValue: function( checked, noChangeEvent ) {
1192 this.getInputElement().$.checked = checked;
1193 !noChangeEvent && this.fire( 'change', { value: checked } );
1194 },
1195
1196 /**
1197 * Gets the state of the checkbox.
1198 *
1199 * @returns {Boolean} `true` means that the checkbox is ticked, `false` means it is not ticked.
1200 */
1201 getValue: function() {
1202 return this.getInputElement().$.checked;
1203 },
1204
1205 /**
1206 * Handler for the access key up event. Toggles the checkbox.
1207 */
1208 accessKeyUp: function() {
1209 this.setValue( !this.getValue() );
1210 },
1211
1212 /**
1213 * Defines the `onChange` event for UI element definitions.
1214 *
1215 * @property {Object}
1216 */
1217 eventProcessors: {
1218 onChange: function( dialog, func ) {
1219 if ( !CKEDITOR.env.ie || ( CKEDITOR.env.version > 8 ) )
1220 return commonEventProcessors.onChange.apply( this, arguments );
1221 else {
1222 dialog.on( 'load', function() {
1223 var element = this._.checkbox.getElement();
1224 element.on( 'propertychange', function( evt ) {
1225 evt = evt.data.$;
1226 if ( evt.propertyName == 'checked' )
1227 this.fire( 'change', { value: element.$.checked } );
1228 }, this );
1229 }, this );
1230 this.on( 'change', func );
1231 }
1232 return null;
1233 }
1234 },
1235
1236 keyboardFocusable: true
1237 }, commonPrototype, true );
1238
1239 /** @class CKEDITOR.ui.dialog.radio */
1240 CKEDITOR.ui.dialog.radio.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
1241 /**
1242 * Selects one of the radio buttons in this button group.
1243 *
1244 * @param {String} value The value of the button to be chcked.
1245 * @param {Boolean} noChangeEvent Internal commit, to supress the `change` event on this element.
1246 */
1247 setValue: function( value, noChangeEvent ) {
1248 var children = this._.children,
1249 item;
1250 for ( var i = 0;
1251 ( i < children.length ) && ( item = children[ i ] ); i++ )
1252 item.getElement().$.checked = ( item.getValue() == value );
1253 !noChangeEvent && this.fire( 'change', { value: value } );
1254 },
1255
1256 /**
1257 * Gets the value of the currently selected radio button.
1258 *
1259 * @returns {String} The currently selected button's value.
1260 */
1261 getValue: function() {
1262 var children = this._.children;
1263 for ( var i = 0; i < children.length; i++ ) {
1264 if ( children[ i ].getElement().$.checked )
1265 return children[ i ].getValue();
1266 }
1267 return null;
1268 },
1269
1270 /**
1271 * Handler for the access key up event. Focuses the currently
1272 * selected radio button, or the first radio button if none is selected.
1273 */
1274 accessKeyUp: function() {
1275 var children = this._.children,
1276 i;
1277 for ( i = 0; i < children.length; i++ ) {
1278 if ( children[ i ].getElement().$.checked ) {
1279 children[ i ].getElement().focus();
1280 return;
1281 }
1282 }
1283 children[ 0 ].getElement().focus();
1284 },
1285
1286 /**
1287 * Defines the `onChange` event for UI element definitions.
1288 *
1289 * @property {Object}
1290 */
1291 eventProcessors: {
1292 onChange: function( dialog, func ) {
1293 if ( !CKEDITOR.env.ie || ( CKEDITOR.env.version > 8 ) )
1294 return commonEventProcessors.onChange.apply( this, arguments );
1295 else {
1296 dialog.on( 'load', function() {
1297 var children = this._.children,
1298 me = this;
1299 for ( var i = 0; i < children.length; i++ ) {
1300 var element = children[ i ].getElement();
1301 element.on( 'propertychange', function( evt ) {
1302 evt = evt.data.$;
1303 if ( evt.propertyName == 'checked' && this.$.checked )
1304 me.fire( 'change', { value: this.getAttribute( 'value' ) } );
1305 } );
1306 }
1307 }, this );
1308 this.on( 'change', func );
1309 }
1310 return null;
1311 }
1312 }
1313 }, commonPrototype, true );
1314
1315 /** @class CKEDITOR.ui.dialog.file */
1316 CKEDITOR.ui.dialog.file.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement(), commonPrototype, {
1317 /**
1318 * Gets the `<input>` element of this file input.
1319 *
1320 * @returns {CKEDITOR.dom.element} The file input element.
1321 */
1322 getInputElement: function() {
1323 var frameDocument = CKEDITOR.document.getById( this._.frameId ).getFrameDocument();
1324 return frameDocument.$.forms.length > 0 ? new CKEDITOR.dom.element( frameDocument.$.forms[ 0 ].elements[ 0 ] ) : this.getElement();
1325 },
1326
1327 /**
1328 * Uploads the file in the file input.
1329 *
1330 * @returns {CKEDITOR.ui.dialog.file} This object.
1331 */
1332 submit: function() {
1333 this.getInputElement().getParent().$.submit();
1334 return this;
1335 },
1336
1337 /**
1338 * Gets the action assigned to the form.
1339 *
1340 * @returns {String} The value of the action.
1341 */
1342 getAction: function() {
1343 return this.getInputElement().getParent().$.action;
1344 },
1345
1346 /**
1347 * The events must be applied to the inner input element, and
1348 * this must be done when the iframe and form have been loaded.
1349 */
1350 registerEvents: function( definition ) {
1351 var regex = /^on([A-Z]\w+)/,
1352 match;
1353
1354 var registerDomEvent = function( uiElement, dialog, eventName, func ) {
1355 uiElement.on( 'formLoaded', function() {
1356 uiElement.getInputElement().on( eventName, func, uiElement );
1357 } );
1358 };
1359
1360 for ( var i in definition ) {
1361 if ( !( match = i.match( regex ) ) )
1362 continue;
1363
1364 if ( this.eventProcessors[ i ] )
1365 this.eventProcessors[ i ].call( this, this._.dialog, definition[ i ] );
1366 else
1367 registerDomEvent( this, this._.dialog, match[ 1 ].toLowerCase(), definition[ i ] );
1368 }
1369
1370 return this;
1371 },
1372
1373 /**
1374 * Redraws the file input and resets the file path in the file input.
1375 * The redrawing logic is necessary because non-IE browsers tend to clear
1376 * the `<iframe>` containing the file input after closing the dialog window.
1377 */
1378 reset: function() {
1379 var _ = this._,
1380 frameElement = CKEDITOR.document.getById( _.frameId ),
1381 frameDocument = frameElement.getFrameDocument(),
1382 elementDefinition = _.definition,
1383 buttons = _.buttons,
1384 callNumber = this.formLoadedNumber,
1385 unloadNumber = this.formUnloadNumber,
1386 langDir = _.dialog._.editor.lang.dir,
1387 langCode = _.dialog._.editor.langCode;
1388
1389 // The callback function for the iframe, but we must call tools.addFunction only once
1390 // so we store the function number in this.formLoadedNumber
1391 if ( !callNumber ) {
1392 callNumber = this.formLoadedNumber = CKEDITOR.tools.addFunction( function() {
1393 // Now we can apply the events to the input type=file
1394 this.fire( 'formLoaded' );
1395 }, this );
1396
1397 // Remove listeners attached to the content of the iframe (the file input)
1398 unloadNumber = this.formUnloadNumber = CKEDITOR.tools.addFunction( function() {
1399 this.getInputElement().clearCustomData();
1400 }, this );
1401
1402 this.getDialog()._.editor.on( 'destroy', function() {
1403 CKEDITOR.tools.removeFunction( callNumber );
1404 CKEDITOR.tools.removeFunction( unloadNumber );
1405 } );
1406 }
1407
1408 function generateFormField() {
1409 frameDocument.$.open();
1410
1411 var size = '';
1412 if ( elementDefinition.size )
1413 size = elementDefinition.size - ( CKEDITOR.env.ie ? 7 : 0 ); // "Browse" button is bigger in IE.
1414
1415 var inputId = _.frameId + '_input';
1416
1417 frameDocument.$.write( [
1418 '<html dir="' + langDir + '" lang="' + langCode + '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',
1419 '<form enctype="multipart/form-data" method="POST" dir="' + langDir + '" lang="' + langCode + '" action="',
1420 CKEDITOR.tools.htmlEncode( elementDefinition.action ),
1421 '">',
1422 // Replicate the field label inside of iframe.
1423 '<label id="', _.labelId, '" for="', inputId, '" style="display:none">',
1424 CKEDITOR.tools.htmlEncode( elementDefinition.label ),
1425 '</label>',
1426 // Set width to make sure that input is not clipped by the iframe (#11253).
1427 '<input style="width:100%" id="', inputId, '" aria-labelledby="', _.labelId, '" type="file" name="',
1428 CKEDITOR.tools.htmlEncode( elementDefinition.id || 'cke_upload' ),
1429 '" size="',
1430 CKEDITOR.tools.htmlEncode( size > 0 ? size : '' ),
1431 '" />',
1432 '</form>',
1433 '</body></html>',
1434 '<script>',
1435 // Support for custom document.domain in IE.
1436 CKEDITOR.env.ie ? '(' + CKEDITOR.tools.fixDomain + ')();' : '',
1437
1438 'window.parent.CKEDITOR.tools.callFunction(' + callNumber + ');',
1439 'window.onbeforeunload = function() {window.parent.CKEDITOR.tools.callFunction(' + unloadNumber + ')}',
1440 '</script>'
1441 ].join( '' ) );
1442
1443 frameDocument.$.close();
1444
1445 for ( var i = 0; i < buttons.length; i++ )
1446 buttons[ i ].enable();
1447 }
1448
1449 // #3465: Wait for the browser to finish rendering the dialog first.
1450 if ( CKEDITOR.env.gecko )
1451 setTimeout( generateFormField, 500 );
1452 else
1453 generateFormField();
1454 },
1455
1456 getValue: function() {
1457 return this.getInputElement().$.value || '';
1458 },
1459
1460 /**
1461 * The default value of input `type="file"` is an empty string, but during the initialization
1462 * of this UI element, the iframe still is not ready so it cannot be read from that object.
1463 * Setting it manually prevents later issues with the current value (`''`) being different
1464 * than the initial value (undefined as it asked for `.value` of a div).
1465 */
1466 setInitValue: function() {
1467 this._.initValue = '';
1468 },
1469
1470 /**
1471 * Defines the `onChange` event for UI element definitions.
1472 *
1473 * @property {Object}
1474 */
1475 eventProcessors: {
1476 onChange: function( dialog, func ) {
1477 // If this method is called several times (I'm not sure about how this can happen but the default
1478 // onChange processor includes this protection)
1479 // In order to reapply to the new element, the property is deleted at the beggining of the registerEvents method
1480 if ( !this._.domOnChangeRegistered ) {
1481 // By listening for the formLoaded event, this handler will get reapplied when a new
1482 // form is created
1483 this.on( 'formLoaded', function() {
1484 this.getInputElement().on( 'change', function() {
1485 this.fire( 'change', { value: this.getValue() } );
1486 }, this );
1487 }, this );
1488 this._.domOnChangeRegistered = true;
1489 }
1490
1491 this.on( 'change', func );
1492 }
1493 },
1494
1495 keyboardFocusable: true
1496 }, true );
1497
1498 CKEDITOR.ui.dialog.fileButton.prototype = new CKEDITOR.ui.dialog.button();
1499
1500 CKEDITOR.ui.dialog.fieldset.prototype = CKEDITOR.tools.clone( CKEDITOR.ui.dialog.hbox.prototype );
1501
1502 CKEDITOR.dialog.addUIElement( 'text', textBuilder );
1503 CKEDITOR.dialog.addUIElement( 'password', textBuilder );
1504 CKEDITOR.dialog.addUIElement( 'textarea', commonBuilder );
1505 CKEDITOR.dialog.addUIElement( 'checkbox', commonBuilder );
1506 CKEDITOR.dialog.addUIElement( 'radio', commonBuilder );
1507 CKEDITOR.dialog.addUIElement( 'button', commonBuilder );
1508 CKEDITOR.dialog.addUIElement( 'select', commonBuilder );
1509 CKEDITOR.dialog.addUIElement( 'file', commonBuilder );
1510 CKEDITOR.dialog.addUIElement( 'fileButton', commonBuilder );
1511 CKEDITOR.dialog.addUIElement( 'html', commonBuilder );
1512 CKEDITOR.dialog.addUIElement( 'fieldset', containerBuilder );
1513 }
1514} );
1515
1516/**
1517 * Fired when the value of the uiElement is changed.
1518 *
1519 * @event change
1520 * @member CKEDITOR.ui.dialog.uiElement
1521 */
1522
1523/**
1524 * Fired when the inner frame created by the element is ready.
1525 * Each time the button is used or the dialog window is loaded, a new
1526 * form might be created.
1527 *
1528 * @event formLoaded
1529 * @member CKEDITOR.ui.dialog.fileButton
1530 */
diff --git a/sources/plugins/elementspath/lang/af.js b/sources/plugins/elementspath/lang/af.js
new file mode 100644
index 0000000..c07fa39
--- /dev/null
+++ b/sources/plugins/elementspath/lang/af.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'af', {
6 eleLabel: 'Elemente-pad',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/ar.js b/sources/plugins/elementspath/lang/ar.js
new file mode 100644
index 0000000..fa0147c
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ar.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ar', {
6 eleLabel: 'مسار العنصر',
7 eleTitle: 'عنصر 1%'
8} );
diff --git a/sources/plugins/elementspath/lang/az.js b/sources/plugins/elementspath/lang/az.js
new file mode 100644
index 0000000..c344c1e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/az.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'az', {
6 eleLabel: 'Elementin izləri',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/bg.js b/sources/plugins/elementspath/lang/bg.js
new file mode 100644
index 0000000..07b990b
--- /dev/null
+++ b/sources/plugins/elementspath/lang/bg.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'bg', {
6 eleLabel: 'Път за елементите',
7 eleTitle: '%1 елемент'
8} );
diff --git a/sources/plugins/elementspath/lang/bn.js b/sources/plugins/elementspath/lang/bn.js
new file mode 100644
index 0000000..493caad
--- /dev/null
+++ b/sources/plugins/elementspath/lang/bn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'bn', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/bs.js b/sources/plugins/elementspath/lang/bs.js
new file mode 100644
index 0000000..f432973
--- /dev/null
+++ b/sources/plugins/elementspath/lang/bs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'bs', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/ca.js b/sources/plugins/elementspath/lang/ca.js
new file mode 100644
index 0000000..d9573c2
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ca', {
6 eleLabel: 'Ruta dels elements',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/cs.js b/sources/plugins/elementspath/lang/cs.js
new file mode 100644
index 0000000..427e5bf
--- /dev/null
+++ b/sources/plugins/elementspath/lang/cs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'cs', {
6 eleLabel: 'Cesta objektu',
7 eleTitle: '%1 objekt'
8} );
diff --git a/sources/plugins/elementspath/lang/cy.js b/sources/plugins/elementspath/lang/cy.js
new file mode 100644
index 0000000..5c9c77d
--- /dev/null
+++ b/sources/plugins/elementspath/lang/cy.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'cy', {
6 eleLabel: 'Llwybr elfennau',
7 eleTitle: 'Elfen %1'
8} );
diff --git a/sources/plugins/elementspath/lang/da.js b/sources/plugins/elementspath/lang/da.js
new file mode 100644
index 0000000..3cd404e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/da.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'da', {
6 eleLabel: 'Sti på element',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/de-ch.js b/sources/plugins/elementspath/lang/de-ch.js
new file mode 100644
index 0000000..ad13b78
--- /dev/null
+++ b/sources/plugins/elementspath/lang/de-ch.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'de-ch', {
6 eleLabel: 'Elementepfad',
7 eleTitle: '%1 Element'
8} );
diff --git a/sources/plugins/elementspath/lang/de.js b/sources/plugins/elementspath/lang/de.js
new file mode 100644
index 0000000..5072d3b
--- /dev/null
+++ b/sources/plugins/elementspath/lang/de.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'de', {
6 eleLabel: 'Elementepfad',
7 eleTitle: '%1 Element'
8} );
diff --git a/sources/plugins/elementspath/lang/el.js b/sources/plugins/elementspath/lang/el.js
new file mode 100644
index 0000000..00a4812
--- /dev/null
+++ b/sources/plugins/elementspath/lang/el.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'el', {
6 eleLabel: 'Διαδρομή Στοιχείων',
7 eleTitle: 'Στοιχείο %1'
8} );
diff --git a/sources/plugins/elementspath/lang/en-au.js b/sources/plugins/elementspath/lang/en-au.js
new file mode 100644
index 0000000..60a838a
--- /dev/null
+++ b/sources/plugins/elementspath/lang/en-au.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'en-au', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/en-ca.js b/sources/plugins/elementspath/lang/en-ca.js
new file mode 100644
index 0000000..8acb5c4
--- /dev/null
+++ b/sources/plugins/elementspath/lang/en-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'en-ca', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/en-gb.js b/sources/plugins/elementspath/lang/en-gb.js
new file mode 100644
index 0000000..86fb78e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/en-gb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'en-gb', {
6 eleLabel: 'Elements path',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/en.js b/sources/plugins/elementspath/lang/en.js
new file mode 100644
index 0000000..96feac7
--- /dev/null
+++ b/sources/plugins/elementspath/lang/en.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'en', {
6 eleLabel: 'Elements path',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/eo.js b/sources/plugins/elementspath/lang/eo.js
new file mode 100644
index 0000000..20e0320
--- /dev/null
+++ b/sources/plugins/elementspath/lang/eo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'eo', {
6 eleLabel: 'Vojo al Elementoj',
7 eleTitle: '%1 elementoj'
8} );
diff --git a/sources/plugins/elementspath/lang/es.js b/sources/plugins/elementspath/lang/es.js
new file mode 100644
index 0000000..815a18d
--- /dev/null
+++ b/sources/plugins/elementspath/lang/es.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'es', {
6 eleLabel: 'Ruta de los elementos',
7 eleTitle: '%1 elemento'
8} );
diff --git a/sources/plugins/elementspath/lang/et.js b/sources/plugins/elementspath/lang/et.js
new file mode 100644
index 0000000..ab62d21
--- /dev/null
+++ b/sources/plugins/elementspath/lang/et.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'et', {
6 eleLabel: 'Elementide asukoht',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/eu.js b/sources/plugins/elementspath/lang/eu.js
new file mode 100644
index 0000000..f3d0bb9
--- /dev/null
+++ b/sources/plugins/elementspath/lang/eu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'eu', {
6 eleLabel: 'Elementuen bidea',
7 eleTitle: '%1 elementua'
8} );
diff --git a/sources/plugins/elementspath/lang/fa.js b/sources/plugins/elementspath/lang/fa.js
new file mode 100644
index 0000000..faeb18e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/fa.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'fa', {
6 eleLabel: 'مسیر عناصر',
7 eleTitle: '%1 عنصر'
8} );
diff --git a/sources/plugins/elementspath/lang/fi.js b/sources/plugins/elementspath/lang/fi.js
new file mode 100644
index 0000000..5f975cf
--- /dev/null
+++ b/sources/plugins/elementspath/lang/fi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'fi', {
6 eleLabel: 'Elementin polku',
7 eleTitle: '%1 elementti'
8} );
diff --git a/sources/plugins/elementspath/lang/fo.js b/sources/plugins/elementspath/lang/fo.js
new file mode 100644
index 0000000..0935eb9
--- /dev/null
+++ b/sources/plugins/elementspath/lang/fo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'fo', {
6 eleLabel: 'Slóð til elementir',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/fr-ca.js b/sources/plugins/elementspath/lang/fr-ca.js
new file mode 100644
index 0000000..0b8796c
--- /dev/null
+++ b/sources/plugins/elementspath/lang/fr-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'fr-ca', {
6 eleLabel: 'Chemin d\'éléments',
7 eleTitle: 'element %1'
8} );
diff --git a/sources/plugins/elementspath/lang/fr.js b/sources/plugins/elementspath/lang/fr.js
new file mode 100644
index 0000000..78488bb
--- /dev/null
+++ b/sources/plugins/elementspath/lang/fr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'fr', {
6 eleLabel: 'Chemin des éléments',
7 eleTitle: 'Élément %1'
8} );
diff --git a/sources/plugins/elementspath/lang/gl.js b/sources/plugins/elementspath/lang/gl.js
new file mode 100644
index 0000000..7dfc457
--- /dev/null
+++ b/sources/plugins/elementspath/lang/gl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'gl', {
6 eleLabel: 'Ruta dos elementos',
7 eleTitle: 'Elemento %1'
8} );
diff --git a/sources/plugins/elementspath/lang/gu.js b/sources/plugins/elementspath/lang/gu.js
new file mode 100644
index 0000000..d6f4f40
--- /dev/null
+++ b/sources/plugins/elementspath/lang/gu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'gu', {
6 eleLabel: 'એલીમેન્ટ્સ નો ',
7 eleTitle: 'એલીમેન્ટ %1'
8} );
diff --git a/sources/plugins/elementspath/lang/he.js b/sources/plugins/elementspath/lang/he.js
new file mode 100644
index 0000000..3e2773f
--- /dev/null
+++ b/sources/plugins/elementspath/lang/he.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'he', {
6 eleLabel: 'עץ האלמנטים',
7 eleTitle: '%1 אלמנט'
8} );
diff --git a/sources/plugins/elementspath/lang/hi.js b/sources/plugins/elementspath/lang/hi.js
new file mode 100644
index 0000000..3d514f2
--- /dev/null
+++ b/sources/plugins/elementspath/lang/hi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'hi', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/hr.js b/sources/plugins/elementspath/lang/hr.js
new file mode 100644
index 0000000..90a7fd0
--- /dev/null
+++ b/sources/plugins/elementspath/lang/hr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'hr', {
6 eleLabel: 'Putanja elemenata',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/hu.js b/sources/plugins/elementspath/lang/hu.js
new file mode 100644
index 0000000..23701f2
--- /dev/null
+++ b/sources/plugins/elementspath/lang/hu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'hu', {
6 eleLabel: 'Elem utak',
7 eleTitle: '%1 elem'
8} );
diff --git a/sources/plugins/elementspath/lang/is.js b/sources/plugins/elementspath/lang/is.js
new file mode 100644
index 0000000..b5711de
--- /dev/null
+++ b/sources/plugins/elementspath/lang/is.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'is', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/it.js b/sources/plugins/elementspath/lang/it.js
new file mode 100644
index 0000000..2e3ed4d
--- /dev/null
+++ b/sources/plugins/elementspath/lang/it.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'it', {
6 eleLabel: 'Percorso degli elementi',
7 eleTitle: '%1 elemento'
8} );
diff --git a/sources/plugins/elementspath/lang/ja.js b/sources/plugins/elementspath/lang/ja.js
new file mode 100644
index 0000000..6fba524
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ja.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ja', {
6 eleLabel: '要素パス',
7 eleTitle: '%1 要素'
8} );
diff --git a/sources/plugins/elementspath/lang/ka.js b/sources/plugins/elementspath/lang/ka.js
new file mode 100644
index 0000000..9923902
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ka.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ka', {
6 eleLabel: 'ელემეტის გზა',
7 eleTitle: '%1 ელემენტი'
8} );
diff --git a/sources/plugins/elementspath/lang/km.js b/sources/plugins/elementspath/lang/km.js
new file mode 100644
index 0000000..2fc661d
--- /dev/null
+++ b/sources/plugins/elementspath/lang/km.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'km', {
6 eleLabel: 'ទីតាំង​ធាតុ',
7 eleTitle: 'ធាតុ %1'
8} );
diff --git a/sources/plugins/elementspath/lang/ko.js b/sources/plugins/elementspath/lang/ko.js
new file mode 100644
index 0000000..843a2de
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ko.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ko', {
6 eleLabel: '요소 경로',
7 eleTitle: '%1 요소'
8} );
diff --git a/sources/plugins/elementspath/lang/ku.js b/sources/plugins/elementspath/lang/ku.js
new file mode 100644
index 0000000..f425c90
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ku.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ku', {
6 eleLabel: 'ڕێڕەوی توخمەکان',
7 eleTitle: '%1 توخم'
8} );
diff --git a/sources/plugins/elementspath/lang/lt.js b/sources/plugins/elementspath/lang/lt.js
new file mode 100644
index 0000000..14c5345
--- /dev/null
+++ b/sources/plugins/elementspath/lang/lt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'lt', {
6 eleLabel: 'Elemento kelias',
7 eleTitle: '%1 elementas'
8} );
diff --git a/sources/plugins/elementspath/lang/lv.js b/sources/plugins/elementspath/lang/lv.js
new file mode 100644
index 0000000..7459ce8
--- /dev/null
+++ b/sources/plugins/elementspath/lang/lv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'lv', {
6 eleLabel: 'Elementa ceļš',
7 eleTitle: '%1 elements'
8} );
diff --git a/sources/plugins/elementspath/lang/mk.js b/sources/plugins/elementspath/lang/mk.js
new file mode 100644
index 0000000..3fb1549
--- /dev/null
+++ b/sources/plugins/elementspath/lang/mk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'mk', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/mn.js b/sources/plugins/elementspath/lang/mn.js
new file mode 100644
index 0000000..e3e9285
--- /dev/null
+++ b/sources/plugins/elementspath/lang/mn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'mn', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/ms.js b/sources/plugins/elementspath/lang/ms.js
new file mode 100644
index 0000000..143b4cd
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ms.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ms', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/nb.js b/sources/plugins/elementspath/lang/nb.js
new file mode 100644
index 0000000..d797354
--- /dev/null
+++ b/sources/plugins/elementspath/lang/nb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'nb', {
6 eleLabel: 'Element-sti',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/nl.js b/sources/plugins/elementspath/lang/nl.js
new file mode 100644
index 0000000..14a3585
--- /dev/null
+++ b/sources/plugins/elementspath/lang/nl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'nl', {
6 eleLabel: 'Elementenpad',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/no.js b/sources/plugins/elementspath/lang/no.js
new file mode 100644
index 0000000..64d05f5
--- /dev/null
+++ b/sources/plugins/elementspath/lang/no.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'no', {
6 eleLabel: 'Element-sti',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/oc.js b/sources/plugins/elementspath/lang/oc.js
new file mode 100644
index 0000000..04c1b30
--- /dev/null
+++ b/sources/plugins/elementspath/lang/oc.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'oc', {
6 eleLabel: 'Camin dels elements',
7 eleTitle: 'Element %1'
8} );
diff --git a/sources/plugins/elementspath/lang/pl.js b/sources/plugins/elementspath/lang/pl.js
new file mode 100644
index 0000000..082224d
--- /dev/null
+++ b/sources/plugins/elementspath/lang/pl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'pl', {
6 eleLabel: 'Ścieżka elementów',
7 eleTitle: 'element %1'
8} );
diff --git a/sources/plugins/elementspath/lang/pt-br.js b/sources/plugins/elementspath/lang/pt-br.js
new file mode 100644
index 0000000..ec265b6
--- /dev/null
+++ b/sources/plugins/elementspath/lang/pt-br.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'pt-br', {
6 eleLabel: 'Caminho dos Elementos',
7 eleTitle: 'Elemento %1'
8} );
diff --git a/sources/plugins/elementspath/lang/pt.js b/sources/plugins/elementspath/lang/pt.js
new file mode 100644
index 0000000..5eed642
--- /dev/null
+++ b/sources/plugins/elementspath/lang/pt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'pt', {
6 eleLabel: 'Caminho dos elementos',
7 eleTitle: 'Elemento %1'
8} );
diff --git a/sources/plugins/elementspath/lang/ro.js b/sources/plugins/elementspath/lang/ro.js
new file mode 100644
index 0000000..bc79113
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ro.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ro', {
6 eleLabel: 'Calea elementelor',
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/ru.js b/sources/plugins/elementspath/lang/ru.js
new file mode 100644
index 0000000..ce9529e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ru.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ru', {
6 eleLabel: 'Путь элементов',
7 eleTitle: 'Элемент %1'
8} );
diff --git a/sources/plugins/elementspath/lang/si.js b/sources/plugins/elementspath/lang/si.js
new file mode 100644
index 0000000..ff4e5dc
--- /dev/null
+++ b/sources/plugins/elementspath/lang/si.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'si', {
6 eleLabel: 'මුලද්‍රව්‍ය මාර්ගය',
7 eleTitle: '%1 මුල'
8} );
diff --git a/sources/plugins/elementspath/lang/sk.js b/sources/plugins/elementspath/lang/sk.js
new file mode 100644
index 0000000..b3eb725
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sk', {
6 eleLabel: 'Cesta prvkov',
7 eleTitle: '%1 prvok'
8} );
diff --git a/sources/plugins/elementspath/lang/sl.js b/sources/plugins/elementspath/lang/sl.js
new file mode 100644
index 0000000..2d2a1c6
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sl', {
6 eleLabel: 'Pot elementov',
7 eleTitle: 'Element %1'
8} );
diff --git a/sources/plugins/elementspath/lang/sq.js b/sources/plugins/elementspath/lang/sq.js
new file mode 100644
index 0000000..0018d6f
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sq.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sq', {
6 eleLabel: 'Rruga e elementeve',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/sr-latn.js b/sources/plugins/elementspath/lang/sr-latn.js
new file mode 100644
index 0000000..65ae9f4
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sr-latn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sr-latn', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/sr.js b/sources/plugins/elementspath/lang/sr.js
new file mode 100644
index 0000000..80d1ba4
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sr', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/sv.js b/sources/plugins/elementspath/lang/sv.js
new file mode 100644
index 0000000..e34dd0e
--- /dev/null
+++ b/sources/plugins/elementspath/lang/sv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'sv', {
6 eleLabel: 'Elementets sökväg',
7 eleTitle: '%1 element'
8} );
diff --git a/sources/plugins/elementspath/lang/th.js b/sources/plugins/elementspath/lang/th.js
new file mode 100644
index 0000000..d56fb77
--- /dev/null
+++ b/sources/plugins/elementspath/lang/th.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'th', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 element' // MISSING
8} );
diff --git a/sources/plugins/elementspath/lang/tr.js b/sources/plugins/elementspath/lang/tr.js
new file mode 100644
index 0000000..e32e4ff
--- /dev/null
+++ b/sources/plugins/elementspath/lang/tr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'tr', {
6 eleLabel: 'Elementlerin yolu',
7 eleTitle: '%1 elementi'
8} );
diff --git a/sources/plugins/elementspath/lang/tt.js b/sources/plugins/elementspath/lang/tt.js
new file mode 100644
index 0000000..63b171c
--- /dev/null
+++ b/sources/plugins/elementspath/lang/tt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'tt', {
6 eleLabel: 'Elements path', // MISSING
7 eleTitle: '%1 элемент'
8} );
diff --git a/sources/plugins/elementspath/lang/ug.js b/sources/plugins/elementspath/lang/ug.js
new file mode 100644
index 0000000..5b66e0f
--- /dev/null
+++ b/sources/plugins/elementspath/lang/ug.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'ug', {
6 eleLabel: 'ئېلېمېنت يولى',
7 eleTitle: '%1 ئېلېمېنت'
8} );
diff --git a/sources/plugins/elementspath/lang/uk.js b/sources/plugins/elementspath/lang/uk.js
new file mode 100644
index 0000000..0d247c6
--- /dev/null
+++ b/sources/plugins/elementspath/lang/uk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'uk', {
6 eleLabel: 'Шлях',
7 eleTitle: '%1 елемент'
8} );
diff --git a/sources/plugins/elementspath/lang/vi.js b/sources/plugins/elementspath/lang/vi.js
new file mode 100644
index 0000000..5ba86b4
--- /dev/null
+++ b/sources/plugins/elementspath/lang/vi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'vi', {
6 eleLabel: 'Nhãn thành phần',
7 eleTitle: '%1 thành phần'
8} );
diff --git a/sources/plugins/elementspath/lang/zh-cn.js b/sources/plugins/elementspath/lang/zh-cn.js
new file mode 100644
index 0000000..e585d13
--- /dev/null
+++ b/sources/plugins/elementspath/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'zh-cn', {
6 eleLabel: '元素路径',
7 eleTitle: '%1 元素'
8} );
diff --git a/sources/plugins/elementspath/lang/zh.js b/sources/plugins/elementspath/lang/zh.js
new file mode 100644
index 0000000..5031d0f
--- /dev/null
+++ b/sources/plugins/elementspath/lang/zh.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'elementspath', 'zh', {
6 eleLabel: '元件路徑',
7 eleTitle: '%1 個元件'
8} );
diff --git a/sources/plugins/elementspath/plugin.js b/sources/plugins/elementspath/plugin.js
new file mode 100644
index 0000000..07ba5c2
--- /dev/null
+++ b/sources/plugins/elementspath/plugin.js
@@ -0,0 +1,244 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The "elementspath" plugin. It shows all elements in the DOM
8 * parent tree relative to the current selection in the editing area.
9 */
10
11( function() {
12 var commands = {
13 toolbarFocus: {
14 editorFocus: false,
15 readOnly: 1,
16 exec: function( editor ) {
17 var idBase = editor._.elementsPath.idBase;
18 var element = CKEDITOR.document.getById( idBase + '0' );
19
20 // Make the first button focus accessible for IE. (#3417)
21 // Adobe AIR instead need while of delay.
22 element && element.focus( CKEDITOR.env.ie || CKEDITOR.env.air );
23 }
24 }
25 };
26
27 var emptyHtml = '<span class="cke_path_empty">&nbsp;</span>';
28
29 var extra = '';
30
31 // Some browsers don't cancel key events in the keydown but in the
32 // keypress.
33 // TODO: Check if really needed.
34 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
35 extra += ' onkeypress="return false;"';
36
37 // With Firefox, we need to force the button to redraw, otherwise it
38 // will remain in the focus state.
39 if ( CKEDITOR.env.gecko )
40 extra += ' onblur="this.style.cssText = this.style.cssText;"';
41
42 var pathItemTpl = CKEDITOR.addTemplate( 'pathItem', '<a' +
43 ' id="{id}"' +
44 ' href="{jsTitle}"' +
45 ' tabindex="-1"' +
46 ' class="cke_path_item"' +
47 ' title="{label}"' +
48 extra +
49 ' hidefocus="true" ' +
50 ' onkeydown="return CKEDITOR.tools.callFunction({keyDownFn},{index}, event );"' +
51 ' onclick="CKEDITOR.tools.callFunction({clickFn},{index}); return false;"' +
52 ' role="button" aria-label="{label}">' +
53 '{text}' +
54 '</a>' );
55
56 CKEDITOR.plugins.add( 'elementspath', {
57 // jscs:disable maximumLineLength
58 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
59 // jscs:enable maximumLineLength
60 init: function( editor ) {
61 editor._.elementsPath = {
62 idBase: 'cke_elementspath_' + CKEDITOR.tools.getNextNumber() + '_',
63 filters: []
64 };
65
66 editor.on( 'uiSpace', function( event ) {
67 if ( event.data.space == 'bottom' )
68 initElementsPath( editor, event.data );
69 } );
70 }
71 } );
72
73 function initElementsPath( editor, bottomSpaceData ) {
74 var spaceId = editor.ui.spaceId( 'path' ),
75 spaceElement,
76 getSpaceElement = function() {
77 if ( !spaceElement )
78 spaceElement = CKEDITOR.document.getById( spaceId );
79 return spaceElement;
80 },
81 elementsPath = editor._.elementsPath,
82 idBase = elementsPath.idBase;
83
84 bottomSpaceData.html += '<span id="' + spaceId + '_label" class="cke_voice_label">' + editor.lang.elementspath.eleLabel + '</span>' +
85 '<span id="' + spaceId + '" class="cke_path" role="group" aria-labelledby="' + spaceId + '_label">' + emptyHtml + '</span>';
86
87 // Register the ui element to the focus manager.
88 editor.on( 'uiReady', function() {
89 var element = editor.ui.space( 'path' );
90 element && editor.focusManager.add( element, 1 );
91 } );
92
93 function onClick( elementIndex ) {
94 var element = elementsPath.list[ elementIndex ],
95 selection;
96
97 if ( element.equals( editor.editable() ) || element.getAttribute( 'contenteditable' ) == 'true' ) {
98 var range = editor.createRange();
99 range.selectNodeContents( element );
100
101 selection = range.select();
102 } else {
103 selection = editor.getSelection();
104 selection.selectElement( element );
105 }
106
107 // Explicitly fire selectionChange when clicking on an element path button. (#13548)
108 if ( CKEDITOR.env.ie ) {
109 editor.fire( 'selectionChange', { selection: selection, path: new CKEDITOR.dom.elementPath( element ) } );
110 }
111
112 // It is important to focus() *after* the above selection
113 // manipulation, otherwise Firefox will have troubles. #10119
114 editor.focus();
115 }
116
117 elementsPath.onClick = onClick;
118
119 var onClickHanlder = CKEDITOR.tools.addFunction( onClick ),
120 onKeyDownHandler = CKEDITOR.tools.addFunction( function( elementIndex, ev ) {
121 var idBase = elementsPath.idBase,
122 element;
123
124 ev = new CKEDITOR.dom.event( ev );
125
126 var rtl = editor.lang.dir == 'rtl';
127 switch ( ev.getKeystroke() ) {
128 case rtl ? 39 : 37: // LEFT-ARROW
129 case 9: // TAB
130 element = CKEDITOR.document.getById( idBase + ( elementIndex + 1 ) );
131 if ( !element )
132 element = CKEDITOR.document.getById( idBase + '0' );
133 element.focus();
134 return false;
135
136 case rtl ? 37 : 39: // RIGHT-ARROW
137 case CKEDITOR.SHIFT + 9: // SHIFT + TAB
138 element = CKEDITOR.document.getById( idBase + ( elementIndex - 1 ) );
139 if ( !element )
140 element = CKEDITOR.document.getById( idBase + ( elementsPath.list.length - 1 ) );
141 element.focus();
142 return false;
143
144 case 27: // ESC
145 editor.focus();
146 return false;
147
148 case 13: // ENTER // Opera
149 case 32: // SPACE
150 onClick( elementIndex );
151 return false;
152 }
153 return true;
154 } );
155
156 editor.on( 'selectionChange', function() {
157 var html = [],
158 elementsList = elementsPath.list = [],
159 namesList = [],
160 filters = elementsPath.filters,
161 isContentEditable = true,
162
163 // Use elementPath to consider children of editable only (#11124).
164 elementsChain = editor.elementPath().elements,
165 name;
166
167 // Starts iteration from body element, skipping html.
168 for ( var j = elementsChain.length; j--; ) {
169 var element = elementsChain[ j ],
170 ignore = 0;
171
172 if ( element.data( 'cke-display-name' ) )
173 name = element.data( 'cke-display-name' );
174 else if ( element.data( 'cke-real-element-type' ) )
175 name = element.data( 'cke-real-element-type' );
176 else
177 name = element.getName();
178
179 isContentEditable = element.hasAttribute( 'contenteditable' ) ?
180 element.getAttribute( 'contenteditable' ) == 'true' : isContentEditable;
181
182 // If elem is non-contenteditable, and it's not specifying contenteditable
183 // attribute - then elem should be ignored.
184 if ( !isContentEditable && !element.hasAttribute( 'contenteditable' ) )
185 ignore = 1;
186
187 for ( var i = 0; i < filters.length; i++ ) {
188 var ret = filters[ i ]( element, name );
189 if ( ret === false ) {
190 ignore = 1;
191 break;
192 }
193 name = ret || name;
194 }
195
196 if ( !ignore ) {
197 elementsList.unshift( element );
198 namesList.unshift( name );
199 }
200 }
201
202 for ( var iterationLimit = elementsList.length, index = 0; index < iterationLimit; index++ ) {
203 name = namesList[ index ];
204 var label = editor.lang.elementspath.eleTitle.replace( /%1/, name ),
205 item = pathItemTpl.output( {
206 id: idBase + index,
207 label: label,
208 text: name,
209 jsTitle: 'javascript:void(\'' + name + '\')', // jshint ignore:line
210 index: index,
211 keyDownFn: onKeyDownHandler,
212 clickFn: onClickHanlder
213 } );
214
215 html.unshift( item );
216 }
217
218 var space = getSpaceElement();
219 space.setHtml( html.join( '' ) + emptyHtml );
220 editor.fire( 'elementsPathUpdate', { space: space } );
221 } );
222
223 function empty() {
224 spaceElement && spaceElement.setHtml( emptyHtml );
225 delete elementsPath.list;
226 }
227
228 editor.on( 'readOnly', empty );
229 editor.on( 'contentDomUnload', empty );
230
231 editor.addCommand( 'elementsPathFocus', commands.toolbarFocus );
232 editor.setKeystroke( CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus' );
233 }
234} )();
235
236/**
237 * Fired when the contents of the elementsPath are changed.
238 *
239 * @event elementsPathUpdate
240 * @member CKEDITOR.editor
241 * @param {CKEDITOR.editor} editor This editor instance.
242 * @param data
243 * @param {CKEDITOR.dom.element} data.space The elementsPath container.
244 */
diff --git a/sources/plugins/enterkey/plugin.js b/sources/plugins/enterkey/plugin.js
new file mode 100644
index 0000000..9410bbd
--- /dev/null
+++ b/sources/plugins/enterkey/plugin.js
@@ -0,0 +1,566 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 CKEDITOR.plugins.add( 'enterkey', {
8 init: function( editor ) {
9 editor.addCommand( 'enter', {
10 modes: { wysiwyg: 1 },
11 editorFocus: false,
12 exec: function( editor ) {
13 enter( editor );
14 }
15 } );
16
17 editor.addCommand( 'shiftEnter', {
18 modes: { wysiwyg: 1 },
19 editorFocus: false,
20 exec: function( editor ) {
21 shiftEnter( editor );
22 }
23 } );
24
25 editor.setKeystroke( [
26 [ 13, 'enter' ],
27 [ CKEDITOR.SHIFT + 13, 'shiftEnter' ]
28 ] );
29 }
30 } );
31
32 var whitespaces = CKEDITOR.dom.walker.whitespaces(),
33 bookmark = CKEDITOR.dom.walker.bookmark();
34
35 CKEDITOR.plugins.enterkey = {
36 enterBlock: function( editor, mode, range, forceMode ) {
37 // Get the range for the current selection.
38 range = range || getRange( editor );
39
40 // We may not have valid ranges to work on, like when inside a
41 // contenteditable=false element.
42 if ( !range )
43 return;
44
45 // When range is in nested editable, we have to replace range with this one,
46 // which have root property set to closest editable, to make auto paragraphing work. (#12162)
47 range = replaceRangeWithClosestEditableRoot( range );
48
49 var doc = range.document;
50
51 var atBlockStart = range.checkStartOfBlock(),
52 atBlockEnd = range.checkEndOfBlock(),
53 path = editor.elementPath( range.startContainer ),
54 block = path.block,
55
56 // Determine the block element to be used.
57 blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ),
58
59 newBlock;
60
61 // Exit the list when we're inside an empty list item block. (#5376)
62 if ( atBlockStart && atBlockEnd ) {
63 // Exit the list when we're inside an empty list item block. (#5376)
64 if ( block && ( block.is( 'li' ) || block.getParent().is( 'li' ) ) ) {
65 // Make sure to point to the li when dealing with empty list item.
66 if ( !block.is( 'li' ) )
67 block = block.getParent();
68
69 var blockParent = block.getParent(),
70 blockGrandParent = blockParent.getParent(),
71
72 firstChild = !block.hasPrevious(),
73 lastChild = !block.hasNext(),
74
75 selection = editor.getSelection(),
76 bookmarks = selection.createBookmarks(),
77
78 orgDir = block.getDirection( 1 ),
79 className = block.getAttribute( 'class' ),
80 style = block.getAttribute( 'style' ),
81 dirLoose = blockGrandParent.getDirection( 1 ) != orgDir,
82
83 enterMode = editor.enterMode,
84 needsBlock = enterMode != CKEDITOR.ENTER_BR || dirLoose || style || className,
85
86 child;
87
88 if ( blockGrandParent.is( 'li' ) ) {
89
90 // If block is the first or the last child of the parent
91 // list, degrade it and move to the outer list:
92 // before the parent list if block is first child and after
93 // the parent list if block is the last child, respectively.
94 //
95 // <ul> => <ul>
96 // <li> => <li>
97 // <ul> => <ul>
98 // <li>x</li> => <li>x</li>
99 // <li>^</li> => </ul>
100 // </ul> => </li>
101 // </li> => <li>^</li>
102 // </ul> => </ul>
103 //
104 // AND
105 //
106 // <ul> => <ul>
107 // <li> => <li>^</li>
108 // <ul> => <li>
109 // <li>^</li> => <ul>
110 // <li>x</li> => <li>x</li>
111 // </ul> => </ul>
112 // </li> => </li>
113 // </ul> => </ul>
114
115 if ( firstChild || lastChild ) {
116
117 // If it's only child, we don't want to keep perent ul anymore.
118 if ( firstChild && lastChild ) {
119 blockParent.remove();
120 }
121
122 block[lastChild ? 'insertAfter' : 'insertBefore']( blockGrandParent );
123
124 // If the empty block is neither first nor last child
125 // then split the list and the block as an element
126 // of outer list.
127 //
128 // => <ul>
129 // => <li>
130 // <ul> => <ul>
131 // <li> => <li>x</li>
132 // <ul> => </ul>
133 // <li>x</li> => </li>
134 // <li>^</li> => <li>^</li>
135 // <li>y</li> => <li>
136 // </ul> => <ul>
137 // </li> => <li>y</li>
138 // </ul> => </ul>
139 // => </li>
140 // => </ul>
141
142 } else {
143 block.breakParent( blockGrandParent );
144 }
145 }
146
147 else if ( !needsBlock ) {
148 block.appendBogus( true );
149
150 // If block is the first or last child of the parent
151 // list, move all block's children out of the list:
152 // before the list if block is first child and after the list
153 // if block is the last child, respectively.
154 //
155 // <ul> => <ul>
156 // <li>x</li> => <li>x</li>
157 // <li>^</li> => </ul>
158 // </ul> => ^
159 //
160 // AND
161 //
162 // <ul> => ^
163 // <li>^</li> => <ul>
164 // <li>x</li> => <li>x</li>
165 // </ul> => </ul>
166
167 if ( firstChild || lastChild ) {
168 while ( ( child = block[ firstChild ? 'getFirst' : 'getLast' ]() ) )
169 child[ firstChild ? 'insertBefore' : 'insertAfter' ]( blockParent );
170 }
171
172 // If the empty block is neither first nor last child
173 // then split the list and put all the block contents
174 // between two lists.
175 //
176 // <ul> => <ul>
177 // <li>x</li> => <li>x</li>
178 // <li>^</li> => </ul>
179 // <li>y</li> => ^
180 // </ul> => <ul>
181 // => <li>y</li>
182 // => </ul>
183
184 else {
185 block.breakParent( blockParent );
186
187 while ( ( child = block.getLast() ) )
188 child.insertAfter( blockParent );
189 }
190
191 block.remove();
192 } else {
193 // Original path block is the list item, create new block for the list item content.
194 if ( path.block.is( 'li' ) ) {
195 // Use <div> block for ENTER_BR and ENTER_DIV.
196 newBlock = doc.createElement( mode == CKEDITOR.ENTER_P ? 'p' : 'div' );
197
198 if ( dirLoose )
199 newBlock.setAttribute( 'dir', orgDir );
200
201 style && newBlock.setAttribute( 'style', style );
202 className && newBlock.setAttribute( 'class', className );
203
204 // Move all the child nodes to the new block.
205 block.moveChildren( newBlock );
206 }
207 // The original path block is not a list item, just copy the block to out side of the list.
208 else {
209 newBlock = path.block;
210 }
211
212 // If block is the first or last child of the parent
213 // list, move it out of the list:
214 // before the list if block is first child and after the list
215 // if block is the last child, respectively.
216 //
217 // <ul> => <ul>
218 // <li>x</li> => <li>x</li>
219 // <li>^</li> => </ul>
220 // </ul> => <p>^</p>
221 //
222 // AND
223 //
224 // <ul> => <p>^</p>
225 // <li>^</li> => <ul>
226 // <li>x</li> => <li>x</li>
227 // </ul> => </ul>
228
229 if ( firstChild || lastChild )
230 newBlock[ firstChild ? 'insertBefore' : 'insertAfter' ]( blockParent );
231
232 // If the empty block is neither first nor last child
233 // then split the list and put the new block between
234 // two lists.
235 //
236 // => <ul>
237 // <ul> => <li>x</li>
238 // <li>x</li> => </ul>
239 // <li>^</li> => <p>^</p>
240 // <li>y</li> => <ul>
241 // </ul> => <li>y</li>
242 // => </ul>
243
244 else {
245 block.breakParent( blockParent );
246 newBlock.insertAfter( blockParent );
247 }
248
249 block.remove();
250 }
251
252 selection.selectBookmarks( bookmarks );
253
254 return;
255 }
256
257 if ( block && block.getParent().is( 'blockquote' ) ) {
258 block.breakParent( block.getParent() );
259
260 // If we were at the start of <blockquote>, there will be an empty element before it now.
261 if ( !block.getPrevious().getFirst( CKEDITOR.dom.walker.invisible( 1 ) ) )
262 block.getPrevious().remove();
263
264 // If we were at the end of <blockquote>, there will be an empty element after it now.
265 if ( !block.getNext().getFirst( CKEDITOR.dom.walker.invisible( 1 ) ) )
266 block.getNext().remove();
267
268 range.moveToElementEditStart( block );
269 range.select();
270 return;
271 }
272 }
273 // Don't split <pre> if we're in the middle of it, act as shift enter key.
274 else if ( block && block.is( 'pre' ) ) {
275 if ( !atBlockEnd ) {
276 enterBr( editor, mode, range, forceMode );
277 return;
278 }
279 }
280
281 // Split the range.
282 var splitInfo = range.splitBlock( blockTag );
283
284 if ( !splitInfo )
285 return;
286
287 // Get the current blocks.
288 var previousBlock = splitInfo.previousBlock,
289 nextBlock = splitInfo.nextBlock;
290
291 var isStartOfBlock = splitInfo.wasStartOfBlock,
292 isEndOfBlock = splitInfo.wasEndOfBlock;
293
294 var node;
295
296 // If this is a block under a list item, split it as well. (#1647)
297 if ( nextBlock ) {
298 node = nextBlock.getParent();
299 if ( node.is( 'li' ) ) {
300 nextBlock.breakParent( node );
301 nextBlock.move( nextBlock.getNext(), 1 );
302 }
303 } else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) ) {
304 previousBlock.breakParent( node );
305 node = previousBlock.getNext();
306 range.moveToElementEditStart( node );
307 previousBlock.move( previousBlock.getPrevious() );
308 }
309
310 // If we have both the previous and next blocks, it means that the
311 // boundaries were on separated blocks, or none of them where on the
312 // block limits (start/end).
313 if ( !isStartOfBlock && !isEndOfBlock ) {
314 // If the next block is an <li> with another list tree as the first
315 // child, we'll need to append a filler (<br>/NBSP) or the list item
316 // wouldn't be editable. (#1420)
317 if ( nextBlock.is( 'li' ) ) {
318 var walkerRange = range.clone();
319 walkerRange.selectNodeContents( nextBlock );
320 var walker = new CKEDITOR.dom.walker( walkerRange );
321 walker.evaluator = function( node ) {
322 return !( bookmark( node ) || whitespaces( node ) || node.type == CKEDITOR.NODE_ELEMENT && node.getName() in CKEDITOR.dtd.$inline && !( node.getName() in CKEDITOR.dtd.$empty ) );
323 };
324
325 node = walker.next();
326 if ( node && node.type == CKEDITOR.NODE_ELEMENT && node.is( 'ul', 'ol' ) )
327 ( CKEDITOR.env.needsBrFiller ? doc.createElement( 'br' ) : doc.createText( '\xa0' ) ).insertBefore( node );
328 }
329
330 // Move the selection to the end block.
331 if ( nextBlock )
332 range.moveToElementEditStart( nextBlock );
333 } else {
334 var newBlockDir;
335
336 if ( previousBlock ) {
337 // Do not enter this block if it's a header tag, or we are in
338 // a Shift+Enter (#77). Create a new block element instead
339 // (later in the code).
340 if ( previousBlock.is( 'li' ) || !( headerTagRegex.test( previousBlock.getName() ) || previousBlock.is( 'pre' ) ) ) {
341 // Otherwise, duplicate the previous block.
342 newBlock = previousBlock.clone();
343 }
344 } else if ( nextBlock ) {
345 newBlock = nextBlock.clone();
346 }
347
348 if ( !newBlock ) {
349 // We have already created a new list item. (#6849)
350 if ( node && node.is( 'li' ) )
351 newBlock = node;
352 else {
353 newBlock = doc.createElement( blockTag );
354 if ( previousBlock && ( newBlockDir = previousBlock.getDirection() ) )
355 newBlock.setAttribute( 'dir', newBlockDir );
356 }
357 }
358 // Force the enter block unless we're talking of a list item.
359 else if ( forceMode && !newBlock.is( 'li' ) ) {
360 newBlock.renameNode( blockTag );
361 }
362
363 // Recreate the inline elements tree, which was available
364 // before hitting enter, so the same styles will be available in
365 // the new block.
366 var elementPath = splitInfo.elementPath;
367 if ( elementPath ) {
368 for ( var i = 0, len = elementPath.elements.length; i < len; i++ ) {
369 var element = elementPath.elements[ i ];
370
371 if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) )
372 break;
373
374 if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] ) {
375 element = element.clone();
376 newBlock.moveChildren( element );
377 newBlock.append( element );
378 }
379 }
380 }
381
382 newBlock.appendBogus();
383
384 if ( !newBlock.getParent() )
385 range.insertNode( newBlock );
386
387 // list item start number should not be duplicated (#7330), but we need
388 // to remove the attribute after it's onto the DOM tree because of old IEs (#7581).
389 newBlock.is( 'li' ) && newBlock.removeAttribute( 'value' );
390
391 // This is tricky, but to make the new block visible correctly
392 // we must select it.
393 // The previousBlock check has been included because it may be
394 // empty if we have fixed a block-less space (like ENTER into an
395 // empty table cell).
396 if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) ) {
397 // Move the selection to the new block.
398 range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock );
399 range.select();
400 }
401
402 // Move the selection to the new block.
403 range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock );
404 }
405
406 range.select();
407 range.scrollIntoView();
408 },
409
410 enterBr: function( editor, mode, range, forceMode ) {
411 // Get the range for the current selection.
412 range = range || getRange( editor );
413
414 // We may not have valid ranges to work on, like when inside a
415 // contenteditable=false element.
416 if ( !range )
417 return;
418
419 var doc = range.document;
420
421 var isEndOfBlock = range.checkEndOfBlock();
422
423 var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() );
424
425 var startBlock = elementPath.block,
426 startBlockTag = startBlock && elementPath.block.getName();
427
428 if ( !forceMode && startBlockTag == 'li' ) {
429 enterBlock( editor, mode, range, forceMode );
430 return;
431 }
432
433 // If we are at the end of a header block.
434 if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) ) {
435 var newBlock, newBlockDir;
436
437 if ( ( newBlockDir = startBlock.getDirection() ) ) {
438 newBlock = doc.createElement( 'div' );
439 newBlock.setAttribute( 'dir', newBlockDir );
440 newBlock.insertAfter( startBlock );
441 range.setStart( newBlock, 0 );
442 } else {
443 // Insert a <br> after the current paragraph.
444 doc.createElement( 'br' ).insertAfter( startBlock );
445
446 // A text node is required by Gecko only to make the cursor blink.
447 if ( CKEDITOR.env.gecko )
448 doc.createText( '' ).insertAfter( startBlock );
449
450 // IE has different behaviors regarding position.
451 range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );
452 }
453 } else {
454 var lineBreak;
455
456 // IE<8 prefers text node as line-break inside of <pre> (#4711).
457 if ( startBlockTag == 'pre' && CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
458 lineBreak = doc.createText( '\r' );
459 else
460 lineBreak = doc.createElement( 'br' );
461
462 range.deleteContents();
463 range.insertNode( lineBreak );
464
465 // Old IEs have different behavior regarding position.
466 if ( !CKEDITOR.env.needsBrFiller )
467 range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END );
468 else {
469 // A text node is required by Gecko only to make the cursor blink.
470 // We need some text inside of it, so the bogus <br> is properly
471 // created.
472 doc.createText( '\ufeff' ).insertAfter( lineBreak );
473
474 // If we are at the end of a block, we must be sure the bogus node is available in that block.
475 if ( isEndOfBlock ) {
476 // In most situations we've got an elementPath.block (e.g. <p>), but in a
477 // blockless editor or when autoP is false that needs to be a block limit.
478 ( startBlock || elementPath.blockLimit ).appendBogus();
479 }
480
481 // Now we can remove the text node contents, so the caret doesn't
482 // stop on it.
483 lineBreak.getNext().$.nodeValue = '';
484
485 range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START );
486
487 }
488 }
489
490 // This collapse guarantees the cursor will be blinking.
491 range.collapse( true );
492
493 range.select();
494 range.scrollIntoView();
495 }
496 };
497
498 var plugin = CKEDITOR.plugins.enterkey,
499 enterBr = plugin.enterBr,
500 enterBlock = plugin.enterBlock,
501 headerTagRegex = /^h[1-6]$/;
502
503 function shiftEnter( editor ) {
504 // On SHIFT+ENTER:
505 // 1. We want to enforce the mode to be respected, instead
506 // of cloning the current block. (#77)
507 return enter( editor, editor.activeShiftEnterMode, 1 );
508 }
509
510 function enter( editor, mode, forceMode ) {
511 forceMode = editor.config.forceEnterMode || forceMode;
512
513 // Only effective within document.
514 if ( editor.mode != 'wysiwyg' )
515 return;
516
517 if ( !mode )
518 mode = editor.activeEnterMode;
519
520 // TODO this should be handled by setting editor.activeEnterMode on selection change.
521 // Check path block specialities:
522 // 1. Cannot be a un-splittable element, e.g. table caption;
523 var path = editor.elementPath();
524 if ( !path.isContextFor( 'p' ) ) {
525 mode = CKEDITOR.ENTER_BR;
526 forceMode = 1;
527 }
528
529 editor.fire( 'saveSnapshot' ); // Save undo step.
530
531 if ( mode == CKEDITOR.ENTER_BR )
532 enterBr( editor, mode, null, forceMode );
533 else
534 enterBlock( editor, mode, null, forceMode );
535
536 editor.fire( 'saveSnapshot' );
537 }
538
539 function getRange( editor ) {
540 // Get the selection ranges.
541 var ranges = editor.getSelection().getRanges( true );
542
543 // Delete the contents of all ranges except the first one.
544 for ( var i = ranges.length - 1; i > 0; i-- ) {
545 ranges[ i ].deleteContents();
546 }
547
548 // Return the first range.
549 return ranges[ 0 ];
550 }
551
552 function replaceRangeWithClosestEditableRoot( range ) {
553 var closestEditable = range.startContainer.getAscendant( function( node ) {
554 return node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'true';
555 }, true );
556
557 if ( range.root.equals( closestEditable ) ) {
558 return range;
559 } else {
560 var newRange = new CKEDITOR.dom.range( closestEditable );
561
562 newRange.moveToRange( range );
563 return newRange;
564 }
565 }
566} )();
diff --git a/sources/plugins/enterkey/samples/enterkey.html b/sources/plugins/enterkey/samples/enterkey.html
new file mode 100644
index 0000000..79afee3
--- /dev/null
+++ b/sources/plugins/enterkey/samples/enterkey.html
@@ -0,0 +1,106 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>ENTER Key Configuration &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link href="../../../samples/old/sample.css" rel="stylesheet">
12 <meta name="ckeditor-sample-name" content="Using the &quot;Enter&quot; key in CKEditor">
13 <meta name="ckeditor-sample-group" content="Advanced Samples">
14 <meta name="ckeditor-sample-description" content="Configuring the behavior of &lt;em&gt;Enter&lt;/em&gt; and &lt;em&gt;Shift+Enter&lt;/em&gt; keys.">
15 <script>
16
17 var editor;
18
19 function changeEnter() {
20 // If we already have an editor, let's destroy it first.
21 if ( editor )
22 editor.destroy( true );
23
24 // Create the editor again, with the appropriate settings.
25 editor = CKEDITOR.replace( 'editor1', {
26 extraPlugins: 'enterkey',
27 enterMode: Number( document.getElementById( 'xEnter' ).value ),
28 shiftEnterMode: Number( document.getElementById( 'xShiftEnter' ).value )
29 });
30 }
31
32 window.onload = changeEnter;
33
34 </script>
35</head>
36<body>
37 <h1 class="samples">
38 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; ENTER Key Configuration
39 </h1>
40 <div class="warning deprecated">
41 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/enterkey.html">brand new version in CKEditor SDK</a>.
42 </div>
43 <div class="description">
44 <p>
45 This sample shows how to configure the <em>Enter</em> and <em>Shift+Enter</em> keys
46 to perform actions specified in the
47 <a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode"><code>enterMode</code></a>
48 and <a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-shiftEnterMode"><code>shiftEnterMode</code></a>
49 parameters, respectively.
50 You can choose from the following options:
51 </p>
52 <ul class="samples">
53 <li><strong><code>ENTER_P</code></strong> &ndash; new <code>&lt;p&gt;</code> paragraphs are created;</li>
54 <li><strong><code>ENTER_BR</code></strong> &ndash; lines are broken with <code>&lt;br&gt;</code> elements;</li>
55 <li><strong><code>ENTER_DIV</code></strong> &ndash; new <code>&lt;div&gt;</code> blocks are created.</li>
56 </ul>
57 <p>
58 The sample code below shows how to configure CKEditor to create a <code>&lt;div&gt;</code> block when <em>Enter</em> key is pressed.
59 </p>
60<pre class="samples">
61CKEDITOR.replace( '<em>textarea_id</em>', {
62 <strong>enterMode: CKEDITOR.ENTER_DIV</strong>
63});</pre>
64 <p>
65 Note that <code><em>textarea_id</em></code> in the code above is the <code>id</code> attribute of
66 the <code>&lt;textarea&gt;</code> element to be replaced.
67 </p>
68 </div>
69 <div style="float: left; margin-right: 20px">
70 When <em>Enter</em> is pressed:<br>
71 <select id="xEnter" onchange="changeEnter();">
72 <option selected="selected" value="1">Create a new &lt;P&gt; (recommended)</option>
73 <option value="3">Create a new &lt;DIV&gt;</option>
74 <option value="2">Break the line with a &lt;BR&gt;</option>
75 </select>
76 </div>
77 <div style="float: left">
78 When <em>Shift+Enter</em> is pressed:<br>
79 <select id="xShiftEnter" onchange="changeEnter();">
80 <option value="1">Create a new &lt;P&gt;</option>
81 <option value="3">Create a new &lt;DIV&gt;</option>
82 <option selected="selected" value="2">Break the line with a &lt;BR&gt; (recommended)</option>
83 </select>
84 </div>
85 <br style="clear: both">
86 <form action="../../../samples/sample_posteddata.php" method="post">
87 <p>
88 <br>
89 <textarea cols="80" id="editor1" name="editor1" rows="10">This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.</textarea>
90 </p>
91 <p>
92 <input type="submit" value="Submit">
93 </p>
94 </form>
95 <div id="footer">
96 <hr>
97 <p>
98 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
99 </p>
100 <p id="copy">
101 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
102 Knabben. All rights reserved.
103 </p>
104 </div>
105</body>
106</html>
diff --git a/sources/plugins/entities/plugin.js b/sources/plugins/entities/plugin.js
new file mode 100644
index 0000000..d457ad1
--- /dev/null
+++ b/sources/plugins/entities/plugin.js
@@ -0,0 +1,239 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 // Basic HTML entities.
8 var htmlbase = 'nbsp,gt,lt,amp';
9
10 var entities =
11 // Latin-1 entities
12 'quot,iexcl,cent,pound,curren,yen,brvbar,sect,uml,copy,ordf,laquo,' +
13 'not,shy,reg,macr,deg,plusmn,sup2,sup3,acute,micro,para,middot,' +
14 'cedil,sup1,ordm,raquo,frac14,frac12,frac34,iquest,times,divide,' +
15
16 // Symbols
17 'fnof,bull,hellip,prime,Prime,oline,frasl,weierp,image,real,trade,' +
18 'alefsym,larr,uarr,rarr,darr,harr,crarr,lArr,uArr,rArr,dArr,hArr,' +
19 'forall,part,exist,empty,nabla,isin,notin,ni,prod,sum,minus,lowast,' +
20 'radic,prop,infin,ang,and,or,cap,cup,int,there4,sim,cong,asymp,ne,' +
21 'equiv,le,ge,sub,sup,nsub,sube,supe,oplus,otimes,perp,sdot,lceil,' +
22 'rceil,lfloor,rfloor,lang,rang,loz,spades,clubs,hearts,diams,' +
23
24 // Other special characters
25 'circ,tilde,ensp,emsp,thinsp,zwnj,zwj,lrm,rlm,ndash,mdash,lsquo,' +
26 'rsquo,sbquo,ldquo,rdquo,bdquo,dagger,Dagger,permil,lsaquo,rsaquo,' +
27 'euro';
28
29 // Latin letters entities
30 var latin = 'Agrave,Aacute,Acirc,Atilde,Auml,Aring,AElig,Ccedil,Egrave,Eacute,' +
31 'Ecirc,Euml,Igrave,Iacute,Icirc,Iuml,ETH,Ntilde,Ograve,Oacute,Ocirc,' +
32 'Otilde,Ouml,Oslash,Ugrave,Uacute,Ucirc,Uuml,Yacute,THORN,szlig,' +
33 'agrave,aacute,acirc,atilde,auml,aring,aelig,ccedil,egrave,eacute,' +
34 'ecirc,euml,igrave,iacute,icirc,iuml,eth,ntilde,ograve,oacute,ocirc,' +
35 'otilde,ouml,oslash,ugrave,uacute,ucirc,uuml,yacute,thorn,yuml,' +
36 'OElig,oelig,Scaron,scaron,Yuml';
37
38 // Greek letters entities.
39 var greek = 'Alpha,Beta,Gamma,Delta,Epsilon,Zeta,Eta,Theta,Iota,Kappa,Lambda,Mu,' +
40 'Nu,Xi,Omicron,Pi,Rho,Sigma,Tau,Upsilon,Phi,Chi,Psi,Omega,alpha,' +
41 'beta,gamma,delta,epsilon,zeta,eta,theta,iota,kappa,lambda,mu,nu,xi,' +
42 'omicron,pi,rho,sigmaf,sigma,tau,upsilon,phi,chi,psi,omega,thetasym,' +
43 'upsih,piv';
44
45 // Create a mapping table between one character and its entity form from a list of entity names.
46 // @param reverse {Boolean} Whether to create a reverse map from the entity string form to an actual character.
47 function buildTable( entities, reverse ) {
48 var table = {},
49 regex = [];
50
51 // Entities that the browsers' DOM does not automatically transform to the
52 // final character.
53 var specialTable = {
54 nbsp: '\u00A0', // IE | FF
55 shy: '\u00AD', // IE
56 gt: '\u003E', // IE | FF | -- | Opera
57 lt: '\u003C', // IE | FF | Safari | Opera
58 amp: '\u0026', // ALL
59 apos: '\u0027', // IE
60 quot: '\u0022' // IE
61 };
62
63 entities = entities.replace( /\b(nbsp|shy|gt|lt|amp|apos|quot)(?:,|$)/g, function( match, entity ) {
64 var org = reverse ? '&' + entity + ';' : specialTable[ entity ],
65 result = reverse ? specialTable[ entity ] : '&' + entity + ';';
66
67 table[ org ] = result;
68 regex.push( org );
69 return '';
70 } );
71
72 if ( !reverse && entities ) {
73 // Transforms the entities string into an array.
74 entities = entities.split( ',' );
75
76 // Put all entities inside a DOM element, transforming them to their
77 // final characters.
78 var div = document.createElement( 'div' ),
79 chars;
80 div.innerHTML = '&' + entities.join( ';&' ) + ';';
81 chars = div.innerHTML;
82 div = null;
83
84 // Add all characters to the table.
85 for ( var i = 0; i < chars.length; i++ ) {
86 var charAt = chars.charAt( i );
87 table[ charAt ] = '&' + entities[ i ] + ';';
88 regex.push( charAt );
89 }
90 }
91
92 table.regex = regex.join( reverse ? '|' : '' );
93
94 return table;
95 }
96
97 CKEDITOR.plugins.add( 'entities', {
98 afterInit: function( editor ) {
99 var config = editor.config;
100
101 function getChar( character ) {
102 return baseEntitiesTable[ character ];
103 }
104
105 function getEntity( character ) {
106 return config.entities_processNumerical == 'force' || !entitiesTable[ character ] ? '&#' + character.charCodeAt( 0 ) + ';'
107 : entitiesTable[ character ];
108 }
109
110 var dataProcessor = editor.dataProcessor,
111 htmlFilter = dataProcessor && dataProcessor.htmlFilter;
112
113 if ( htmlFilter ) {
114 // Mandatory HTML basic entities.
115 var selectedEntities = [];
116
117 if ( config.basicEntities !== false )
118 selectedEntities.push( htmlbase );
119
120 if ( config.entities ) {
121 if ( selectedEntities.length )
122 selectedEntities.push( entities );
123
124 if ( config.entities_latin )
125 selectedEntities.push( latin );
126
127 if ( config.entities_greek )
128 selectedEntities.push( greek );
129
130 if ( config.entities_additional )
131 selectedEntities.push( config.entities_additional );
132 }
133
134 var entitiesTable = buildTable( selectedEntities.join( ',' ) );
135
136 // Create the Regex used to find entities in the text, leave it matches nothing if entities are empty.
137 var entitiesRegex = entitiesTable.regex ? '[' + entitiesTable.regex + ']' : 'a^';
138 delete entitiesTable.regex;
139
140 if ( config.entities && config.entities_processNumerical )
141 entitiesRegex = '[^ -~]|' + entitiesRegex;
142
143 entitiesRegex = new RegExp( entitiesRegex, 'g' );
144
145 // Decode entities that the browsers has transformed
146 // at first place.
147 var baseEntitiesTable = buildTable( [ htmlbase, 'shy' ].join( ',' ), true ),
148 baseEntitiesRegex = new RegExp( baseEntitiesTable.regex, 'g' );
149
150 htmlFilter.addRules( {
151 text: function( text ) {
152 return text.replace( baseEntitiesRegex, getChar ).replace( entitiesRegex, getEntity );
153 }
154 }, {
155 applyToAll: true,
156 excludeNestedEditable: true
157 } );
158 }
159 }
160 } );
161} )();
162
163/**
164 * Whether to escape basic HTML entities in the document, including:
165 *
166 * * `&nbsp;`
167 * * `&gt;`
168 * * `&lt;`
169 * * `&amp;`
170 *
171 * **Note:** This option should not be changed unless when outputting a non-HTML data format like BBCode.
172 *
173 * config.basicEntities = false;
174 *
175 * @cfg {Boolean} [basicEntities=true]
176 * @member CKEDITOR.config
177 */
178CKEDITOR.config.basicEntities = true;
179
180/**
181 * Whether to use HTML entities in the editor output.
182 *
183 * config.entities = false;
184 *
185 * @cfg {Boolean} [entities=true]
186 * @member CKEDITOR.config
187 */
188CKEDITOR.config.entities = true;
189
190/**
191 * Whether to convert some Latin characters (Latin alphabet No. 1, ISO 8859-1)
192 * to HTML entities. The list of entities can be found in the
193 * [W3C HTML 4.01 Specification, section 24.2.1](http://www.w3.org/TR/html4/sgml/entities.html#h-24.2.1).
194 *
195 * config.entities_latin = false;
196 *
197 * @cfg {Boolean} [entities_latin=true]
198 * @member CKEDITOR.config
199 */
200CKEDITOR.config.entities_latin = true;
201
202/**
203 * Whether to convert some symbols, mathematical symbols, and Greek letters to
204 * HTML entities. This may be more relevant for users typing text written in Greek.
205 * The list of entities can be found in the
206 * [W3C HTML 4.01 Specification, section 24.3.1](http://www.w3.org/TR/html4/sgml/entities.html#h-24.3.1).
207 *
208 * config.entities_greek = false;
209 *
210 * @cfg {Boolean} [entities_greek=true]
211 * @member CKEDITOR.config
212 */
213CKEDITOR.config.entities_greek = true;
214
215/**
216 * Whether to convert all remaining characters not included in the ASCII
217 * character table to their relative decimal numeric representation of HTML entity.
218 * When set to `force`, it will convert all entities into this format.
219 *
220 * For example the phrase: `'This is Chinese: 汉语.'` would be output
221 * as: `'This is Chinese: &#27721;&#35821;.'`
222 *
223 * config.entities_processNumerical = true;
224 * config.entities_processNumerical = 'force'; // Converts from '&nbsp;' into '&#160;';
225 *
226 * @cfg {Boolean/String} [entities_processNumerical=false]
227 * @member CKEDITOR.config
228 */
229
230/**
231 * A comma-separated list of additional entities to be used. Entity names
232 * or numbers must be used in a form that excludes the `'&amp;'` prefix and the `';'` ending.
233 *
234 * config.entities_additional = '#1049'; // Adds Cyrillic capital letter Short I (Й).
235 *
236 * @cfg {String} [entities_additional='#39' (The single quote (') character)]
237 * @member CKEDITOR.config
238 */
239CKEDITOR.config.entities_additional = '#39';
diff --git a/sources/plugins/fakeobjects/lang/af.js b/sources/plugins/fakeobjects/lang/af.js
new file mode 100644
index 0000000..835d45b
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/af.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'af', {
6 anchor: 'Anker',
7 flash: 'Flash animasie',
8 hiddenfield: 'Verborge veld',
9 iframe: 'IFrame',
10 unknown: 'Onbekende objek'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ar.js b/sources/plugins/fakeobjects/lang/ar.js
new file mode 100644
index 0000000..44363c9
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ar.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ar', {
6 anchor: 'إرساء',
7 flash: 'رسم متحرك بالفلاش',
8 hiddenfield: 'إدراج حقل خفي',
9 iframe: 'iframe',
10 unknown: 'عنصر غير معروف'
11} );
diff --git a/sources/plugins/fakeobjects/lang/az.js b/sources/plugins/fakeobjects/lang/az.js
new file mode 100644
index 0000000..01fa87d
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/az.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'az', {
6 anchor: 'Lövbər',
7 flash: 'Flash animasiya',
8 hiddenfield: 'Gizli xana',
9 iframe: 'IFrame',
10 unknown: 'Tanımamış obyekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/bg.js b/sources/plugins/fakeobjects/lang/bg.js
new file mode 100644
index 0000000..538cdf1
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/bg.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'bg', {
6 anchor: 'Кука',
7 flash: 'Флаш анимация',
8 hiddenfield: 'Скрито поле',
9 iframe: 'IFrame',
10 unknown: 'Неизвестен обект'
11} );
diff --git a/sources/plugins/fakeobjects/lang/bn.js b/sources/plugins/fakeobjects/lang/bn.js
new file mode 100644
index 0000000..70c9ce9
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/bn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'bn', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/bs.js b/sources/plugins/fakeobjects/lang/bs.js
new file mode 100644
index 0000000..4a17242
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/bs.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'bs', {
6 anchor: 'Anchor',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/ca.js b/sources/plugins/fakeobjects/lang/ca.js
new file mode 100644
index 0000000..cc09e6c
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ca', {
6 anchor: 'Àncora',
7 flash: 'Animació Flash',
8 hiddenfield: 'Camp ocult',
9 iframe: 'IFrame',
10 unknown: 'Objecte desconegut'
11} );
diff --git a/sources/plugins/fakeobjects/lang/cs.js b/sources/plugins/fakeobjects/lang/cs.js
new file mode 100644
index 0000000..7355f4a
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/cs.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'cs', {
6 anchor: 'Záložka',
7 flash: 'Flash animace',
8 hiddenfield: 'Skryté pole',
9 iframe: 'IFrame',
10 unknown: 'Neznámý objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/cy.js b/sources/plugins/fakeobjects/lang/cy.js
new file mode 100644
index 0000000..8b0ffc9
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/cy.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'cy', {
6 anchor: 'Angor',
7 flash: 'Animeiddiant Flash',
8 hiddenfield: 'Maes Cudd',
9 iframe: 'IFrame',
10 unknown: 'Gwrthrych Anhysbys'
11} );
diff --git a/sources/plugins/fakeobjects/lang/da.js b/sources/plugins/fakeobjects/lang/da.js
new file mode 100644
index 0000000..06a869f
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/da.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'da', {
6 anchor: 'Anker',
7 flash: 'Flashanimation',
8 hiddenfield: 'Skjult felt',
9 iframe: 'Iframe',
10 unknown: 'Ukendt objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/de-ch.js b/sources/plugins/fakeobjects/lang/de-ch.js
new file mode 100644
index 0000000..068a003
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/de-ch.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'de-ch', {
6 anchor: 'Anker',
7 flash: 'Flash-Animation',
8 hiddenfield: 'Verstecktes Feld',
9 iframe: 'IFrame',
10 unknown: 'Unbekanntes Objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/de.js b/sources/plugins/fakeobjects/lang/de.js
new file mode 100644
index 0000000..32326cf
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/de.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'de', {
6 anchor: 'Anker',
7 flash: 'Flash-Animation',
8 hiddenfield: 'Verstecktes Feld',
9 iframe: 'IFrame',
10 unknown: 'Unbekanntes Objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/el.js b/sources/plugins/fakeobjects/lang/el.js
new file mode 100644
index 0000000..211c8d4
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/el.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'el', {
6 anchor: 'Άγκυρα',
7 flash: 'Ταινία Flash',
8 hiddenfield: 'Κρυφό Πεδίο',
9 iframe: 'IFrame',
10 unknown: 'Άγνωστο Αντικείμενο'
11} );
diff --git a/sources/plugins/fakeobjects/lang/en-au.js b/sources/plugins/fakeobjects/lang/en-au.js
new file mode 100644
index 0000000..189e5c8
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/en-au.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'en-au', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/en-ca.js b/sources/plugins/fakeobjects/lang/en-ca.js
new file mode 100644
index 0000000..071bc10
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/en-ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'en-ca', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/en-gb.js b/sources/plugins/fakeobjects/lang/en-gb.js
new file mode 100644
index 0000000..e38f16c
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/en-gb.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'en-gb', {
6 anchor: 'Anchor',
7 flash: 'Flash Animation',
8 hiddenfield: 'Hidden Field',
9 iframe: 'IFrame',
10 unknown: 'Unknown Object'
11} );
diff --git a/sources/plugins/fakeobjects/lang/en.js b/sources/plugins/fakeobjects/lang/en.js
new file mode 100644
index 0000000..d871231
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/en.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'en', {
6 anchor: 'Anchor',
7 flash: 'Flash Animation',
8 hiddenfield: 'Hidden Field',
9 iframe: 'IFrame',
10 unknown: 'Unknown Object'
11} );
diff --git a/sources/plugins/fakeobjects/lang/eo.js b/sources/plugins/fakeobjects/lang/eo.js
new file mode 100644
index 0000000..bbce7f8
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/eo.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'eo', {
6 anchor: 'Ankro',
7 flash: 'FlaŝAnimacio',
8 hiddenfield: 'Kaŝita kampo',
9 iframe: 'Enlinia Kadro (IFrame)',
10 unknown: 'Nekonata objekto'
11} );
diff --git a/sources/plugins/fakeobjects/lang/es.js b/sources/plugins/fakeobjects/lang/es.js
new file mode 100644
index 0000000..46ac72f
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/es.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'es', {
6 anchor: 'Ancla',
7 flash: 'Animación flash',
8 hiddenfield: 'Campo oculto',
9 iframe: 'IFrame',
10 unknown: 'Objeto desconocido'
11} );
diff --git a/sources/plugins/fakeobjects/lang/et.js b/sources/plugins/fakeobjects/lang/et.js
new file mode 100644
index 0000000..2c25f43
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/et.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'et', {
6 anchor: 'Ankur',
7 flash: 'Flashi animatsioon',
8 hiddenfield: 'Varjatud väli',
9 iframe: 'IFrame',
10 unknown: 'Tundmatu objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/eu.js b/sources/plugins/fakeobjects/lang/eu.js
new file mode 100644
index 0000000..dfc4460
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/eu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'eu', {
6 anchor: 'Aingura',
7 flash: 'Flash animazioa',
8 hiddenfield: 'Ezkutuko eremua',
9 iframe: 'IFrame-a',
10 unknown: 'Objektu ezezaguna'
11} );
diff --git a/sources/plugins/fakeobjects/lang/fa.js b/sources/plugins/fakeobjects/lang/fa.js
new file mode 100644
index 0000000..4104d1f
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/fa.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'fa', {
6 anchor: 'لنگر',
7 flash: 'انیمشن فلش',
8 hiddenfield: 'فیلد پنهان',
9 iframe: 'IFrame',
10 unknown: 'شیء ناشناخته'
11} );
diff --git a/sources/plugins/fakeobjects/lang/fi.js b/sources/plugins/fakeobjects/lang/fi.js
new file mode 100644
index 0000000..c663093
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/fi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'fi', {
6 anchor: 'Ankkuri',
7 flash: 'Flash animaatio',
8 hiddenfield: 'Piilokenttä',
9 iframe: 'IFrame-kehys',
10 unknown: 'Tuntematon objekti'
11} );
diff --git a/sources/plugins/fakeobjects/lang/fo.js b/sources/plugins/fakeobjects/lang/fo.js
new file mode 100644
index 0000000..8b7c2f9
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/fo.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'fo', {
6 anchor: 'Anchor',
7 flash: 'Flash Animation',
8 hiddenfield: 'Fjaldur teigur',
9 iframe: 'IFrame',
10 unknown: 'Ókent Object'
11} );
diff --git a/sources/plugins/fakeobjects/lang/fr-ca.js b/sources/plugins/fakeobjects/lang/fr-ca.js
new file mode 100644
index 0000000..c281f4f
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/fr-ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'fr-ca', {
6 anchor: 'Ancre',
7 flash: 'Animation Flash',
8 hiddenfield: 'Champ caché',
9 iframe: 'IFrame',
10 unknown: 'Objet inconnu'
11} );
diff --git a/sources/plugins/fakeobjects/lang/fr.js b/sources/plugins/fakeobjects/lang/fr.js
new file mode 100644
index 0000000..be306ec
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/fr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'fr', {
6 anchor: 'Ancre',
7 flash: 'Animation Flash',
8 hiddenfield: 'Champ invisible',
9 iframe: 'Cadre de contenu incorporé',
10 unknown: 'Objet inconnu'
11} );
diff --git a/sources/plugins/fakeobjects/lang/gl.js b/sources/plugins/fakeobjects/lang/gl.js
new file mode 100644
index 0000000..2c353a4
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/gl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'gl', {
6 anchor: 'Ancoraxe',
7 flash: 'Animación «Flash»',
8 hiddenfield: 'Campo agochado',
9 iframe: 'IFrame',
10 unknown: 'Obxecto descoñecido'
11} );
diff --git a/sources/plugins/fakeobjects/lang/gu.js b/sources/plugins/fakeobjects/lang/gu.js
new file mode 100644
index 0000000..66fb428
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/gu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'gu', {
6 anchor: 'અનકર',
7 flash: 'ફ્લેશ ',
8 hiddenfield: 'હિડન ',
9 iframe: 'IFrame',
10 unknown: 'અનનોન ઓબ્જેક્ટ'
11} );
diff --git a/sources/plugins/fakeobjects/lang/he.js b/sources/plugins/fakeobjects/lang/he.js
new file mode 100644
index 0000000..bc0d472
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/he.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'he', {
6 anchor: 'עוגן',
7 flash: 'סרטון פלאש',
8 hiddenfield: 'שדה חבוי',
9 iframe: 'חלון פנימי (iframe)',
10 unknown: 'אובייקט לא ידוע'
11} );
diff --git a/sources/plugins/fakeobjects/lang/hi.js b/sources/plugins/fakeobjects/lang/hi.js
new file mode 100644
index 0000000..e2cc724
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/hi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'hi', {
6 anchor: 'ऐंकर इन्सर्ट/संपादन',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'गुप्त फ़ील्ड',
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/hr.js b/sources/plugins/fakeobjects/lang/hr.js
new file mode 100644
index 0000000..11f3574
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/hr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'hr', {
6 anchor: 'Sidro',
7 flash: 'Flash animacija',
8 hiddenfield: 'Sakriveno polje',
9 iframe: 'IFrame',
10 unknown: 'Nepoznati objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/hu.js b/sources/plugins/fakeobjects/lang/hu.js
new file mode 100644
index 0000000..24cec55
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/hu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'hu', {
6 anchor: 'Horgony',
7 flash: 'Flash animáció',
8 hiddenfield: 'Rejtett mezõ',
9 iframe: 'IFrame',
10 unknown: 'Ismeretlen objektum'
11} );
diff --git a/sources/plugins/fakeobjects/lang/id.js b/sources/plugins/fakeobjects/lang/id.js
new file mode 100644
index 0000000..85d8c14
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/id.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'id', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Animasi Flash',
8 hiddenfield: 'Kolom Tersembunyi',
9 iframe: 'IFrame',
10 unknown: 'Obyek Tak Dikenal'
11} );
diff --git a/sources/plugins/fakeobjects/lang/is.js b/sources/plugins/fakeobjects/lang/is.js
new file mode 100644
index 0000000..40df479
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/is.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'is', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/it.js b/sources/plugins/fakeobjects/lang/it.js
new file mode 100644
index 0000000..8993951
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/it.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'it', {
6 anchor: 'Ancora',
7 flash: 'Animazione Flash',
8 hiddenfield: 'Campo Nascosto',
9 iframe: 'IFrame',
10 unknown: 'Oggetto sconosciuto'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ja.js b/sources/plugins/fakeobjects/lang/ja.js
new file mode 100644
index 0000000..db21eeb
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ja.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ja', {
6 anchor: 'アンカー',
7 flash: 'Flash Animation',
8 hiddenfield: '不可視フィールド',
9 iframe: 'IFrame',
10 unknown: 'Unknown Object'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ka.js b/sources/plugins/fakeobjects/lang/ka.js
new file mode 100644
index 0000000..3544161
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ka.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ka', {
6 anchor: 'ღუზა',
7 flash: 'Flash ანიმაცია',
8 hiddenfield: 'მალული ველი',
9 iframe: 'IFrame',
10 unknown: 'უცნობი ობიექტი'
11} );
diff --git a/sources/plugins/fakeobjects/lang/km.js b/sources/plugins/fakeobjects/lang/km.js
new file mode 100644
index 0000000..54be6d0
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/km.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'km', {
6 anchor: 'យុថ្កា',
7 flash: 'Flash មាន​ចលនា',
8 hiddenfield: 'វាល​កំបាំង',
9 iframe: 'IFrame',
10 unknown: 'វត្ថុ​មិន​ស្គាល់'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ko.js b/sources/plugins/fakeobjects/lang/ko.js
new file mode 100644
index 0000000..b5c0593
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ko.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ko', {
6 anchor: '책갈피',
7 flash: '플래시 애니메이션',
8 hiddenfield: '숨은 입력 칸',
9 iframe: '아이프레임',
10 unknown: '알 수 없는 객체'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ku.js b/sources/plugins/fakeobjects/lang/ku.js
new file mode 100644
index 0000000..bbfb9f6
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ku.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ku', {
6 anchor: 'لەنگەر',
7 flash: 'فلاش',
8 hiddenfield: 'شاردنەوەی خانه',
9 iframe: 'لەچوارچێوە',
10 unknown: 'بەرکارێکی نەناسراو'
11} );
diff --git a/sources/plugins/fakeobjects/lang/lt.js b/sources/plugins/fakeobjects/lang/lt.js
new file mode 100644
index 0000000..e14c211
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/lt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'lt', {
6 anchor: 'Žymė',
7 flash: 'Flash animacija',
8 hiddenfield: 'Paslėptas laukas',
9 iframe: 'IFrame',
10 unknown: 'Nežinomas objektas'
11} );
diff --git a/sources/plugins/fakeobjects/lang/lv.js b/sources/plugins/fakeobjects/lang/lv.js
new file mode 100644
index 0000000..388e486
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/lv.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'lv', {
6 anchor: 'Iezīme',
7 flash: 'Flash animācija',
8 hiddenfield: 'Slēpts lauks',
9 iframe: 'Iframe',
10 unknown: 'Nezināms objekts'
11} );
diff --git a/sources/plugins/fakeobjects/lang/mk.js b/sources/plugins/fakeobjects/lang/mk.js
new file mode 100644
index 0000000..deacc87
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/mk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'mk', {
6 anchor: 'Anchor',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Скриено поле',
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/mn.js b/sources/plugins/fakeobjects/lang/mn.js
new file mode 100644
index 0000000..a2857cc
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/mn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'mn', {
6 anchor: 'Зангуу',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Нууц талбар',
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/ms.js b/sources/plugins/fakeobjects/lang/ms.js
new file mode 100644
index 0000000..7325f14
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ms.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ms', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/nb.js b/sources/plugins/fakeobjects/lang/nb.js
new file mode 100644
index 0000000..b6a6527
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/nb.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'nb', {
6 anchor: 'Anker',
7 flash: 'Flash-animasjon',
8 hiddenfield: 'Skjult felt',
9 iframe: 'IFrame',
10 unknown: 'Ukjent objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/nl.js b/sources/plugins/fakeobjects/lang/nl.js
new file mode 100644
index 0000000..158985a
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/nl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'nl', {
6 anchor: 'Interne link',
7 flash: 'Flash animatie',
8 hiddenfield: 'Verborgen veld',
9 iframe: 'IFrame',
10 unknown: 'Onbekend object'
11} );
diff --git a/sources/plugins/fakeobjects/lang/no.js b/sources/plugins/fakeobjects/lang/no.js
new file mode 100644
index 0000000..cbbb4cf
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/no.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'no', {
6 anchor: 'Anker',
7 flash: 'Flash-animasjon',
8 hiddenfield: 'Skjult felt',
9 iframe: 'IFrame',
10 unknown: 'Ukjent objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/oc.js b/sources/plugins/fakeobjects/lang/oc.js
new file mode 100644
index 0000000..0ecfcf8
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/oc.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'oc', {
6 anchor: 'Ancòra',
7 flash: 'Animacion Flash',
8 hiddenfield: 'Camp invisible',
9 iframe: 'Quadre de contengut incorporat',
10 unknown: 'Objècte desconegut'
11} );
diff --git a/sources/plugins/fakeobjects/lang/pl.js b/sources/plugins/fakeobjects/lang/pl.js
new file mode 100644
index 0000000..06b3a20
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/pl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'pl', {
6 anchor: 'Kotwica',
7 flash: 'Animacja Flash',
8 hiddenfield: 'Pole ukryte',
9 iframe: 'IFrame',
10 unknown: 'Nieznany obiekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/pt-br.js b/sources/plugins/fakeobjects/lang/pt-br.js
new file mode 100644
index 0000000..6198bf3
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/pt-br.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'pt-br', {
6 anchor: 'Âncora',
7 flash: 'Animação em Flash',
8 hiddenfield: 'Campo Oculto',
9 iframe: 'IFrame',
10 unknown: 'Objeto desconhecido'
11} );
diff --git a/sources/plugins/fakeobjects/lang/pt.js b/sources/plugins/fakeobjects/lang/pt.js
new file mode 100644
index 0000000..c3d762f
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/pt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'pt', {
6 anchor: ' Inserir/Editar âncora',
7 flash: 'Animação Flash',
8 hiddenfield: 'Campo oculto',
9 iframe: 'IFrame',
10 unknown: 'Objeto desconhecido'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ro.js b/sources/plugins/fakeobjects/lang/ro.js
new file mode 100644
index 0000000..25535d3
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ro.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ro', {
6 anchor: 'Inserează/Editează ancoră',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Câmp ascuns (HiddenField)',
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/ru.js b/sources/plugins/fakeobjects/lang/ru.js
new file mode 100644
index 0000000..7f93bc7
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ru.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ru', {
6 anchor: 'Якорь',
7 flash: 'Flash анимация',
8 hiddenfield: 'Скрытое поле',
9 iframe: 'iFrame',
10 unknown: 'Неизвестный объект'
11} );
diff --git a/sources/plugins/fakeobjects/lang/si.js b/sources/plugins/fakeobjects/lang/si.js
new file mode 100644
index 0000000..319240b
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/si.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'si', {
6 anchor: 'ආධාරය',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'සැඟවුණු ප්‍රදේශය',
9 iframe: 'IFrame',
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/sk.js b/sources/plugins/fakeobjects/lang/sk.js
new file mode 100644
index 0000000..1372c54
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sk', {
6 anchor: 'Kotva',
7 flash: 'Flash animácia',
8 hiddenfield: 'Skryté pole',
9 iframe: 'IFrame',
10 unknown: 'Neznámy objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/sl.js b/sources/plugins/fakeobjects/lang/sl.js
new file mode 100644
index 0000000..f6d9827
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sl', {
6 anchor: 'Sidro',
7 flash: 'Animacija flash',
8 hiddenfield: 'Skrito polje',
9 iframe: 'IFrame',
10 unknown: 'Neznan objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/sq.js b/sources/plugins/fakeobjects/lang/sq.js
new file mode 100644
index 0000000..05f0987
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sq.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sq', {
6 anchor: 'Spirancë',
7 flash: 'Objekt flash',
8 hiddenfield: 'Fushë e fshehur',
9 iframe: 'IFrame',
10 unknown: 'Objekt i Panjohur'
11} );
diff --git a/sources/plugins/fakeobjects/lang/sr-latn.js b/sources/plugins/fakeobjects/lang/sr-latn.js
new file mode 100644
index 0000000..fb497f0
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sr-latn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sr-latn', {
6 anchor: 'Unesi/izmeni sidro',
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Skriveno polje',
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/sr.js b/sources/plugins/fakeobjects/lang/sr.js
new file mode 100644
index 0000000..82a59cb
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sr', {
6 anchor: 'Anchor', // MISSING
7 flash: 'Flash Animation', // MISSING
8 hiddenfield: 'Hidden Field', // MISSING
9 iframe: 'IFrame', // MISSING
10 unknown: 'Unknown Object' // MISSING
11} );
diff --git a/sources/plugins/fakeobjects/lang/sv.js b/sources/plugins/fakeobjects/lang/sv.js
new file mode 100644
index 0000000..3db31fb
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/sv.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'sv', {
6 anchor: 'Ankare',
7 flash: 'Flashanimation',
8 hiddenfield: 'Gömt fält',
9 iframe: 'iFrame',
10 unknown: 'Okänt objekt'
11} );
diff --git a/sources/plugins/fakeobjects/lang/th.js b/sources/plugins/fakeobjects/lang/th.js
new file mode 100644
index 0000000..c0d1f4e
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/th.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'th', {
6 anchor: 'แทรก/แก้ไข Anchor',
7 flash: 'ภาพอนิเมชั่นแฟลช',
8 hiddenfield: 'ฮิดเดนฟิลด์',
9 iframe: 'IFrame',
10 unknown: 'วัตถุไม่ทราบชนิด'
11} );
diff --git a/sources/plugins/fakeobjects/lang/tr.js b/sources/plugins/fakeobjects/lang/tr.js
new file mode 100644
index 0000000..768b7c1
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/tr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'tr', {
6 anchor: 'Bağlantı',
7 flash: 'Flash Animasyonu',
8 hiddenfield: 'Gizli Alan',
9 iframe: 'IFrame',
10 unknown: 'Bilinmeyen Nesne'
11} );
diff --git a/sources/plugins/fakeobjects/lang/tt.js b/sources/plugins/fakeobjects/lang/tt.js
new file mode 100644
index 0000000..df1a714
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/tt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'tt', {
6 anchor: 'Якорь',
7 flash: 'Флеш анимациясы',
8 hiddenfield: 'Яшерен кыр',
9 iframe: 'IFrame',
10 unknown: 'Танылмаган объект'
11} );
diff --git a/sources/plugins/fakeobjects/lang/ug.js b/sources/plugins/fakeobjects/lang/ug.js
new file mode 100644
index 0000000..c44b8de
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/ug.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'ug', {
6 anchor: 'لەڭگەرلىك نۇقتا',
7 flash: 'Flash جانلاندۇرۇم',
8 hiddenfield: 'يوشۇرۇن دائىرە',
9 iframe: 'IFrame',
10 unknown: 'يوچۇن نەڭ'
11} );
diff --git a/sources/plugins/fakeobjects/lang/uk.js b/sources/plugins/fakeobjects/lang/uk.js
new file mode 100644
index 0000000..81da8ca
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/uk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'uk', {
6 anchor: 'Якір',
7 flash: 'Flash-анімація',
8 hiddenfield: 'Приховані Поля',
9 iframe: 'IFrame',
10 unknown: 'Невідомий об\'єкт'
11} );
diff --git a/sources/plugins/fakeobjects/lang/vi.js b/sources/plugins/fakeobjects/lang/vi.js
new file mode 100644
index 0000000..f1346aa
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/vi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'vi', {
6 anchor: 'Điểm neo',
7 flash: 'Flash',
8 hiddenfield: 'Trường ẩn',
9 iframe: 'IFrame',
10 unknown: 'Đối tượng không rõ ràng'
11} );
diff --git a/sources/plugins/fakeobjects/lang/zh-cn.js b/sources/plugins/fakeobjects/lang/zh-cn.js
new file mode 100644
index 0000000..8d304c2
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/zh-cn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'zh-cn', {
6 anchor: '锚点',
7 flash: 'Flash 动画',
8 hiddenfield: '隐藏域',
9 iframe: 'IFrame',
10 unknown: '未知对象'
11} );
diff --git a/sources/plugins/fakeobjects/lang/zh.js b/sources/plugins/fakeobjects/lang/zh.js
new file mode 100644
index 0000000..1255003
--- /dev/null
+++ b/sources/plugins/fakeobjects/lang/zh.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'fakeobjects', 'zh', {
6 anchor: '錨點',
7 flash: 'Flash 動畫',
8 hiddenfield: '隱藏欄位',
9 iframe: 'IFrame',
10 unknown: '無法辨識的物件'
11} );
diff --git a/sources/plugins/fakeobjects/plugin.js b/sources/plugins/fakeobjects/plugin.js
new file mode 100644
index 0000000..d35698b
--- /dev/null
+++ b/sources/plugins/fakeobjects/plugin.js
@@ -0,0 +1,183 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var cssStyle = CKEDITOR.htmlParser.cssStyle,
8 cssLength = CKEDITOR.tools.cssLength;
9
10 var cssLengthRegex = /^((?:\d*(?:\.\d+))|(?:\d+))(.*)?$/i;
11
12 // Replacing the former CSS length value with the later one, with
13 // adjustment to the length unit.
14 function replaceCssLength( length1, length2 ) {
15 var parts1 = cssLengthRegex.exec( length1 ),
16 parts2 = cssLengthRegex.exec( length2 );
17
18 // Omit pixel length unit when necessary,
19 // e.g. replaceCssLength( 10, '20px' ) -> 20
20 if ( parts1 ) {
21 if ( !parts1[ 2 ] && parts2[ 2 ] == 'px' )
22 return parts2[ 1 ];
23 if ( parts1[ 2 ] == 'px' && !parts2[ 2 ] )
24 return parts2[ 1 ] + 'px';
25 }
26
27 return length2;
28 }
29
30 var htmlFilterRules = {
31 elements: {
32 $: function( element ) {
33 var attributes = element.attributes,
34 realHtml = attributes && attributes[ 'data-cke-realelement' ],
35 realFragment = realHtml && new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( realHtml ) ),
36 realElement = realFragment && realFragment.children[ 0 ];
37
38 // Width/height in the fake object are subjected to clone into the real element.
39 if ( realElement && element.attributes[ 'data-cke-resizable' ] ) {
40 var styles = new cssStyle( element ).rules,
41 realAttrs = realElement.attributes,
42 width = styles.width,
43 height = styles.height;
44
45 width && ( realAttrs.width = replaceCssLength( realAttrs.width, width ) );
46 height && ( realAttrs.height = replaceCssLength( realAttrs.height, height ) );
47 }
48
49 return realElement;
50 }
51 }
52 };
53
54 CKEDITOR.plugins.add( 'fakeobjects', {
55 // jscs:disable maximumLineLength
56 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
57 // jscs:enable maximumLineLength
58
59 init: function( editor ) {
60 // Allow image with all styles and classes plus src, alt and title attributes.
61 // We need them when fakeobject is pasted.
62 editor.filter.allow( 'img[!data-cke-realelement,src,alt,title](*){*}', 'fakeobjects' );
63 },
64
65 afterInit: function( editor ) {
66 var dataProcessor = editor.dataProcessor,
67 htmlFilter = dataProcessor && dataProcessor.htmlFilter;
68
69 if ( htmlFilter ) {
70 htmlFilter.addRules( htmlFilterRules, {
71 applyToAll: true
72 } );
73 }
74 }
75 } );
76
77 /**
78 * @member CKEDITOR.editor
79 * @todo
80 */
81 CKEDITOR.editor.prototype.createFakeElement = function( realElement, className, realElementType, isResizable ) {
82 var lang = this.lang.fakeobjects,
83 label = lang[ realElementType ] || lang.unknown;
84
85 var attributes = {
86 'class': className,
87 'data-cke-realelement': encodeURIComponent( realElement.getOuterHtml() ),
88 'data-cke-real-node-type': realElement.type,
89 alt: label,
90 title: label,
91 align: realElement.getAttribute( 'align' ) || ''
92 };
93
94 // Do not set "src" on high-contrast so the alt text is displayed. (#8945)
95 if ( !CKEDITOR.env.hc )
96 attributes.src = CKEDITOR.tools.transparentImageData;
97
98 if ( realElementType )
99 attributes[ 'data-cke-real-element-type' ] = realElementType;
100
101 if ( isResizable ) {
102 attributes[ 'data-cke-resizable' ] = isResizable;
103
104 var fakeStyle = new cssStyle();
105
106 var width = realElement.getAttribute( 'width' ),
107 height = realElement.getAttribute( 'height' );
108
109 width && ( fakeStyle.rules.width = cssLength( width ) );
110 height && ( fakeStyle.rules.height = cssLength( height ) );
111 fakeStyle.populate( attributes );
112 }
113
114 return this.document.createElement( 'img', { attributes: attributes } );
115 };
116
117 /**
118 * @member CKEDITOR.editor
119 * @todo
120 */
121 CKEDITOR.editor.prototype.createFakeParserElement = function( realElement, className, realElementType, isResizable ) {
122 var lang = this.lang.fakeobjects,
123 label = lang[ realElementType ] || lang.unknown,
124 html;
125
126 var writer = new CKEDITOR.htmlParser.basicWriter();
127 realElement.writeHtml( writer );
128 html = writer.getHtml();
129
130 var attributes = {
131 'class': className,
132 'data-cke-realelement': encodeURIComponent( html ),
133 'data-cke-real-node-type': realElement.type,
134 alt: label,
135 title: label,
136 align: realElement.attributes.align || ''
137 };
138
139 // Do not set "src" on high-contrast so the alt text is displayed. (#8945)
140 if ( !CKEDITOR.env.hc )
141 attributes.src = CKEDITOR.tools.transparentImageData;
142
143 if ( realElementType )
144 attributes[ 'data-cke-real-element-type' ] = realElementType;
145
146 if ( isResizable ) {
147 attributes[ 'data-cke-resizable' ] = isResizable;
148 var realAttrs = realElement.attributes,
149 fakeStyle = new cssStyle();
150
151 var width = realAttrs.width,
152 height = realAttrs.height;
153
154 width !== undefined && ( fakeStyle.rules.width = cssLength( width ) );
155 height !== undefined && ( fakeStyle.rules.height = cssLength( height ) );
156 fakeStyle.populate( attributes );
157 }
158
159 return new CKEDITOR.htmlParser.element( 'img', attributes );
160 };
161
162 /**
163 * @member CKEDITOR.editor
164 * @todo
165 */
166 CKEDITOR.editor.prototype.restoreRealElement = function( fakeElement ) {
167 if ( fakeElement.data( 'cke-real-node-type' ) != CKEDITOR.NODE_ELEMENT )
168 return null;
169
170 var element = CKEDITOR.dom.element.createFromHtml( decodeURIComponent( fakeElement.data( 'cke-realelement' ) ), this.document );
171
172 if ( fakeElement.data( 'cke-resizable' ) ) {
173 var width = fakeElement.getStyle( 'width' ),
174 height = fakeElement.getStyle( 'height' );
175
176 width && element.setAttribute( 'width', replaceCssLength( element.getAttribute( 'width' ), width ) );
177 height && element.setAttribute( 'height', replaceCssLength( element.getAttribute( 'height' ), height ) );
178 }
179
180 return element;
181 };
182
183} )();
diff --git a/sources/plugins/filebrowser/plugin.js b/sources/plugins/filebrowser/plugin.js
new file mode 100644
index 0000000..a622a37
--- /dev/null
+++ b/sources/plugins/filebrowser/plugin.js
@@ -0,0 +1,573 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The "filebrowser" plugin that adds support for file uploads and
8 * browsing.
9 *
10 * When a file is uploaded or selected inside the file browser, its URL is
11 * inserted automatically into a field defined in the <code>filebrowser</code>
12 * attribute. In order to specify a field that should be updated, pass the tab ID and
13 * the element ID, separated with a colon.<br /><br />
14 *
15 * <strong>Example 1: (Browse)</strong>
16 *
17 * <pre>
18 * {
19 * type : 'button',
20 * id : 'browse',
21 * filebrowser : 'tabId:elementId',
22 * label : editor.lang.common.browseServer
23 * }
24 * </pre>
25 *
26 * If you set the <code>filebrowser</code> attribute for an element other than
27 * the <code>fileButton</code>, the <code>Browse</code> action will be triggered.<br /><br />
28 *
29 * <strong>Example 2: (Quick Upload)</strong>
30 *
31 * <pre>
32 * {
33 * type : 'fileButton',
34 * id : 'uploadButton',
35 * filebrowser : 'tabId:elementId',
36 * label : editor.lang.common.uploadSubmit,
37 * 'for' : [ 'upload', 'upload' ]
38 * }
39 * </pre>
40 *
41 * If you set the <code>filebrowser</code> attribute for a <code>fileButton</code>
42 * element, the <code>QuickUpload</code> action will be executed.<br /><br />
43 *
44 * The filebrowser plugin also supports more advanced configuration performed through
45 * a JavaScript object.
46 *
47 * The following settings are supported:
48 *
49 * <ul>
50 * <li><code>action</code> &ndash; <code>Browse</code> or <code>QuickUpload</code>.</li>
51 * <li><code>target</code> &ndash; the field to update in the <code><em>tabId:elementId</em></code> format.</li>
52 * <li><code>params</code> &ndash; additional arguments to be passed to the server connector (optional).</li>
53 * <li><code>onSelect</code> &ndash; a function to execute when the file is selected/uploaded (optional).</li>
54 * <li><code>url</code> &ndash; the URL to be called (optional).</li>
55 * </ul>
56 *
57 * <strong>Example 3: (Quick Upload)</strong>
58 *
59 * <pre>
60 * {
61 * type : 'fileButton',
62 * label : editor.lang.common.uploadSubmit,
63 * id : 'buttonId',
64 * filebrowser :
65 * {
66 * action : 'QuickUpload', // required
67 * target : 'tab1:elementId', // required
68 * params : // optional
69 * {
70 * type : 'Files',
71 * currentFolder : '/folder/'
72 * },
73 * onSelect : function( fileUrl, errorMessage ) // optional
74 * {
75 * // Do not call the built-in selectFuntion.
76 * // return false;
77 * }
78 * },
79 * 'for' : [ 'tab1', 'myFile' ]
80 * }
81 * </pre>
82 *
83 * Suppose you have a file element with an ID of <code>myFile</code>, a text
84 * field with an ID of <code>elementId</code> and a <code>fileButton</code>.
85 * If the <code>filebowser.url</code> attribute is not specified explicitly,
86 * the form action will be set to <code>filebrowser[<em>DialogWindowName</em>]UploadUrl</code>
87 * or, if not specified, to <code>filebrowserUploadUrl</code>. Additional parameters
88 * from the <code>params</code> object will be added to the query string. It is
89 * possible to create your own <code>uploadHandler</code> and cancel the built-in
90 * <code>updateTargetElement</code> command.<br /><br />
91 *
92 * <strong>Example 4: (Browse)</strong>
93 *
94 * <pre>
95 * {
96 * type : 'button',
97 * id : 'buttonId',
98 * label : editor.lang.common.browseServer,
99 * filebrowser :
100 * {
101 * action : 'Browse',
102 * url : '/ckfinder/ckfinder.html&amp;type=Images',
103 * target : 'tab1:elementId'
104 * }
105 * }
106 * </pre>
107 *
108 * In this example, when the button is pressed, the file browser will be opened in a
109 * popup window. If you do not specify the <code>filebrowser.url</code> attribute,
110 * <code>filebrowser[<em>DialogName</em>]BrowseUrl</code> or
111 * <code>filebrowserBrowseUrl</code> will be used. After selecting a file in the file
112 * browser, an element with an ID of <code>elementId</code> will be updated. Just
113 * like in the third example, a custom <code>onSelect</code> function may be defined.
114 */
115
116( function() {
117 // Default input element name for CSRF protection token.
118 var TOKEN_INPUT_NAME = 'ckCsrfToken';
119
120 // Adds (additional) arguments to given url.
121 //
122 // @param {String}
123 // url The url.
124 // @param {Object}
125 // params Additional parameters.
126 function addQueryString( url, params ) {
127 var queryString = [];
128
129 if ( !params )
130 return url;
131 else {
132 for ( var i in params )
133 queryString.push( i + '=' + encodeURIComponent( params[ i ] ) );
134 }
135
136 return url + ( ( url.indexOf( '?' ) != -1 ) ? '&' : '?' ) + queryString.join( '&' );
137 }
138
139 // Make a string's first character uppercase.
140 //
141 // @param {String}
142 // str String.
143 function ucFirst( str ) {
144 str += '';
145 var f = str.charAt( 0 ).toUpperCase();
146 return f + str.substr( 1 );
147 }
148
149 // The onlick function assigned to the 'Browse Server' button. Opens the
150 // file browser and updates target field when file is selected.
151 //
152 // @param {CKEDITOR.event}
153 // evt The event object.
154 function browseServer() {
155 var dialog = this.getDialog();
156 var editor = dialog.getParentEditor();
157
158 editor._.filebrowserSe = this;
159
160 var width = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowWidth' ] || editor.config.filebrowserWindowWidth || '80%';
161 var height = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowHeight' ] || editor.config.filebrowserWindowHeight || '70%';
162
163 var params = this.filebrowser.params || {};
164 params.CKEditor = editor.name;
165 params.CKEditorFuncNum = editor._.filebrowserFn;
166 if ( !params.langCode )
167 params.langCode = editor.langCode;
168
169 var url = addQueryString( this.filebrowser.url, params );
170 // TODO: V4: Remove backward compatibility (#8163).
171 editor.popup( url, width, height, editor.config.filebrowserWindowFeatures || editor.config.fileBrowserWindowFeatures );
172 }
173
174 // Appends token preventing CSRF attacks to the form of provided file input.
175 //
176 // @since 4.5.6
177 // @param {CKEDITOR.dom.element} fileInput
178 function appendToken( fileInput ) {
179 var tokenElement;
180 var form = new CKEDITOR.dom.element( fileInput.$.form );
181
182 if ( form ) {
183 // Check if token input element already exists.
184 tokenElement = form.$.elements[ TOKEN_INPUT_NAME ];
185
186 // Create new if needed.
187 if ( !tokenElement ) {
188 tokenElement = new CKEDITOR.dom.element( 'input' );
189 tokenElement.setAttributes( {
190 name: TOKEN_INPUT_NAME,
191 type: 'hidden'
192 } );
193
194 form.append( tokenElement );
195 } else {
196 tokenElement = new CKEDITOR.dom.element( tokenElement );
197 }
198
199 tokenElement.setAttribute( 'value', CKEDITOR.tools.getCsrfToken() );
200 }
201 }
202
203 // The onlick function assigned to the 'Upload' button. Makes the final
204 // decision whether form is really submitted and updates target field when
205 // file is uploaded.
206 //
207 // @param {CKEDITOR.event}
208 // evt The event object.
209 function uploadFile() {
210 var dialog = this.getDialog();
211 var editor = dialog.getParentEditor();
212
213 editor._.filebrowserSe = this;
214
215 // If user didn't select the file, stop the upload.
216 if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getInputElement().$.value )
217 return false;
218
219 if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getAction() )
220 return false;
221
222 return true;
223 }
224
225 // Setups the file element.
226 //
227 // @param {CKEDITOR.ui.dialog.file}
228 // fileInput The file element used during file upload.
229 // @param {Object}
230 // filebrowser Object containing filebrowser settings assigned to
231 // the fileButton associated with this file element.
232 function setupFileElement( editor, fileInput, filebrowser ) {
233 var params = filebrowser.params || {};
234 params.CKEditor = editor.name;
235 params.CKEditorFuncNum = editor._.filebrowserFn;
236 if ( !params.langCode )
237 params.langCode = editor.langCode;
238
239 fileInput.action = addQueryString( filebrowser.url, params );
240 fileInput.filebrowser = filebrowser;
241 }
242
243 // Traverse through the content definition and attach filebrowser to
244 // elements with 'filebrowser' attribute.
245 //
246 // @param String
247 // dialogName Dialog name.
248 // @param {CKEDITOR.dialog.definitionObject}
249 // definition Dialog definition.
250 // @param {Array}
251 // elements Array of {@link CKEDITOR.dialog.definition.content}
252 // objects.
253 function attachFileBrowser( editor, dialogName, definition, elements ) {
254 if ( !elements || !elements.length )
255 return;
256
257 var element;
258
259 for ( var i = elements.length; i--; ) {
260 element = elements[ i ];
261
262 if ( element.type == 'hbox' || element.type == 'vbox' || element.type == 'fieldset' )
263 attachFileBrowser( editor, dialogName, definition, element.children );
264
265 if ( !element.filebrowser )
266 continue;
267
268 if ( typeof element.filebrowser == 'string' ) {
269 var fb = {
270 action: ( element.type == 'fileButton' ) ? 'QuickUpload' : 'Browse',
271 target: element.filebrowser
272 };
273 element.filebrowser = fb;
274 }
275
276 if ( element.filebrowser.action == 'Browse' ) {
277 var url = element.filebrowser.url;
278 if ( url === undefined ) {
279 url = editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'BrowseUrl' ];
280 if ( url === undefined )
281 url = editor.config.filebrowserBrowseUrl;
282 }
283
284 if ( url ) {
285 element.onClick = browseServer;
286 element.filebrowser.url = url;
287 element.hidden = false;
288 }
289 } else if ( element.filebrowser.action == 'QuickUpload' && element[ 'for' ] ) {
290 url = element.filebrowser.url;
291 if ( url === undefined ) {
292 url = editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'UploadUrl' ];
293 if ( url === undefined )
294 url = editor.config.filebrowserUploadUrl;
295 }
296
297 if ( url ) {
298 var onClick = element.onClick;
299 element.onClick = function( evt ) {
300 // "element" here means the definition object, so we need to find the correct
301 // button to scope the event call
302 var sender = evt.sender;
303 if ( onClick && onClick.call( sender, evt ) === false )
304 return false;
305
306 if ( uploadFile.call( sender, evt ) ) {
307 var fileInput = sender.getDialog().getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getInputElement();
308
309 // Append token preventing CSRF attacks.
310 appendToken( fileInput );
311 return true;
312 }
313
314
315 return false;
316 };
317
318 element.filebrowser.url = url;
319 element.hidden = false;
320 setupFileElement( editor, definition.getContents( element[ 'for' ][ 0 ] ).get( element[ 'for' ][ 1 ] ), element.filebrowser );
321 }
322 }
323 }
324 }
325
326 // Updates the target element with the url of uploaded/selected file.
327 //
328 // @param {String}
329 // url The url of a file.
330 function updateTargetElement( url, sourceElement ) {
331 var dialog = sourceElement.getDialog();
332 var targetElement = sourceElement.filebrowser.target || null;
333
334 // If there is a reference to targetElement, update it.
335 if ( targetElement ) {
336 var target = targetElement.split( ':' );
337 var element = dialog.getContentElement( target[ 0 ], target[ 1 ] );
338 if ( element ) {
339 element.setValue( url );
340 dialog.selectPage( target[ 0 ] );
341 }
342 }
343 }
344
345 // Returns true if filebrowser is configured in one of the elements.
346 //
347 // @param {CKEDITOR.dialog.definitionObject}
348 // definition Dialog definition.
349 // @param String
350 // tabId The tab id where element(s) can be found.
351 // @param String
352 // elementId The element id (or ids, separated with a semicolon) to check.
353 function isConfigured( definition, tabId, elementId ) {
354 if ( elementId.indexOf( ';' ) !== -1 ) {
355 var ids = elementId.split( ';' );
356 for ( var i = 0; i < ids.length; i++ ) {
357 if ( isConfigured( definition, tabId, ids[ i ] ) )
358 return true;
359 }
360 return false;
361 }
362
363 var elementFileBrowser = definition.getContents( tabId ).get( elementId ).filebrowser;
364 return ( elementFileBrowser && elementFileBrowser.url );
365 }
366
367 function setUrl( fileUrl, data ) {
368 var dialog = this._.filebrowserSe.getDialog(),
369 targetInput = this._.filebrowserSe[ 'for' ],
370 onSelect = this._.filebrowserSe.filebrowser.onSelect;
371
372 if ( targetInput )
373 dialog.getContentElement( targetInput[ 0 ], targetInput[ 1 ] ).reset();
374
375 if ( typeof data == 'function' && data.call( this._.filebrowserSe ) === false )
376 return;
377
378 if ( onSelect && onSelect.call( this._.filebrowserSe, fileUrl, data ) === false )
379 return;
380
381 // The "data" argument may be used to pass the error message to the editor.
382 if ( typeof data == 'string' && data )
383 alert( data ); // jshint ignore:line
384
385 if ( fileUrl )
386 updateTargetElement( fileUrl, this._.filebrowserSe );
387 }
388
389 CKEDITOR.plugins.add( 'filebrowser', {
390 requires: 'popup',
391 init: function( editor ) {
392 editor._.filebrowserFn = CKEDITOR.tools.addFunction( setUrl, editor );
393 editor.on( 'destroy', function() {
394 CKEDITOR.tools.removeFunction( this._.filebrowserFn );
395 } );
396 }
397 } );
398
399 CKEDITOR.on( 'dialogDefinition', function( evt ) {
400 // We require filebrowser plugin to be loaded.
401 if ( !evt.editor.plugins.filebrowser )
402 return;
403
404 var definition = evt.data.definition,
405 element;
406 // Associate filebrowser to elements with 'filebrowser' attribute.
407 for ( var i = 0; i < definition.contents.length; ++i ) {
408 if ( ( element = definition.contents[ i ] ) ) {
409 attachFileBrowser( evt.editor, evt.data.name, definition, element.elements );
410 if ( element.hidden && element.filebrowser )
411 element.hidden = !isConfigured( definition, element.id, element.filebrowser );
412
413 }
414 }
415 } );
416
417} )();
418
419/**
420 * The location of an external file manager that should be launched when the **Browse Server**
421 * button is pressed. If configured, the **Browse Server** button will appear in the
422 * **Link**, **Image**, and **Flash** dialog windows.
423 *
424 * Read more in the [documentation](#!/guide/dev_file_browse_upload)
425 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
426 *
427 * config.filebrowserBrowseUrl = '/browser/browse.php';
428 *
429 * @since 3.0
430 * @cfg {String} [filebrowserBrowseUrl='' (empty string = disabled)]
431 * @member CKEDITOR.config
432 */
433
434/**
435 * The location of the script that handles file uploads.
436 * If set, the **Upload** tab will appear in the **Link**, **Image**,
437 * and **Flash** dialog windows.
438 *
439 * Read more in the [documentation](#!/guide/dev_file_browse_upload)
440 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
441 *
442 * config.filebrowserUploadUrl = '/uploader/upload.php';
443 *
444 * **Note:** This is a configuration setting for a [file browser/uploader](#!/guide/dev_file_browse_upload).
445 * To configure [uploading dropped or pasted files](#!/guide/dev_file_upload) use the {@link CKEDITOR.config#uploadUrl}
446 * configuration option.
447 *
448 * @since 3.0
449 * @cfg {String} [filebrowserUploadUrl='' (empty string = disabled)]
450 * @member CKEDITOR.config
451 */
452
453/**
454 * The location of an external file manager that should be launched when the **Browse Server**
455 * button is pressed in the **Image** dialog window.
456 *
457 * If not set, CKEditor will use {@link CKEDITOR.config#filebrowserBrowseUrl}.
458 *
459 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-adding-file-manager-scripts-for-selected-dialog-windows)
460 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
461 *
462 * config.filebrowserImageBrowseUrl = '/browser/browse.php?type=Images';
463 *
464 * @since 3.0
465 * @cfg {String} [filebrowserImageBrowseUrl='' (empty string = disabled)]
466 * @member CKEDITOR.config
467 */
468
469/**
470 * The location of an external file browser that should be launched when the **Browse Server**
471 * button is pressed in the **Flash** dialog window.
472 *
473 * If not set, CKEditor will use {@link CKEDITOR.config#filebrowserBrowseUrl}.
474 *
475 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-adding-file-manager-scripts-for-selected-dialog-windows)
476 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
477 *
478 * config.filebrowserFlashBrowseUrl = '/browser/browse.php?type=Flash';
479 *
480 * @since 3.0
481 * @cfg {String} [filebrowserFlashBrowseUrl='' (empty string = disabled)]
482 * @member CKEDITOR.config
483 */
484
485/**
486 * The location of the script that handles file uploads in the **Image** dialog window.
487 *
488 * If not set, CKEditor will use {@link CKEDITOR.config#filebrowserUploadUrl}.
489 *
490 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-adding-file-manager-scripts-for-selected-dialog-windows)
491 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
492 *
493 * config.filebrowserImageUploadUrl = '/uploader/upload.php?type=Images';
494 *
495 * **Note:** This is a configuration setting for a [file browser/uploader](#!/guide/dev_file_browse_upload).
496 * To configure [uploading dropped or pasted files](#!/guide/dev_file_upload) use the {@link CKEDITOR.config#uploadUrl}
497 * or {@link CKEDITOR.config#imageUploadUrl} configuration option.
498 *
499 * @since 3.0
500 * @cfg {String} [filebrowserImageUploadUrl='' (empty string = disabled)]
501 * @member CKEDITOR.config
502 */
503
504/**
505 * The location of the script that handles file uploads in the **Flash** dialog window.
506 *
507 * If not set, CKEditor will use {@link CKEDITOR.config#filebrowserUploadUrl}.
508 *
509 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-adding-file-manager-scripts-for-selected-dialog-windows)
510 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
511 *
512 * config.filebrowserFlashUploadUrl = '/uploader/upload.php?type=Flash';
513 *
514 * @since 3.0
515 * @cfg {String} filebrowserFlashUploadUrl='' (empty string = disabled)]
516 * @member CKEDITOR.config
517 */
518
519/**
520 * The location of an external file manager that should be launched when the **Browse Server**
521 * button is pressed in the **Link** tab of the **Image** dialog window.
522 *
523 * If not set, CKEditor will use {@link CKEDITOR.config#filebrowserBrowseUrl}.
524 *
525 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-adding-file-manager-scripts-for-selected-dialog-windows)
526 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
527 *
528 * config.filebrowserImageBrowseLinkUrl = '/browser/browse.php';
529 *
530 * @since 3.2
531 * @cfg {String} [filebrowserImageBrowseLinkUrl='' (empty string = disabled)]
532 * @member CKEDITOR.config
533 */
534
535/**
536 * The features to use in the file manager popup window.
537 *
538 * config.filebrowserWindowFeatures = 'resizable=yes,scrollbars=no';
539 *
540 * @since 3.4.1
541 * @cfg {String} [filebrowserWindowFeatures='location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes,scrollbars=yes']
542 * @member CKEDITOR.config
543 */
544
545/**
546 * The width of the file manager popup window. It can be a number denoting a value in
547 * pixels or a percent string.
548 *
549 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-file-manager-window-size)
550 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
551 *
552 * config.filebrowserWindowWidth = 750;
553 *
554 * config.filebrowserWindowWidth = '50%';
555 *
556 * @cfg {Number/String} [filebrowserWindowWidth='80%']
557 * @member CKEDITOR.config
558 */
559
560/**
561 * The height of the file manager popup window. It can be a number denoting a value in
562 * pixels or a percent string.
563 *
564 * Read more in the [documentation](#!/guide/dev_file_manager_configuration-section-file-manager-window-size)
565 * and see the [SDK sample](http://sdk.ckeditor.com/samples/fileupload.html).
566 *
567 * config.filebrowserWindowHeight = 580;
568 *
569 * config.filebrowserWindowHeight = '50%';
570 *
571 * @cfg {Number/String} [filebrowserWindowHeight='70%']
572 * @member CKEDITOR.config
573 */
diff --git a/sources/plugins/floatingspace/plugin.js b/sources/plugins/floatingspace/plugin.js
new file mode 100644
index 0000000..878d952
--- /dev/null
+++ b/sources/plugins/floatingspace/plugin.js
@@ -0,0 +1,406 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var win = CKEDITOR.document.getWindow(),
8 pixelate = CKEDITOR.tools.cssLength;
9
10 CKEDITOR.plugins.add( 'floatingspace', {
11 init: function( editor ) {
12 // Add listener with lower priority than that in themedui creator.
13 // Thereby floatingspace will be created only if themedui wasn't used.
14 editor.on( 'loaded', function() {
15 attach( this );
16 }, null, null, 20 );
17 }
18 } );
19
20 function scrollOffset( side ) {
21 var pageOffset = side == 'left' ? 'pageXOffset' : 'pageYOffset',
22 docScrollOffset = side == 'left' ? 'scrollLeft' : 'scrollTop';
23
24 return ( pageOffset in win.$ ) ? win.$[ pageOffset ] : CKEDITOR.document.$.documentElement[ docScrollOffset ];
25 }
26
27 function attach( editor ) {
28 var config = editor.config,
29
30 // Get the HTML for the predefined spaces.
31 topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html,
32
33 // Re-positioning of the space.
34 layout = ( function() {
35 // Mode indicates the vertical aligning mode.
36 var mode, editable,
37 spaceRect, editorRect, viewRect, spaceHeight, pageScrollX,
38
39 // Allow minor adjustments of the float space from custom configs.
40 dockedOffsetX = config.floatSpaceDockedOffsetX || 0,
41 dockedOffsetY = config.floatSpaceDockedOffsetY || 0,
42 pinnedOffsetX = config.floatSpacePinnedOffsetX || 0,
43 pinnedOffsetY = config.floatSpacePinnedOffsetY || 0;
44
45 // Update the float space position.
46 function updatePos( pos, prop, val ) {
47 floatSpace.setStyle( prop, pixelate( val ) );
48 floatSpace.setStyle( 'position', pos );
49 }
50
51 // Change the current mode and update float space position accordingly.
52 function changeMode( newMode ) {
53 var editorPos = editable.getDocumentPosition();
54
55 switch ( newMode ) {
56 case 'top':
57 updatePos( 'absolute', 'top', editorPos.y - spaceHeight - dockedOffsetY );
58 break;
59 case 'pin':
60 updatePos( 'fixed', 'top', pinnedOffsetY );
61 break;
62 case 'bottom':
63 updatePos( 'absolute', 'top', editorPos.y + ( editorRect.height || editorRect.bottom - editorRect.top ) + dockedOffsetY );
64 break;
65 }
66
67 mode = newMode;
68 }
69
70 return function( evt ) {
71 // #10112 Do not fail on editable-less editor.
72 if ( !( editable = editor.editable() ) )
73 return;
74
75 var show = ( evt && evt.name == 'focus' );
76
77 // Show up the space on focus gain.
78 if ( show ) {
79 floatSpace.show();
80 }
81
82 editor.fire( 'floatingSpaceLayout', { show: show } );
83
84 // Reset the horizontal position for below measurement.
85 floatSpace.removeStyle( 'left' );
86 floatSpace.removeStyle( 'right' );
87
88 // Compute the screen position from the TextRectangle object would
89 // be very simple, even though the "width"/"height" property is not
90 // available for all, it's safe to figure that out from the rest.
91
92 // http://help.dottoro.com/ljgupwlp.php
93 spaceRect = floatSpace.getClientRect();
94 editorRect = editable.getClientRect();
95 viewRect = win.getViewPaneSize();
96 spaceHeight = spaceRect.height;
97 pageScrollX = scrollOffset( 'left' );
98
99 // We initialize it as pin mode.
100 if ( !mode ) {
101 mode = 'pin';
102 changeMode( 'pin' );
103 // Call for a refresh to the actual layout.
104 layout( evt );
105 return;
106 }
107
108 // +------------------------ Viewport -+ \
109 // | | |-> floatSpaceDockedOffsetY
110 // | ................................. | /
111 // | |
112 // | +------ Space -+ |
113 // | | | |
114 // | +--------------+ |
115 // | +------------------ Editor -+ |
116 // | | | |
117 //
118 if ( spaceHeight + dockedOffsetY <= editorRect.top )
119 changeMode( 'top' );
120
121 // +- - - - - - - - - Editor -+
122 // | |
123 // +------------------------ Viewport -+ \
124 // | | | | |-> floatSpacePinnedOffsetY
125 // | ................................. | /
126 // | +------ Space -+ | |
127 // | | | | |
128 // | +--------------+ | |
129 // | | | |
130 // | +---------------------------+ |
131 // +-----------------------------------+
132 //
133 else if ( spaceHeight + dockedOffsetY > viewRect.height - editorRect.bottom )
134 changeMode( 'pin' );
135
136 // +- - - - - - - - - Editor -+
137 // | |
138 // +------------------------ Viewport -+ \
139 // | | | | |-> floatSpacePinnedOffsetY
140 // | ................................. | /
141 // | | | |
142 // | | | |
143 // | +---------------------------+ |
144 // | +------ Space -+ |
145 // | | | |
146 // | +--------------+ |
147 //
148 else
149 changeMode( 'bottom' );
150
151 var mid = viewRect.width / 2,
152 alignSide, offset;
153
154 if ( config.floatSpacePreferRight ) {
155 alignSide = 'right';
156 } else if ( editorRect.left > 0 && editorRect.right < viewRect.width && editorRect.width > spaceRect.width ) {
157 alignSide = config.contentsLangDirection == 'rtl' ? 'right' : 'left';
158 } else {
159 alignSide = mid - editorRect.left > editorRect.right - mid ? 'left' : 'right';
160 }
161
162 // (#9769) If viewport width is less than space width,
163 // make sure space never cross the left boundary of the viewport.
164 // In other words: top-left corner of the space is always visible.
165 if ( spaceRect.width > viewRect.width ) {
166 alignSide = 'left';
167 offset = 0;
168 }
169 else {
170 if ( alignSide == 'left' ) {
171 // If the space rect fits into viewport, align it
172 // to the left edge of editor:
173 //
174 // +------------------------ Viewport -+
175 // | |
176 // | +------------- Space -+ |
177 // | | | |
178 // | +---------------------+ |
179 // | +------------------ Editor -+ |
180 // | | | |
181 //
182 if ( editorRect.left > 0 )
183 offset = editorRect.left;
184
185 // If the left part of the editor is cut off by the left
186 // edge of the viewport, stick the space to the viewport:
187 //
188 // +------------------------ Viewport -+
189 // | |
190 // +---------------- Space -+ |
191 // | | |
192 // +------------------------+ |
193 // +----|------------- Editor -+ |
194 // | | | |
195 //
196 else
197 offset = 0;
198 }
199 else {
200 // If the space rect fits into viewport, align it
201 // to the right edge of editor:
202 //
203 // +------------------------ Viewport -+
204 // | |
205 // | +------------- Space -+ |
206 // | | | |
207 // | +---------------------+ |
208 // | +------------------ Editor -+ |
209 // | | | |
210 //
211 if ( editorRect.right < viewRect.width )
212 offset = viewRect.width - editorRect.right;
213
214 // If the right part of the editor is cut off by the right
215 // edge of the viewport, stick the space to the viewport:
216 //
217 // +------------------------ Viewport -+
218 // | |
219 // | +------------- Space -+
220 // | | |
221 // | +---------------------+
222 // | +-----------------|- Editor -+
223 // | | | |
224 //
225 else
226 offset = 0;
227 }
228
229 // (#9769) Finally, stick the space to the opposite side of
230 // the viewport when it's cut off horizontally on the left/right
231 // side like below.
232 //
233 // This trick reveals cut off space in some edge cases and
234 // hence it improves accessibility.
235 //
236 // +------------------------ Viewport -+
237 // | |
238 // | +--------------------|-- Space -+
239 // | | | |
240 // | +--------------------|----------+
241 // | +------- Editor -+ |
242 // | | | |
243 //
244 // becomes:
245 //
246 // +------------------------ Viewport -+
247 // | |
248 // | +----------------------- Space -+
249 // | | |
250 // | +-------------------------------+
251 // | +------- Editor -+ |
252 // | | | |
253 //
254 if ( offset + spaceRect.width > viewRect.width ) {
255 alignSide = alignSide == 'left' ? 'right' : 'left';
256 offset = 0;
257 }
258 }
259
260 // Pin mode is fixed, so don't include scroll-x.
261 // (#9903) For mode is "top" or "bottom", add opposite scroll-x for right-aligned space.
262 var scroll = mode == 'pin' ? 0 : alignSide == 'left' ? pageScrollX : -pageScrollX;
263
264 floatSpace.setStyle( alignSide, pixelate( ( mode == 'pin' ? pinnedOffsetX : dockedOffsetX ) + offset + scroll ) );
265 };
266 } )();
267
268 if ( topHtml ) {
269 var floatSpaceTpl = new CKEDITOR.template(
270 '<div' +
271 ' id="cke_{name}"' +
272 ' class="cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} ' + CKEDITOR.env.cssClass + '"' +
273 ' dir="{langDir}"' +
274 ' title="' + ( CKEDITOR.env.gecko ? ' ' : '' ) + '"' +
275 ' lang="{langCode}"' +
276 ' role="application"' +
277 ' style="{style}"' +
278 ( editor.title ? ' aria-labelledby="cke_{name}_arialbl"' : ' ' ) +
279 '>' +
280 ( editor.title ? '<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' : ' ' ) +
281 '<div class="cke_inner">' +
282 '<div id="{topId}" class="cke_top" role="presentation">{content}</div>' +
283 '</div>' +
284 '</div>' ),
285 floatSpace = CKEDITOR.document.getBody().append( CKEDITOR.dom.element.createFromHtml( floatSpaceTpl.output( {
286 content: topHtml,
287 id: editor.id,
288 langDir: editor.lang.dir,
289 langCode: editor.langCode,
290 name: editor.name,
291 style: 'display:none;z-index:' + ( config.baseFloatZIndex - 1 ),
292 topId: editor.ui.spaceId( 'top' ),
293 voiceLabel: editor.title
294 } ) ) ),
295
296 // Use event buffers to reduce CPU load when tons of events are fired.
297 changeBuffer = CKEDITOR.tools.eventsBuffer( 500, layout ),
298 uiBuffer = CKEDITOR.tools.eventsBuffer( 100, layout );
299
300 // There's no need for the floatSpace to be selectable.
301 floatSpace.unselectable();
302
303 // Prevent clicking on non-buttons area of the space from blurring editor.
304 floatSpace.on( 'mousedown', function( evt ) {
305 evt = evt.data;
306 if ( !evt.getTarget().hasAscendant( 'a', 1 ) )
307 evt.preventDefault();
308 } );
309
310 editor.on( 'focus', function( evt ) {
311 layout( evt );
312 editor.on( 'change', changeBuffer.input );
313 win.on( 'scroll', uiBuffer.input );
314 win.on( 'resize', uiBuffer.input );
315 } );
316
317 editor.on( 'blur', function() {
318 floatSpace.hide();
319 editor.removeListener( 'change', changeBuffer.input );
320 win.removeListener( 'scroll', uiBuffer.input );
321 win.removeListener( 'resize', uiBuffer.input );
322 } );
323
324 editor.on( 'destroy', function() {
325 win.removeListener( 'scroll', uiBuffer.input );
326 win.removeListener( 'resize', uiBuffer.input );
327 floatSpace.clearCustomData();
328 floatSpace.remove();
329 } );
330
331 // Handle initial focus.
332 if ( editor.focusManager.hasFocus )
333 floatSpace.show();
334
335 // Register this UI space to the focus manager.
336 editor.focusManager.add( floatSpace, 1 );
337 }
338 }
339} )();
340
341/**
342 * Along with {@link #floatSpaceDockedOffsetY} it defines the
343 * amount of offset (in pixels) between the float space and the editable left/right
344 * boundaries when the space element is docked on either side of the editable.
345 *
346 * config.floatSpaceDockedOffsetX = 10;
347 *
348 * @cfg {Number} [floatSpaceDockedOffsetX=0]
349 * @member CKEDITOR.config
350 */
351
352/**
353 * Along with {@link #floatSpaceDockedOffsetX} it defines the
354 * amount of offset (in pixels) between the float space and the editable top/bottom
355 * boundaries when the space element is docked on either side of the editable.
356 *
357 * config.floatSpaceDockedOffsetY = 10;
358 *
359 * @cfg {Number} [floatSpaceDockedOffsetY=0]
360 * @member CKEDITOR.config
361 */
362
363/**
364 * Along with {@link #floatSpacePinnedOffsetY} it defines the
365 * amount of offset (in pixels) between the float space and the viewport boundaries
366 * when the space element is pinned.
367 *
368 * config.floatSpacePinnedOffsetX = 20;
369 *
370 * @cfg {Number} [floatSpacePinnedOffsetX=0]
371 * @member CKEDITOR.config
372 */
373
374/**
375 * Along with {@link #floatSpacePinnedOffsetX} it defines the
376 * amount of offset (in pixels) between the float space and the viewport boundaries
377 * when the space element is pinned.
378 *
379 * config.floatSpacePinnedOffsetY = 20;
380 *
381 * @cfg {Number} [floatSpacePinnedOffsetY=0]
382 * @member CKEDITOR.config
383 */
384
385/**
386 * Indicates that the float space should be aligned to the right side
387 * of the editable area rather than to the left (if possible).
388 *
389 * config.floatSpacePreferRight = true;
390 *
391 * @since 4.5
392 * @cfg {Boolean} [floatSpacePreferRight=false]
393 * @member CKEDITOR.config
394 */
395
396/**
397 * Fired when the viewport or editor parameters change and the floating space needs to check and
398 * eventually update its position and dimensions.
399 *
400 * @since 4.5
401 * @event floatingSpaceLayout
402 * @member CKEDITOR.editor
403 * @param {CKEDITOR.editor} editor The editor instance.
404 * @param data
405 * @param {Boolean} data.show True if the float space should show up as a result of this event.
406 */
diff --git a/sources/plugins/floatpanel/plugin.js b/sources/plugins/floatpanel/plugin.js
new file mode 100644
index 0000000..1a851f9
--- /dev/null
+++ b/sources/plugins/floatpanel/plugin.js
@@ -0,0 +1,598 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'floatpanel', {
7 requires: 'panel'
8} );
9
10( function() {
11 var panels = {};
12
13 function getPanel( editor, doc, parentElement, definition, level ) {
14 // Generates the panel key: docId-eleId-skinName-langDir[-uiColor][-CSSs][-level]
15 var key = CKEDITOR.tools.genKey( doc.getUniqueId(), parentElement.getUniqueId(), editor.lang.dir, editor.uiColor || '', definition.css || '', level || '' ),
16 panel = panels[ key ];
17
18 if ( !panel ) {
19 panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition );
20 panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.render( editor ), doc ) );
21
22 panel.element.setStyles( {
23 display: 'none',
24 position: 'absolute'
25 } );
26 }
27
28 return panel;
29 }
30
31 /**
32 * Represents a floating panel UI element.
33 *
34 * It is reused by rich combos, color combos, menus, etc.
35 * and it renders its content using {@link CKEDITOR.ui.panel}.
36 *
37 * @class
38 * @todo
39 */
40 CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass( {
41 /**
42 * Creates a floatPanel class instance.
43 *
44 * @constructor
45 * @param {CKEDITOR.editor} editor
46 * @param {CKEDITOR.dom.element} parentElement
47 * @param {Object} definition Definition of the panel that will be floating.
48 * @param {Number} level
49 */
50 $: function( editor, parentElement, definition, level ) {
51 definition.forceIFrame = 1;
52
53 // In case of editor with floating toolbar append panels that should float
54 // to the main UI element.
55 if ( definition.toolbarRelated && editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE )
56 parentElement = CKEDITOR.document.getById( 'cke_' + editor.name );
57
58 var doc = parentElement.getDocument(),
59 panel = getPanel( editor, doc, parentElement, definition, level || 0 ),
60 element = panel.element,
61 iframe = element.getFirst(),
62 that = this;
63
64 // Disable native browser menu. (#4825)
65 element.disableContextMenu();
66
67 this.element = element;
68
69 this._ = {
70 editor: editor,
71 // The panel that will be floating.
72 panel: panel,
73 parentElement: parentElement,
74 definition: definition,
75 document: doc,
76 iframe: iframe,
77 children: [],
78 dir: editor.lang.dir,
79 showBlockParams: null
80 };
81
82 editor.on( 'mode', hide );
83 editor.on( 'resize', hide );
84
85 // When resize of the window is triggered floatpanel should be repositioned according to new dimensions.
86 // #11724. Fixes issue with undesired panel hiding on Android and iOS.
87 doc.getWindow().on( 'resize', function() {
88 this.reposition();
89 }, this );
90
91 // We need a wrapper because events implementation doesn't allow to attach
92 // one listener more than once for the same event on the same object.
93 // Remember that floatPanel#hide is shared between all instances.
94 function hide() {
95 that.hide();
96 }
97 },
98
99 proto: {
100 /**
101 * @todo
102 */
103 addBlock: function( name, block ) {
104 return this._.panel.addBlock( name, block );
105 },
106
107 /**
108 * @todo
109 */
110 addListBlock: function( name, multiSelect ) {
111 return this._.panel.addListBlock( name, multiSelect );
112 },
113
114 /**
115 * @todo
116 */
117 getBlock: function( name ) {
118 return this._.panel.getBlock( name );
119 },
120
121 /**
122 * Shows the panel block.
123 *
124 * @param {String} name
125 * @param {CKEDITOR.dom.element} offsetParent Positioned parent.
126 * @param {Number} corner
127 *
128 * * For LTR (left to right) oriented editor:
129 * * `1` = top-left
130 * * `2` = top-right
131 * * `3` = bottom-right
132 * * `4` = bottom-left
133 * * For RTL (right to left):
134 * * `1` = top-right
135 * * `2` = top-left
136 * * `3` = bottom-left
137 * * `4` = bottom-right
138 *
139 * @param {Number} [offsetX=0]
140 * @param {Number} [offsetY=0]
141 * @param {Function} [callback] A callback function executed when block positioning is done.
142 * @todo what do exactly these params mean (especially corner)?
143 */
144 showBlock: function( name, offsetParent, corner, offsetX, offsetY, callback ) {
145 var panel = this._.panel,
146 block = panel.showBlock( name );
147
148 this._.showBlockParams = [].slice.call( arguments );
149 this.allowBlur( false );
150
151 // Record from where the focus is when open panel.
152 var editable = this._.editor.editable();
153 this._.returnFocus = editable.hasFocus ? editable : new CKEDITOR.dom.element( CKEDITOR.document.$.activeElement );
154 this._.hideTimeout = 0;
155
156 var element = this.element,
157 iframe = this._.iframe,
158 // Edge prefers iframe's window to the iframe, just like the rest of the browsers (#13143).
159 focused = CKEDITOR.env.ie && !CKEDITOR.env.edge ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow ),
160 doc = element.getDocument(),
161 positionedAncestor = this._.parentElement.getPositionedAncestor(),
162 position = offsetParent.getDocumentPosition( doc ),
163 positionedAncestorPosition = positionedAncestor ? positionedAncestor.getDocumentPosition( doc ) : { x: 0, y: 0 },
164 rtl = this._.dir == 'rtl',
165 left = position.x + ( offsetX || 0 ) - positionedAncestorPosition.x,
166 top = position.y + ( offsetY || 0 ) - positionedAncestorPosition.y;
167
168 // Floating panels are off by (-1px, 0px) in RTL mode. (#3438)
169 if ( rtl && ( corner == 1 || corner == 4 ) )
170 left += offsetParent.$.offsetWidth;
171 else if ( !rtl && ( corner == 2 || corner == 3 ) )
172 left += offsetParent.$.offsetWidth - 1;
173
174 if ( corner == 3 || corner == 4 )
175 top += offsetParent.$.offsetHeight - 1;
176
177 // Memorize offsetParent by it's ID.
178 this._.panel._.offsetParentId = offsetParent.getId();
179
180 element.setStyles( {
181 top: top + 'px',
182 left: 0,
183 display: ''
184 } );
185
186 // Don't use display or visibility style because we need to
187 // calculate the rendering layout later and focus the element.
188 element.setOpacity( 0 );
189
190 // To allow the context menu to decrease back their width
191 element.getFirst().removeStyle( 'width' );
192
193 // Report to focus manager.
194 this._.editor.focusManager.add( focused );
195
196 // Configure the IFrame blur event. Do that only once.
197 if ( !this._.blurSet ) {
198
199 // With addEventListener compatible browsers, we must
200 // useCapture when registering the focus/blur events to
201 // guarantee they will be firing in all situations. (#3068, #3222 )
202 CKEDITOR.event.useCapture = true;
203
204 focused.on( 'blur', function( ev ) {
205 // As we are using capture to register the listener,
206 // the blur event may get fired even when focusing
207 // inside the window itself, so we must ensure the
208 // target is out of it.
209 if ( !this.allowBlur() || ev.data.getPhase() != CKEDITOR.EVENT_PHASE_AT_TARGET )
210 return;
211
212 if ( this.visible && !this._.activeChild ) {
213 // [iOS] Allow hide to be prevented if touch is bound
214 // to any parent of the iframe blur happens before touch (#10714).
215 if ( CKEDITOR.env.iOS ) {
216 if ( !this._.hideTimeout )
217 this._.hideTimeout = CKEDITOR.tools.setTimeout( doHide, 0, this );
218 } else {
219 doHide.call( this );
220 }
221 }
222
223 function doHide() {
224 // Panel close is caused by user's navigating away the focus, e.g. click outside the panel.
225 // DO NOT restore focus in this case.
226 delete this._.returnFocus;
227 this.hide();
228 }
229 }, this );
230
231 focused.on( 'focus', function() {
232 this._.focused = true;
233 this.hideChild();
234 this.allowBlur( true );
235 }, this );
236
237 // [iOS] if touch is bound to any parent of the iframe blur
238 // happens twice before touchstart and before touchend (#10714).
239 if ( CKEDITOR.env.iOS ) {
240 // Prevent false hiding on blur.
241 // We don't need to return focus here because touchend will fire anyway.
242 // If user scrolls and pointer gets out of the panel area touchend will also fire.
243 focused.on( 'touchstart', function() {
244 clearTimeout( this._.hideTimeout );
245 }, this );
246
247 // Set focus back to handle blur and hide panel when needed.
248 focused.on( 'touchend', function() {
249 this._.hideTimeout = 0;
250 this.focus();
251 }, this );
252 }
253
254 CKEDITOR.event.useCapture = false;
255
256 this._.blurSet = 1;
257 }
258
259 panel.onEscape = CKEDITOR.tools.bind( function( keystroke ) {
260 if ( this.onEscape && this.onEscape( keystroke ) === false )
261 return false;
262 }, this );
263
264 CKEDITOR.tools.setTimeout( function() {
265 var panelLoad = CKEDITOR.tools.bind( function() {
266 var target = element;
267
268 // Reset panel width as the new content can be narrower
269 // than the old one. (#9355)
270 target.removeStyle( 'width' );
271
272 if ( block.autoSize ) {
273 var panelDoc = block.element.getDocument(),
274 width = ( ( CKEDITOR.env.webkit || CKEDITOR.env.edge ) ? block.element : panelDoc.getBody() ).$.scrollWidth;
275
276 // Account for extra height needed due to IE quirks box model bug:
277 // http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug
278 // (#3426)
279 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && width > 0 )
280 width += ( target.$.offsetWidth || 0 ) - ( target.$.clientWidth || 0 ) + 3;
281
282 // Add some extra pixels to improve the appearance.
283 width += 10;
284
285 target.setStyle( 'width', width + 'px' );
286
287 var height = block.element.$.scrollHeight;
288
289 // Account for extra height needed due to IE quirks box model bug:
290 // http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug
291 // (#3426)
292 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && height > 0 )
293 height += ( target.$.offsetHeight || 0 ) - ( target.$.clientHeight || 0 ) + 3;
294
295 target.setStyle( 'height', height + 'px' );
296
297 // Fix IE < 8 visibility.
298 panel._.currentBlock.element.setStyle( 'display', 'none' ).removeStyle( 'display' );
299 } else {
300 target.removeStyle( 'height' );
301 }
302
303 // Flip panel layout horizontally in RTL with known width.
304 if ( rtl )
305 left -= element.$.offsetWidth;
306
307 // Pop the style now for measurement.
308 element.setStyle( 'left', left + 'px' );
309
310 /* panel layout smartly fit the viewport size. */
311 var panelElement = panel.element,
312 panelWindow = panelElement.getWindow(),
313 rect = element.$.getBoundingClientRect(),
314 viewportSize = panelWindow.getViewPaneSize();
315
316 // Compensation for browsers that dont support "width" and "height".
317 var rectWidth = rect.width || rect.right - rect.left,
318 rectHeight = rect.height || rect.bottom - rect.top;
319
320 // Check if default horizontal layout is impossible.
321 var spaceAfter = rtl ? rect.right : viewportSize.width - rect.left,
322 spaceBefore = rtl ? viewportSize.width - rect.right : rect.left;
323
324 if ( rtl ) {
325 if ( spaceAfter < rectWidth ) {
326 // Flip to show on right.
327 if ( spaceBefore > rectWidth )
328 left += rectWidth;
329 // Align to window left.
330 else if ( viewportSize.width > rectWidth )
331 left = left - rect.left;
332 // Align to window right, never cutting the panel at right.
333 else
334 left = left - rect.right + viewportSize.width;
335 }
336 } else if ( spaceAfter < rectWidth ) {
337 // Flip to show on left.
338 if ( spaceBefore > rectWidth )
339 left -= rectWidth;
340 // Align to window right.
341 else if ( viewportSize.width > rectWidth )
342 left = left - rect.right + viewportSize.width;
343 // Align to window left, never cutting the panel at left.
344 else
345 left = left - rect.left;
346 }
347
348
349 // Check if the default vertical layout is possible.
350 var spaceBelow = viewportSize.height - rect.top,
351 spaceAbove = rect.top;
352
353 if ( spaceBelow < rectHeight ) {
354 // Flip to show above.
355 if ( spaceAbove > rectHeight )
356 top -= rectHeight;
357 // Align to window bottom.
358 else if ( viewportSize.height > rectHeight )
359 top = top - rect.bottom + viewportSize.height;
360 // Align to top, never cutting the panel at top.
361 else
362 top = top - rect.top;
363 }
364
365 // If IE is in RTL, we have troubles with absolute
366 // position and horizontal scrolls. Here we have a
367 // series of hacks to workaround it. (#6146)
368 if ( CKEDITOR.env.ie ) {
369 var offsetParent = new CKEDITOR.dom.element( element.$.offsetParent ),
370 scrollParent = offsetParent;
371
372 // Quirks returns <body>, but standards returns <html>.
373 if ( scrollParent.getName() == 'html' )
374 scrollParent = scrollParent.getDocument().getBody();
375
376 if ( scrollParent.getComputedStyle( 'direction' ) == 'rtl' ) {
377 // For IE8, there is not much logic on this, but it works.
378 if ( CKEDITOR.env.ie8Compat )
379 left -= element.getDocument().getDocumentElement().$.scrollLeft * 2;
380 else
381 left -= ( offsetParent.$.scrollWidth - offsetParent.$.clientWidth );
382 }
383 }
384
385 // Trigger the onHide event of the previously active panel to prevent
386 // incorrect styles from being applied (#6170)
387 var innerElement = element.getFirst(),
388 activePanel;
389 if ( ( activePanel = innerElement.getCustomData( 'activePanel' ) ) )
390 activePanel.onHide && activePanel.onHide.call( this, 1 );
391 innerElement.setCustomData( 'activePanel', this );
392
393 element.setStyles( {
394 top: top + 'px',
395 left: left + 'px'
396 } );
397 element.setOpacity( 1 );
398
399 callback && callback();
400 }, this );
401
402 panel.isLoaded ? panelLoad() : panel.onLoad = panelLoad;
403
404 CKEDITOR.tools.setTimeout( function() {
405 var scrollTop = CKEDITOR.env.webkit && CKEDITOR.document.getWindow().getScrollPosition().y;
406
407 // Focus the panel frame first, so blur gets fired.
408 this.focus();
409
410 // Focus the block now.
411 block.element.focus();
412
413 // #10623, #10951 - restore the viewport's scroll position after focusing list element.
414 if ( CKEDITOR.env.webkit )
415 CKEDITOR.document.getBody().$.scrollTop = scrollTop;
416
417 // We need this get fired manually because of unfired focus() function.
418 this.allowBlur( true );
419 this._.editor.fire( 'panelShow', this );
420 }, 0, this );
421 }, CKEDITOR.env.air ? 200 : 0, this );
422 this.visible = 1;
423
424 if ( this.onShow )
425 this.onShow.call( this );
426 },
427
428 /**
429 * Repositions the panel with the same parameters that were used in the last {@link #showBlock} call.
430 *
431 * @since 4.5.4
432 */
433 reposition: function() {
434 var blockParams = this._.showBlockParams;
435
436 if ( this.visible && this._.showBlockParams ) {
437 this.hide();
438 this.showBlock.apply( this, blockParams );
439 }
440 },
441
442 /**
443 * Restores the last focused element or simply focuses the panel window.
444 */
445 focus: function() {
446 // Webkit requires to blur any previous focused page element, in
447 // order to properly fire the "focus" event.
448 if ( CKEDITOR.env.webkit ) {
449 var active = CKEDITOR.document.getActive();
450 active && !active.equals( this._.iframe ) && active.$.blur();
451 }
452
453 // Restore last focused element or simply focus panel window.
454 var focus = this._.lastFocused || this._.iframe.getFrameDocument().getWindow();
455 focus.focus();
456 },
457
458 /**
459 * @todo
460 */
461 blur: function() {
462 var doc = this._.iframe.getFrameDocument(),
463 active = doc.getActive();
464
465 active && active.is( 'a' ) && ( this._.lastFocused = active );
466 },
467
468 /**
469 * Hides the panel.
470 *
471 * @todo
472 */
473 hide: function( returnFocus ) {
474 if ( this.visible && ( !this.onHide || this.onHide.call( this ) !== true ) ) {
475 this.hideChild();
476 // Blur previously focused element. (#6671)
477 CKEDITOR.env.gecko && this._.iframe.getFrameDocument().$.activeElement.blur();
478 this.element.setStyle( 'display', 'none' );
479 this.visible = 0;
480 this.element.getFirst().removeCustomData( 'activePanel' );
481
482 // Return focus properly. (#6247)
483 var focusReturn = returnFocus && this._.returnFocus;
484 if ( focusReturn ) {
485 // Webkit requires focus moved out panel iframe first.
486 if ( CKEDITOR.env.webkit && focusReturn.type )
487 focusReturn.getWindow().$.focus();
488
489 focusReturn.focus();
490 }
491
492 delete this._.lastFocused;
493 this._.showBlockParams = null;
494
495 this._.editor.fire( 'panelHide', this );
496 }
497 },
498
499 /**
500 * @todo
501 */
502 allowBlur: function( allow ) {
503 // Prevent editor from hiding the panel. (#3222)
504 var panel = this._.panel;
505 if ( allow !== undefined )
506 panel.allowBlur = allow;
507
508 return panel.allowBlur;
509 },
510
511 /**
512 * Shows the specified panel as a child of one block of this one.
513 *
514 * @param {CKEDITOR.ui.floatPanel} panel
515 * @param {String} blockName
516 * @param {CKEDITOR.dom.element} offsetParent Positioned parent.
517 * @param {Number} corner
518 *
519 * * For LTR (left to right) oriented editor:
520 * * `1` = top-left
521 * * `2` = top-right
522 * * `3` = bottom-right
523 * * `4` = bottom-left
524 * * For RTL (right to left):
525 * * `1` = top-right
526 * * `2` = top-left
527 * * `3` = bottom-left
528 * * `4` = bottom-right
529 *
530 * @param {Number} [offsetX=0]
531 * @param {Number} [offsetY=0]
532 * @todo
533 */
534 showAsChild: function( panel, blockName, offsetParent, corner, offsetX, offsetY ) {
535 // Skip reshowing of child which is already visible.
536 if ( this._.activeChild == panel && panel._.panel._.offsetParentId == offsetParent.getId() )
537 return;
538
539 this.hideChild();
540
541 panel.onHide = CKEDITOR.tools.bind( function() {
542 // Use a timeout, so we give time for this menu to get
543 // potentially focused.
544 CKEDITOR.tools.setTimeout( function() {
545 if ( !this._.focused )
546 this.hide();
547 }, 0, this );
548 }, this );
549
550 this._.activeChild = panel;
551 this._.focused = false;
552
553 panel.showBlock( blockName, offsetParent, corner, offsetX, offsetY );
554 this.blur();
555
556 /* #3767 IE: Second level menu may not have borders */
557 if ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) {
558 setTimeout( function() {
559 panel.element.getChild( 0 ).$.style.cssText += '';
560 }, 100 );
561 }
562 },
563
564 /**
565 * @todo
566 */
567 hideChild: function( restoreFocus ) {
568 var activeChild = this._.activeChild;
569
570 if ( activeChild ) {
571 delete activeChild.onHide;
572 delete this._.activeChild;
573 activeChild.hide();
574
575 // At this point focus should be moved back to parent panel.
576 restoreFocus && this.focus();
577 }
578 }
579 }
580 } );
581
582 CKEDITOR.on( 'instanceDestroyed', function() {
583 var isLastInstance = CKEDITOR.tools.isEmpty( CKEDITOR.instances );
584
585 for ( var i in panels ) {
586 var panel = panels[ i ];
587 // Safe to destroy it since there're no more instances.(#4241)
588 if ( isLastInstance )
589 panel.destroy();
590 // Panel might be used by other instances, just hide them.(#4552)
591 else
592 panel.element.hide();
593 }
594 // Remove the registration.
595 isLastInstance && ( panels = {} );
596
597 } );
598} )();
diff --git a/sources/plugins/format/lang/af.js b/sources/plugins/format/lang/af.js
new file mode 100644
index 0000000..b38cd33
--- /dev/null
+++ b/sources/plugins/format/lang/af.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'af', {
6 label: 'Opmaak',
7 panelTitle: 'Opmaak',
8 tag_address: 'Adres',
9 tag_div: 'Normaal (DIV)',
10 tag_h1: 'Opskrif 1',
11 tag_h2: 'Opskrif 2',
12 tag_h3: 'Opskrif 3',
13 tag_h4: 'Opskrif 4',
14 tag_h5: 'Opskrif 5',
15 tag_h6: 'Opskrif 6',
16 tag_p: 'Normaal',
17 tag_pre: 'Opgemaak'
18} );
diff --git a/sources/plugins/format/lang/ar.js b/sources/plugins/format/lang/ar.js
new file mode 100644
index 0000000..8fc1c38
--- /dev/null
+++ b/sources/plugins/format/lang/ar.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ar', {
6 label: 'تنسيق',
7 panelTitle: 'تنسيق الفقرة',
8 tag_address: 'عنوان',
9 tag_div: 'عادي (DIV)',
10 tag_h1: 'العنوان 1',
11 tag_h2: 'العنوان 2',
12 tag_h3: 'العنوان 3',
13 tag_h4: 'العنوان 4',
14 tag_h5: 'العنوان 5',
15 tag_h6: 'العنوان 6',
16 tag_p: 'عادي',
17 tag_pre: 'منسّق'
18} );
diff --git a/sources/plugins/format/lang/az.js b/sources/plugins/format/lang/az.js
new file mode 100644
index 0000000..05b2d54
--- /dev/null
+++ b/sources/plugins/format/lang/az.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'az', {
6 label: 'Format',
7 panelTitle: 'Abzasın formatı',
8 tag_address: 'Ünvan',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Başlıq 1',
11 tag_h2: 'Başlıq 2',
12 tag_h3: 'Başlıq 3',
13 tag_h4: 'Başlıq 4',
14 tag_h5: 'Başlıq 5',
15 tag_h6: 'Başlıq 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatı saxla'
18} );
diff --git a/sources/plugins/format/lang/bg.js b/sources/plugins/format/lang/bg.js
new file mode 100644
index 0000000..3de0ac4
--- /dev/null
+++ b/sources/plugins/format/lang/bg.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'bg', {
6 label: 'Формат',
7 panelTitle: 'Формат',
8 tag_address: 'Адрес',
9 tag_div: 'Параграф (DIV)',
10 tag_h1: 'Заглавие 1',
11 tag_h2: 'Заглавие 2',
12 tag_h3: 'Заглавие 3',
13 tag_h4: 'Заглавие 4',
14 tag_h5: 'Заглавие 5',
15 tag_h6: 'Заглавие 6',
16 tag_p: 'Нормален',
17 tag_pre: 'Форматиран'
18} );
diff --git a/sources/plugins/format/lang/bn.js b/sources/plugins/format/lang/bn.js
new file mode 100644
index 0000000..45857a2
--- /dev/null
+++ b/sources/plugins/format/lang/bn.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'bn', {
6 label: 'ধরন-প্রকৃতি',
7 panelTitle: 'ফন্ট ফরমেট',
8 tag_address: 'ঠিকানা',
9 tag_div: 'শীর্ষক (DIV)',
10 tag_h1: 'শীর্ষক ১',
11 tag_h2: 'শীর্ষক ২',
12 tag_h3: 'শীর্ষক ৩',
13 tag_h4: 'শীর্ষক ৪',
14 tag_h5: 'শীর্ষক ৫',
15 tag_h6: 'শীর্ষক ৬',
16 tag_p: 'সাধারণ',
17 tag_pre: 'ফর্মেটেড'
18} );
diff --git a/sources/plugins/format/lang/bs.js b/sources/plugins/format/lang/bs.js
new file mode 100644
index 0000000..4e9482a
--- /dev/null
+++ b/sources/plugins/format/lang/bs.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'bs', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)', // MISSING
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/ca.js b/sources/plugins/format/lang/ca.js
new file mode 100644
index 0000000..5345898
--- /dev/null
+++ b/sources/plugins/format/lang/ca.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ca', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Adreça',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Encapçalament 1',
11 tag_h2: 'Encapçalament 2',
12 tag_h3: 'Encapçalament 3',
13 tag_h4: 'Encapçalament 4',
14 tag_h5: 'Encapçalament 5',
15 tag_h6: 'Encapçalament 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatejat'
18} );
diff --git a/sources/plugins/format/lang/cs.js b/sources/plugins/format/lang/cs.js
new file mode 100644
index 0000000..b96a6c4
--- /dev/null
+++ b/sources/plugins/format/lang/cs.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'cs', {
6 label: 'Formát',
7 panelTitle: 'Formát',
8 tag_address: 'Adresa',
9 tag_div: 'Normální (DIV)',
10 tag_h1: 'Nadpis 1',
11 tag_h2: 'Nadpis 2',
12 tag_h3: 'Nadpis 3',
13 tag_h4: 'Nadpis 4',
14 tag_h5: 'Nadpis 5',
15 tag_h6: 'Nadpis 6',
16 tag_p: 'Normální',
17 tag_pre: 'Naformátováno'
18} );
diff --git a/sources/plugins/format/lang/cy.js b/sources/plugins/format/lang/cy.js
new file mode 100644
index 0000000..a8f618f
--- /dev/null
+++ b/sources/plugins/format/lang/cy.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'cy', {
6 label: 'Fformat',
7 panelTitle: 'Fformat Paragraff',
8 tag_address: 'Cyfeiriad',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Pennawd 1',
11 tag_h2: 'Pennawd 2',
12 tag_h3: 'Pennawd 3',
13 tag_h4: 'Pennawd 4',
14 tag_h5: 'Pennawd 5',
15 tag_h6: 'Pennawd 6',
16 tag_p: 'Normal',
17 tag_pre: 'Wedi\'i Fformatio'
18} );
diff --git a/sources/plugins/format/lang/da.js b/sources/plugins/format/lang/da.js
new file mode 100644
index 0000000..1f7c654
--- /dev/null
+++ b/sources/plugins/format/lang/da.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'da', {
6 label: 'Formatering',
7 panelTitle: 'Formatering',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Overskrift 1',
11 tag_h2: 'Overskrift 2',
12 tag_h3: 'Overskrift 3',
13 tag_h4: 'Overskrift 4',
14 tag_h5: 'Overskrift 5',
15 tag_h6: 'Overskrift 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formateret'
18} );
diff --git a/sources/plugins/format/lang/de-ch.js b/sources/plugins/format/lang/de-ch.js
new file mode 100644
index 0000000..68b8879
--- /dev/null
+++ b/sources/plugins/format/lang/de-ch.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'de-ch', {
6 label: 'Format',
7 panelTitle: 'Absatzformat',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Überschrift 1',
11 tag_h2: 'Überschrift 2',
12 tag_h3: 'Überschrift 3',
13 tag_h4: 'Überschrift 4',
14 tag_h5: 'Überschrift 5',
15 tag_h6: 'Überschrift 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatiert'
18} );
diff --git a/sources/plugins/format/lang/de.js b/sources/plugins/format/lang/de.js
new file mode 100644
index 0000000..e6f6677
--- /dev/null
+++ b/sources/plugins/format/lang/de.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'de', {
6 label: 'Format',
7 panelTitle: 'Absatzformat',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Überschrift 1',
11 tag_h2: 'Überschrift 2',
12 tag_h3: 'Überschrift 3',
13 tag_h4: 'Überschrift 4',
14 tag_h5: 'Überschrift 5',
15 tag_h6: 'Überschrift 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatiert'
18} );
diff --git a/sources/plugins/format/lang/el.js b/sources/plugins/format/lang/el.js
new file mode 100644
index 0000000..9b34051
--- /dev/null
+++ b/sources/plugins/format/lang/el.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'el', {
6 label: 'Μορφοποίηση',
7 panelTitle: 'Μορφοποίηση Παραγράφου',
8 tag_address: 'Διεύθυνση',
9 tag_div: 'Κανονική (DIV)',
10 tag_h1: 'Κεφαλίδα 1',
11 tag_h2: 'Κεφαλίδα 2',
12 tag_h3: 'Κεφαλίδα 3',
13 tag_h4: 'Κεφαλίδα 4',
14 tag_h5: 'Κεφαλίδα 5',
15 tag_h6: 'Κεφαλίδα 6',
16 tag_p: 'Κανονική',
17 tag_pre: 'Προ-μορφοποιημένη'
18} );
diff --git a/sources/plugins/format/lang/en-au.js b/sources/plugins/format/lang/en-au.js
new file mode 100644
index 0000000..5ec7d8e
--- /dev/null
+++ b/sources/plugins/format/lang/en-au.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'en-au', {
6 label: 'Format',
7 panelTitle: 'Paragraph Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/en-ca.js b/sources/plugins/format/lang/en-ca.js
new file mode 100644
index 0000000..75d66c3
--- /dev/null
+++ b/sources/plugins/format/lang/en-ca.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'en-ca', {
6 label: 'Format',
7 panelTitle: 'Paragraph Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/en-gb.js b/sources/plugins/format/lang/en-gb.js
new file mode 100644
index 0000000..a91bcbf
--- /dev/null
+++ b/sources/plugins/format/lang/en-gb.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'en-gb', {
6 label: 'Format',
7 panelTitle: 'Paragraph Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/en.js b/sources/plugins/format/lang/en.js
new file mode 100644
index 0000000..3a6ebda
--- /dev/null
+++ b/sources/plugins/format/lang/en.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'en', {
6 label: 'Format',
7 panelTitle: 'Paragraph Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/eo.js b/sources/plugins/format/lang/eo.js
new file mode 100644
index 0000000..0d77730
--- /dev/null
+++ b/sources/plugins/format/lang/eo.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'eo', {
6 label: 'Formato',
7 panelTitle: 'ParagrafFormato',
8 tag_address: 'Adreso',
9 tag_div: 'Normala (DIV)',
10 tag_h1: 'Titolo 1',
11 tag_h2: 'Titolo 2',
12 tag_h3: 'Titolo 3',
13 tag_h4: 'Titolo 4',
14 tag_h5: 'Titolo 5',
15 tag_h6: 'Titolo 6',
16 tag_p: 'Normala',
17 tag_pre: 'Formatita'
18} );
diff --git a/sources/plugins/format/lang/es.js b/sources/plugins/format/lang/es.js
new file mode 100644
index 0000000..549f611
--- /dev/null
+++ b/sources/plugins/format/lang/es.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'es', {
6 label: 'Formato',
7 panelTitle: 'Formato',
8 tag_address: 'Dirección',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Encabezado 1',
11 tag_h2: 'Encabezado 2',
12 tag_h3: 'Encabezado 3',
13 tag_h4: 'Encabezado 4',
14 tag_h5: 'Encabezado 5',
15 tag_h6: 'Encabezado 6',
16 tag_p: 'Normal',
17 tag_pre: 'Con formato'
18} );
diff --git a/sources/plugins/format/lang/et.js b/sources/plugins/format/lang/et.js
new file mode 100644
index 0000000..43bc350
--- /dev/null
+++ b/sources/plugins/format/lang/et.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'et', {
6 label: 'Vorming',
7 panelTitle: 'Vorming',
8 tag_address: 'Aadress',
9 tag_div: 'Tavaline (DIV)',
10 tag_h1: 'Pealkiri 1',
11 tag_h2: 'Pealkiri 2',
12 tag_h3: 'Pealkiri 3',
13 tag_h4: 'Pealkiri 4',
14 tag_h5: 'Pealkiri 5',
15 tag_h6: 'Pealkiri 6',
16 tag_p: 'Tavaline',
17 tag_pre: 'Vormindatud'
18} );
diff --git a/sources/plugins/format/lang/eu.js b/sources/plugins/format/lang/eu.js
new file mode 100644
index 0000000..18832bc
--- /dev/null
+++ b/sources/plugins/format/lang/eu.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'eu', {
6 label: 'Formatua',
7 panelTitle: 'Paragrafoaren formatua',
8 tag_address: 'Helbidea',
9 tag_div: 'Normala (DIV)',
10 tag_h1: 'Izenburua 1',
11 tag_h2: 'Izenburua 2',
12 tag_h3: 'Izenburua 3',
13 tag_h4: 'Izenburua 4',
14 tag_h5: 'Izenburua 5',
15 tag_h6: 'Izenburua 6',
16 tag_p: 'Normala',
17 tag_pre: 'Formatuduna'
18} );
diff --git a/sources/plugins/format/lang/fa.js b/sources/plugins/format/lang/fa.js
new file mode 100644
index 0000000..c92db53
--- /dev/null
+++ b/sources/plugins/format/lang/fa.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'fa', {
6 label: 'قالب',
7 panelTitle: 'قالب بند',
8 tag_address: 'نشانی',
9 tag_div: 'بند',
10 tag_h1: 'سرنویس ۱',
11 tag_h2: 'سرنویس ۲',
12 tag_h3: 'سرنویس ۳',
13 tag_h4: 'سرنویس ۴',
14 tag_h5: 'سرنویس ۵',
15 tag_h6: 'سرنویس ۶',
16 tag_p: 'معمولی',
17 tag_pre: 'قالب‌دار'
18} );
diff --git a/sources/plugins/format/lang/fi.js b/sources/plugins/format/lang/fi.js
new file mode 100644
index 0000000..249183d
--- /dev/null
+++ b/sources/plugins/format/lang/fi.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'fi', {
6 label: 'Muotoilu',
7 panelTitle: 'Muotoilu',
8 tag_address: 'Osoite',
9 tag_div: 'Normaali (DIV)',
10 tag_h1: 'Otsikko 1',
11 tag_h2: 'Otsikko 2',
12 tag_h3: 'Otsikko 3',
13 tag_h4: 'Otsikko 4',
14 tag_h5: 'Otsikko 5',
15 tag_h6: 'Otsikko 6',
16 tag_p: 'Normaali',
17 tag_pre: 'Muotoiltu'
18} );
diff --git a/sources/plugins/format/lang/fo.js b/sources/plugins/format/lang/fo.js
new file mode 100644
index 0000000..2c88021
--- /dev/null
+++ b/sources/plugins/format/lang/fo.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'fo', {
6 label: 'Skriftsnið',
7 panelTitle: 'Skriftsnið',
8 tag_address: 'Adressa',
9 tag_div: 'Vanligt (DIV)',
10 tag_h1: 'Yvirskrift 1',
11 tag_h2: 'Yvirskrift 2',
12 tag_h3: 'Yvirskrift 3',
13 tag_h4: 'Yvirskrift 4',
14 tag_h5: 'Yvirskrift 5',
15 tag_h6: 'Yvirskrift 6',
16 tag_p: 'Vanligt',
17 tag_pre: 'Sniðgivið'
18} );
diff --git a/sources/plugins/format/lang/fr-ca.js b/sources/plugins/format/lang/fr-ca.js
new file mode 100644
index 0000000..8f190c2
--- /dev/null
+++ b/sources/plugins/format/lang/fr-ca.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'fr-ca', {
6 label: 'Format',
7 panelTitle: 'Format de paragraphe',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'En-tête 1',
11 tag_h2: 'En-tête 2',
12 tag_h3: 'En-tête 3',
13 tag_h4: 'En-tête 4',
14 tag_h5: 'En-tête 5',
15 tag_h6: 'En-tête 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formaté'
18} );
diff --git a/sources/plugins/format/lang/fr.js b/sources/plugins/format/lang/fr.js
new file mode 100644
index 0000000..6962da7
--- /dev/null
+++ b/sources/plugins/format/lang/fr.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'fr', {
6 label: 'Format',
7 panelTitle: 'Format de paragraphe',
8 tag_address: 'Adresse',
9 tag_div: 'Division',
10 tag_h1: 'Titre 1',
11 tag_h2: 'Titre 2',
12 tag_h3: 'Titre 3',
13 tag_h4: 'Titre 4',
14 tag_h5: 'Titre 5',
15 tag_h6: 'Titre 6',
16 tag_p: 'Normal',
17 tag_pre: 'Préformaté'
18} );
diff --git a/sources/plugins/format/lang/gl.js b/sources/plugins/format/lang/gl.js
new file mode 100644
index 0000000..d14946c
--- /dev/null
+++ b/sources/plugins/format/lang/gl.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'gl', {
6 label: 'Formato',
7 panelTitle: 'Formato do parágrafo',
8 tag_address: 'Enderezo',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Enacabezado 1',
11 tag_h2: 'Encabezado 2',
12 tag_h3: 'Encabezado 3',
13 tag_h4: 'Encabezado 4',
14 tag_h5: 'Encabezado 5',
15 tag_h6: 'Encabezado 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatado'
18} );
diff --git a/sources/plugins/format/lang/gu.js b/sources/plugins/format/lang/gu.js
new file mode 100644
index 0000000..8d8897a
--- /dev/null
+++ b/sources/plugins/format/lang/gu.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'gu', {
6 label: 'ફૉન્ટ ફૉર્મટ, રચનાની શૈલી',
7 panelTitle: 'ફૉન્ટ ફૉર્મટ, રચનાની શૈલી',
8 tag_address: 'સરનામું',
9 tag_div: 'શીર્ષક (DIV)',
10 tag_h1: 'શીર્ષક 1',
11 tag_h2: 'શીર્ષક 2',
12 tag_h3: 'શીર્ષક 3',
13 tag_h4: 'શીર્ષક 4',
14 tag_h5: 'શીર્ષક 5',
15 tag_h6: 'શીર્ષક 6',
16 tag_p: 'સામાન્ય',
17 tag_pre: 'ફૉર્મટેડ'
18} );
diff --git a/sources/plugins/format/lang/he.js b/sources/plugins/format/lang/he.js
new file mode 100644
index 0000000..5fb53a7
--- /dev/null
+++ b/sources/plugins/format/lang/he.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'he', {
6 label: 'עיצוב',
7 panelTitle: 'עיצוב',
8 tag_address: 'כתובת',
9 tag_div: 'נורמלי (DIV)',
10 tag_h1: 'כותרת',
11 tag_h2: 'כותרת 2',
12 tag_h3: 'כותרת 3',
13 tag_h4: 'כותרת 4',
14 tag_h5: 'כותרת 5',
15 tag_h6: 'כותרת 6',
16 tag_p: 'נורמלי',
17 tag_pre: 'קוד'
18} );
diff --git a/sources/plugins/format/lang/hi.js b/sources/plugins/format/lang/hi.js
new file mode 100644
index 0000000..ce4224d
--- /dev/null
+++ b/sources/plugins/format/lang/hi.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'hi', {
6 label: 'फ़ॉर्मैट',
7 panelTitle: 'फ़ॉर्मैट',
8 tag_address: 'पता',
9 tag_div: 'शीर्षक (DIV)',
10 tag_h1: 'शीर्षक 1',
11 tag_h2: 'शीर्षक 2',
12 tag_h3: 'शीर्षक 3',
13 tag_h4: 'शीर्षक 4',
14 tag_h5: 'शीर्षक 5',
15 tag_h6: 'शीर्षक 6',
16 tag_p: 'साधारण',
17 tag_pre: 'फ़ॉर्मैटॅड'
18} );
diff --git a/sources/plugins/format/lang/hr.js b/sources/plugins/format/lang/hr.js
new file mode 100644
index 0000000..2d6ec21
--- /dev/null
+++ b/sources/plugins/format/lang/hr.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'hr', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Address',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatirano'
18} );
diff --git a/sources/plugins/format/lang/hu.js b/sources/plugins/format/lang/hu.js
new file mode 100644
index 0000000..a5467cf
--- /dev/null
+++ b/sources/plugins/format/lang/hu.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'hu', {
6 label: 'Formátum',
7 panelTitle: 'Formátum',
8 tag_address: 'Címsor',
9 tag_div: 'Bekezdés (DIV)',
10 tag_h1: 'Fejléc 1',
11 tag_h2: 'Fejléc 2',
12 tag_h3: 'Fejléc 3',
13 tag_h4: 'Fejléc 4',
14 tag_h5: 'Fejléc 5',
15 tag_h6: 'Fejléc 6',
16 tag_p: 'Normál',
17 tag_pre: 'Formázott'
18} );
diff --git a/sources/plugins/format/lang/id.js b/sources/plugins/format/lang/id.js
new file mode 100644
index 0000000..e8e83f7
--- /dev/null
+++ b/sources/plugins/format/lang/id.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'id', {
6 label: 'Bentuk',
7 panelTitle: 'Bentuk Paragraf',
8 tag_address: 'Alamat',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Membentuk'
18} );
diff --git a/sources/plugins/format/lang/is.js b/sources/plugins/format/lang/is.js
new file mode 100644
index 0000000..862e52e
--- /dev/null
+++ b/sources/plugins/format/lang/is.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'is', {
6 label: 'Stílsnið',
7 panelTitle: 'Stílsnið',
8 tag_address: 'Vistfang',
9 tag_div: 'Venjulegt (DIV)',
10 tag_h1: 'Fyrirsögn 1',
11 tag_h2: 'Fyrirsögn 2',
12 tag_h3: 'Fyrirsögn 3',
13 tag_h4: 'Fyrirsögn 4',
14 tag_h5: 'Fyrirsögn 5',
15 tag_h6: 'Fyrirsögn 6',
16 tag_p: 'Venjulegt letur',
17 tag_pre: 'Forsniðið'
18} );
diff --git a/sources/plugins/format/lang/it.js b/sources/plugins/format/lang/it.js
new file mode 100644
index 0000000..6d47500
--- /dev/null
+++ b/sources/plugins/format/lang/it.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'it', {
6 label: 'Formato',
7 panelTitle: 'Formato',
8 tag_address: 'Indirizzo',
9 tag_div: 'Paragrafo (DIV)',
10 tag_h1: 'Titolo 1',
11 tag_h2: 'Titolo 2',
12 tag_h3: 'Titolo 3',
13 tag_h4: 'Titolo 4',
14 tag_h5: 'Titolo 5',
15 tag_h6: 'Titolo 6',
16 tag_p: 'Normale',
17 tag_pre: 'Formattato'
18} );
diff --git a/sources/plugins/format/lang/ja.js b/sources/plugins/format/lang/ja.js
new file mode 100644
index 0000000..a611f3d
--- /dev/null
+++ b/sources/plugins/format/lang/ja.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ja', {
6 label: '書式',
7 panelTitle: '段落の書式',
8 tag_address: 'アドレス',
9 tag_div: '標準 (DIV)',
10 tag_h1: '見出し 1',
11 tag_h2: '見出し 2',
12 tag_h3: '見出し 3',
13 tag_h4: '見出し 4',
14 tag_h5: '見出し 5',
15 tag_h6: '見出し 6',
16 tag_p: '標準',
17 tag_pre: '書式付き'
18} );
diff --git a/sources/plugins/format/lang/ka.js b/sources/plugins/format/lang/ka.js
new file mode 100644
index 0000000..f5c95b8
--- /dev/null
+++ b/sources/plugins/format/lang/ka.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ka', {
6 label: 'ფიორმატირება',
7 panelTitle: 'ფორმატირება',
8 tag_address: 'მისამართი',
9 tag_div: 'ჩვეულებრივი (DIV)',
10 tag_h1: 'სათაური 1',
11 tag_h2: 'სათაური 2',
12 tag_h3: 'სათაური 3',
13 tag_h4: 'სათაური 4',
14 tag_h5: 'სათაური 5',
15 tag_h6: 'სათაური 6',
16 tag_p: 'ჩვეულებრივი',
17 tag_pre: 'ფორმატირებული'
18} );
diff --git a/sources/plugins/format/lang/km.js b/sources/plugins/format/lang/km.js
new file mode 100644
index 0000000..74ca185
--- /dev/null
+++ b/sources/plugins/format/lang/km.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'km', {
6 label: 'ទម្រង់',
7 panelTitle: 'ទម្រង់​កថាខណ្ឌ',
8 tag_address: 'អាសយដ្ឋាន',
9 tag_div: 'ធម្មតា (DIV)',
10 tag_h1: 'ចំណង​ជើង 1',
11 tag_h2: 'ចំណង​ជើង 2',
12 tag_h3: 'ចំណង​ជើង 3',
13 tag_h4: 'ចំណង​ជើង 4',
14 tag_h5: 'ចំណង​ជើង 5',
15 tag_h6: 'ចំណង​ជើង 6',
16 tag_p: 'ធម្មតា',
17 tag_pre: 'Formatted' // MISSING
18} );
diff --git a/sources/plugins/format/lang/ko.js b/sources/plugins/format/lang/ko.js
new file mode 100644
index 0000000..e5ed44c
--- /dev/null
+++ b/sources/plugins/format/lang/ko.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ko', {
6 label: '문단',
7 panelTitle: '문단 형식',
8 tag_address: '글쓴이',
9 tag_div: '기본 (DIV)',
10 tag_h1: '제목 1',
11 tag_h2: '제목 2',
12 tag_h3: '제목 3',
13 tag_h4: '제목 4',
14 tag_h5: '제목 5',
15 tag_h6: '제목 6',
16 tag_p: '본문',
17 tag_pre: '정형 문단'
18} );
diff --git a/sources/plugins/format/lang/ku.js b/sources/plugins/format/lang/ku.js
new file mode 100644
index 0000000..277bf8e
--- /dev/null
+++ b/sources/plugins/format/lang/ku.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ku', {
6 label: 'ڕازاندنەوە',
7 panelTitle: 'بەشی ڕازاندنەوه',
8 tag_address: 'ناونیشان',
9 tag_div: '(DIV)-ی ئاسایی',
10 tag_h1: 'سەرنووسەی ١',
11 tag_h2: 'سەرنووسەی ٢',
12 tag_h3: 'سەرنووسەی ٣',
13 tag_h4: 'سەرنووسەی ٤',
14 tag_h5: 'سەرنووسەی ٥',
15 tag_h6: 'سەرنووسەی ٦',
16 tag_p: 'ئاسایی',
17 tag_pre: 'شێوازکراو'
18} );
diff --git a/sources/plugins/format/lang/lt.js b/sources/plugins/format/lang/lt.js
new file mode 100644
index 0000000..9733443
--- /dev/null
+++ b/sources/plugins/format/lang/lt.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'lt', {
6 label: 'Šrifto formatas',
7 panelTitle: 'Šrifto formatas',
8 tag_address: 'Kreipinio',
9 tag_div: 'Normalus (DIV)',
10 tag_h1: 'Antraštinis 1',
11 tag_h2: 'Antraštinis 2',
12 tag_h3: 'Antraštinis 3',
13 tag_h4: 'Antraštinis 4',
14 tag_h5: 'Antraštinis 5',
15 tag_h6: 'Antraštinis 6',
16 tag_p: 'Normalus',
17 tag_pre: 'Formuotas'
18} );
diff --git a/sources/plugins/format/lang/lv.js b/sources/plugins/format/lang/lv.js
new file mode 100644
index 0000000..ace8333
--- /dev/null
+++ b/sources/plugins/format/lang/lv.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'lv', {
6 label: 'Formāts',
7 panelTitle: 'Formāts',
8 tag_address: 'Adrese',
9 tag_div: 'Rindkopa (DIV)',
10 tag_h1: 'Virsraksts 1',
11 tag_h2: 'Virsraksts 2',
12 tag_h3: 'Virsraksts 3',
13 tag_h4: 'Virsraksts 4',
14 tag_h5: 'Virsraksts 5',
15 tag_h6: 'Virsraksts 6',
16 tag_p: 'Normāls teksts',
17 tag_pre: 'Formatēts teksts'
18} );
diff --git a/sources/plugins/format/lang/mk.js b/sources/plugins/format/lang/mk.js
new file mode 100644
index 0000000..5c0bb3b
--- /dev/null
+++ b/sources/plugins/format/lang/mk.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'mk', {
6 label: 'Format', // MISSING
7 panelTitle: 'Paragraph Format', // MISSING
8 tag_address: 'Address', // MISSING
9 tag_div: 'Normal (DIV)', // MISSING
10 tag_h1: 'Heading 1', // MISSING
11 tag_h2: 'Heading 2', // MISSING
12 tag_h3: 'Heading 3', // MISSING
13 tag_h4: 'Heading 4', // MISSING
14 tag_h5: 'Heading 5', // MISSING
15 tag_h6: 'Heading 6', // MISSING
16 tag_p: 'Normal', // MISSING
17 tag_pre: 'Formatted' // MISSING
18} );
diff --git a/sources/plugins/format/lang/mn.js b/sources/plugins/format/lang/mn.js
new file mode 100644
index 0000000..f3c0dfd
--- /dev/null
+++ b/sources/plugins/format/lang/mn.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'mn', {
6 label: 'Параргафын загвар',
7 panelTitle: 'Параргафын загвар',
8 tag_address: 'Хаяг',
9 tag_div: 'Paragraph (DIV)',
10 tag_h1: 'Гарчиг 1',
11 tag_h2: 'Гарчиг 2',
12 tag_h3: 'Гарчиг 3',
13 tag_h4: 'Гарчиг 4',
14 tag_h5: 'Гарчиг 5',
15 tag_h6: 'Гарчиг 6',
16 tag_p: 'Хэвийн',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/ms.js b/sources/plugins/format/lang/ms.js
new file mode 100644
index 0000000..56deba9
--- /dev/null
+++ b/sources/plugins/format/lang/ms.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ms', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Alamat',
9 tag_div: 'Perenggan (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Telah Diformat'
18} );
diff --git a/sources/plugins/format/lang/nb.js b/sources/plugins/format/lang/nb.js
new file mode 100644
index 0000000..6bfffb5
--- /dev/null
+++ b/sources/plugins/format/lang/nb.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'nb', {
6 label: 'Format',
7 panelTitle: 'Avsnittsformat',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Overskrift 1',
11 tag_h2: 'Overskrift 2',
12 tag_h3: 'Overskrift 3',
13 tag_h4: 'Overskrift 4',
14 tag_h5: 'Overskrift 5',
15 tag_h6: 'Overskrift 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatert'
18} );
diff --git a/sources/plugins/format/lang/nl.js b/sources/plugins/format/lang/nl.js
new file mode 100644
index 0000000..ef2676a
--- /dev/null
+++ b/sources/plugins/format/lang/nl.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'nl', {
6 label: 'Opmaak',
7 panelTitle: 'Opmaak',
8 tag_address: 'Adres',
9 tag_div: 'Normaal (DIV)',
10 tag_h1: 'Kop 1',
11 tag_h2: 'Kop 2',
12 tag_h3: 'Kop 3',
13 tag_h4: 'Kop 4',
14 tag_h5: 'Kop 5',
15 tag_h6: 'Kop 6',
16 tag_p: 'Normaal',
17 tag_pre: 'Met opmaak'
18} );
diff --git a/sources/plugins/format/lang/no.js b/sources/plugins/format/lang/no.js
new file mode 100644
index 0000000..d9b0586
--- /dev/null
+++ b/sources/plugins/format/lang/no.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'no', {
6 label: 'Format',
7 panelTitle: 'Avsnittsformat',
8 tag_address: 'Adresse',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Overskrift 1',
11 tag_h2: 'Overskrift 2',
12 tag_h3: 'Overskrift 3',
13 tag_h4: 'Overskrift 4',
14 tag_h5: 'Overskrift 5',
15 tag_h6: 'Overskrift 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatert'
18} );
diff --git a/sources/plugins/format/lang/oc.js b/sources/plugins/format/lang/oc.js
new file mode 100644
index 0000000..5083f3f
--- /dev/null
+++ b/sources/plugins/format/lang/oc.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'oc', {
6 label: 'Format',
7 panelTitle: 'Format de paragraf',
8 tag_address: 'Adreça',
9 tag_div: 'Division (DIV)',
10 tag_h1: 'Títol 1',
11 tag_h2: 'Títol 2',
12 tag_h3: 'Títol 3',
13 tag_h4: 'Títol 4',
14 tag_h5: 'Títol 5',
15 tag_h6: 'Títol 6',
16 tag_p: 'Normal',
17 tag_pre: 'Preformatat'
18} );
diff --git a/sources/plugins/format/lang/pl.js b/sources/plugins/format/lang/pl.js
new file mode 100644
index 0000000..d1274f9
--- /dev/null
+++ b/sources/plugins/format/lang/pl.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'pl', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Adres',
9 tag_div: 'Normalny (DIV)',
10 tag_h1: 'Nagłówek 1',
11 tag_h2: 'Nagłówek 2',
12 tag_h3: 'Nagłówek 3',
13 tag_h4: 'Nagłówek 4',
14 tag_h5: 'Nagłówek 5',
15 tag_h6: 'Nagłówek 6',
16 tag_p: 'Normalny',
17 tag_pre: 'Tekst sformatowany'
18} );
diff --git a/sources/plugins/format/lang/pt-br.js b/sources/plugins/format/lang/pt-br.js
new file mode 100644
index 0000000..151d1d1
--- /dev/null
+++ b/sources/plugins/format/lang/pt-br.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'pt-br', {
6 label: 'Formatação',
7 panelTitle: 'Formatação',
8 tag_address: 'Endereço',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Título 1',
11 tag_h2: 'Título 2',
12 tag_h3: 'Título 3',
13 tag_h4: 'Título 4',
14 tag_h5: 'Título 5',
15 tag_h6: 'Título 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatado'
18} );
diff --git a/sources/plugins/format/lang/pt.js b/sources/plugins/format/lang/pt.js
new file mode 100644
index 0000000..013021d
--- /dev/null
+++ b/sources/plugins/format/lang/pt.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'pt', {
6 label: 'Formatar',
7 panelTitle: 'Formatar Parágrafo',
8 tag_address: 'Endereço',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Título 1',
11 tag_h2: 'Título 2',
12 tag_h3: 'Título 3',
13 tag_h4: 'Título 4',
14 tag_h5: 'Título 5',
15 tag_h6: 'Título 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatado'
18} );
diff --git a/sources/plugins/format/lang/ro.js b/sources/plugins/format/lang/ro.js
new file mode 100644
index 0000000..549a1b5
--- /dev/null
+++ b/sources/plugins/format/lang/ro.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ro', {
6 label: 'Formatare',
7 panelTitle: 'Formatare',
8 tag_address: 'Adresă',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatat'
18} );
diff --git a/sources/plugins/format/lang/ru.js b/sources/plugins/format/lang/ru.js
new file mode 100644
index 0000000..8e63455
--- /dev/null
+++ b/sources/plugins/format/lang/ru.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ru', {
6 label: 'Форматирование',
7 panelTitle: 'Форматирование',
8 tag_address: 'Адрес',
9 tag_div: 'Обычное (div)',
10 tag_h1: 'Заголовок 1',
11 tag_h2: 'Заголовок 2',
12 tag_h3: 'Заголовок 3',
13 tag_h4: 'Заголовок 4',
14 tag_h5: 'Заголовок 5',
15 tag_h6: 'Заголовок 6',
16 tag_p: 'Обычное',
17 tag_pre: 'Моноширинное'
18} );
diff --git a/sources/plugins/format/lang/si.js b/sources/plugins/format/lang/si.js
new file mode 100644
index 0000000..f27eb7f
--- /dev/null
+++ b/sources/plugins/format/lang/si.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'si', {
6 label: 'ආකෘතිය',
7 panelTitle: 'චේදයේ ',
8 tag_address: 'ලිපිනය',
9 tag_div: 'සාමාන්‍ය(DIV)',
10 tag_h1: 'ශීර්ෂය 1',
11 tag_h2: 'ශීර්ෂය 2',
12 tag_h3: 'ශීර්ෂය 3',
13 tag_h4: 'ශීර්ෂය 4',
14 tag_h5: 'ශීර්ෂය 5',
15 tag_h6: 'ශීර්ෂය 6',
16 tag_p: 'සාමාන්‍ය',
17 tag_pre: 'ආකෘතියන්'
18} );
diff --git a/sources/plugins/format/lang/sk.js b/sources/plugins/format/lang/sk.js
new file mode 100644
index 0000000..30ca66c
--- /dev/null
+++ b/sources/plugins/format/lang/sk.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sk', {
6 label: 'Formát',
7 panelTitle: 'Odsek',
8 tag_address: 'Adresa',
9 tag_div: 'Normálny (DIV)',
10 tag_h1: 'Nadpis 1',
11 tag_h2: 'Nadpis 2',
12 tag_h3: 'Nadpis 3',
13 tag_h4: 'Nadpis 4',
14 tag_h5: 'Nadpis 5',
15 tag_h6: 'Nadpis 6',
16 tag_p: 'Normálny',
17 tag_pre: 'Formátovaný'
18} );
diff --git a/sources/plugins/format/lang/sl.js b/sources/plugins/format/lang/sl.js
new file mode 100644
index 0000000..2dad54f
--- /dev/null
+++ b/sources/plugins/format/lang/sl.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sl', {
6 label: 'Oblika',
7 panelTitle: 'Oblika odstavka',
8 tag_address: 'Napis',
9 tag_div: 'Navaden (DIV)',
10 tag_h1: 'Naslov 1',
11 tag_h2: 'Naslov 2',
12 tag_h3: 'Naslov 3',
13 tag_h4: 'Naslov 4',
14 tag_h5: 'Naslov 5',
15 tag_h6: 'Naslov 6',
16 tag_p: 'Navaden',
17 tag_pre: 'Oblikovan'
18} );
diff --git a/sources/plugins/format/lang/sq.js b/sources/plugins/format/lang/sq.js
new file mode 100644
index 0000000..5ddb6ef
--- /dev/null
+++ b/sources/plugins/format/lang/sq.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sq', {
6 label: 'Formati',
7 panelTitle: 'Formati i Paragrafit',
8 tag_address: 'Adresa',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Titulli 1',
11 tag_h2: 'Titulli 2',
12 tag_h3: 'Titulli 3',
13 tag_h4: 'Titulli 4',
14 tag_h5: 'Titulli 5',
15 tag_h6: 'Titulli 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatuar'
18} );
diff --git a/sources/plugins/format/lang/sr-latn.js b/sources/plugins/format/lang/sr-latn.js
new file mode 100644
index 0000000..d971950
--- /dev/null
+++ b/sources/plugins/format/lang/sr-latn.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sr-latn', {
6 label: 'Format',
7 panelTitle: 'Format',
8 tag_address: 'Adresa',
9 tag_div: 'Normalno (DIV)',
10 tag_h1: 'Naslov 1',
11 tag_h2: 'Naslov 2',
12 tag_h3: 'Naslov 3',
13 tag_h4: 'Naslov 4',
14 tag_h5: 'Naslov 5',
15 tag_h6: 'Naslov 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatirano'
18} );
diff --git a/sources/plugins/format/lang/sr.js b/sources/plugins/format/lang/sr.js
new file mode 100644
index 0000000..012a14d
--- /dev/null
+++ b/sources/plugins/format/lang/sr.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sr', {
6 label: 'Формат',
7 panelTitle: 'Формат',
8 tag_address: 'Adresa',
9 tag_div: 'Нормално (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatirano'
18} );
diff --git a/sources/plugins/format/lang/sv.js b/sources/plugins/format/lang/sv.js
new file mode 100644
index 0000000..31850e0
--- /dev/null
+++ b/sources/plugins/format/lang/sv.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'sv', {
6 label: 'Teckenformat',
7 panelTitle: 'Teckenformat',
8 tag_address: 'Adress',
9 tag_div: 'Normal (DIV)',
10 tag_h1: 'Rubrik 1',
11 tag_h2: 'Rubrik 2',
12 tag_h3: 'Rubrik 3',
13 tag_h4: 'Rubrik 4',
14 tag_h5: 'Rubrik 5',
15 tag_h6: 'Rubrik 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formaterad'
18} );
diff --git a/sources/plugins/format/lang/th.js b/sources/plugins/format/lang/th.js
new file mode 100644
index 0000000..4c8a1d2
--- /dev/null
+++ b/sources/plugins/format/lang/th.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'th', {
6 label: 'รูปแบบ',
7 panelTitle: 'รูปแบบ',
8 tag_address: 'Address',
9 tag_div: 'Paragraph (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Normal',
17 tag_pre: 'Formatted'
18} );
diff --git a/sources/plugins/format/lang/tr.js b/sources/plugins/format/lang/tr.js
new file mode 100644
index 0000000..2de6ce2
--- /dev/null
+++ b/sources/plugins/format/lang/tr.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'tr', {
6 label: 'Biçim',
7 panelTitle: 'Biçim',
8 tag_address: 'Adres',
9 tag_div: 'Paragraf (DIV)',
10 tag_h1: 'Başlık 1',
11 tag_h2: 'Başlık 2',
12 tag_h3: 'Başlık 3',
13 tag_h4: 'Başlık 4',
14 tag_h5: 'Başlık 5',
15 tag_h6: 'Başlık 6',
16 tag_p: 'Normal',
17 tag_pre: 'Biçimli'
18} );
diff --git a/sources/plugins/format/lang/tt.js b/sources/plugins/format/lang/tt.js
new file mode 100644
index 0000000..160a192
--- /dev/null
+++ b/sources/plugins/format/lang/tt.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'tt', {
6 label: 'Форматлау',
7 panelTitle: 'Параграф форматлавы',
8 tag_address: 'Адрес',
9 tag_div: 'Гади (DIV)',
10 tag_h1: 'Башлам 1',
11 tag_h2: 'Башлам 2',
12 tag_h3: 'Башлам 3',
13 tag_h4: 'Башлам 4',
14 tag_h5: 'Башлам 5',
15 tag_h6: 'Башлам 6',
16 tag_p: 'Гади',
17 tag_pre: 'Форматлаулы'
18} );
diff --git a/sources/plugins/format/lang/ug.js b/sources/plugins/format/lang/ug.js
new file mode 100644
index 0000000..0be2a15
--- /dev/null
+++ b/sources/plugins/format/lang/ug.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'ug', {
6 label: 'پىچىم',
7 panelTitle: 'پىچىم',
8 tag_address: 'ئادرېس',
9 tag_div: 'ئابزاس (DIV)',
10 tag_h1: 'ماۋزۇ 1',
11 tag_h2: 'ماۋزۇ 2',
12 tag_h3: 'ماۋزۇ 3',
13 tag_h4: 'ماۋزۇ 4',
14 tag_h5: 'ماۋزۇ 5',
15 tag_h6: 'ماۋزۇ 6',
16 tag_p: 'ئادەتتىكى',
17 tag_pre: 'تىزىلغان پىچىم'
18} );
diff --git a/sources/plugins/format/lang/uk.js b/sources/plugins/format/lang/uk.js
new file mode 100644
index 0000000..2e2726d
--- /dev/null
+++ b/sources/plugins/format/lang/uk.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'uk', {
6 label: 'Форматування',
7 panelTitle: 'Форматування параграфа',
8 tag_address: 'Адреса',
9 tag_div: 'Нормальний (div)',
10 tag_h1: 'Заголовок 1',
11 tag_h2: 'Заголовок 2',
12 tag_h3: 'Заголовок 3',
13 tag_h4: 'Заголовок 4',
14 tag_h5: 'Заголовок 5',
15 tag_h6: 'Заголовок 6',
16 tag_p: 'Нормальний',
17 tag_pre: 'Форматований'
18} );
diff --git a/sources/plugins/format/lang/vi.js b/sources/plugins/format/lang/vi.js
new file mode 100644
index 0000000..d051440
--- /dev/null
+++ b/sources/plugins/format/lang/vi.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'vi', {
6 label: 'Định dạng',
7 panelTitle: 'Định dạng',
8 tag_address: 'Address',
9 tag_div: 'Bình thường (DIV)',
10 tag_h1: 'Heading 1',
11 tag_h2: 'Heading 2',
12 tag_h3: 'Heading 3',
13 tag_h4: 'Heading 4',
14 tag_h5: 'Heading 5',
15 tag_h6: 'Heading 6',
16 tag_p: 'Bình thường (P)',
17 tag_pre: 'Đã thiết lập'
18} );
diff --git a/sources/plugins/format/lang/zh-cn.js b/sources/plugins/format/lang/zh-cn.js
new file mode 100644
index 0000000..addaa23
--- /dev/null
+++ b/sources/plugins/format/lang/zh-cn.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'zh-cn', {
6 label: '格式',
7 panelTitle: '格式',
8 tag_address: '地址',
9 tag_div: '段落(DIV)',
10 tag_h1: '标题 1',
11 tag_h2: '标题 2',
12 tag_h3: '标题 3',
13 tag_h4: '标题 4',
14 tag_h5: '标题 5',
15 tag_h6: '标题 6',
16 tag_p: '普通',
17 tag_pre: '已编排格式'
18} );
diff --git a/sources/plugins/format/lang/zh.js b/sources/plugins/format/lang/zh.js
new file mode 100644
index 0000000..bb044ad
--- /dev/null
+++ b/sources/plugins/format/lang/zh.js
@@ -0,0 +1,18 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'format', 'zh', {
6 label: '格式',
7 panelTitle: '段落格式',
8 tag_address: '地址',
9 tag_div: '標準 (DIV)',
10 tag_h1: '標題 1',
11 tag_h2: '標題 2',
12 tag_h3: '標題 3',
13 tag_h4: '標題 4',
14 tag_h5: '標題 5',
15 tag_h6: '標題 6',
16 tag_p: '標準',
17 tag_pre: '格式設定'
18} );
diff --git a/sources/plugins/format/plugin.js b/sources/plugins/format/plugin.js
new file mode 100644
index 0000000..826cbcf
--- /dev/null
+++ b/sources/plugins/format/plugin.js
@@ -0,0 +1,279 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'format', {
7 requires: 'richcombo',
8 // jscs:disable maximumLineLength
9 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
10 // jscs:enable maximumLineLength
11 init: function( editor ) {
12 if ( editor.blockless )
13 return;
14
15 var config = editor.config,
16 lang = editor.lang.format;
17
18 // Gets the list of tags from the settings.
19 var tags = config.format_tags.split( ';' );
20
21 // Create style objects for all defined styles.
22 var styles = {},
23 stylesCount = 0,
24 allowedContent = [];
25 for ( var i = 0; i < tags.length; i++ ) {
26 var tag = tags[ i ];
27 var style = new CKEDITOR.style( config[ 'format_' + tag ] );
28 if ( !editor.filter.customConfig || editor.filter.check( style ) ) {
29 stylesCount++;
30 styles[ tag ] = style;
31 styles[ tag ]._.enterMode = editor.config.enterMode;
32 allowedContent.push( style );
33 }
34 }
35
36 // Hide entire combo when all formats are rejected.
37 if ( stylesCount === 0 )
38 return;
39
40 editor.ui.addRichCombo( 'Format', {
41 label: lang.label,
42 title: lang.panelTitle,
43 toolbar: 'styles,20',
44 allowedContent: allowedContent,
45
46 panel: {
47 css: [ CKEDITOR.skin.getPath( 'editor' ) ].concat( config.contentsCss ),
48 multiSelect: false,
49 attributes: { 'aria-label': lang.panelTitle }
50 },
51
52 init: function() {
53 this.startGroup( lang.panelTitle );
54
55 for ( var tag in styles ) {
56 var label = lang[ 'tag_' + tag ];
57
58 // Add the tag entry to the panel list.
59 this.add( tag, styles[ tag ].buildPreview( label ), label );
60 }
61 },
62
63 onClick: function( value ) {
64 editor.focus();
65 editor.fire( 'saveSnapshot' );
66
67 var style = styles[ value ],
68 elementPath = editor.elementPath();
69
70 editor[ style.checkActive( elementPath, editor ) ? 'removeStyle' : 'applyStyle' ]( style );
71
72 // Save the undo snapshot after all changes are affected. (#4899)
73 setTimeout( function() {
74 editor.fire( 'saveSnapshot' );
75 }, 0 );
76 },
77
78 onRender: function() {
79 editor.on( 'selectionChange', function( ev ) {
80 var currentTag = this.getValue(),
81 elementPath = ev.data.path;
82
83 this.refresh();
84
85 for ( var tag in styles ) {
86 if ( styles[ tag ].checkActive( elementPath, editor ) ) {
87 if ( tag != currentTag )
88 this.setValue( tag, editor.lang.format[ 'tag_' + tag ] );
89 return;
90 }
91 }
92
93 // If no styles match, just empty it.
94 this.setValue( '' );
95
96 }, this );
97 },
98
99 onOpen: function() {
100 this.showAll();
101 for ( var name in styles ) {
102 var style = styles[ name ];
103
104 // Check if that style is enabled in activeFilter.
105 if ( !editor.activeFilter.check( style ) )
106 this.hideItem( name );
107
108 }
109 },
110
111 refresh: function() {
112 var elementPath = editor.elementPath();
113
114 if ( !elementPath )
115 return;
116
117 // Check if element path contains 'p' element.
118 if ( !elementPath.isContextFor( 'p' ) ) {
119 this.setState( CKEDITOR.TRISTATE_DISABLED );
120 return;
121 }
122
123 // Check if there is any available style.
124 for ( var name in styles ) {
125 if ( editor.activeFilter.check( styles[ name ] ) )
126 return;
127 }
128 this.setState( CKEDITOR.TRISTATE_DISABLED );
129 }
130 } );
131 }
132} );
133
134/**
135 * A list of semicolon-separated style names (by default: tags) representing
136 * the style definition for each entry to be displayed in the Format drop-down list
137 * in the toolbar. Each entry must have a corresponding configuration in a
138 * setting named `'format_(tagName)'`. For example, the `'p'` entry has its
139 * definition taken from [config.format_p](#!/api/CKEDITOR.config-cfg-format_p).
140 *
141 * Read more in the [documentation](#!/guide/dev_format)
142 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
143 *
144 * config.format_tags = 'p;h2;h3;pre';
145 *
146 * @cfg {String} [format_tags='p;h1;h2;h3;h4;h5;h6;pre;address;div']
147 * @member CKEDITOR.config
148 */
149CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;h5;h6;pre;address;div';
150
151/**
152 * The style definition to be used to apply the `Normal` format.
153 *
154 * Read more in the [documentation](#!/guide/dev_format)
155 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
156 *
157 * config.format_p = { element: 'p', attributes: { 'class': 'normalPara' } };
158 *
159 * @cfg {Object} [format_p={ element: 'p' }]
160 * @member CKEDITOR.config
161 */
162CKEDITOR.config.format_p = { element: 'p' };
163
164/**
165 * The style definition to be used to apply the `Normal (DIV)` format.
166 *
167 * Read more in the [documentation](#!/guide/dev_format)
168 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
169 *
170 * config.format_div = { element: 'div', attributes: { 'class': 'normalDiv' } };
171 *
172 * @cfg {Object} [format_div={ element: 'div' }]
173 * @member CKEDITOR.config
174 */
175CKEDITOR.config.format_div = { element: 'div' };
176
177/**
178 * The style definition to be used to apply the `Formatted` format.
179 *
180 * Read more in the [documentation](#!/guide/dev_format)
181 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
182 *
183 * config.format_pre = { element: 'pre', attributes: { 'class': 'code' } };
184 *
185 * @cfg {Object} [format_pre={ element: 'pre' }]
186 * @member CKEDITOR.config
187 */
188CKEDITOR.config.format_pre = { element: 'pre' };
189
190/**
191 * The style definition to be used to apply the `Address` format.
192 *
193 * Read more in the [documentation](#!/guide/dev_format)
194 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
195 *
196 * config.format_address = { element: 'address', attributes: { 'class': 'styledAddress' } };
197 *
198 * @cfg {Object} [format_address={ element: 'address' }]
199 * @member CKEDITOR.config
200 */
201CKEDITOR.config.format_address = { element: 'address' };
202
203/**
204 * The style definition to be used to apply the `Heading 1` format.
205 *
206 * Read more in the [documentation](#!/guide/dev_format)
207 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
208 *
209 * config.format_h1 = { element: 'h1', attributes: { 'class': 'contentTitle1' } };
210 *
211 * @cfg {Object} [format_h1={ element: 'h1' }]
212 * @member CKEDITOR.config
213 */
214CKEDITOR.config.format_h1 = { element: 'h1' };
215
216/**
217 * The style definition to be used to apply the `Heading 2` format.
218 *
219 * Read more in the [documentation](#!/guide/dev_format)
220 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
221 *
222 * config.format_h2 = { element: 'h2', attributes: { 'class': 'contentTitle2' } };
223 *
224 * @cfg {Object} [format_h2={ element: 'h2' }]
225 * @member CKEDITOR.config
226 */
227CKEDITOR.config.format_h2 = { element: 'h2' };
228
229/**
230 * The style definition to be used to apply the `Heading 3` format.
231 *
232 * Read more in the [documentation](#!/guide/dev_format)
233 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
234 *
235 * config.format_h3 = { element: 'h3', attributes: { 'class': 'contentTitle3' } };
236 *
237 * @cfg {Object} [format_h3={ element: 'h3' }]
238 * @member CKEDITOR.config
239 */
240CKEDITOR.config.format_h3 = { element: 'h3' };
241
242/**
243 * The style definition to be used to apply the `Heading 4` format.
244 *
245 * Read more in the [documentation](#!/guide/dev_format)
246 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
247 *
248 * config.format_h4 = { element: 'h4', attributes: { 'class': 'contentTitle4' } };
249 *
250 * @cfg {Object} [format_h4={ element: 'h4' }]
251 * @member CKEDITOR.config
252 */
253CKEDITOR.config.format_h4 = { element: 'h4' };
254
255/**
256 * The style definition to be used to apply the `Heading 5` format.
257 *
258 * Read more in the [documentation](#!/guide/dev_format)
259 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
260 *
261 * config.format_h5 = { element: 'h5', attributes: { 'class': 'contentTitle5' } };
262 *
263 * @cfg {Object} [format_h5={ element: 'h5' }]
264 * @member CKEDITOR.config
265 */
266CKEDITOR.config.format_h5 = { element: 'h5' };
267
268/**
269 * The style definition to be used to apply the `Heading 6` format.
270 *
271 * Read more in the [documentation](#!/guide/dev_format)
272 * and see the [SDK sample](http://sdk.ckeditor.com/samples/format.html).
273 *
274 * config.format_h6 = { element: 'h6', attributes: { 'class': 'contentTitle6' } };
275 *
276 * @cfg {Object} [format_h6={ element: 'h6' }]
277 * @member CKEDITOR.config
278 */
279CKEDITOR.config.format_h6 = { element: 'h6' };
diff --git a/sources/plugins/horizontalrule/icons/hidpi/horizontalrule.png b/sources/plugins/horizontalrule/icons/hidpi/horizontalrule.png
new file mode 100644
index 0000000..ad97e09
--- /dev/null
+++ b/sources/plugins/horizontalrule/icons/hidpi/horizontalrule.png
Binary files differ
diff --git a/sources/plugins/horizontalrule/icons/horizontalrule.png b/sources/plugins/horizontalrule/icons/horizontalrule.png
new file mode 100644
index 0000000..0592614
--- /dev/null
+++ b/sources/plugins/horizontalrule/icons/horizontalrule.png
Binary files differ
diff --git a/sources/plugins/horizontalrule/lang/af.js b/sources/plugins/horizontalrule/lang/af.js
new file mode 100644
index 0000000..9232187
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/af.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'af', {
6 toolbar: 'Horisontale lyn invoeg'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ar.js b/sources/plugins/horizontalrule/lang/ar.js
new file mode 100644
index 0000000..edf9101
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ar.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ar', {
6 toolbar: 'خط فاصل'
7} );
diff --git a/sources/plugins/horizontalrule/lang/az.js b/sources/plugins/horizontalrule/lang/az.js
new file mode 100644
index 0000000..2343630
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/az.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'az', {
6 toolbar: 'Sərhəd xətti yarat'
7} );
diff --git a/sources/plugins/horizontalrule/lang/bg.js b/sources/plugins/horizontalrule/lang/bg.js
new file mode 100644
index 0000000..b20914c
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/bg.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'bg', {
6 toolbar: 'Вмъкване на хоризонтална линия'
7} );
diff --git a/sources/plugins/horizontalrule/lang/bn.js b/sources/plugins/horizontalrule/lang/bn.js
new file mode 100644
index 0000000..d846125
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/bn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'bn', {
6 toolbar: 'অনুভূমিক লাইন যোগ করি'
7} );
diff --git a/sources/plugins/horizontalrule/lang/bs.js b/sources/plugins/horizontalrule/lang/bs.js
new file mode 100644
index 0000000..3917873
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/bs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'bs', {
6 toolbar: 'Ubaci horizontalnu liniju'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ca.js b/sources/plugins/horizontalrule/lang/ca.js
new file mode 100644
index 0000000..81d9457
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ca', {
6 toolbar: 'Insereix línia horitzontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/cs.js b/sources/plugins/horizontalrule/lang/cs.js
new file mode 100644
index 0000000..5178139
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/cs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'cs', {
6 toolbar: 'Vložit vodorovnou linku'
7} );
diff --git a/sources/plugins/horizontalrule/lang/cy.js b/sources/plugins/horizontalrule/lang/cy.js
new file mode 100644
index 0000000..df74af5
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/cy.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'cy', {
6 toolbar: 'Mewnosod Llinell Lorweddol'
7} );
diff --git a/sources/plugins/horizontalrule/lang/da.js b/sources/plugins/horizontalrule/lang/da.js
new file mode 100644
index 0000000..cd8cb2a
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/da.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'da', {
6 toolbar: 'Indsæt vandret streg'
7} );
diff --git a/sources/plugins/horizontalrule/lang/de-ch.js b/sources/plugins/horizontalrule/lang/de-ch.js
new file mode 100644
index 0000000..64230b5
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/de-ch.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'de-ch', {
6 toolbar: 'Horizontale Linie einfügen'
7} );
diff --git a/sources/plugins/horizontalrule/lang/de.js b/sources/plugins/horizontalrule/lang/de.js
new file mode 100644
index 0000000..a1705a6
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/de.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'de', {
6 toolbar: 'Horizontale Linie einfügen'
7} );
diff --git a/sources/plugins/horizontalrule/lang/el.js b/sources/plugins/horizontalrule/lang/el.js
new file mode 100644
index 0000000..d281f47
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/el.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'el', {
6 toolbar: 'Εισαγωγή Οριζόντιας Γραμμής'
7} );
diff --git a/sources/plugins/horizontalrule/lang/en-au.js b/sources/plugins/horizontalrule/lang/en-au.js
new file mode 100644
index 0000000..0548518
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/en-au.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'en-au', {
6 toolbar: 'Insert Horizontal Line'
7} );
diff --git a/sources/plugins/horizontalrule/lang/en-ca.js b/sources/plugins/horizontalrule/lang/en-ca.js
new file mode 100644
index 0000000..feab44d
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/en-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'en-ca', {
6 toolbar: 'Insert Horizontal Line'
7} );
diff --git a/sources/plugins/horizontalrule/lang/en-gb.js b/sources/plugins/horizontalrule/lang/en-gb.js
new file mode 100644
index 0000000..5cf987f
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/en-gb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'en-gb', {
6 toolbar: 'Insert Horizontal Line'
7} );
diff --git a/sources/plugins/horizontalrule/lang/en.js b/sources/plugins/horizontalrule/lang/en.js
new file mode 100644
index 0000000..6c750d1
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/en.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'en', {
6 toolbar: 'Insert Horizontal Line'
7} );
diff --git a/sources/plugins/horizontalrule/lang/eo.js b/sources/plugins/horizontalrule/lang/eo.js
new file mode 100644
index 0000000..f2ddd72
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/eo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'eo', {
6 toolbar: 'Enmeti Horizontalan Linion'
7} );
diff --git a/sources/plugins/horizontalrule/lang/es.js b/sources/plugins/horizontalrule/lang/es.js
new file mode 100644
index 0000000..ac42e14
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/es.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'es', {
6 toolbar: 'Insertar Línea Horizontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/et.js b/sources/plugins/horizontalrule/lang/et.js
new file mode 100644
index 0000000..156b1c1
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/et.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'et', {
6 toolbar: 'Horisontaaljoone sisestamine'
7} );
diff --git a/sources/plugins/horizontalrule/lang/eu.js b/sources/plugins/horizontalrule/lang/eu.js
new file mode 100644
index 0000000..7eeabb8
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/eu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'eu', {
6 toolbar: 'Txertatu marra horizontala'
7} );
diff --git a/sources/plugins/horizontalrule/lang/fa.js b/sources/plugins/horizontalrule/lang/fa.js
new file mode 100644
index 0000000..f18d1d0
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/fa.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'fa', {
6 toolbar: 'گنجاندن خط افقی'
7} );
diff --git a/sources/plugins/horizontalrule/lang/fi.js b/sources/plugins/horizontalrule/lang/fi.js
new file mode 100644
index 0000000..c18cd70
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/fi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'fi', {
6 toolbar: 'Lisää murtoviiva'
7} );
diff --git a/sources/plugins/horizontalrule/lang/fo.js b/sources/plugins/horizontalrule/lang/fo.js
new file mode 100644
index 0000000..d0d3bea
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/fo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'fo', {
6 toolbar: 'Ger vatnrætta linju'
7} );
diff --git a/sources/plugins/horizontalrule/lang/fr-ca.js b/sources/plugins/horizontalrule/lang/fr-ca.js
new file mode 100644
index 0000000..a232a14
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/fr-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'fr-ca', {
6 toolbar: 'Insérer un séparateur horizontale'
7} );
diff --git a/sources/plugins/horizontalrule/lang/fr.js b/sources/plugins/horizontalrule/lang/fr.js
new file mode 100644
index 0000000..c0c6322
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/fr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'fr', {
6 toolbar: 'Ligne horizontale'
7} );
diff --git a/sources/plugins/horizontalrule/lang/gl.js b/sources/plugins/horizontalrule/lang/gl.js
new file mode 100644
index 0000000..6215e71
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/gl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'gl', {
6 toolbar: 'Inserir unha liña horizontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/gu.js b/sources/plugins/horizontalrule/lang/gu.js
new file mode 100644
index 0000000..f6abc17
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/gu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'gu', {
6 toolbar: 'સમસ્તરીય રેખા ઇન્સર્ટ/દાખલ કરવી'
7} );
diff --git a/sources/plugins/horizontalrule/lang/he.js b/sources/plugins/horizontalrule/lang/he.js
new file mode 100644
index 0000000..56c4ebd
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/he.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'he', {
6 toolbar: 'הוספת קו אופקי'
7} );
diff --git a/sources/plugins/horizontalrule/lang/hi.js b/sources/plugins/horizontalrule/lang/hi.js
new file mode 100644
index 0000000..1d576c2
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/hi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'hi', {
6 toolbar: 'हॉरिज़ॉन्टल रेखा इन्सर्ट करें'
7} );
diff --git a/sources/plugins/horizontalrule/lang/hr.js b/sources/plugins/horizontalrule/lang/hr.js
new file mode 100644
index 0000000..53d80f3
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/hr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'hr', {
6 toolbar: 'Ubaci vodoravnu liniju'
7} );
diff --git a/sources/plugins/horizontalrule/lang/hu.js b/sources/plugins/horizontalrule/lang/hu.js
new file mode 100644
index 0000000..31fcbfc
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/hu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'hu', {
6 toolbar: 'Elválasztóvonal beillesztése'
7} );
diff --git a/sources/plugins/horizontalrule/lang/id.js b/sources/plugins/horizontalrule/lang/id.js
new file mode 100644
index 0000000..3d341ad
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/id.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'id', {
6 toolbar: 'Sisip Garis Horisontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/is.js b/sources/plugins/horizontalrule/lang/is.js
new file mode 100644
index 0000000..1515abc
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/is.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'is', {
6 toolbar: 'Lóðrétt lína'
7} );
diff --git a/sources/plugins/horizontalrule/lang/it.js b/sources/plugins/horizontalrule/lang/it.js
new file mode 100644
index 0000000..c2e23fb
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/it.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'it', {
6 toolbar: 'Inserisci riga orizzontale'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ja.js b/sources/plugins/horizontalrule/lang/ja.js
new file mode 100644
index 0000000..e174c32
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ja.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ja', {
6 toolbar: '水平線'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ka.js b/sources/plugins/horizontalrule/lang/ka.js
new file mode 100644
index 0000000..2c798c2
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ka.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ka', {
6 toolbar: 'ჰორიზონტალური ხაზის ჩასმა'
7} );
diff --git a/sources/plugins/horizontalrule/lang/km.js b/sources/plugins/horizontalrule/lang/km.js
new file mode 100644
index 0000000..8c8ab9f
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/km.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'km', {
6 toolbar: 'បន្ថែមបន្ទាត់ផ្តេក'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ko.js b/sources/plugins/horizontalrule/lang/ko.js
new file mode 100644
index 0000000..69df02c
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ko.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ko', {
6 toolbar: '가로 줄 삽입'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ku.js b/sources/plugins/horizontalrule/lang/ku.js
new file mode 100644
index 0000000..c8a0fa5
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ku.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ku', {
6 toolbar: 'دانانی هێلی ئاسۆیی'
7} );
diff --git a/sources/plugins/horizontalrule/lang/lt.js b/sources/plugins/horizontalrule/lang/lt.js
new file mode 100644
index 0000000..86cbdaf
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/lt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'lt', {
6 toolbar: 'Įterpti horizontalią liniją'
7} );
diff --git a/sources/plugins/horizontalrule/lang/lv.js b/sources/plugins/horizontalrule/lang/lv.js
new file mode 100644
index 0000000..a227a00
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/lv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'lv', {
6 toolbar: 'Ievietot horizontālu Atdalītājsvītru'
7} );
diff --git a/sources/plugins/horizontalrule/lang/mk.js b/sources/plugins/horizontalrule/lang/mk.js
new file mode 100644
index 0000000..51efe3d
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/mk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'mk', {
6 toolbar: 'Insert Horizontal Line' // MISSING
7} );
diff --git a/sources/plugins/horizontalrule/lang/mn.js b/sources/plugins/horizontalrule/lang/mn.js
new file mode 100644
index 0000000..bd0ba0f
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/mn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'mn', {
6 toolbar: 'Хөндлөн зураас оруулах'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ms.js b/sources/plugins/horizontalrule/lang/ms.js
new file mode 100644
index 0000000..fa22359
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ms.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ms', {
6 toolbar: 'Masukkan Garisan Membujur'
7} );
diff --git a/sources/plugins/horizontalrule/lang/nb.js b/sources/plugins/horizontalrule/lang/nb.js
new file mode 100644
index 0000000..7edefa5
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/nb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'nb', {
6 toolbar: 'Sett inn horisontal linje'
7} );
diff --git a/sources/plugins/horizontalrule/lang/nl.js b/sources/plugins/horizontalrule/lang/nl.js
new file mode 100644
index 0000000..47efd3f
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/nl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'nl', {
6 toolbar: 'Horizontale lijn invoegen'
7} );
diff --git a/sources/plugins/horizontalrule/lang/no.js b/sources/plugins/horizontalrule/lang/no.js
new file mode 100644
index 0000000..009fc4b
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/no.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'no', {
6 toolbar: 'Sett inn horisontal linje'
7} );
diff --git a/sources/plugins/horizontalrule/lang/oc.js b/sources/plugins/horizontalrule/lang/oc.js
new file mode 100644
index 0000000..42d1797
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/oc.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'oc', {
6 toolbar: 'Inserir una linha orizontala'
7} );
diff --git a/sources/plugins/horizontalrule/lang/pl.js b/sources/plugins/horizontalrule/lang/pl.js
new file mode 100644
index 0000000..0604f4d
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/pl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'pl', {
6 toolbar: 'Wstaw poziomą linię'
7} );
diff --git a/sources/plugins/horizontalrule/lang/pt-br.js b/sources/plugins/horizontalrule/lang/pt-br.js
new file mode 100644
index 0000000..038616b
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/pt-br.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'pt-br', {
6 toolbar: 'Inserir Linha Horizontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/pt.js b/sources/plugins/horizontalrule/lang/pt.js
new file mode 100644
index 0000000..c8d710d
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/pt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'pt', {
6 toolbar: 'Inserir linha horizontal'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ro.js b/sources/plugins/horizontalrule/lang/ro.js
new file mode 100644
index 0000000..4b8f9b8
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ro.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ro', {
6 toolbar: 'Inserează linie orizontală'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ru.js b/sources/plugins/horizontalrule/lang/ru.js
new file mode 100644
index 0000000..5424765
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ru.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ru', {
6 toolbar: 'Вставить горизонтальную линию'
7} );
diff --git a/sources/plugins/horizontalrule/lang/si.js b/sources/plugins/horizontalrule/lang/si.js
new file mode 100644
index 0000000..b0bb9b1
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/si.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'si', {
6 toolbar: 'තිරස් රේඛාවක් ඇතුලත් කරන්න'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sk.js b/sources/plugins/horizontalrule/lang/sk.js
new file mode 100644
index 0000000..07bce6c
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sk', {
6 toolbar: 'Vložiť vodorovnú čiaru'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sl.js b/sources/plugins/horizontalrule/lang/sl.js
new file mode 100644
index 0000000..44e19ae
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sl', {
6 toolbar: 'Vstavi vodoravno črto'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sq.js b/sources/plugins/horizontalrule/lang/sq.js
new file mode 100644
index 0000000..9fa6a40
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sq.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sq', {
6 toolbar: 'Vendos Vijë Horizontale'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sr-latn.js b/sources/plugins/horizontalrule/lang/sr-latn.js
new file mode 100644
index 0000000..eb16b98
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sr-latn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sr-latn', {
6 toolbar: 'Unesi horizontalnu liniju'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sr.js b/sources/plugins/horizontalrule/lang/sr.js
new file mode 100644
index 0000000..a260b4a
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sr', {
6 toolbar: 'Унеси хоризонталну линију'
7} );
diff --git a/sources/plugins/horizontalrule/lang/sv.js b/sources/plugins/horizontalrule/lang/sv.js
new file mode 100644
index 0000000..bf6280f
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/sv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'sv', {
6 toolbar: 'Infoga horisontal linje'
7} );
diff --git a/sources/plugins/horizontalrule/lang/th.js b/sources/plugins/horizontalrule/lang/th.js
new file mode 100644
index 0000000..164f496
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/th.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'th', {
6 toolbar: 'แทรกเส้นคั่นบรรทัด'
7} );
diff --git a/sources/plugins/horizontalrule/lang/tr.js b/sources/plugins/horizontalrule/lang/tr.js
new file mode 100644
index 0000000..aeb6fb8
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/tr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'tr', {
6 toolbar: 'Yatay Satır Ekle'
7} );
diff --git a/sources/plugins/horizontalrule/lang/tt.js b/sources/plugins/horizontalrule/lang/tt.js
new file mode 100644
index 0000000..411166d
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/tt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'tt', {
6 toolbar: 'Ятма сызык өстәү'
7} );
diff --git a/sources/plugins/horizontalrule/lang/ug.js b/sources/plugins/horizontalrule/lang/ug.js
new file mode 100644
index 0000000..92f2434
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/ug.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'ug', {
6 toolbar: 'توغرا سىزىق قىستۇر'
7} );
diff --git a/sources/plugins/horizontalrule/lang/uk.js b/sources/plugins/horizontalrule/lang/uk.js
new file mode 100644
index 0000000..d84f428
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/uk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'uk', {
6 toolbar: 'Горизонтальна лінія'
7} );
diff --git a/sources/plugins/horizontalrule/lang/vi.js b/sources/plugins/horizontalrule/lang/vi.js
new file mode 100644
index 0000000..339eb06
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/vi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'vi', {
6 toolbar: 'Chèn đường phân cách ngang'
7} );
diff --git a/sources/plugins/horizontalrule/lang/zh-cn.js b/sources/plugins/horizontalrule/lang/zh-cn.js
new file mode 100644
index 0000000..2dfdb50
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/zh-cn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'zh-cn', {
6 toolbar: '插入水平线'
7} );
diff --git a/sources/plugins/horizontalrule/lang/zh.js b/sources/plugins/horizontalrule/lang/zh.js
new file mode 100644
index 0000000..b2e4272
--- /dev/null
+++ b/sources/plugins/horizontalrule/lang/zh.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'horizontalrule', 'zh', {
6 toolbar: '插入水平線'
7} );
diff --git a/sources/plugins/horizontalrule/plugin.js b/sources/plugins/horizontalrule/plugin.js
new file mode 100644
index 0000000..6e52c31
--- /dev/null
+++ b/sources/plugins/horizontalrule/plugin.js
@@ -0,0 +1,43 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Horizontal Rule plugin.
8 */
9
10( function() {
11 var horizontalruleCmd = {
12 canUndo: false, // The undo snapshot will be handled by 'insertElement'.
13 exec: function( editor ) {
14 var hr = editor.document.createElement( 'hr' );
15 editor.insertElement( hr );
16 },
17
18 allowedContent: 'hr',
19 requiredContent: 'hr'
20 };
21
22 var pluginName = 'horizontalrule';
23
24 // Register a plugin named "horizontalrule".
25 CKEDITOR.plugins.add( pluginName, {
26 // jscs:disable maximumLineLength
27 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
28 // jscs:enable maximumLineLength
29 icons: 'horizontalrule', // %REMOVE_LINE_CORE%
30 hidpi: true, // %REMOVE_LINE_CORE%
31 init: function( editor ) {
32 if ( editor.blockless )
33 return;
34
35 editor.addCommand( pluginName, horizontalruleCmd );
36 editor.ui.addButton && editor.ui.addButton( 'HorizontalRule', {
37 label: editor.lang.horizontalrule.toolbar,
38 command: pluginName,
39 toolbar: 'insert,40'
40 } );
41 }
42 } );
43} )();
diff --git a/sources/plugins/htmlwriter/plugin.js b/sources/plugins/htmlwriter/plugin.js
new file mode 100644
index 0000000..b6d2716
--- /dev/null
+++ b/sources/plugins/htmlwriter/plugin.js
@@ -0,0 +1,360 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'htmlwriter', {
7 init: function( editor ) {
8 var writer = new CKEDITOR.htmlWriter();
9
10 writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
11 writer.indentationChars = editor.config.dataIndentationChars || '\t';
12
13 // Overwrite default basicWriter initialized in hmtlDataProcessor constructor.
14 editor.dataProcessor.writer = writer;
15 }
16} );
17
18/**
19 * The class used to write HTML data.
20 *
21 * var writer = new CKEDITOR.htmlWriter();
22 * writer.openTag( 'p' );
23 * writer.attribute( 'class', 'MyClass' );
24 * writer.openTagClose( 'p' );
25 * writer.text( 'Hello' );
26 * writer.closeTag( 'p' );
27 * alert( writer.getHtml() ); // '<p class="MyClass">Hello</p>'
28 *
29 * @class
30 * @extends CKEDITOR.htmlParser.basicWriter
31 */
32CKEDITOR.htmlWriter = CKEDITOR.tools.createClass( {
33 base: CKEDITOR.htmlParser.basicWriter,
34
35 /**
36 * Creates an `htmlWriter` class instance.
37 *
38 * @constructor
39 */
40 $: function() {
41 // Call the base contructor.
42 this.base();
43
44 /**
45 * The characters to be used for each indentation step.
46 *
47 * // Use tab for indentation.
48 * editorInstance.dataProcessor.writer.indentationChars = '\t';
49 */
50 this.indentationChars = '\t';
51
52 /**
53 * The characters to be used to close "self-closing" elements, like `<br>` or `<img>`.
54 *
55 * // Use HTML4 notation for self-closing elements.
56 * editorInstance.dataProcessor.writer.selfClosingEnd = '>';
57 */
58 this.selfClosingEnd = ' />';
59
60 /**
61 * The characters to be used for line breaks.
62 *
63 * // Use CRLF for line breaks.
64 * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';
65 */
66 this.lineBreakChars = '\n';
67
68 this.sortAttributes = 1;
69
70 this._.indent = 0;
71 this._.indentation = '';
72 // Indicate preformatted block context status. (#5789)
73 this._.inPre = 0;
74 this._.rules = {};
75
76 var dtd = CKEDITOR.dtd;
77
78 for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) {
79 this.setRules( e, {
80 indent: !dtd[ e ][ '#' ],
81 breakBeforeOpen: 1,
82 breakBeforeClose: !dtd[ e ][ '#' ],
83 breakAfterClose: 1,
84 needsSpace: ( e in dtd.$block ) && !( e in { li: 1, dt: 1, dd: 1 } )
85 } );
86 }
87
88 this.setRules( 'br', { breakAfterOpen: 1 } );
89
90 this.setRules( 'title', {
91 indent: 0,
92 breakAfterOpen: 0
93 } );
94
95 this.setRules( 'style', {
96 indent: 0,
97 breakBeforeClose: 1
98 } );
99
100 this.setRules( 'pre', {
101 breakAfterOpen: 1, // Keep line break after the opening tag
102 indent: 0 // Disable indentation on <pre>.
103 } );
104 },
105
106 proto: {
107 /**
108 * Writes the tag opening part for an opener tag.
109 *
110 * // Writes '<p'.
111 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
112 *
113 * @param {String} tagName The element name for this tag.
114 * @param {Object} attributes The attributes defined for this tag. The
115 * attributes could be used to inspect the tag.
116 */
117 openTag: function( tagName ) {
118 var rules = this._.rules[ tagName ];
119
120 if ( this._.afterCloser && rules && rules.needsSpace && this._.needsSpace )
121 this._.output.push( '\n' );
122
123 if ( this._.indent )
124 this.indentation();
125 // Do not break if indenting.
126 else if ( rules && rules.breakBeforeOpen ) {
127 this.lineBreak();
128 this.indentation();
129 }
130
131 this._.output.push( '<', tagName );
132
133 this._.afterCloser = 0;
134 },
135
136 /**
137 * Writes the tag closing part for an opener tag.
138 *
139 * // Writes '>'.
140 * writer.openTagClose( 'p', false );
141 *
142 * // Writes ' />'.
143 * writer.openTagClose( 'br', true );
144 *
145 * @param {String} tagName The element name for this tag.
146 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
147 * like `<br>` or `<img>`.
148 */
149 openTagClose: function( tagName, isSelfClose ) {
150 var rules = this._.rules[ tagName ];
151
152 if ( isSelfClose ) {
153 this._.output.push( this.selfClosingEnd );
154
155 if ( rules && rules.breakAfterClose )
156 this._.needsSpace = rules.needsSpace;
157 } else {
158 this._.output.push( '>' );
159
160 if ( rules && rules.indent )
161 this._.indentation += this.indentationChars;
162 }
163
164 if ( rules && rules.breakAfterOpen )
165 this.lineBreak();
166 tagName == 'pre' && ( this._.inPre = 1 );
167 },
168
169 /**
170 * Writes an attribute. This function should be called after opening the
171 * tag with {@link #openTagClose}.
172 *
173 * // Writes ' class="MyClass"'.
174 * writer.attribute( 'class', 'MyClass' );
175 *
176 * @param {String} attName The attribute name.
177 * @param {String} attValue The attribute value.
178 */
179 attribute: function( attName, attValue ) {
180
181 if ( typeof attValue == 'string' ) {
182 this.forceSimpleAmpersand && ( attValue = attValue.replace( /&amp;/g, '&' ) );
183 // Browsers don't always escape special character in attribute values. (#4683, #4719).
184 attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );
185 }
186
187 this._.output.push( ' ', attName, '="', attValue, '"' );
188 },
189
190 /**
191 * Writes a closer tag.
192 *
193 * // Writes '</p>'.
194 * writer.closeTag( 'p' );
195 *
196 * @param {String} tagName The element name for this tag.
197 */
198 closeTag: function( tagName ) {
199 var rules = this._.rules[ tagName ];
200
201 if ( rules && rules.indent )
202 this._.indentation = this._.indentation.substr( this.indentationChars.length );
203
204 if ( this._.indent )
205 this.indentation();
206 // Do not break if indenting.
207 else if ( rules && rules.breakBeforeClose ) {
208 this.lineBreak();
209 this.indentation();
210 }
211
212 this._.output.push( '</', tagName, '>' );
213 tagName == 'pre' && ( this._.inPre = 0 );
214
215 if ( rules && rules.breakAfterClose ) {
216 this.lineBreak();
217 this._.needsSpace = rules.needsSpace;
218 }
219
220 this._.afterCloser = 1;
221 },
222
223 /**
224 * Writes text.
225 *
226 * // Writes 'Hello Word'.
227 * writer.text( 'Hello Word' );
228 *
229 * @param {String} text The text value
230 */
231 text: function( text ) {
232 if ( this._.indent ) {
233 this.indentation();
234 !this._.inPre && ( text = CKEDITOR.tools.ltrim( text ) );
235 }
236
237 this._.output.push( text );
238 },
239
240 /**
241 * Writes a comment.
242 *
243 * // Writes "<!-- My comment -->".
244 * writer.comment( ' My comment ' );
245 *
246 * @param {String} comment The comment text.
247 */
248 comment: function( comment ) {
249 if ( this._.indent )
250 this.indentation();
251
252 this._.output.push( '<!--', comment, '-->' );
253 },
254
255 /**
256 * Writes a line break. It uses the {@link #lineBreakChars} property for it.
257 *
258 * // Writes '\n' (e.g.).
259 * writer.lineBreak();
260 */
261 lineBreak: function() {
262 if ( !this._.inPre && this._.output.length > 0 )
263 this._.output.push( this.lineBreakChars );
264 this._.indent = 1;
265 },
266
267 /**
268 * Writes the current indentation character. It uses the {@link #indentationChars}
269 * property, repeating it for the current indentation steps.
270 *
271 * // Writes '\t' (e.g.).
272 * writer.indentation();
273 */
274 indentation: function() {
275 if ( !this._.inPre && this._.indentation )
276 this._.output.push( this._.indentation );
277 this._.indent = 0;
278 },
279
280 /**
281 * Empties the current output buffer. It also brings back the default
282 * values of the writer flags.
283 *
284 * writer.reset();
285 */
286 reset: function() {
287 this._.output = [];
288 this._.indent = 0;
289 this._.indentation = '';
290 this._.afterCloser = 0;
291 this._.inPre = 0;
292 this._.needsSpace = 0;
293 },
294
295 /**
296 * Sets formatting rules for a given element. Possible rules are:
297 *
298 * * `indent` &ndash; indent the element content.
299 * * `breakBeforeOpen` &ndash; break line before the opener tag for this element.
300 * * `breakAfterOpen` &ndash; break line after the opener tag for this element.
301 * * `breakBeforeClose` &ndash; break line before the closer tag for this element.
302 * * `breakAfterClose` &ndash; break line after the closer tag for this element.
303 *
304 * All rules default to `false`. Each function call overrides rules that are
305 * already present, leaving the undefined ones untouched.
306 *
307 * By default, all elements available in the {@link CKEDITOR.dtd#$block},
308 * {@link CKEDITOR.dtd#$listItem}, and {@link CKEDITOR.dtd#$tableContent}
309 * lists have all the above rules set to `true`. Additionaly, the `<br>`
310 * element has the `breakAfterOpen` rule set to `true`.
311 *
312 * // Break line before and after "img" tags.
313 * writer.setRules( 'img', {
314 * breakBeforeOpen: true
315 * breakAfterOpen: true
316 * } );
317 *
318 * // Reset the rules for the "h1" tag.
319 * writer.setRules( 'h1', {} );
320 *
321 * @param {String} tagName The name of the element for which the rules are set.
322 * @param {Object} rules An object containing the element rules.
323 */
324 setRules: function( tagName, rules ) {
325 var currentRules = this._.rules[ tagName ];
326
327 if ( currentRules )
328 CKEDITOR.tools.extend( currentRules, rules, true );
329 else
330 this._.rules[ tagName ] = rules;
331 }
332 }
333} );
334
335/**
336 * Whether to force using `'&'` instead of `'&amp;'` in element attributes
337 * values. It is not recommended to change this setting for compliance with the
338 * W3C XHTML 1.0 standards ([C.12, XHTML 1.0](http://www.w3.org/TR/xhtml1/#C_12)).
339 *
340 * // Use `'&'` instead of `'&amp;'`
341 * CKEDITOR.config.forceSimpleAmpersand = true;
342 *
343 * @cfg {Boolean} [forceSimpleAmpersand=false]
344 * @member CKEDITOR.config
345 */
346
347/**
348 * The characters to be used for indenting HTML output produced by the editor.
349 * Using characters different from `' '` (space) and `'\t'` (tab) is not recommended
350 * as it will mess the code.
351 *
352 * // No indentation.
353 * CKEDITOR.config.dataIndentationChars = '';
354 *
355 * // Use two spaces for indentation.
356 * CKEDITOR.config.dataIndentationChars = ' ';
357 *
358 * @cfg {String} [dataIndentationChars='\t']
359 * @member CKEDITOR.config
360 */
diff --git a/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.fla b/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.fla
new file mode 100644
index 0000000..27e68cc
--- /dev/null
+++ b/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.fla
Binary files differ
diff --git a/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.swf b/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.swf
new file mode 100644
index 0000000..dbe17b6
--- /dev/null
+++ b/sources/plugins/htmlwriter/samples/assets/outputforflash/outputforflash.swf
Binary files differ
diff --git a/sources/plugins/htmlwriter/samples/assets/outputforflash/swfobject.js b/sources/plugins/htmlwriter/samples/assets/outputforflash/swfobject.js
new file mode 100644
index 0000000..90cdcc9
--- /dev/null
+++ b/sources/plugins/htmlwriter/samples/assets/outputforflash/swfobject.js
@@ -0,0 +1,5 @@
1
2/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
3 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
4*/
5var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();
diff --git a/sources/plugins/htmlwriter/samples/outputforflash.html b/sources/plugins/htmlwriter/samples/outputforflash.html
new file mode 100644
index 0000000..f72616d
--- /dev/null
+++ b/sources/plugins/htmlwriter/samples/outputforflash.html
@@ -0,0 +1,283 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Output for Flash &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../samples/old/sample.js"></script>
12 <script src="assets/outputforflash/swfobject.js"></script>
13 <link href="../../../samples/old/sample.css" rel="stylesheet">
14 <meta name="ckeditor-sample-required-plugins" content="sourcearea">
15 <meta name="ckeditor-sample-name" content="Output for Flash">
16 <meta name="ckeditor-sample-group" content="Advanced Samples">
17 <meta name="ckeditor-sample-description" content="Configuring CKEditor to produce HTML code that can be used with Adobe Flash.">
18 <style>
19
20 .alert
21 {
22 background: #ffa84c;
23 padding: 10px 15px;
24 font-weight: bold;
25 display: block;
26 margin-bottom: 20px;
27 }
28
29 </style>
30</head>
31<body>
32 <h1 class="samples">
33 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Producing Flash Compliant HTML Output
34 </h1>
35 <div class="warning deprecated">
36 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
37 </div>
38 <div class="description">
39 <p>
40 This sample shows how to configure CKEditor to output
41 HTML code that can be used with
42 <a class="samples" href="http://www.adobe.com/livedocs/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&amp;file=00000922.html">
43 Adobe Flash</a>.
44 The code will contain a subset of standard HTML elements like <code>&lt;b&gt;</code>,
45 <code>&lt;i&gt;</code>, and <code>&lt;p&gt;</code> as well as HTML attributes.
46 </p>
47 <p>
48 To add a CKEditor instance outputting Flash compliant HTML code, load the editor using a standard
49 JavaScript call, and define CKEditor features to use HTML elements and attributes.
50 </p>
51 <p>
52 For details on how to create this setup check the source code of this sample page.
53 </p>
54 </div>
55 <p>
56 To see how it works, create some content in the editing area of CKEditor on the left
57 and send it to the Flash object on the right side of the page by using the
58 <strong>Send to Flash</strong> button.
59 </p>
60 <table style="width: 100%; border-spacing: 0; border-collapse:collapse;">
61 <tr>
62 <td style="width: 100%">
63 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;&lt;b&gt;&lt;font size=&quot;18&quot; style=&quot;font-size:18px;&quot;&gt;Flash and HTML&lt;/font&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;It is possible to have &lt;a href=&quot;http://ckeditor.com&quot;&gt;CKEditor&lt;/a&gt; creating content that will be later loaded inside &lt;b&gt;Flash&lt;/b&gt; objects and animations.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Flash has a few limitations when dealing with HTML:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;It has limited support on tags.&lt;/li&gt;&lt;li&gt;There is no margin between block elements, like paragraphs.&lt;/li&gt;&lt;/ul&gt;</textarea>
64 <script>
65
66 if ( document.location.protocol == 'file:' )
67 alert( 'Warning: This samples does not work when loaded from local filesystem' +
68 'due to security restrictions implemented in Flash.' +
69 '\n\nPlease load the sample from a web server instead.' );
70
71 var editor = CKEDITOR.replace( 'editor1', {
72 /*
73 * Ensure that htmlwriter plugin, which is required for this sample, is loaded.
74 */
75 extraPlugins: 'htmlwriter',
76
77 height: 290,
78 width: '100%',
79 toolbar: [
80 [ 'Source', '-', 'Bold', 'Italic', 'Underline', '-', 'BulletedList', '-', 'Link', 'Unlink' ],
81 [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ],
82 '/',
83 [ 'Font', 'FontSize' ],
84 [ 'TextColor', '-', 'About' ]
85 ],
86
87 /*
88 * Style sheet for the contents
89 */
90 contentsCss: 'body {color:#000; background-color#FFF; font-family: Arial; font-size:80%;} p, ol, ul {margin-top: 0px; margin-bottom: 0px;}',
91
92 /*
93 * Quirks doctype
94 */
95 docType: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">',
96
97 /*
98 * Core styles.
99 */
100 coreStyles_bold: { element: 'b' },
101 coreStyles_italic: { element: 'i' },
102 coreStyles_underline: { element: 'u' },
103
104 /*
105 * Font face.
106 */
107
108 // Define the way font elements will be applied to the document. The "font"
109 // element will be used.
110 font_style: {
111 element: 'font',
112 attributes: { 'face': '#(family)' }
113 },
114
115 /*
116 * Font sizes.
117 */
118
119 // The CSS part of the font sizes isn't used by Flash, it is there to get the
120 // font rendered correctly in CKEditor.
121 fontSize_sizes: '8px/8;9px/9;10px/10;11px/11;12px/12;14px/14;16px/16;18px/18;20px/20;22px/22;24px/24;26px/26;28px/28;36px/36;48px/48;72px/72',
122 fontSize_style: {
123 element: 'font',
124 attributes: { 'size': '#(size)' },
125 styles: { 'font-size': '#(size)px' }
126 } ,
127
128 /*
129 * Font colors.
130 */
131 colorButton_enableMore: true,
132
133 colorButton_foreStyle: {
134 element: 'font',
135 attributes: { 'color': '#(color)' }
136 },
137
138 colorButton_backStyle: {
139 element: 'font',
140 styles: { 'background-color': '#(color)' }
141 },
142
143 on: { 'instanceReady': configureFlashOutput }
144 });
145
146 /*
147 * Adjust the behavior of the dataProcessor to match the
148 * requirements of Flash
149 */
150 function configureFlashOutput( ev ) {
151 var editor = ev.editor,
152 dataProcessor = editor.dataProcessor,
153 htmlFilter = dataProcessor && dataProcessor.htmlFilter;
154
155 // Out self closing tags the HTML4 way, like <br>.
156 dataProcessor.writer.selfClosingEnd = '>';
157
158 // Make output formatting match Flash expectations
159 var dtd = CKEDITOR.dtd;
160 for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) {
161 dataProcessor.writer.setRules( e, {
162 indent: false,
163 breakBeforeOpen: false,
164 breakAfterOpen: false,
165 breakBeforeClose: false,
166 breakAfterClose: false
167 });
168 }
169 dataProcessor.writer.setRules( 'br', {
170 indent: false,
171 breakBeforeOpen: false,
172 breakAfterOpen: false,
173 breakBeforeClose: false,
174 breakAfterClose: false
175 });
176
177 // Output properties as attributes, not styles.
178 htmlFilter.addRules( {
179 elements: {
180 $: function( element ) {
181 var style, match, width, height, align;
182
183 // Output dimensions of images as width and height
184 if ( element.name == 'img' ) {
185 style = element.attributes.style;
186
187 if ( style ) {
188 // Get the width from the style.
189 match = ( /(?:^|\s)width\s*:\s*(\d+)px/i ).exec( style );
190 width = match && match[1];
191
192 // Get the height from the style.
193 match = ( /(?:^|\s)height\s*:\s*(\d+)px/i ).exec( style );
194 height = match && match[1];
195
196 if ( width ) {
197 element.attributes.style = element.attributes.style.replace( /(?:^|\s)width\s*:\s*(\d+)px;?/i , '' );
198 element.attributes.width = width;
199 }
200
201 if ( height ) {
202 element.attributes.style = element.attributes.style.replace( /(?:^|\s)height\s*:\s*(\d+)px;?/i , '' );
203 element.attributes.height = height;
204 }
205 }
206 }
207
208 // Output alignment of paragraphs using align
209 if ( element.name == 'p' ) {
210 style = element.attributes.style;
211
212 if ( style ) {
213 // Get the align from the style.
214 match = ( /(?:^|\s)text-align\s*:\s*(\w*);?/i ).exec( style );
215 align = match && match[1];
216
217 if ( align ) {
218 element.attributes.style = element.attributes.style.replace( /(?:^|\s)text-align\s*:\s*(\w*);?/i , '' );
219 element.attributes.align = align;
220 }
221 }
222 }
223
224 if ( element.attributes.style === '' )
225 delete element.attributes.style;
226
227 return element;
228 }
229 }
230 });
231 }
232
233 function sendToFlash() {
234 var html = CKEDITOR.instances.editor1.getData() ;
235
236 // Quick fix for link color.
237 html = html.replace( /<a /g, '<font color="#0000FF"><u><a ' )
238 html = html.replace( /<\/a>/g, '</a></u></font>' )
239
240 var flash = document.getElementById( 'ckFlashContainer' ) ;
241 flash.setData( html ) ;
242 }
243
244 CKEDITOR.domReady( function() {
245 if ( !swfobject.hasFlashPlayerVersion( '8' ) ) {
246 CKEDITOR.dom.element.createFromHtml( '<span class="alert">' +
247 'At least Adobe Flash Player 8 is required to run this sample. ' +
248 'You can download it from <a href="http://get.adobe.com/flashplayer">Adobe\'s website</a>.' +
249 '</span>' ).insertBefore( editor.element );
250 }
251
252 swfobject.embedSWF(
253 'assets/outputforflash/outputforflash.swf',
254 'ckFlashContainer',
255 '550',
256 '400',
257 '8',
258 { wmode: 'transparent' }
259 );
260 });
261
262 </script>
263 <p>
264 <input type="button" value="Send to Flash" onclick="sendToFlash();">
265 </p>
266 </td>
267 <td style="vertical-align: top; padding-left: 20px">
268 <div id="ckFlashContainer"></div>
269 </td>
270 </tr>
271 </table>
272 <div id="footer">
273 <hr>
274 <p>
275 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
276 </p>
277 <p id="copy">
278 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
279 Knabben. All rights reserved.
280 </p>
281 </div>
282</body>
283</html>
diff --git a/sources/plugins/htmlwriter/samples/outputhtml.html b/sources/plugins/htmlwriter/samples/outputhtml.html
new file mode 100644
index 0000000..a433025
--- /dev/null
+++ b/sources/plugins/htmlwriter/samples/outputhtml.html
@@ -0,0 +1,224 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>HTML Compliant Output &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../samples/old/sample.js"></script>
12 <link href="../../../samples/old/sample.css" rel="stylesheet">
13 <meta name="ckeditor-sample-required-plugins" content="sourcearea">
14 <meta name="ckeditor-sample-name" content="Output HTML">
15 <meta name="ckeditor-sample-group" content="Advanced Samples">
16 <meta name="ckeditor-sample-description" content="Configuring CKEditor to produce legacy HTML 4 code.">
17</head>
18<body>
19 <h1 class="samples">
20 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Producing HTML Compliant Output
21 </h1>
22 <div class="warning deprecated">
23 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
24 </div>
25 <div class="description">
26 <p>
27 This sample shows how to configure CKEditor to output valid
28 <a class="samples" href="http://www.w3.org/TR/html401/">HTML 4.01</a> code.
29 Traditional HTML elements like <code>&lt;b&gt;</code>,
30 <code>&lt;i&gt;</code>, and <code>&lt;font&gt;</code> are used in place of
31 <code>&lt;strong&gt;</code>, <code>&lt;em&gt;</code>, and CSS styles.
32 </p>
33 <p>
34 To add a CKEditor instance outputting legacy HTML 4.01 code, load the editor using a standard
35 JavaScript call, and define CKEditor features to use the HTML compliant elements and attributes.
36 </p>
37 <p>
38 A snippet of the configuration code can be seen below; check the source of this page for
39 full definition:
40 </p>
41<pre class="samples">
42CKEDITOR.replace( '<em>textarea_id</em>', {
43 coreStyles_bold: { element: 'b' },
44 coreStyles_italic: { element: 'i' },
45
46 fontSize_style: {
47 element: 'font',
48 attributes: { 'size': '#(size)' }
49 }
50
51 ...
52});</pre>
53 </div>
54 <form action="../../../samples/sample_posteddata.php" method="post">
55 <p>
56 <label for="editor1">
57 Editor 1:
58 </label>
59 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;b&gt;sample text&lt;/b&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
60 <script>
61
62 CKEDITOR.replace( 'editor1', {
63 /*
64 * Ensure that htmlwriter plugin, which is required for this sample, is loaded.
65 */
66 extraPlugins: 'htmlwriter',
67
68 /*
69 * Style sheet for the contents
70 */
71 contentsCss: 'body {color:#000; background-color#:FFF;}',
72
73 /*
74 * Simple HTML5 doctype
75 */
76 docType: '<!DOCTYPE HTML>',
77
78 /*
79 * Allowed content rules which beside limiting allowed HTML
80 * will also take care of transforming styles to attributes
81 * (currently only for img - see transformation rules defined below).
82 *
83 * Read more: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
84 */
85 allowedContent:
86 'h1 h2 h3 p pre[align]; ' +
87 'blockquote code kbd samp var del ins cite q b i u strike ul ol li hr table tbody tr td th caption; ' +
88 'img[!src,alt,align,width,height]; font[!face]; font[!family]; font[!color]; font[!size]; font{!background-color}; a[!href]; a[!name]',
89
90 /*
91 * Core styles.
92 */
93 coreStyles_bold: { element: 'b' },
94 coreStyles_italic: { element: 'i' },
95 coreStyles_underline: { element: 'u' },
96 coreStyles_strike: { element: 'strike' },
97
98 /*
99 * Font face.
100 */
101
102 // Define the way font elements will be applied to the document.
103 // The "font" element will be used.
104 font_style: {
105 element: 'font',
106 attributes: { 'face': '#(family)' }
107 },
108
109 /*
110 * Font sizes.
111 */
112 fontSize_sizes: 'xx-small/1;x-small/2;small/3;medium/4;large/5;x-large/6;xx-large/7',
113 fontSize_style: {
114 element: 'font',
115 attributes: { 'size': '#(size)' }
116 },
117
118 /*
119 * Font colors.
120 */
121
122 colorButton_foreStyle: {
123 element: 'font',
124 attributes: { 'color': '#(color)' }
125 },
126
127 colorButton_backStyle: {
128 element: 'font',
129 styles: { 'background-color': '#(color)' }
130 },
131
132 /*
133 * Styles combo.
134 */
135 stylesSet: [
136 { name: 'Computer Code', element: 'code' },
137 { name: 'Keyboard Phrase', element: 'kbd' },
138 { name: 'Sample Text', element: 'samp' },
139 { name: 'Variable', element: 'var' },
140 { name: 'Deleted Text', element: 'del' },
141 { name: 'Inserted Text', element: 'ins' },
142 { name: 'Cited Work', element: 'cite' },
143 { name: 'Inline Quotation', element: 'q' }
144 ],
145
146 on: {
147 pluginsLoaded: configureTransformations,
148 loaded: configureHtmlWriter
149 }
150 });
151
152 /*
153 * Add missing content transformations.
154 */
155 function configureTransformations( evt ) {
156 var editor = evt.editor;
157
158 editor.dataProcessor.htmlFilter.addRules( {
159 attributes: {
160 style: function( value, element ) {
161 // Return #RGB for background and border colors
162 return CKEDITOR.tools.convertRgbToHex( value );
163 }
164 }
165 } );
166
167 // Default automatic content transformations do not yet take care of
168 // align attributes on blocks, so we need to add our own transformation rules.
169 function alignToAttribute( element ) {
170 if ( element.styles[ 'text-align' ] ) {
171 element.attributes.align = element.styles[ 'text-align' ];
172 delete element.styles[ 'text-align' ];
173 }
174 }
175 editor.filter.addTransformations( [
176 [ { element: 'p', right: alignToAttribute } ],
177 [ { element: 'h1', right: alignToAttribute } ],
178 [ { element: 'h2', right: alignToAttribute } ],
179 [ { element: 'h3', right: alignToAttribute } ],
180 [ { element: 'pre', right: alignToAttribute } ]
181 ] );
182 }
183
184 /*
185 * Adjust the behavior of htmlWriter to make it output HTML like FCKeditor.
186 */
187 function configureHtmlWriter( evt ) {
188 var editor = evt.editor,
189 dataProcessor = editor.dataProcessor;
190
191 // Out self closing tags the HTML4 way, like <br>.
192 dataProcessor.writer.selfClosingEnd = '>';
193
194 // Make output formatting behave similar to FCKeditor.
195 var dtd = CKEDITOR.dtd;
196 for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) {
197 dataProcessor.writer.setRules( e, {
198 indent: true,
199 breakBeforeOpen: true,
200 breakAfterOpen: false,
201 breakBeforeClose: !dtd[ e ][ '#' ],
202 breakAfterClose: true
203 });
204 }
205 }
206
207 </script>
208 </p>
209 <p>
210 <input type="submit" value="Submit">
211 </p>
212 </form>
213 <div id="footer">
214 <hr>
215 <p>
216 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
217 </p>
218 <p id="copy">
219 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
220 Knabben. All rights reserved.
221 </p>
222 </div>
223</body>
224</html>
diff --git a/sources/plugins/iframe/dialogs/iframe.js b/sources/plugins/iframe/dialogs/iframe.js
new file mode 100644
index 0000000..bb39bdf
--- /dev/null
+++ b/sources/plugins/iframe/dialogs/iframe.js
@@ -0,0 +1,207 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 // Map 'true' and 'false' values to match W3C's specifications
8 // http://www.w3.org/TR/REC-html40/present/frames.html#h-16.5
9 var checkboxValues = {
10 scrolling: { 'true': 'yes', 'false': 'no' },
11 frameborder: { 'true': '1', 'false': '0' }
12 };
13
14 function loadValue( iframeNode ) {
15 var isCheckbox = this instanceof CKEDITOR.ui.dialog.checkbox;
16 if ( iframeNode.hasAttribute( this.id ) ) {
17 var value = iframeNode.getAttribute( this.id );
18 if ( isCheckbox )
19 this.setValue( checkboxValues[ this.id ][ 'true' ] == value.toLowerCase() );
20 else
21 this.setValue( value );
22 }
23 }
24
25 function commitValue( iframeNode ) {
26 var isRemove = this.getValue() === '',
27 isCheckbox = this instanceof CKEDITOR.ui.dialog.checkbox,
28 value = this.getValue();
29 if ( isRemove )
30 iframeNode.removeAttribute( this.att || this.id );
31 else if ( isCheckbox )
32 iframeNode.setAttribute( this.id, checkboxValues[ this.id ][ value ] );
33 else
34 iframeNode.setAttribute( this.att || this.id, value );
35 }
36
37 CKEDITOR.dialog.add( 'iframe', function( editor ) {
38 var iframeLang = editor.lang.iframe,
39 commonLang = editor.lang.common,
40 dialogadvtab = editor.plugins.dialogadvtab;
41 return {
42 title: iframeLang.title,
43 minWidth: 350,
44 minHeight: 260,
45 onShow: function() {
46 // Clear previously saved elements.
47 this.fakeImage = this.iframeNode = null;
48
49 var fakeImage = this.getSelectedElement();
50 if ( fakeImage && fakeImage.data( 'cke-real-element-type' ) && fakeImage.data( 'cke-real-element-type' ) == 'iframe' ) {
51 this.fakeImage = fakeImage;
52
53 var iframeNode = editor.restoreRealElement( fakeImage );
54 this.iframeNode = iframeNode;
55
56 this.setupContent( iframeNode );
57 }
58 },
59 onOk: function() {
60 var iframeNode;
61 if ( !this.fakeImage )
62 iframeNode = new CKEDITOR.dom.element( 'iframe' );
63 else
64 iframeNode = this.iframeNode;
65
66 // A subset of the specified attributes/styles
67 // should also be applied on the fake element to
68 // have better visual effect. (#5240)
69 var extraStyles = {},
70 extraAttributes = {};
71 this.commitContent( iframeNode, extraStyles, extraAttributes );
72
73 // Refresh the fake image.
74 var newFakeImage = editor.createFakeElement( iframeNode, 'cke_iframe', 'iframe', true );
75 newFakeImage.setAttributes( extraAttributes );
76 newFakeImage.setStyles( extraStyles );
77 if ( this.fakeImage ) {
78 newFakeImage.replace( this.fakeImage );
79 editor.getSelection().selectElement( newFakeImage );
80 } else {
81 editor.insertElement( newFakeImage );
82 }
83 },
84 contents: [ {
85 id: 'info',
86 label: commonLang.generalTab,
87 accessKey: 'I',
88 elements: [ {
89 type: 'vbox',
90 padding: 0,
91 children: [ {
92 id: 'src',
93 type: 'text',
94 label: commonLang.url,
95 required: true,
96 validate: CKEDITOR.dialog.validate.notEmpty( iframeLang.noUrl ),
97 setup: loadValue,
98 commit: commitValue
99 } ]
100 },
101 {
102 type: 'hbox',
103 children: [ {
104 id: 'width',
105 type: 'text',
106 requiredContent: 'iframe[width]',
107 style: 'width:100%',
108 labelLayout: 'vertical',
109 label: commonLang.width,
110 validate: CKEDITOR.dialog.validate.htmlLength( commonLang.invalidHtmlLength.replace( '%1', commonLang.width ) ),
111 setup: loadValue,
112 commit: commitValue
113 },
114 {
115 id: 'height',
116 type: 'text',
117 requiredContent: 'iframe[height]',
118 style: 'width:100%',
119 labelLayout: 'vertical',
120 label: commonLang.height,
121 validate: CKEDITOR.dialog.validate.htmlLength( commonLang.invalidHtmlLength.replace( '%1', commonLang.height ) ),
122 setup: loadValue,
123 commit: commitValue
124 },
125 {
126 id: 'align',
127 type: 'select',
128 requiredContent: 'iframe[align]',
129 'default': '',
130 items: [
131 [ commonLang.notSet, '' ],
132 [ commonLang.alignLeft, 'left' ],
133 [ commonLang.alignRight, 'right' ],
134 [ commonLang.alignTop, 'top' ],
135 [ commonLang.alignMiddle, 'middle' ],
136 [ commonLang.alignBottom, 'bottom' ]
137 ],
138 style: 'width:100%',
139 labelLayout: 'vertical',
140 label: commonLang.align,
141 setup: function( iframeNode, fakeImage ) {
142 loadValue.apply( this, arguments );
143 if ( fakeImage ) {
144 var fakeImageAlign = fakeImage.getAttribute( 'align' );
145 this.setValue( fakeImageAlign && fakeImageAlign.toLowerCase() || '' );
146 }
147 },
148 commit: function( iframeNode, extraStyles, extraAttributes ) {
149 commitValue.apply( this, arguments );
150 if ( this.getValue() )
151 extraAttributes.align = this.getValue();
152 }
153 } ]
154 },
155 {
156 type: 'hbox',
157 widths: [ '50%', '50%' ],
158 children: [ {
159 id: 'scrolling',
160 type: 'checkbox',
161 requiredContent: 'iframe[scrolling]',
162 label: iframeLang.scrolling,
163 setup: loadValue,
164 commit: commitValue
165 },
166 {
167 id: 'frameborder',
168 type: 'checkbox',
169 requiredContent: 'iframe[frameborder]',
170 label: iframeLang.border,
171 setup: loadValue,
172 commit: commitValue
173 } ]
174 },
175 {
176 type: 'hbox',
177 widths: [ '50%', '50%' ],
178 children: [ {
179 id: 'name',
180 type: 'text',
181 requiredContent: 'iframe[name]',
182 label: commonLang.name,
183 setup: loadValue,
184 commit: commitValue
185 },
186 {
187 id: 'title',
188 type: 'text',
189 requiredContent: 'iframe[title]',
190 label: commonLang.advisoryTitle,
191 setup: loadValue,
192 commit: commitValue
193 } ]
194 },
195 {
196 id: 'longdesc',
197 type: 'text',
198 requiredContent: 'iframe[longdesc]',
199 label: commonLang.longDescr,
200 setup: loadValue,
201 commit: commitValue
202 } ]
203 },
204 dialogadvtab && dialogadvtab.createAdvancedTab( editor, { id: 1, classes: 1, styles: 1 }, 'iframe' )
205 ] };
206 } );
207} )();
diff --git a/sources/plugins/iframe/icons/hidpi/iframe.png b/sources/plugins/iframe/icons/hidpi/iframe.png
new file mode 100644
index 0000000..d99d0f3
--- /dev/null
+++ b/sources/plugins/iframe/icons/hidpi/iframe.png
Binary files differ
diff --git a/sources/plugins/iframe/icons/iframe.png b/sources/plugins/iframe/icons/iframe.png
new file mode 100644
index 0000000..a2f5545
--- /dev/null
+++ b/sources/plugins/iframe/icons/iframe.png
Binary files differ
diff --git a/sources/plugins/iframe/images/placeholder.png b/sources/plugins/iframe/images/placeholder.png
new file mode 100644
index 0000000..4af0956
--- /dev/null
+++ b/sources/plugins/iframe/images/placeholder.png
Binary files differ
diff --git a/sources/plugins/iframe/lang/af.js b/sources/plugins/iframe/lang/af.js
new file mode 100644
index 0000000..9fa9387
--- /dev/null
+++ b/sources/plugins/iframe/lang/af.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'af', {
6 border: 'Wys rand van raam',
7 noUrl: 'Gee die iframe URL',
8 scrolling: 'Skuifbalke aan',
9 title: 'IFrame Eienskappe',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ar.js b/sources/plugins/iframe/lang/ar.js
new file mode 100644
index 0000000..6388d75
--- /dev/null
+++ b/sources/plugins/iframe/lang/ar.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ar', {
6 border: 'إظهار حدود الإطار',
7 noUrl: 'فضلا أكتب رابط الـ iframe',
8 scrolling: 'تفعيل أشرطة الإنتقال',
9 title: 'خصائص iframe',
10 toolbar: 'iframe'
11} );
diff --git a/sources/plugins/iframe/lang/az.js b/sources/plugins/iframe/lang/az.js
new file mode 100644
index 0000000..e4b72e6
--- /dev/null
+++ b/sources/plugins/iframe/lang/az.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'az', {
6 border: 'Çərçivə sərhədlərini göstər',
7 noUrl: 'Çərçivənin ünvanı daxil edin',
8 scrolling: 'Şürüşdürmələri əlavə et',
9 title: 'İFRAME elementinin alətləri',
10 toolbar: 'İFRAME'
11} );
diff --git a/sources/plugins/iframe/lang/bg.js b/sources/plugins/iframe/lang/bg.js
new file mode 100644
index 0000000..4adb22c
--- /dev/null
+++ b/sources/plugins/iframe/lang/bg.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'bg', {
6 border: 'Показва рамка на карето',
7 noUrl: 'Моля въведете URL за iFrame',
8 scrolling: 'Вкл. скролбаровете',
9 title: 'IFrame настройки',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/bn.js b/sources/plugins/iframe/lang/bn.js
new file mode 100644
index 0000000..3479c1f
--- /dev/null
+++ b/sources/plugins/iframe/lang/bn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'bn', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/bs.js b/sources/plugins/iframe/lang/bs.js
new file mode 100644
index 0000000..51ca8a7
--- /dev/null
+++ b/sources/plugins/iframe/lang/bs.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'bs', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/ca.js b/sources/plugins/iframe/lang/ca.js
new file mode 100644
index 0000000..a0d7d92
--- /dev/null
+++ b/sources/plugins/iframe/lang/ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ca', {
6 border: 'Mostra la vora del marc',
7 noUrl: 'Si us plau, introdueixi la URL de l\'iframe',
8 scrolling: 'Activa les barres de desplaçament',
9 title: 'Propietats de l\'IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/cs.js b/sources/plugins/iframe/lang/cs.js
new file mode 100644
index 0000000..388fa61
--- /dev/null
+++ b/sources/plugins/iframe/lang/cs.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'cs', {
6 border: 'Zobrazit okraj',
7 noUrl: 'Zadejte prosím URL obsahu pro IFrame',
8 scrolling: 'Zapnout posuvníky',
9 title: 'Vlastnosti IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/cy.js b/sources/plugins/iframe/lang/cy.js
new file mode 100644
index 0000000..a23b2ff
--- /dev/null
+++ b/sources/plugins/iframe/lang/cy.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'cy', {
6 border: 'Dangos ymyl y ffrâm',
7 noUrl: 'Rhowch URL yr iframe',
8 scrolling: 'Galluogi bariau sgrolio',
9 title: 'Priodweddau IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/da.js b/sources/plugins/iframe/lang/da.js
new file mode 100644
index 0000000..88b4fab
--- /dev/null
+++ b/sources/plugins/iframe/lang/da.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'da', {
6 border: 'Vis kant på rammen',
7 noUrl: 'Venligst indsæt URL på iframen',
8 scrolling: 'Aktiver scrollbars',
9 title: 'Iframe egenskaber',
10 toolbar: 'Iframe'
11} );
diff --git a/sources/plugins/iframe/lang/de-ch.js b/sources/plugins/iframe/lang/de-ch.js
new file mode 100644
index 0000000..2a56ccf
--- /dev/null
+++ b/sources/plugins/iframe/lang/de-ch.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'de-ch', {
6 border: 'Rahmen anzeigen',
7 noUrl: 'Bitte geben Sie die IFrame-URL an',
8 scrolling: 'Rollbalken anzeigen',
9 title: 'IFrame-Eigenschaften',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/de.js b/sources/plugins/iframe/lang/de.js
new file mode 100644
index 0000000..7988dfa
--- /dev/null
+++ b/sources/plugins/iframe/lang/de.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'de', {
6 border: 'Rahmen anzeigen',
7 noUrl: 'Bitte geben Sie die IFrame-URL an',
8 scrolling: 'Rollbalken anzeigen',
9 title: 'IFrame-Eigenschaften',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/el.js b/sources/plugins/iframe/lang/el.js
new file mode 100644
index 0000000..5abdfb0
--- /dev/null
+++ b/sources/plugins/iframe/lang/el.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'el', {
6 border: 'Προβολή περιγράμματος πλαισίου',
7 noUrl: 'Παρακαλούμε εισάγεται το URL του iframe',
8 scrolling: 'Ενεργοποίηση μπαρών κύλισης',
9 title: 'Ιδιότητες IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/en-au.js b/sources/plugins/iframe/lang/en-au.js
new file mode 100644
index 0000000..59048db
--- /dev/null
+++ b/sources/plugins/iframe/lang/en-au.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'en-au', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/en-ca.js b/sources/plugins/iframe/lang/en-ca.js
new file mode 100644
index 0000000..401ff49
--- /dev/null
+++ b/sources/plugins/iframe/lang/en-ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'en-ca', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/en-gb.js b/sources/plugins/iframe/lang/en-gb.js
new file mode 100644
index 0000000..78d4000
--- /dev/null
+++ b/sources/plugins/iframe/lang/en-gb.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'en-gb', {
6 border: 'Show frame border',
7 noUrl: 'Please type the iframe URL',
8 scrolling: 'Enable scrollbars',
9 title: 'IFrame Properties',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/en.js b/sources/plugins/iframe/lang/en.js
new file mode 100644
index 0000000..1e224b9
--- /dev/null
+++ b/sources/plugins/iframe/lang/en.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'en', {
6 border: 'Show frame border',
7 noUrl: 'Please type the iframe URL',
8 scrolling: 'Enable scrollbars',
9 title: 'IFrame Properties',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/eo.js b/sources/plugins/iframe/lang/eo.js
new file mode 100644
index 0000000..eba244d
--- /dev/null
+++ b/sources/plugins/iframe/lang/eo.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'eo', {
6 border: 'Montri borderon de kadro (frame)',
7 noUrl: 'Bonvolu entajpi la retadreson de la ligilo al la enlinia kadro (IFrame)',
8 scrolling: 'Ebligi rulumskalon',
9 title: 'Atributoj de la enlinia kadro (IFrame)',
10 toolbar: 'Enlinia kadro (IFrame)'
11} );
diff --git a/sources/plugins/iframe/lang/es.js b/sources/plugins/iframe/lang/es.js
new file mode 100644
index 0000000..1cf5c29
--- /dev/null
+++ b/sources/plugins/iframe/lang/es.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'es', {
6 border: 'Mostrar borde del marco',
7 noUrl: 'Por favor, escriba la dirección del iframe',
8 scrolling: 'Activar barras de desplazamiento',
9 title: 'Propiedades de iframe',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/et.js b/sources/plugins/iframe/lang/et.js
new file mode 100644
index 0000000..aac467d
--- /dev/null
+++ b/sources/plugins/iframe/lang/et.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'et', {
6 border: 'Raami äärise näitamine',
7 noUrl: 'Vali iframe URLi liik',
8 scrolling: 'Kerimisribade lubamine',
9 title: 'IFrame omadused',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/eu.js b/sources/plugins/iframe/lang/eu.js
new file mode 100644
index 0000000..1f77367
--- /dev/null
+++ b/sources/plugins/iframe/lang/eu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'eu', {
6 border: 'Erakutsi markoaren ertza',
7 noUrl: 'Idatzi iframe-aren URLa, mesedez.',
8 scrolling: 'Gaitu korritze-barrak',
9 title: 'IFrame-aren propietateak',
10 toolbar: 'IFrame-a'
11} );
diff --git a/sources/plugins/iframe/lang/fa.js b/sources/plugins/iframe/lang/fa.js
new file mode 100644
index 0000000..0c7a09f
--- /dev/null
+++ b/sources/plugins/iframe/lang/fa.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'fa', {
6 border: 'نمایش خطوط frame',
7 noUrl: 'لطفا مسیر URL iframe را درج کنید',
8 scrolling: 'نمایش خطکشها',
9 title: 'ویژگیهای IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/fi.js b/sources/plugins/iframe/lang/fi.js
new file mode 100644
index 0000000..0aa7f37
--- /dev/null
+++ b/sources/plugins/iframe/lang/fi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'fi', {
6 border: 'Näytä kehyksen reunat',
7 noUrl: 'Anna IFrame-kehykselle lähdeosoite (src)',
8 scrolling: 'Näytä vierityspalkit',
9 title: 'IFrame-kehyksen ominaisuudet',
10 toolbar: 'IFrame-kehys'
11} );
diff --git a/sources/plugins/iframe/lang/fo.js b/sources/plugins/iframe/lang/fo.js
new file mode 100644
index 0000000..05fdfe8
--- /dev/null
+++ b/sources/plugins/iframe/lang/fo.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'fo', {
6 border: 'Vís frame kant',
7 noUrl: 'Vinarliga skriva URL til iframe',
8 scrolling: 'Loyv scrollbars',
9 title: 'Møguleikar fyri IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/fr-ca.js b/sources/plugins/iframe/lang/fr-ca.js
new file mode 100644
index 0000000..cf7947e
--- /dev/null
+++ b/sources/plugins/iframe/lang/fr-ca.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'fr-ca', {
6 border: 'Afficher la bordure du cadre',
7 noUrl: 'Veuillez entre l\'URL du IFrame',
8 scrolling: 'Activer les barres de défilement',
9 title: 'Propriétés du IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/fr.js b/sources/plugins/iframe/lang/fr.js
new file mode 100644
index 0000000..34fc64e
--- /dev/null
+++ b/sources/plugins/iframe/lang/fr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'fr', {
6 border: 'Afficher la bordure du cadre',
7 noUrl: 'Veuillez entrer l\'URL du contenu du cadre',
8 scrolling: 'Activer les barres de défilement',
9 title: 'Propriétés du cadre de contenu incorporé',
10 toolbar: 'Cadre de contenu incorporé'
11} );
diff --git a/sources/plugins/iframe/lang/gl.js b/sources/plugins/iframe/lang/gl.js
new file mode 100644
index 0000000..449e28d
--- /dev/null
+++ b/sources/plugins/iframe/lang/gl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'gl', {
6 border: 'Amosar o bordo do marco',
7 noUrl: 'Escriba o enderezo do iframe',
8 scrolling: 'Activar as barras de desprazamento',
9 title: 'Propiedades do iFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/gu.js b/sources/plugins/iframe/lang/gu.js
new file mode 100644
index 0000000..91bb8bb
--- /dev/null
+++ b/sources/plugins/iframe/lang/gu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'gu', {
6 border: 'ફ્રેમ બોર્ડેર બતાવવી',
7 noUrl: 'iframe URL ટાઈપ્ કરો',
8 scrolling: 'સ્ક્રોલબાર ચાલુ કરવા',
9 title: 'IFrame વિકલ્પો',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/he.js b/sources/plugins/iframe/lang/he.js
new file mode 100644
index 0000000..87467be
--- /dev/null
+++ b/sources/plugins/iframe/lang/he.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'he', {
6 border: 'הראה מסגרת לחלון',
7 noUrl: 'יש להכניס כתובת לחלון.',
8 scrolling: 'אפשר פסי גלילה',
9 title: 'מאפייני חלון פנימי (iframe)',
10 toolbar: 'חלון פנימי (iframe)'
11} );
diff --git a/sources/plugins/iframe/lang/hi.js b/sources/plugins/iframe/lang/hi.js
new file mode 100644
index 0000000..96d30fb
--- /dev/null
+++ b/sources/plugins/iframe/lang/hi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'hi', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/hr.js b/sources/plugins/iframe/lang/hr.js
new file mode 100644
index 0000000..986e000
--- /dev/null
+++ b/sources/plugins/iframe/lang/hr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'hr', {
6 border: 'Prikaži okvir IFrame-a',
7 noUrl: 'Unesite URL iframe-a',
8 scrolling: 'Omogući trake za skrolanje',
9 title: 'IFrame svojstva',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/hu.js b/sources/plugins/iframe/lang/hu.js
new file mode 100644
index 0000000..096d311
--- /dev/null
+++ b/sources/plugins/iframe/lang/hu.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'hu', {
6 border: 'Legyen keret',
7 noUrl: 'Kérem írja be a iframe URL-t',
8 scrolling: 'Gördítősáv bekapcsolása',
9 title: 'IFrame Tulajdonságok',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/id.js b/sources/plugins/iframe/lang/id.js
new file mode 100644
index 0000000..c351eda
--- /dev/null
+++ b/sources/plugins/iframe/lang/id.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'id', {
6 border: 'Tampilkan Batas Bingkai',
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Aktifkan Scrollbar',
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/is.js b/sources/plugins/iframe/lang/is.js
new file mode 100644
index 0000000..bc7cf08
--- /dev/null
+++ b/sources/plugins/iframe/lang/is.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'is', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/it.js b/sources/plugins/iframe/lang/it.js
new file mode 100644
index 0000000..e020c27
--- /dev/null
+++ b/sources/plugins/iframe/lang/it.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'it', {
6 border: 'Mostra il bordo',
7 noUrl: 'Inserire l\'URL del campo IFrame',
8 scrolling: 'Abilita scrollbar',
9 title: 'Proprietà IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ja.js b/sources/plugins/iframe/lang/ja.js
new file mode 100644
index 0000000..b104ccd
--- /dev/null
+++ b/sources/plugins/iframe/lang/ja.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ja', {
6 border: 'フレームの枠を表示',
7 noUrl: 'iframeのURLを入力してください。',
8 scrolling: 'スクロールバーの表示を許可',
9 title: 'iFrameのプロパティ',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ka.js b/sources/plugins/iframe/lang/ka.js
new file mode 100644
index 0000000..7d98f68
--- /dev/null
+++ b/sources/plugins/iframe/lang/ka.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ka', {
6 border: 'ჩარჩოს გამოჩენა',
7 noUrl: 'აკრიფეთ iframe-ის URL',
8 scrolling: 'გადახვევის ზოლების დაშვება',
9 title: 'IFrame-ის პარამეტრები',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/km.js b/sources/plugins/iframe/lang/km.js
new file mode 100644
index 0000000..9331b23
--- /dev/null
+++ b/sources/plugins/iframe/lang/km.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'km', {
6 border: 'បង្ហាញ​បន្ទាត់​ស៊ុម',
7 noUrl: 'សូម​បញ្ចូល URL របស់ iframe',
8 scrolling: 'ប្រើ​របារ​រំកិល',
9 title: 'លក្ខណៈ​សម្បត្តិ IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ko.js b/sources/plugins/iframe/lang/ko.js
new file mode 100644
index 0000000..f5c16a0
--- /dev/null
+++ b/sources/plugins/iframe/lang/ko.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ko', {
6 border: '프레임 테두리 표시',
7 noUrl: '아이프레임 주소(URL)를 입력해주세요.',
8 scrolling: '스크롤바 사용',
9 title: '아이프레임 속성',
10 toolbar: '아이프레임'
11} );
diff --git a/sources/plugins/iframe/lang/ku.js b/sources/plugins/iframe/lang/ku.js
new file mode 100644
index 0000000..852c3b4
--- /dev/null
+++ b/sources/plugins/iframe/lang/ku.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ku', {
6 border: 'نیشاندانی لاکێشه بە چوواردەوری چووارچێوە',
7 noUrl: 'تکایه ناونیشانی بەستەر بنووسه بۆ چووارچێوه',
8 scrolling: 'چالاککردنی هاتووچۆپێکردن',
9 title: 'دیالۆگی چووارچێوه',
10 toolbar: 'چووارچێوه'
11} );
diff --git a/sources/plugins/iframe/lang/lt.js b/sources/plugins/iframe/lang/lt.js
new file mode 100644
index 0000000..c69817f
--- /dev/null
+++ b/sources/plugins/iframe/lang/lt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'lt', {
6 border: 'Rodyti rėmelį',
7 noUrl: 'Nurodykite iframe nuorodą',
8 scrolling: 'Įjungti slankiklius',
9 title: 'IFrame nustatymai',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/lv.js b/sources/plugins/iframe/lang/lv.js
new file mode 100644
index 0000000..50a6743
--- /dev/null
+++ b/sources/plugins/iframe/lang/lv.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'lv', {
6 border: 'Rādīt rāmi',
7 noUrl: 'Norādiet iframe adresi',
8 scrolling: 'Atļaut ritjoslas',
9 title: 'IFrame uzstādījumi',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/mk.js b/sources/plugins/iframe/lang/mk.js
new file mode 100644
index 0000000..d576e21
--- /dev/null
+++ b/sources/plugins/iframe/lang/mk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'mk', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/mn.js b/sources/plugins/iframe/lang/mn.js
new file mode 100644
index 0000000..dd9d927
--- /dev/null
+++ b/sources/plugins/iframe/lang/mn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'mn', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/ms.js b/sources/plugins/iframe/lang/ms.js
new file mode 100644
index 0000000..f0342bf
--- /dev/null
+++ b/sources/plugins/iframe/lang/ms.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ms', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/nb.js b/sources/plugins/iframe/lang/nb.js
new file mode 100644
index 0000000..c02990e
--- /dev/null
+++ b/sources/plugins/iframe/lang/nb.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'nb', {
6 border: 'Vis ramme rundt iframe',
7 noUrl: 'Vennligst skriv inn URL for iframe',
8 scrolling: 'Aktiver scrollefelt',
9 title: 'Egenskaper for IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/nl.js b/sources/plugins/iframe/lang/nl.js
new file mode 100644
index 0000000..555025d
--- /dev/null
+++ b/sources/plugins/iframe/lang/nl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'nl', {
6 border: 'Framerand tonen',
7 noUrl: 'Vul de IFrame URL in',
8 scrolling: 'Scrollbalken inschakelen',
9 title: 'IFrame-eigenschappen',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/no.js b/sources/plugins/iframe/lang/no.js
new file mode 100644
index 0000000..bb44fe5
--- /dev/null
+++ b/sources/plugins/iframe/lang/no.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'no', {
6 border: 'Viss ramme rundt iframe',
7 noUrl: 'Vennligst skriv inn URL for iframe',
8 scrolling: 'Aktiver scrollefelt',
9 title: 'Egenskaper for IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/oc.js b/sources/plugins/iframe/lang/oc.js
new file mode 100644
index 0000000..890a571
--- /dev/null
+++ b/sources/plugins/iframe/lang/oc.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'oc', {
6 border: 'Afichar la bordadura del quadre',
7 noUrl: 'Entratz l\'URL del contengut del quadre',
8 scrolling: 'Activar las barras de desfilament',
9 title: 'Proprietats del quadre de contengut incorporat',
10 toolbar: 'Quadre de contengut incorporat'
11} );
diff --git a/sources/plugins/iframe/lang/pl.js b/sources/plugins/iframe/lang/pl.js
new file mode 100644
index 0000000..6d05dd1
--- /dev/null
+++ b/sources/plugins/iframe/lang/pl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'pl', {
6 border: 'Pokaż obramowanie obiektu IFrame',
7 noUrl: 'Podaj adres URL elementu IFrame',
8 scrolling: 'Włącz paski przewijania',
9 title: 'Właściwości elementu IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/pt-br.js b/sources/plugins/iframe/lang/pt-br.js
new file mode 100644
index 0000000..58ec356
--- /dev/null
+++ b/sources/plugins/iframe/lang/pt-br.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'pt-br', {
6 border: 'Mostra borda do iframe',
7 noUrl: 'Insira a URL do iframe',
8 scrolling: 'Abilita scrollbars',
9 title: 'Propriedade do IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/pt.js b/sources/plugins/iframe/lang/pt.js
new file mode 100644
index 0000000..1b1cd9f
--- /dev/null
+++ b/sources/plugins/iframe/lang/pt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'pt', {
6 border: 'Mostrar a borda da Frame',
7 noUrl: 'Por favor, digite o URL da iframe',
8 scrolling: 'Ativar barras de rolamento',
9 title: 'Propriedades da IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ro.js b/sources/plugins/iframe/lang/ro.js
new file mode 100644
index 0000000..deeb0c4
--- /dev/null
+++ b/sources/plugins/iframe/lang/ro.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ro', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/ru.js b/sources/plugins/iframe/lang/ru.js
new file mode 100644
index 0000000..e352aa3
--- /dev/null
+++ b/sources/plugins/iframe/lang/ru.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ru', {
6 border: 'Показать границы фрейма',
7 noUrl: 'Пожалуйста, введите ссылку фрейма',
8 scrolling: 'Отображать полосы прокрутки',
9 title: 'Свойства iFrame',
10 toolbar: 'iFrame'
11} );
diff --git a/sources/plugins/iframe/lang/si.js b/sources/plugins/iframe/lang/si.js
new file mode 100644
index 0000000..d7660ef
--- /dev/null
+++ b/sources/plugins/iframe/lang/si.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'si', {
6 border: 'සැකිල්ලේ කඩයිම් ',
7 noUrl: 'කරුණාකර රුපයේ URL ලියන්න',
8 scrolling: 'සක්ක්‍රිය කරන්න',
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/sk.js b/sources/plugins/iframe/lang/sk.js
new file mode 100644
index 0000000..ac0b91d
--- /dev/null
+++ b/sources/plugins/iframe/lang/sk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sk', {
6 border: 'Zobraziť rám frame-u',
7 noUrl: 'Prosím, vložte URL iframe',
8 scrolling: 'Povoliť skrolovanie',
9 title: 'Vlastnosti IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/sl.js b/sources/plugins/iframe/lang/sl.js
new file mode 100644
index 0000000..2b0e375
--- /dev/null
+++ b/sources/plugins/iframe/lang/sl.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sl', {
6 border: 'Pokaži obrobo okvirja',
7 noUrl: 'Prosimo, vnesite iframe URL',
8 scrolling: 'Omogoči drsnike',
9 title: 'Lastnosti IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/sq.js b/sources/plugins/iframe/lang/sq.js
new file mode 100644
index 0000000..a274000
--- /dev/null
+++ b/sources/plugins/iframe/lang/sq.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sq', {
6 border: 'Shfaq kufirin e kornizës',
7 noUrl: 'Ju lutemi shkruani URL-në e iframe-it',
8 scrolling: 'Lejo shiritët zvarritës',
9 title: 'Karakteristikat e IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/sr-latn.js b/sources/plugins/iframe/lang/sr-latn.js
new file mode 100644
index 0000000..29685a9
--- /dev/null
+++ b/sources/plugins/iframe/lang/sr-latn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sr-latn', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/sr.js b/sources/plugins/iframe/lang/sr.js
new file mode 100644
index 0000000..acd9876
--- /dev/null
+++ b/sources/plugins/iframe/lang/sr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sr', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame' // MISSING
11} );
diff --git a/sources/plugins/iframe/lang/sv.js b/sources/plugins/iframe/lang/sv.js
new file mode 100644
index 0000000..fab04a5
--- /dev/null
+++ b/sources/plugins/iframe/lang/sv.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'sv', {
6 border: 'Visa ramkant',
7 noUrl: 'Skriv in URL för iFrame',
8 scrolling: 'Aktivera rullningslister',
9 title: 'iFrame-egenskaper',
10 toolbar: 'iFrame'
11} );
diff --git a/sources/plugins/iframe/lang/th.js b/sources/plugins/iframe/lang/th.js
new file mode 100644
index 0000000..57926b9
--- /dev/null
+++ b/sources/plugins/iframe/lang/th.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'th', {
6 border: 'Show frame border', // MISSING
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame Properties', // MISSING
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/tr.js b/sources/plugins/iframe/lang/tr.js
new file mode 100644
index 0000000..d828f65
--- /dev/null
+++ b/sources/plugins/iframe/lang/tr.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'tr', {
6 border: 'Çerceve sınırlarını göster',
7 noUrl: 'Lütfen IFrame köprü (URL) bağlantısını yazın',
8 scrolling: 'Kaydırma çubuklarını aktif et',
9 title: 'IFrame Özellikleri',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/tt.js b/sources/plugins/iframe/lang/tt.js
new file mode 100644
index 0000000..869f67b
--- /dev/null
+++ b/sources/plugins/iframe/lang/tt.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'tt', {
6 border: 'Frame чикләрен күрсәтү',
7 noUrl: 'Please type the iframe URL', // MISSING
8 scrolling: 'Enable scrollbars', // MISSING
9 title: 'IFrame үзлекләре',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/ug.js b/sources/plugins/iframe/lang/ug.js
new file mode 100644
index 0000000..b46f6da
--- /dev/null
+++ b/sources/plugins/iframe/lang/ug.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'ug', {
6 border: 'كاندۇك گىرۋەكلىرىنى كۆرسەت',
7 noUrl: 'كاندۇكنىڭ ئادرېسى(Url)نى كىرگۈزۈڭ',
8 scrolling: 'دومىلىما سۈرگۈچكە يول قوي',
9 title: 'IFrame خاسلىق',
10 toolbar: 'IFrame '
11} );
diff --git a/sources/plugins/iframe/lang/uk.js b/sources/plugins/iframe/lang/uk.js
new file mode 100644
index 0000000..3f91ef6
--- /dev/null
+++ b/sources/plugins/iframe/lang/uk.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'uk', {
6 border: 'Показати рамки фрейму',
7 noUrl: 'Будь ласка введіть URL посилання для IFrame',
8 scrolling: 'Увімкнути прокрутку',
9 title: 'Налаштування для IFrame',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/vi.js b/sources/plugins/iframe/lang/vi.js
new file mode 100644
index 0000000..be8ebfb
--- /dev/null
+++ b/sources/plugins/iframe/lang/vi.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'vi', {
6 border: 'Hiển thị viền khung',
7 noUrl: 'Vui lòng nhập địa chỉ iframe',
8 scrolling: 'Kích hoạt thanh cuộn',
9 title: 'Thuộc tính iframe',
10 toolbar: 'Iframe'
11} );
diff --git a/sources/plugins/iframe/lang/zh-cn.js b/sources/plugins/iframe/lang/zh-cn.js
new file mode 100644
index 0000000..a35bd8c
--- /dev/null
+++ b/sources/plugins/iframe/lang/zh-cn.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'zh-cn', {
6 border: '显示框架边框',
7 noUrl: '请输入框架的 URL',
8 scrolling: '允许滚动条',
9 title: 'IFrame 属性',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/lang/zh.js b/sources/plugins/iframe/lang/zh.js
new file mode 100644
index 0000000..4f7472a
--- /dev/null
+++ b/sources/plugins/iframe/lang/zh.js
@@ -0,0 +1,11 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'iframe', 'zh', {
6 border: '顯示框架框線',
7 noUrl: '請輸入 iframe URL',
8 scrolling: '啟用捲軸列',
9 title: 'IFrame 屬性',
10 toolbar: 'IFrame'
11} );
diff --git a/sources/plugins/iframe/plugin.js b/sources/plugins/iframe/plugin.js
new file mode 100644
index 0000000..52c816a
--- /dev/null
+++ b/sources/plugins/iframe/plugin.js
@@ -0,0 +1,85 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 CKEDITOR.plugins.add( 'iframe', {
8 requires: 'dialog,fakeobjects',
9 // jscs:disable maximumLineLength
10 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
11 // jscs:enable maximumLineLength
12 icons: 'iframe', // %REMOVE_LINE_CORE%
13 hidpi: true, // %REMOVE_LINE_CORE%
14 onLoad: function() {
15 CKEDITOR.addCss( 'img.cke_iframe' +
16 '{' +
17 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/placeholder.png' ) + ');' +
18 'background-position: center center;' +
19 'background-repeat: no-repeat;' +
20 'border: 1px solid #a9a9a9;' +
21 'width: 80px;' +
22 'height: 80px;' +
23 '}'
24 );
25 },
26 init: function( editor ) {
27 var pluginName = 'iframe',
28 lang = editor.lang.iframe,
29 allowed = 'iframe[align,longdesc,frameborder,height,name,scrolling,src,title,width]';
30
31 if ( editor.plugins.dialogadvtab )
32 allowed += ';iframe' + editor.plugins.dialogadvtab.allowedContent( { id: 1, classes: 1, styles: 1 } );
33
34 CKEDITOR.dialog.add( pluginName, this.path + 'dialogs/iframe.js' );
35 editor.addCommand( pluginName, new CKEDITOR.dialogCommand( pluginName, {
36 allowedContent: allowed,
37 requiredContent: 'iframe'
38 } ) );
39
40 editor.ui.addButton && editor.ui.addButton( 'Iframe', {
41 label: lang.toolbar,
42 command: pluginName,
43 toolbar: 'insert,80'
44 } );
45
46 editor.on( 'doubleclick', function( evt ) {
47 var element = evt.data.element;
48 if ( element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'iframe' )
49 evt.data.dialog = 'iframe';
50 } );
51
52 if ( editor.addMenuItems ) {
53 editor.addMenuItems( {
54 iframe: {
55 label: lang.title,
56 command: 'iframe',
57 group: 'image'
58 }
59 } );
60 }
61
62 // If the "contextmenu" plugin is loaded, register the listeners.
63 if ( editor.contextMenu ) {
64 editor.contextMenu.addListener( function( element ) {
65 if ( element && element.is( 'img' ) && element.data( 'cke-real-element-type' ) == 'iframe' )
66 return { iframe: CKEDITOR.TRISTATE_OFF };
67 } );
68 }
69 },
70 afterInit: function( editor ) {
71 var dataProcessor = editor.dataProcessor,
72 dataFilter = dataProcessor && dataProcessor.dataFilter;
73
74 if ( dataFilter ) {
75 dataFilter.addRules( {
76 elements: {
77 iframe: function( element ) {
78 return editor.createFakeParserElement( element, 'cke_iframe', 'iframe', true );
79 }
80 }
81 } );
82 }
83 }
84 } );
85} )();
diff --git a/sources/plugins/image/dialogs/image.js b/sources/plugins/image/dialogs/image.js
new file mode 100644
index 0000000..7d7537a
--- /dev/null
+++ b/sources/plugins/image/dialogs/image.js
@@ -0,0 +1,1254 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var imageDialog = function( editor, dialogType ) {
8 // Load image preview.
9 var IMAGE = 1,
10 LINK = 2,
11 PREVIEW = 4,
12 CLEANUP = 8,
13 regexGetSize = /^\s*(\d+)((px)|\%)?\s*$/i,
14 regexGetSizeOrEmpty = /(^\s*(\d+)((px)|\%)?\s*$)|^$/i,
15 pxLengthRegex = /^\d+px$/;
16
17 var onSizeChange = function() {
18 var value = this.getValue(),
19 // This = input element.
20 dialog = this.getDialog(),
21 aMatch = value.match( regexGetSize ); // Check value
22 if ( aMatch ) {
23 if ( aMatch[ 2 ] == '%' ) // % is allowed - > unlock ratio.
24 switchLockRatio( dialog, false ); // Unlock.
25 value = aMatch[ 1 ];
26 }
27
28 // Only if ratio is locked
29 if ( dialog.lockRatio ) {
30 var oImageOriginal = dialog.originalElement;
31 if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' ) {
32 if ( this.id == 'txtHeight' ) {
33 if ( value && value != '0' )
34 value = Math.round( oImageOriginal.$.width * ( value / oImageOriginal.$.height ) );
35 if ( !isNaN( value ) )
36 dialog.setValueOf( 'info', 'txtWidth', value );
37 }
38 // this.id = txtWidth.
39 else {
40 if ( value && value != '0' )
41 value = Math.round( oImageOriginal.$.height * ( value / oImageOriginal.$.width ) );
42 if ( !isNaN( value ) )
43 dialog.setValueOf( 'info', 'txtHeight', value );
44 }
45 }
46 }
47 updatePreview( dialog );
48 };
49
50 var updatePreview = function( dialog ) {
51 //Don't load before onShow.
52 if ( !dialog.originalElement || !dialog.preview )
53 return 1;
54
55 // Read attributes and update imagePreview;
56 dialog.commitContent( PREVIEW, dialog.preview );
57 return 0;
58 };
59
60 // Custom commit dialog logic, where we're intended to give inline style
61 // field (txtdlgGenStyle) higher priority to avoid overwriting styles contribute
62 // by other fields.
63 function commitContent() {
64 var args = arguments;
65 var inlineStyleField = this.getContentElement( 'advanced', 'txtdlgGenStyle' );
66 inlineStyleField && inlineStyleField.commit.apply( inlineStyleField, args );
67
68 this.foreach( function( widget ) {
69 if ( widget.commit && widget.id != 'txtdlgGenStyle' )
70 widget.commit.apply( widget, args );
71 } );
72 }
73
74 // Avoid recursions.
75 var incommit;
76
77 // Synchronous field values to other impacted fields is required, e.g. border
78 // size change should alter inline-style text as well.
79 function commitInternally( targetFields ) {
80 if ( incommit )
81 return;
82
83 incommit = 1;
84
85 var dialog = this.getDialog(),
86 element = dialog.imageElement;
87 if ( element ) {
88 // Commit this field and broadcast to target fields.
89 this.commit( IMAGE, element );
90
91 targetFields = [].concat( targetFields );
92 var length = targetFields.length,
93 field;
94 for ( var i = 0; i < length; i++ ) {
95 field = dialog.getContentElement.apply( dialog, targetFields[ i ].split( ':' ) );
96 // May cause recursion.
97 field && field.setup( IMAGE, element );
98 }
99 }
100
101 incommit = 0;
102 }
103
104 var switchLockRatio = function( dialog, value ) {
105 if ( !dialog.getContentElement( 'info', 'ratioLock' ) )
106 return null;
107
108 var oImageOriginal = dialog.originalElement;
109
110 // Dialog may already closed. (#5505)
111 if ( !oImageOriginal )
112 return null;
113
114 // Check image ratio and original image ratio, but respecting user's preference.
115 if ( value == 'check' ) {
116 if ( !dialog.userlockRatio && oImageOriginal.getCustomData( 'isReady' ) == 'true' ) {
117 var width = dialog.getValueOf( 'info', 'txtWidth' ),
118 height = dialog.getValueOf( 'info', 'txtHeight' ),
119 originalRatio = oImageOriginal.$.width * 1000 / oImageOriginal.$.height,
120 thisRatio = width * 1000 / height;
121 dialog.lockRatio = false; // Default: unlock ratio
122
123 if ( !width && !height )
124 dialog.lockRatio = true;
125 else if ( !isNaN( originalRatio ) && !isNaN( thisRatio ) ) {
126 if ( Math.round( originalRatio ) == Math.round( thisRatio ) )
127 dialog.lockRatio = true;
128 }
129 }
130 } else if ( value !== undefined )
131 dialog.lockRatio = value;
132 else {
133 dialog.userlockRatio = 1;
134 dialog.lockRatio = !dialog.lockRatio;
135 }
136
137 var ratioButton = CKEDITOR.document.getById( btnLockSizesId );
138 if ( dialog.lockRatio )
139 ratioButton.removeClass( 'cke_btn_unlocked' );
140 else
141 ratioButton.addClass( 'cke_btn_unlocked' );
142
143 ratioButton.setAttribute( 'aria-checked', dialog.lockRatio );
144
145 // Ratio button hc presentation - WHITE SQUARE / BLACK SQUARE
146 if ( CKEDITOR.env.hc ) {
147 var icon = ratioButton.getChild( 0 );
148 icon.setHtml( dialog.lockRatio ? CKEDITOR.env.ie ? '\u25A0' : '\u25A3' : CKEDITOR.env.ie ? '\u25A1' : '\u25A2' );
149 }
150
151 return dialog.lockRatio;
152 };
153
154 var resetSize = function( dialog, emptyValues ) {
155 var oImageOriginal = dialog.originalElement,
156 ready = oImageOriginal.getCustomData( 'isReady' ) == 'true';
157
158 if ( ready ) {
159 var widthField = dialog.getContentElement( 'info', 'txtWidth' ),
160 heightField = dialog.getContentElement( 'info', 'txtHeight' ),
161 widthValue, heightValue;
162
163 if ( emptyValues ) {
164 widthValue = 0;
165 heightValue = 0;
166 } else {
167 widthValue = oImageOriginal.$.width;
168 heightValue = oImageOriginal.$.height;
169 }
170
171 widthField && widthField.setValue( widthValue );
172 heightField && heightField.setValue( heightValue );
173 }
174 updatePreview( dialog );
175 };
176
177 var setupDimension = function( type, element ) {
178 if ( type != IMAGE )
179 return;
180
181 function checkDimension( size, defaultValue ) {
182 var aMatch = size.match( regexGetSize );
183 if ( aMatch ) {
184 // % is allowed.
185 if ( aMatch[ 2 ] == '%' ) {
186 aMatch[ 1 ] += '%';
187 switchLockRatio( dialog, false ); // Unlock ratio
188 }
189 return aMatch[ 1 ];
190 }
191 return defaultValue;
192 }
193
194 var dialog = this.getDialog(),
195 value = '',
196 dimension = this.id == 'txtWidth' ? 'width' : 'height',
197 size = element.getAttribute( dimension );
198
199 if ( size )
200 value = checkDimension( size, value );
201 value = checkDimension( element.getStyle( dimension ), value );
202
203 this.setValue( value );
204 };
205
206 var previewPreloader;
207
208 var onImgLoadEvent = function() {
209 // Image is ready.
210 var original = this.originalElement,
211 loader = CKEDITOR.document.getById( imagePreviewLoaderId );
212
213 original.setCustomData( 'isReady', 'true' );
214 original.removeListener( 'load', onImgLoadEvent );
215 original.removeListener( 'error', onImgLoadErrorEvent );
216 original.removeListener( 'abort', onImgLoadErrorEvent );
217
218 // Hide loader.
219 if ( loader )
220 loader.setStyle( 'display', 'none' );
221
222 // New image -> new dimensions
223 if ( !this.dontResetSize ) {
224 resetSize( this, editor.config.image_prefillDimensions === false );
225 }
226
227 if ( this.firstLoad ) {
228 CKEDITOR.tools.setTimeout( function() {
229 switchLockRatio( this, 'check' );
230 }, 0, this );
231 }
232
233 this.firstLoad = false;
234 this.dontResetSize = false;
235
236 // Possible fix for #12818.
237 updatePreview( this );
238 };
239
240 var onImgLoadErrorEvent = function() {
241 // Error. Image is not loaded.
242 var original = this.originalElement,
243 loader = CKEDITOR.document.getById( imagePreviewLoaderId );
244
245 original.removeListener( 'load', onImgLoadEvent );
246 original.removeListener( 'error', onImgLoadErrorEvent );
247 original.removeListener( 'abort', onImgLoadErrorEvent );
248
249 // Set Error image.
250 var noimage = CKEDITOR.getUrl( CKEDITOR.plugins.get( 'image' ).path + 'images/noimage.png' );
251
252 if ( this.preview )
253 this.preview.setAttribute( 'src', noimage );
254
255 // Hide loader.
256 if ( loader )
257 loader.setStyle( 'display', 'none' );
258
259 switchLockRatio( this, false ); // Unlock.
260 };
261
262 var numbering = function( id ) {
263 return CKEDITOR.tools.getNextId() + '_' + id;
264 },
265 btnLockSizesId = numbering( 'btnLockSizes' ),
266 btnResetSizeId = numbering( 'btnResetSize' ),
267 imagePreviewLoaderId = numbering( 'ImagePreviewLoader' ),
268 previewLinkId = numbering( 'previewLink' ),
269 previewImageId = numbering( 'previewImage' );
270
271 return {
272 title: editor.lang.image[ dialogType == 'image' ? 'title' : 'titleButton' ],
273 minWidth: ( CKEDITOR.skinName || editor.config.skin ) == 'moono-lisa' ? 500 : 420,
274 minHeight: 360,
275 onShow: function() {
276 this.imageElement = false;
277 this.linkElement = false;
278
279 // Default: create a new element.
280 this.imageEditMode = false;
281 this.linkEditMode = false;
282
283 this.lockRatio = true;
284 this.userlockRatio = 0;
285 this.dontResetSize = false;
286 this.firstLoad = true;
287 this.addLink = false;
288
289 var editor = this.getParentEditor(),
290 sel = editor.getSelection(),
291 element = sel && sel.getSelectedElement(),
292 link = element && editor.elementPath( element ).contains( 'a', 1 ),
293 loader = CKEDITOR.document.getById( imagePreviewLoaderId );
294
295 // Hide loader.
296 if ( loader )
297 loader.setStyle( 'display', 'none' );
298
299 // Create the preview before setup the dialog contents.
300 previewPreloader = new CKEDITOR.dom.element( 'img', editor.document );
301 this.preview = CKEDITOR.document.getById( previewImageId );
302
303 // Copy of the image
304 this.originalElement = editor.document.createElement( 'img' );
305 this.originalElement.setAttribute( 'alt', '' );
306 this.originalElement.setCustomData( 'isReady', 'false' );
307
308 if ( link ) {
309 this.linkElement = link;
310 this.linkEditMode = true;
311
312 // If there is an existing link, by default keep it (true).
313 // It will be removed if certain conditions are met and Link tab is enabled. (#13351)
314 this.addLink = true;
315
316 // Look for Image element.
317 var linkChildren = link.getChildren();
318 if ( linkChildren.count() == 1 ) {
319 var childTag = linkChildren.getItem( 0 );
320
321 if ( childTag.type == CKEDITOR.NODE_ELEMENT ) {
322 if ( childTag.is( 'img' ) || childTag.is( 'input' ) ) {
323 this.imageElement = linkChildren.getItem( 0 );
324 if ( this.imageElement.is( 'img' ) )
325 this.imageEditMode = 'img';
326 else if ( this.imageElement.is( 'input' ) )
327 this.imageEditMode = 'input';
328 }
329 }
330 }
331 // Fill out all fields.
332 if ( dialogType == 'image' )
333 this.setupContent( LINK, link );
334 }
335
336 // Edit given image element instead the one from selection.
337 if ( this.customImageElement ) {
338 this.imageEditMode = 'img';
339 this.imageElement = this.customImageElement;
340 delete this.customImageElement;
341 }
342 else if ( element && element.getName() == 'img' && !element.data( 'cke-realelement' ) ||
343 element && element.getName() == 'input' && element.getAttribute( 'type' ) == 'image' ) {
344 this.imageEditMode = element.getName();
345 this.imageElement = element;
346 }
347
348 if ( this.imageEditMode ) {
349 // Use the original element as a buffer from since we don't want
350 // temporary changes to be committed, e.g. if the dialog is canceled.
351 this.cleanImageElement = this.imageElement;
352 this.imageElement = this.cleanImageElement.clone( true, true );
353
354 // Fill out all fields.
355 this.setupContent( IMAGE, this.imageElement );
356 }
357
358 // Refresh LockRatio button
359 switchLockRatio( this, true );
360
361 // Dont show preview if no URL given.
362 if ( !CKEDITOR.tools.trim( this.getValueOf( 'info', 'txtUrl' ) ) ) {
363 this.preview.removeAttribute( 'src' );
364 this.preview.setStyle( 'display', 'none' );
365 }
366 },
367 onOk: function() {
368 // Edit existing Image.
369 if ( this.imageEditMode ) {
370 var imgTagName = this.imageEditMode;
371
372 // Image dialog and Input element.
373 if ( dialogType == 'image' && imgTagName == 'input' && confirm( editor.lang.image.button2Img ) ) { // jshint ignore:line
374 // Replace INPUT-> IMG
375 imgTagName = 'img';
376 this.imageElement = editor.document.createElement( 'img' );
377 this.imageElement.setAttribute( 'alt', '' );
378 editor.insertElement( this.imageElement );
379 }
380 // ImageButton dialog and Image element.
381 else if ( dialogType != 'image' && imgTagName == 'img' && confirm( editor.lang.image.img2Button ) ) { // jshint ignore:line
382 // Replace IMG -> INPUT
383 imgTagName = 'input';
384 this.imageElement = editor.document.createElement( 'input' );
385 this.imageElement.setAttributes( {
386 type: 'image',
387 alt: ''
388 } );
389 editor.insertElement( this.imageElement );
390 } else {
391 // Restore the original element before all commits.
392 this.imageElement = this.cleanImageElement;
393 delete this.cleanImageElement;
394 }
395 }
396 // Create a new image.
397 else {
398 // Image dialog -> create IMG element.
399 if ( dialogType == 'image' )
400 this.imageElement = editor.document.createElement( 'img' );
401 else {
402 this.imageElement = editor.document.createElement( 'input' );
403 this.imageElement.setAttribute( 'type', 'image' );
404 }
405 this.imageElement.setAttribute( 'alt', '' );
406 }
407
408 // Create a new link.
409 if ( !this.linkEditMode )
410 this.linkElement = editor.document.createElement( 'a' );
411
412 // Set attributes.
413 this.commitContent( IMAGE, this.imageElement );
414 this.commitContent( LINK, this.linkElement );
415
416 // Remove empty style attribute.
417 if ( !this.imageElement.getAttribute( 'style' ) )
418 this.imageElement.removeAttribute( 'style' );
419
420 // Insert a new Image.
421 if ( !this.imageEditMode ) {
422 if ( this.addLink ) {
423 if ( !this.linkEditMode ) {
424 // Insert a new link.
425 editor.insertElement( this.linkElement );
426 this.linkElement.append( this.imageElement, false );
427 } else {
428 // We already have a link in editor.
429 if ( this.linkElement.equals( editor.getSelection().getSelectedElement() ) ) {
430 // If the link is selected outside, replace it's content rather than the link itself. ([<a>foo</a>])
431 this.linkElement.setHtml( '' );
432 this.linkElement.append( this.imageElement, false );
433 } else {
434 // Only inside of the link is selected, so replace it with image. (<a>[foo]</a>, <a>[f]oo</a>)
435 editor.insertElement( this.imageElement );
436 }
437 }
438 } else {
439 editor.insertElement( this.imageElement );
440 }
441 }
442 // Image already exists.
443 else {
444 // Add a new link element.
445 if ( !this.linkEditMode && this.addLink ) {
446 editor.insertElement( this.linkElement );
447 this.imageElement.appendTo( this.linkElement );
448 }
449 // Remove Link, Image exists.
450 else if ( this.linkEditMode && !this.addLink ) {
451 editor.getSelection().selectElement( this.linkElement );
452 editor.insertElement( this.imageElement );
453 }
454 }
455 },
456 onLoad: function() {
457 if ( dialogType != 'image' )
458 this.hidePage( 'Link' ); //Hide Link tab.
459 var doc = this._.element.getDocument();
460
461 if ( this.getContentElement( 'info', 'ratioLock' ) ) {
462 this.addFocusable( doc.getById( btnResetSizeId ), 5 );
463 this.addFocusable( doc.getById( btnLockSizesId ), 5 );
464 }
465
466 this.commitContent = commitContent;
467 },
468 onHide: function() {
469 if ( this.preview )
470 this.commitContent( CLEANUP, this.preview );
471
472 if ( this.originalElement ) {
473 this.originalElement.removeListener( 'load', onImgLoadEvent );
474 this.originalElement.removeListener( 'error', onImgLoadErrorEvent );
475 this.originalElement.removeListener( 'abort', onImgLoadErrorEvent );
476 this.originalElement.remove();
477 this.originalElement = false; // Dialog is closed.
478 }
479
480 delete this.imageElement;
481 },
482 contents: [ {
483 id: 'info',
484 label: editor.lang.image.infoTab,
485 accessKey: 'I',
486 elements: [ {
487 type: 'vbox',
488 padding: 0,
489 children: [ {
490 type: 'hbox',
491 widths: [ '280px', '110px' ],
492 align: 'right',
493 className: 'cke_dialog_image_url',
494 children: [ {
495 id: 'txtUrl',
496 type: 'text',
497 label: editor.lang.common.url,
498 required: true,
499 onChange: function() {
500 var dialog = this.getDialog(),
501 newUrl = this.getValue();
502
503 // Update original image.
504 // Prevent from load before onShow.
505 if ( newUrl.length > 0 ) {
506 dialog = this.getDialog();
507 var original = dialog.originalElement;
508
509 if ( dialog.preview ) {
510 dialog.preview.removeStyle( 'display' );
511 }
512
513 original.setCustomData( 'isReady', 'false' );
514 // Show loader.
515 var loader = CKEDITOR.document.getById( imagePreviewLoaderId );
516 if ( loader )
517 loader.setStyle( 'display', '' );
518
519 original.on( 'load', onImgLoadEvent, dialog );
520 original.on( 'error', onImgLoadErrorEvent, dialog );
521 original.on( 'abort', onImgLoadErrorEvent, dialog );
522 original.setAttribute( 'src', newUrl );
523
524 if ( dialog.preview ) {
525 // Query the preloader to figure out the url impacted by based href.
526 previewPreloader.setAttribute( 'src', newUrl );
527 dialog.preview.setAttribute( 'src', previewPreloader.$.src );
528 updatePreview( dialog );
529 }
530 }
531 // Dont show preview if no URL given.
532 else if ( dialog.preview ) {
533 dialog.preview.removeAttribute( 'src' );
534 dialog.preview.setStyle( 'display', 'none' );
535 }
536 },
537 setup: function( type, element ) {
538 if ( type == IMAGE ) {
539 var url = element.data( 'cke-saved-src' ) || element.getAttribute( 'src' );
540 var field = this;
541
542 this.getDialog().dontResetSize = true;
543
544 field.setValue( url ); // And call this.onChange()
545 // Manually set the initial value.(#4191)
546 field.setInitValue();
547 }
548 },
549 commit: function( type, element ) {
550 if ( type == IMAGE && ( this.getValue() || this.isChanged() ) ) {
551 element.data( 'cke-saved-src', this.getValue() );
552 element.setAttribute( 'src', this.getValue() );
553 } else if ( type == CLEANUP ) {
554 element.setAttribute( 'src', '' ); // If removeAttribute doesn't work.
555 element.removeAttribute( 'src' );
556 }
557 },
558 validate: CKEDITOR.dialog.validate.notEmpty( editor.lang.image.urlMissing )
559 },
560 {
561 type: 'button',
562 id: 'browse',
563 // v-align with the 'txtUrl' field.
564 // TODO: We need something better than a fixed size here.
565 style: 'display:inline-block;margin-top:14px;',
566 align: 'center',
567 label: editor.lang.common.browseServer,
568 hidden: true,
569 filebrowser: 'info:txtUrl'
570 } ]
571 } ]
572 },
573 {
574 id: 'txtAlt',
575 type: 'text',
576 label: editor.lang.image.alt,
577 accessKey: 'T',
578 'default': '',
579 onChange: function() {
580 updatePreview( this.getDialog() );
581 },
582 setup: function( type, element ) {
583 if ( type == IMAGE )
584 this.setValue( element.getAttribute( 'alt' ) );
585 },
586 commit: function( type, element ) {
587 if ( type == IMAGE ) {
588 if ( this.getValue() || this.isChanged() )
589 element.setAttribute( 'alt', this.getValue() );
590 } else if ( type == PREVIEW )
591 element.setAttribute( 'alt', this.getValue() );
592 else if ( type == CLEANUP ) {
593 element.removeAttribute( 'alt' );
594 }
595
596 }
597 },
598 {
599 type: 'hbox',
600 children: [ {
601 id: 'basic',
602 type: 'vbox',
603 children: [ {
604 type: 'hbox',
605 requiredContent: 'img{width,height}',
606 widths: [ '50%', '50%' ],
607 children: [ {
608 type: 'vbox',
609 padding: 1,
610 children: [ {
611 type: 'text',
612 width: '45px',
613 id: 'txtWidth',
614 label: editor.lang.common.width,
615 onKeyUp: onSizeChange,
616 onChange: function() {
617 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
618 },
619 validate: function() {
620 var aMatch = this.getValue().match( regexGetSizeOrEmpty ),
621 isValid = !!( aMatch && parseInt( aMatch[ 1 ], 10 ) !== 0 );
622 if ( !isValid )
623 alert( editor.lang.common.invalidWidth ); // jshint ignore:line
624 return isValid;
625 },
626 setup: setupDimension,
627 commit: function( type, element ) {
628 var value = this.getValue();
629 if ( type == IMAGE ) {
630 if ( value && editor.activeFilter.check( 'img{width,height}' ) )
631 element.setStyle( 'width', CKEDITOR.tools.cssLength( value ) );
632 else
633 element.removeStyle( 'width' );
634
635 element.removeAttribute( 'width' );
636 } else if ( type == PREVIEW ) {
637 var aMatch = value.match( regexGetSize );
638 if ( !aMatch ) {
639 var oImageOriginal = this.getDialog().originalElement;
640 if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
641 element.setStyle( 'width', oImageOriginal.$.width + 'px' );
642 } else {
643 element.setStyle( 'width', CKEDITOR.tools.cssLength( value ) );
644 }
645 } else if ( type == CLEANUP ) {
646 element.removeAttribute( 'width' );
647 element.removeStyle( 'width' );
648 }
649 }
650 },
651 {
652 type: 'text',
653 id: 'txtHeight',
654 width: '45px',
655 label: editor.lang.common.height,
656 onKeyUp: onSizeChange,
657 onChange: function() {
658 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
659 },
660 validate: function() {
661 var aMatch = this.getValue().match( regexGetSizeOrEmpty ),
662 isValid = !!( aMatch && parseInt( aMatch[ 1 ], 10 ) !== 0 );
663 if ( !isValid )
664 alert( editor.lang.common.invalidHeight ); // jshint ignore:line
665 return isValid;
666 },
667 setup: setupDimension,
668 commit: function( type, element ) {
669 var value = this.getValue();
670 if ( type == IMAGE ) {
671 if ( value && editor.activeFilter.check( 'img{width,height}' ) )
672 element.setStyle( 'height', CKEDITOR.tools.cssLength( value ) );
673 else
674 element.removeStyle( 'height' );
675
676 element.removeAttribute( 'height' );
677 } else if ( type == PREVIEW ) {
678 var aMatch = value.match( regexGetSize );
679 if ( !aMatch ) {
680 var oImageOriginal = this.getDialog().originalElement;
681 if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
682 element.setStyle( 'height', oImageOriginal.$.height + 'px' );
683 } else {
684 element.setStyle( 'height', CKEDITOR.tools.cssLength( value ) );
685 }
686 } else if ( type == CLEANUP ) {
687 element.removeAttribute( 'height' );
688 element.removeStyle( 'height' );
689 }
690 }
691 } ]
692 },
693 {
694 id: 'ratioLock',
695 type: 'html',
696 className: 'cke_dialog_image_ratiolock',
697 style: 'margin-top:30px;width:40px;height:40px;',
698 onLoad: function() {
699 // Activate Reset button
700 var resetButton = CKEDITOR.document.getById( btnResetSizeId ),
701 ratioButton = CKEDITOR.document.getById( btnLockSizesId );
702 if ( resetButton ) {
703 resetButton.on( 'click', function( evt ) {
704 resetSize( this );
705 evt.data && evt.data.preventDefault();
706 }, this.getDialog() );
707 resetButton.on( 'mouseover', function() {
708 this.addClass( 'cke_btn_over' );
709 }, resetButton );
710 resetButton.on( 'mouseout', function() {
711 this.removeClass( 'cke_btn_over' );
712 }, resetButton );
713 }
714 // Activate (Un)LockRatio button
715 if ( ratioButton ) {
716 ratioButton.on( 'click', function( evt ) {
717 switchLockRatio( this );
718
719 var oImageOriginal = this.originalElement,
720 width = this.getValueOf( 'info', 'txtWidth' );
721
722 if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' && width ) {
723 var height = oImageOriginal.$.height / oImageOriginal.$.width * width;
724 if ( !isNaN( height ) ) {
725 this.setValueOf( 'info', 'txtHeight', Math.round( height ) );
726 updatePreview( this );
727 }
728 }
729 evt.data && evt.data.preventDefault();
730 }, this.getDialog() );
731 ratioButton.on( 'mouseover', function() {
732 this.addClass( 'cke_btn_over' );
733 }, ratioButton );
734 ratioButton.on( 'mouseout', function() {
735 this.removeClass( 'cke_btn_over' );
736 }, ratioButton );
737 }
738 },
739 html: '<div>' +
740 '<a href="javascript:void(0)" tabindex="-1" title="' + editor.lang.image.lockRatio +
741 '" class="cke_btn_locked" id="' + btnLockSizesId + '" role="checkbox"><span class="cke_icon"></span><span class="cke_label">' + editor.lang.image.lockRatio + '</span></a>' +
742 '<a href="javascript:void(0)" tabindex="-1" title="' + editor.lang.image.resetSize +
743 '" class="cke_btn_reset" id="' + btnResetSizeId + '" role="button"><span class="cke_label">' + editor.lang.image.resetSize + '</span></a>' +
744 '</div>'
745 } ]
746 },
747 {
748 type: 'vbox',
749 padding: 1,
750 children: [ {
751 type: 'text',
752 id: 'txtBorder',
753 requiredContent: 'img{border-width}',
754 width: '60px',
755 label: editor.lang.image.border,
756 'default': '',
757 onKeyUp: function() {
758 updatePreview( this.getDialog() );
759 },
760 onChange: function() {
761 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
762 },
763 validate: CKEDITOR.dialog.validate.integer( editor.lang.image.validateBorder ),
764 setup: function( type, element ) {
765 if ( type == IMAGE ) {
766 var value,
767 borderStyle = element.getStyle( 'border-width' );
768 borderStyle = borderStyle && borderStyle.match( /^(\d+px)(?: \1 \1 \1)?$/ );
769 value = borderStyle && parseInt( borderStyle[ 1 ], 10 );
770 isNaN( parseInt( value, 10 ) ) && ( value = element.getAttribute( 'border' ) );
771 this.setValue( value );
772 }
773 },
774 commit: function( type, element ) {
775 var value = parseInt( this.getValue(), 10 );
776 if ( type == IMAGE || type == PREVIEW ) {
777 if ( !isNaN( value ) ) {
778 element.setStyle( 'border-width', CKEDITOR.tools.cssLength( value ) );
779 element.setStyle( 'border-style', 'solid' );
780 } else if ( !value && this.isChanged() ) {
781 element.removeStyle( 'border' );
782 }
783
784 if ( type == IMAGE )
785 element.removeAttribute( 'border' );
786 } else if ( type == CLEANUP ) {
787 element.removeAttribute( 'border' );
788 element.removeStyle( 'border-width' );
789 element.removeStyle( 'border-style' );
790 element.removeStyle( 'border-color' );
791 }
792 }
793 },
794 {
795 type: 'text',
796 id: 'txtHSpace',
797 requiredContent: 'img{margin-left,margin-right}',
798 width: '60px',
799 label: editor.lang.image.hSpace,
800 'default': '',
801 onKeyUp: function() {
802 updatePreview( this.getDialog() );
803 },
804 onChange: function() {
805 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
806 },
807 validate: CKEDITOR.dialog.validate.integer( editor.lang.image.validateHSpace ),
808 setup: function( type, element ) {
809 if ( type == IMAGE ) {
810 var value, marginLeftPx, marginRightPx,
811 marginLeftStyle = element.getStyle( 'margin-left' ),
812 marginRightStyle = element.getStyle( 'margin-right' );
813
814 marginLeftStyle = marginLeftStyle && marginLeftStyle.match( pxLengthRegex );
815 marginRightStyle = marginRightStyle && marginRightStyle.match( pxLengthRegex );
816 marginLeftPx = parseInt( marginLeftStyle, 10 );
817 marginRightPx = parseInt( marginRightStyle, 10 );
818
819 value = ( marginLeftPx == marginRightPx ) && marginLeftPx;
820 isNaN( parseInt( value, 10 ) ) && ( value = element.getAttribute( 'hspace' ) );
821
822 this.setValue( value );
823 }
824 },
825 commit: function( type, element ) {
826 var value = parseInt( this.getValue(), 10 );
827 if ( type == IMAGE || type == PREVIEW ) {
828 if ( !isNaN( value ) ) {
829 element.setStyle( 'margin-left', CKEDITOR.tools.cssLength( value ) );
830 element.setStyle( 'margin-right', CKEDITOR.tools.cssLength( value ) );
831 } else if ( !value && this.isChanged() ) {
832 element.removeStyle( 'margin-left' );
833 element.removeStyle( 'margin-right' );
834 }
835
836 if ( type == IMAGE )
837 element.removeAttribute( 'hspace' );
838 } else if ( type == CLEANUP ) {
839 element.removeAttribute( 'hspace' );
840 element.removeStyle( 'margin-left' );
841 element.removeStyle( 'margin-right' );
842 }
843 }
844 },
845 {
846 type: 'text',
847 id: 'txtVSpace',
848 requiredContent: 'img{margin-top,margin-bottom}',
849 width: '60px',
850 label: editor.lang.image.vSpace,
851 'default': '',
852 onKeyUp: function() {
853 updatePreview( this.getDialog() );
854 },
855 onChange: function() {
856 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
857 },
858 validate: CKEDITOR.dialog.validate.integer( editor.lang.image.validateVSpace ),
859 setup: function( type, element ) {
860 if ( type == IMAGE ) {
861 var value, marginTopPx, marginBottomPx,
862 marginTopStyle = element.getStyle( 'margin-top' ),
863 marginBottomStyle = element.getStyle( 'margin-bottom' );
864
865 marginTopStyle = marginTopStyle && marginTopStyle.match( pxLengthRegex );
866 marginBottomStyle = marginBottomStyle && marginBottomStyle.match( pxLengthRegex );
867 marginTopPx = parseInt( marginTopStyle, 10 );
868 marginBottomPx = parseInt( marginBottomStyle, 10 );
869
870 value = ( marginTopPx == marginBottomPx ) && marginTopPx;
871 isNaN( parseInt( value, 10 ) ) && ( value = element.getAttribute( 'vspace' ) );
872 this.setValue( value );
873 }
874 },
875 commit: function( type, element ) {
876 var value = parseInt( this.getValue(), 10 );
877 if ( type == IMAGE || type == PREVIEW ) {
878 if ( !isNaN( value ) ) {
879 element.setStyle( 'margin-top', CKEDITOR.tools.cssLength( value ) );
880 element.setStyle( 'margin-bottom', CKEDITOR.tools.cssLength( value ) );
881 } else if ( !value && this.isChanged() ) {
882 element.removeStyle( 'margin-top' );
883 element.removeStyle( 'margin-bottom' );
884 }
885
886 if ( type == IMAGE )
887 element.removeAttribute( 'vspace' );
888 } else if ( type == CLEANUP ) {
889 element.removeAttribute( 'vspace' );
890 element.removeStyle( 'margin-top' );
891 element.removeStyle( 'margin-bottom' );
892 }
893 }
894 },
895 {
896 id: 'cmbAlign',
897 requiredContent: 'img{float}',
898 type: 'select',
899 widths: [ '35%', '65%' ],
900 style: 'width:90px',
901 label: editor.lang.common.align,
902 'default': '',
903 items: [
904 [ editor.lang.common.notSet, '' ],
905 [ editor.lang.common.alignLeft, 'left' ],
906 [ editor.lang.common.alignRight, 'right' ]
907 // Backward compatible with v2 on setup when specified as attribute value,
908 // while these values are no more available as select options.
909 // [ editor.lang.image.alignAbsBottom , 'absBottom'],
910 // [ editor.lang.image.alignAbsMiddle , 'absMiddle'],
911 // [ editor.lang.image.alignBaseline , 'baseline'],
912 // [ editor.lang.image.alignTextTop , 'text-top'],
913 // [ editor.lang.image.alignBottom , 'bottom'],
914 // [ editor.lang.image.alignMiddle , 'middle'],
915 // [ editor.lang.image.alignTop , 'top']
916 ],
917 onChange: function() {
918 updatePreview( this.getDialog() );
919 commitInternally.call( this, 'advanced:txtdlgGenStyle' );
920 },
921 setup: function( type, element ) {
922 if ( type == IMAGE ) {
923 var value = element.getStyle( 'float' );
924 switch ( value ) {
925 // Ignore those unrelated values.
926 case 'inherit':
927 case 'none':
928 value = '';
929 }
930
931 !value && ( value = ( element.getAttribute( 'align' ) || '' ).toLowerCase() );
932 this.setValue( value );
933 }
934 },
935 commit: function( type, element ) {
936 var value = this.getValue();
937 if ( type == IMAGE || type == PREVIEW ) {
938 if ( value )
939 element.setStyle( 'float', value );
940 else
941 element.removeStyle( 'float' );
942
943 if ( type == IMAGE ) {
944 value = ( element.getAttribute( 'align' ) || '' ).toLowerCase();
945 switch ( value ) {
946 // we should remove it only if it matches "left" or "right",
947 // otherwise leave it intact.
948 case 'left':
949 case 'right':
950 element.removeAttribute( 'align' );
951 }
952 }
953 } else if ( type == CLEANUP ) {
954 element.removeStyle( 'float' );
955 }
956 }
957 } ]
958 } ]
959 },
960 {
961 type: 'vbox',
962 height: '250px',
963 children: [ {
964 type: 'html',
965 id: 'htmlPreview',
966 style: 'width:95%;',
967 html: '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.common.preview ) + '<br>' +
968 '<div id="' + imagePreviewLoaderId + '" class="ImagePreviewLoader" style="display:none"><div class="loading">&nbsp;</div></div>' +
969 '<div class="ImagePreviewBox"><table><tr><td>' +
970 '<a href="javascript:void(0)" target="_blank" onclick="return false;" id="' + previewLinkId + '">' +
971 '<img id="' + previewImageId + '" alt="" /></a>' +
972 // jscs:disable maximumLineLength
973 ( editor.config.image_previewText || 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ' +
974 'Maecenas feugiat consequat diam. Maecenas metus. Vivamus diam purus, cursus a, commodo non, facilisis vitae, ' +
975 'nulla. Aenean dictum lacinia tortor. Nunc iaculis, nibh non iaculis aliquam, orci felis euismod neque, sed ornare massa mauris sed velit. Nulla pretium mi et risus. Fusce mi pede, tempor id, cursus ac, ullamcorper nec, enim. Sed tortor. Curabitur molestie. Duis velit augue, condimentum at, ultrices a, luctus ut, orci. Donec pellentesque egestas eros. Integer cursus, augue in cursus faucibus, eros pede bibendum sem, in tempus tellus justo quis ligula. Etiam eget tortor. Vestibulum rutrum, est ut placerat elementum, lectus nisl aliquam velit, tempor aliquam eros nunc nonummy metus. In eros metus, gravida a, gravida sed, lobortis id, turpis. Ut ultrices, ipsum at venenatis fringilla, sem nulla lacinia tellus, eget aliquet turpis mauris non enim. Nam turpis. Suspendisse lacinia. Curabitur ac tortor ut ipsum egestas elementum. Nunc imperdiet gravida mauris.' ) +
976 // jscs:enable maximumLineLength
977 '</td></tr></table></div></div>'
978 } ]
979 } ]
980 } ]
981 },
982 {
983 id: 'Link',
984 requiredContent: 'a[href]',
985 label: editor.lang.image.linkTab,
986 padding: 0,
987 elements: [ {
988 id: 'txtUrl',
989 type: 'text',
990 label: editor.lang.common.url,
991 style: 'width: 100%',
992 'default': '',
993 setup: function( type, element ) {
994 if ( type == LINK ) {
995 var href = element.data( 'cke-saved-href' );
996 if ( !href )
997 href = element.getAttribute( 'href' );
998 this.setValue( href );
999 }
1000 },
1001 commit: function( type, element ) {
1002 if ( type == LINK ) {
1003 if ( this.getValue() || this.isChanged() ) {
1004 var url = this.getValue();
1005 element.data( 'cke-saved-href', url );
1006 element.setAttribute( 'href', url );
1007
1008 if ( this.getValue() || !editor.config.image_removeLinkByEmptyURL )
1009 this.getDialog().addLink = true;
1010 else
1011 this.getDialog().addLink = false;
1012 }
1013 }
1014 }
1015 },
1016 {
1017 type: 'button',
1018 id: 'browse',
1019 className: 'cke_dialog_image_browse',
1020 filebrowser: {
1021 action: 'Browse',
1022 target: 'Link:txtUrl',
1023 url: editor.config.filebrowserImageBrowseLinkUrl
1024 },
1025 style: 'float:right',
1026 hidden: true,
1027 label: editor.lang.common.browseServer
1028 },
1029 {
1030 id: 'cmbTarget',
1031 type: 'select',
1032 requiredContent: 'a[target]',
1033 label: editor.lang.common.target,
1034 'default': '',
1035 items: [
1036 [ editor.lang.common.notSet, '' ],
1037 [ editor.lang.common.targetNew, '_blank' ],
1038 [ editor.lang.common.targetTop, '_top' ],
1039 [ editor.lang.common.targetSelf, '_self' ],
1040 [ editor.lang.common.targetParent, '_parent' ]
1041 ],
1042 setup: function( type, element ) {
1043 if ( type == LINK )
1044 this.setValue( element.getAttribute( 'target' ) || '' );
1045 },
1046 commit: function( type, element ) {
1047 if ( type == LINK ) {
1048 if ( this.getValue() || this.isChanged() )
1049 element.setAttribute( 'target', this.getValue() );
1050 }
1051 }
1052 } ]
1053 },
1054 {
1055 id: 'Upload',
1056 hidden: true,
1057 filebrowser: 'uploadButton',
1058 label: editor.lang.image.upload,
1059 elements: [ {
1060 type: 'file',
1061 id: 'upload',
1062 label: editor.lang.image.btnUpload,
1063 style: 'height:40px',
1064 size: 38
1065 },
1066 {
1067 type: 'fileButton',
1068 id: 'uploadButton',
1069 filebrowser: 'info:txtUrl',
1070 label: editor.lang.image.btnUpload,
1071 'for': [ 'Upload', 'upload' ]
1072 } ]
1073 },
1074 {
1075 id: 'advanced',
1076 label: editor.lang.common.advancedTab,
1077 elements: [ {
1078 type: 'hbox',
1079 widths: [ '50%', '25%', '25%' ],
1080 children: [ {
1081 type: 'text',
1082 id: 'linkId',
1083 requiredContent: 'img[id]',
1084 label: editor.lang.common.id,
1085 setup: function( type, element ) {
1086 if ( type == IMAGE )
1087 this.setValue( element.getAttribute( 'id' ) );
1088 },
1089 commit: function( type, element ) {
1090 if ( type == IMAGE ) {
1091 if ( this.getValue() || this.isChanged() )
1092 element.setAttribute( 'id', this.getValue() );
1093 }
1094 }
1095 },
1096 {
1097 id: 'cmbLangDir',
1098 type: 'select',
1099 requiredContent: 'img[dir]',
1100 style: 'width : 100px;',
1101 label: editor.lang.common.langDir,
1102 'default': '',
1103 items: [
1104 [ editor.lang.common.notSet, '' ],
1105 [ editor.lang.common.langDirLtr, 'ltr' ],
1106 [ editor.lang.common.langDirRtl, 'rtl' ]
1107 ],
1108 setup: function( type, element ) {
1109 if ( type == IMAGE )
1110 this.setValue( element.getAttribute( 'dir' ) );
1111 },
1112 commit: function( type, element ) {
1113 if ( type == IMAGE ) {
1114 if ( this.getValue() || this.isChanged() )
1115 element.setAttribute( 'dir', this.getValue() );
1116 }
1117 }
1118 },
1119 {
1120 type: 'text',
1121 id: 'txtLangCode',
1122 requiredContent: 'img[lang]',
1123 label: editor.lang.common.langCode,
1124 'default': '',
1125 setup: function( type, element ) {
1126 if ( type == IMAGE )
1127 this.setValue( element.getAttribute( 'lang' ) );
1128 },
1129 commit: function( type, element ) {
1130 if ( type == IMAGE ) {
1131 if ( this.getValue() || this.isChanged() )
1132 element.setAttribute( 'lang', this.getValue() );
1133 }
1134 }
1135 } ]
1136 },
1137 {
1138 type: 'text',
1139 id: 'txtGenLongDescr',
1140 requiredContent: 'img[longdesc]',
1141 label: editor.lang.common.longDescr,
1142 setup: function( type, element ) {
1143 if ( type == IMAGE )
1144 this.setValue( element.getAttribute( 'longDesc' ) );
1145 },
1146 commit: function( type, element ) {
1147 if ( type == IMAGE ) {
1148 if ( this.getValue() || this.isChanged() )
1149 element.setAttribute( 'longDesc', this.getValue() );
1150 }
1151 }
1152 },
1153 {
1154 type: 'hbox',
1155 widths: [ '50%', '50%' ],
1156 children: [ {
1157 type: 'text',
1158 id: 'txtGenClass',
1159 requiredContent: 'img(cke-xyz)', // Random text like 'xyz' will check if all are allowed.
1160 label: editor.lang.common.cssClass,
1161 'default': '',
1162 setup: function( type, element ) {
1163 if ( type == IMAGE )
1164 this.setValue( element.getAttribute( 'class' ) );
1165 },
1166 commit: function( type, element ) {
1167 if ( type == IMAGE ) {
1168 if ( this.getValue() || this.isChanged() )
1169 element.setAttribute( 'class', this.getValue() );
1170 }
1171 }
1172 },
1173 {
1174 type: 'text',
1175 id: 'txtGenTitle',
1176 requiredContent: 'img[title]',
1177 label: editor.lang.common.advisoryTitle,
1178 'default': '',
1179 onChange: function() {
1180 updatePreview( this.getDialog() );
1181 },
1182 setup: function( type, element ) {
1183 if ( type == IMAGE )
1184 this.setValue( element.getAttribute( 'title' ) );
1185 },
1186 commit: function( type, element ) {
1187 if ( type == IMAGE ) {
1188 if ( this.getValue() || this.isChanged() )
1189 element.setAttribute( 'title', this.getValue() );
1190 } else if ( type == PREVIEW )
1191 element.setAttribute( 'title', this.getValue() );
1192 else if ( type == CLEANUP ) {
1193 element.removeAttribute( 'title' );
1194 }
1195 }
1196 } ]
1197 },
1198 {
1199 type: 'text',
1200 id: 'txtdlgGenStyle',
1201 requiredContent: 'img{cke-xyz}', // Random text like 'xyz' will check if all are allowed.
1202 label: editor.lang.common.cssStyle,
1203 validate: CKEDITOR.dialog.validate.inlineStyle( editor.lang.common.invalidInlineStyle ),
1204 'default': '',
1205 setup: function( type, element ) {
1206 if ( type == IMAGE ) {
1207 var genStyle = element.getAttribute( 'style' );
1208 if ( !genStyle && element.$.style.cssText )
1209 genStyle = element.$.style.cssText;
1210 this.setValue( genStyle );
1211
1212 var height = element.$.style.height,
1213 width = element.$.style.width,
1214 aMatchH = ( height ? height : '' ).match( regexGetSize ),
1215 aMatchW = ( width ? width : '' ).match( regexGetSize );
1216
1217 this.attributesInStyle = {
1218 height: !!aMatchH,
1219 width: !!aMatchW
1220 };
1221 }
1222 },
1223 onChange: function() {
1224 commitInternally.call(
1225 this, [
1226 'info:cmbFloat',
1227 'info:cmbAlign',
1228 'info:txtVSpace',
1229 'info:txtHSpace',
1230 'info:txtBorder',
1231 'info:txtWidth',
1232 'info:txtHeight'
1233 ]
1234 );
1235 updatePreview( this );
1236 },
1237 commit: function( type, element ) {
1238 if ( type == IMAGE && ( this.getValue() || this.isChanged() ) )
1239 element.setAttribute( 'style', this.getValue() );
1240
1241 }
1242 } ]
1243 } ]
1244 };
1245 };
1246
1247 CKEDITOR.dialog.add( 'image', function( editor ) {
1248 return imageDialog( editor, 'image' );
1249 } );
1250
1251 CKEDITOR.dialog.add( 'imagebutton', function( editor ) {
1252 return imageDialog( editor, 'imagebutton' );
1253 } );
1254} )();
diff --git a/sources/plugins/image/icons/hidpi/image.png b/sources/plugins/image/icons/hidpi/image.png
new file mode 100644
index 0000000..d0f21ae
--- /dev/null
+++ b/sources/plugins/image/icons/hidpi/image.png
Binary files differ
diff --git a/sources/plugins/image/icons/image.png b/sources/plugins/image/icons/image.png
new file mode 100644
index 0000000..8ea9725
--- /dev/null
+++ b/sources/plugins/image/icons/image.png
Binary files differ
diff --git a/sources/plugins/image/images/noimage.png b/sources/plugins/image/images/noimage.png
new file mode 100644
index 0000000..74c6ee9
--- /dev/null
+++ b/sources/plugins/image/images/noimage.png
Binary files differ
diff --git a/sources/plugins/image/lang/af.js b/sources/plugins/image/lang/af.js
new file mode 100644
index 0000000..8cc5b5f
--- /dev/null
+++ b/sources/plugins/image/lang/af.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'af', {
6 alt: 'Alternatiewe teks',
7 border: 'Rand',
8 btnUpload: 'Stuur na bediener',
9 button2Img: 'Wil u die geselekteerde afbeeldingsknop vervang met \'n eenvoudige afbeelding?',
10 hSpace: 'HSpasie',
11 img2Button: 'Wil u die geselekteerde afbeelding vervang met \'n afbeeldingsknop?',
12 infoTab: 'Afbeelding informasie',
13 linkTab: 'Skakel',
14 lockRatio: 'Vaste proporsie',
15 menu: 'Afbeelding eienskappe',
16 resetSize: 'Herstel grootte',
17 title: 'Afbeelding eienskappe',
18 titleButton: 'Afbeeldingsknop eienskappe',
19 upload: 'Oplaai',
20 urlMissing: 'Die URL na die afbeelding ontbreek.',
21 vSpace: 'VSpasie',
22 validateBorder: 'Rand moet \'n heelgetal wees.',
23 validateHSpace: 'HSpasie moet \'n heelgetal wees.',
24 validateVSpace: 'VSpasie moet \'n heelgetal wees.'
25} );
diff --git a/sources/plugins/image/lang/ar.js b/sources/plugins/image/lang/ar.js
new file mode 100644
index 0000000..a755b3e
--- /dev/null
+++ b/sources/plugins/image/lang/ar.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ar', {
6 alt: 'عنوان الصورة',
7 border: 'سمك الحدود',
8 btnUpload: 'أرسلها للخادم',
9 button2Img: 'هل تريد تحويل زر الصورة المختار إلى صورة بسيطة؟',
10 hSpace: 'تباعد أفقي',
11 img2Button: 'هل تريد تحويل الصورة المختارة إلى زر صورة؟',
12 infoTab: 'معلومات الصورة',
13 linkTab: 'الرابط',
14 lockRatio: 'تناسق الحجم',
15 menu: 'خصائص الصورة',
16 resetSize: 'إستعادة الحجم الأصلي',
17 title: 'خصائص الصورة',
18 titleButton: 'خصائص زر الصورة',
19 upload: 'رفع',
20 urlMissing: 'عنوان مصدر الصورة مفقود',
21 vSpace: 'تباعد عمودي',
22 validateBorder: 'الإطار يجب أن يكون عددا',
23 validateHSpace: 'HSpace يجب أن يكون عدداً.',
24 validateVSpace: 'VSpace يجب أن يكون عدداً.'
25} );
diff --git a/sources/plugins/image/lang/az.js b/sources/plugins/image/lang/az.js
new file mode 100644
index 0000000..79009fa
--- /dev/null
+++ b/sources/plugins/image/lang/az.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'az', {
6 alt: 'Alternativ mətn',
7 border: 'Sərhəd',
8 btnUpload: 'Serverə yüklə',
9 button2Img: 'Şəkil tipli düyməni şəklə çevirmək istədiyinizə əminsinizmi?',
10 hSpace: 'Üfüqi boşluq',
11 img2Button: 'Şəkli şəkil tipli düyməyə çevirmək istədiyinizə əminsinizmi?',
12 infoTab: 'Şəkil haqqında məlumat',
13 linkTab: 'Link',
14 lockRatio: 'Ölçülərin uyğunluğu saxla',
15 menu: 'Şəklin seçimləri',
16 resetSize: 'Ölçüləri qaytar',
17 title: 'Şəklin seçimləri',
18 titleButton: 'Şəkil tipli düyməsinin seçimləri',
19 upload: 'Serverə yüklə',
20 urlMissing: 'Şəklin ünvanı yanlışdır.',
21 vSpace: 'Şaquli boşluq',
22 validateBorder: 'Sərhədin eni rəqəm olmalıdır.',
23 validateHSpace: 'Üfüqi boşluq rəqəm olmalıdır.',
24 validateVSpace: 'Şaquli boşluq rəqəm olmalıdır.'
25} );
diff --git a/sources/plugins/image/lang/bg.js b/sources/plugins/image/lang/bg.js
new file mode 100644
index 0000000..6c0b064
--- /dev/null
+++ b/sources/plugins/image/lang/bg.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'bg', {
6 alt: 'Алтернативен текст',
7 border: 'Рамка',
8 btnUpload: 'Изпрати я на сървъра',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'Хоризонтален отстъп',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Инфо за снимка',
13 linkTab: 'Връзка',
14 lockRatio: 'Заключване на съотношението',
15 menu: 'Настройки за снимка',
16 resetSize: 'Нулиране на размер',
17 title: 'Настройки за снимка',
18 titleButton: 'Настойки за бутон за снимка',
19 upload: 'Качване',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'Вертикален отстъп',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/bn.js b/sources/plugins/image/lang/bn.js
new file mode 100644
index 0000000..bbecfc6
--- /dev/null
+++ b/sources/plugins/image/lang/bn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'bn', {
6 alt: 'বিকল্প টেক্সট',
7 border: 'বর্ডার',
8 btnUpload: 'ইহাকে সার্ভারে প্রেরন কর',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'হরাইজন্টাল স্পেস',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'ছবির তথ্য',
13 linkTab: 'লিংক',
14 lockRatio: 'অনুপাত লক কর',
15 menu: 'ছবির প্রোপার্টি',
16 resetSize: 'সাইজ পূর্বাবস্থায় ফিরিয়ে দাও',
17 title: 'ছবির প্রোপার্টি',
18 titleButton: 'ছবির বাটন সম্বন্ধীয়',
19 upload: 'আপলোড',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'ভার্টিকেল স্পেস',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/bs.js b/sources/plugins/image/lang/bs.js
new file mode 100644
index 0000000..06dd8bf
--- /dev/null
+++ b/sources/plugins/image/lang/bs.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'bs', {
6 alt: 'Tekst na slici',
7 border: 'Okvir',
8 btnUpload: 'Šalji na server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Info slike',
13 linkTab: 'Link',
14 lockRatio: 'Zakljuèaj odnos',
15 menu: 'Svojstva slike',
16 resetSize: 'Resetuj dimenzije',
17 title: 'Svojstva slike',
18 titleButton: 'Image Button Properties', // MISSING
19 upload: 'Šalji',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/ca.js b/sources/plugins/image/lang/ca.js
new file mode 100644
index 0000000..858013e
--- /dev/null
+++ b/sources/plugins/image/lang/ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ca', {
6 alt: 'Text alternatiu',
7 border: 'Vora',
8 btnUpload: 'Envia-la al servidor',
9 button2Img: 'Voleu transformar el botó d\'imatge seleccionat en una simple imatge?',
10 hSpace: 'Espaiat horit.',
11 img2Button: 'Voleu transformar la imatge seleccionada en un botó d\'imatge?',
12 infoTab: 'Informació de la imatge',
13 linkTab: 'Enllaç',
14 lockRatio: 'Bloqueja les proporcions',
15 menu: 'Propietats de la imatge',
16 resetSize: 'Restaura la mida',
17 title: 'Propietats de la imatge',
18 titleButton: 'Propietats del botó d\'imatge',
19 upload: 'Puja',
20 urlMissing: 'Falta la URL de la imatge.',
21 vSpace: 'Espaiat vert.',
22 validateBorder: 'La vora ha de ser un nombre enter.',
23 validateHSpace: 'HSpace ha de ser un nombre enter.',
24 validateVSpace: 'VSpace ha de ser un nombre enter.'
25} );
diff --git a/sources/plugins/image/lang/cs.js b/sources/plugins/image/lang/cs.js
new file mode 100644
index 0000000..a18a753
--- /dev/null
+++ b/sources/plugins/image/lang/cs.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'cs', {
6 alt: 'Alternativní text',
7 border: 'Okraje',
8 btnUpload: 'Odeslat na server',
9 button2Img: 'Skutečně chcete převést zvolené obrázkové tlačítko na obyčejný obrázek?',
10 hSpace: 'Horizontální mezera',
11 img2Button: 'Skutečně chcete převést zvolený obrázek na obrázkové tlačítko?',
12 infoTab: 'Informace o obrázku',
13 linkTab: 'Odkaz',
14 lockRatio: 'Zámek',
15 menu: 'Vlastnosti obrázku',
16 resetSize: 'Původní velikost',
17 title: 'Vlastnosti obrázku',
18 titleButton: 'Vlastností obrázkového tlačítka',
19 upload: 'Odeslat',
20 urlMissing: 'Zadané URL zdroje obrázku nebylo nalezeno.',
21 vSpace: 'Vertikální mezera',
22 validateBorder: 'Okraj musí být nastaven v celých číslech.',
23 validateHSpace: 'Horizontální mezera musí být nastavena v celých číslech.',
24 validateVSpace: 'Vertikální mezera musí být nastavena v celých číslech.'
25} );
diff --git a/sources/plugins/image/lang/cy.js b/sources/plugins/image/lang/cy.js
new file mode 100644
index 0000000..7407310
--- /dev/null
+++ b/sources/plugins/image/lang/cy.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'cy', {
6 alt: 'Testun Amgen',
7 border: 'Ymyl',
8 btnUpload: 'Anfon i\'r Gweinydd',
9 button2Img: 'Ydych am drawsffurfio\'r botwm ddelwedd hwn ar ddelwedd syml?',
10 hSpace: 'BwlchLl',
11 img2Button: 'Ydych am drawsffurfio\'r ddelwedd hon ar fotwm delwedd?',
12 infoTab: 'Gwyb Delwedd',
13 linkTab: 'Dolen',
14 lockRatio: 'Cloi Cymhareb',
15 menu: 'Priodweddau Delwedd',
16 resetSize: 'Ailosod Maint',
17 title: 'Priodweddau Delwedd',
18 titleButton: 'Priodweddau Botwm Delwedd',
19 upload: 'Lanlwytho',
20 urlMissing: 'URL gwreiddiol y ddelwedd ar goll.',
21 vSpace: 'BwlchF',
22 validateBorder: 'Rhaid i\'r ymyl fod yn gyfanrif.',
23 validateHSpace: 'Rhaid i\'r HSpace fod yn gyfanrif.',
24 validateVSpace: 'Rhaid i\'r VSpace fod yn gyfanrif.'
25} );
diff --git a/sources/plugins/image/lang/da.js b/sources/plugins/image/lang/da.js
new file mode 100644
index 0000000..bec69ba
--- /dev/null
+++ b/sources/plugins/image/lang/da.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'da', {
6 alt: 'Alternativ tekst',
7 border: 'Ramme',
8 btnUpload: 'Upload fil til serveren',
9 button2Img: 'Vil du lave billedknappen om til et almindeligt billede?',
10 hSpace: 'Vandret margen',
11 img2Button: 'Vil du lave billedet om til en billedknap?',
12 infoTab: 'Generelt',
13 linkTab: 'Hyperlink',
14 lockRatio: 'Lås størrelsesforhold',
15 menu: 'Egenskaber for billede',
16 resetSize: 'Nulstil størrelse',
17 title: 'Egenskaber for billede',
18 titleButton: 'Egenskaber for billedknap',
19 upload: 'Upload',
20 urlMissing: 'Kilde på billed-URL mangler',
21 vSpace: 'Lodret margen',
22 validateBorder: 'Kant skal være et helt nummer.',
23 validateHSpace: 'HSpace skal være et helt nummer.',
24 validateVSpace: 'VSpace skal være et helt nummer.'
25} );
diff --git a/sources/plugins/image/lang/de-ch.js b/sources/plugins/image/lang/de-ch.js
new file mode 100644
index 0000000..6ba1570
--- /dev/null
+++ b/sources/plugins/image/lang/de-ch.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'de-ch', {
6 alt: 'Alternativer Text',
7 border: 'Rahmen',
8 btnUpload: 'Zum Server senden',
9 button2Img: 'Möchten Sie die ausgewählte Bildschaltfläche in ein einfaches Bild umwandeln?',
10 hSpace: 'Horizontal-Abstand',
11 img2Button: 'Möchten Sie das ausgewählte Bild in eine Bildschaltfläche umwandeln?',
12 infoTab: 'Bildinfo',
13 linkTab: 'Link',
14 lockRatio: 'Grössenverhältnis beibehalten',
15 menu: 'Bildeigenschaften',
16 resetSize: 'Grösse zurücksetzen',
17 title: 'Bildeigenschaften',
18 titleButton: 'Bildschaltflächeneigenschaften',
19 upload: 'Hochladen',
20 urlMissing: 'Bildquellen-URL fehlt.',
21 vSpace: 'Vertikal-Abstand',
22 validateBorder: 'Rahmen muss eine ganze Zahl sein.',
23 validateHSpace: 'Horizontal-Abstand muss eine ganze Zahl sein.',
24 validateVSpace: 'Vertikal-Abstand muss eine ganze Zahl sein.'
25} );
diff --git a/sources/plugins/image/lang/de.js b/sources/plugins/image/lang/de.js
new file mode 100644
index 0000000..a391934
--- /dev/null
+++ b/sources/plugins/image/lang/de.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'de', {
6 alt: 'Alternativer Text',
7 border: 'Rahmen',
8 btnUpload: 'Zum Server senden',
9 button2Img: 'Möchten Sie die ausgewählte Bildschaltfläche in ein einfaches Bild umwandeln?',
10 hSpace: 'Horizontal-Abstand',
11 img2Button: 'Möchten Sie das ausgewählte Bild in eine Bildschaltfläche umwandeln?',
12 infoTab: 'Bildinfo',
13 linkTab: 'Link',
14 lockRatio: 'Größenverhältnis beibehalten',
15 menu: 'Bildeigenschaften',
16 resetSize: 'Größe zurücksetzen',
17 title: 'Bildeigenschaften',
18 titleButton: 'Bildschaltflächeneigenschaften',
19 upload: 'Hochladen',
20 urlMissing: 'Bildquellen-URL fehlt.',
21 vSpace: 'Vertikal-Abstand',
22 validateBorder: 'Rahmen muss eine ganze Zahl sein.',
23 validateHSpace: 'Horizontal-Abstand muss eine ganze Zahl sein.',
24 validateVSpace: 'Vertikal-Abstand muss eine ganze Zahl sein.'
25} );
diff --git a/sources/plugins/image/lang/el.js b/sources/plugins/image/lang/el.js
new file mode 100644
index 0000000..3453c3d
--- /dev/null
+++ b/sources/plugins/image/lang/el.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'el', {
6 alt: 'Εναλλακτικό Κείμενο',
7 border: 'Περίγραμμα',
8 btnUpload: 'Αποστολή στον Διακομιστή',
9 button2Img: 'Θέλετε να μετατρέψετε το επιλεγμένο κουμπί εικόνας σε απλή εικόνα;',
10 hSpace: 'HSpace',
11 img2Button: 'Θέλετε να μεταμορφώσετε την επιλεγμένη εικόνα που είναι πάνω σε ένα κουμπί;',
12 infoTab: 'Πληροφορίες Εικόνας',
13 linkTab: 'Σύνδεσμος',
14 lockRatio: 'Κλείδωμα Αναλογίας',
15 menu: 'Ιδιότητες Εικόνας',
16 resetSize: 'Επαναφορά Αρχικού Μεγέθους',
17 title: 'Ιδιότητες Εικόνας',
18 titleButton: 'Ιδιότητες Κουμπιού Εικόνας',
19 upload: 'Αποστολή',
20 urlMissing: 'Το URL πηγής για την εικόνα λείπει.',
21 vSpace: 'VSpace',
22 validateBorder: 'Το περίγραμμα πρέπει να είναι ένας ακέραιος αριθμός.',
23 validateHSpace: 'Το HSpace πρέπει να είναι ένας ακέραιος αριθμός.',
24 validateVSpace: 'Το VSpace πρέπει να είναι ένας ακέραιος αριθμός.'
25} );
diff --git a/sources/plugins/image/lang/en-au.js b/sources/plugins/image/lang/en-au.js
new file mode 100644
index 0000000..dba29c7
--- /dev/null
+++ b/sources/plugins/image/lang/en-au.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'en-au', {
6 alt: 'Alternative Text',
7 border: 'Border',
8 btnUpload: 'Send it to the Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?',
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?',
12 infoTab: 'Image Info',
13 linkTab: 'Link',
14 lockRatio: 'Lock Ratio',
15 menu: 'Image Properties',
16 resetSize: 'Reset Size',
17 title: 'Image Properties',
18 titleButton: 'Image Button Properties',
19 upload: 'Upload',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/en-ca.js b/sources/plugins/image/lang/en-ca.js
new file mode 100644
index 0000000..e78f83e
--- /dev/null
+++ b/sources/plugins/image/lang/en-ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'en-ca', {
6 alt: 'Alternative Text',
7 border: 'Border',
8 btnUpload: 'Send it to the Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?',
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?',
12 infoTab: 'Image Info',
13 linkTab: 'Link',
14 lockRatio: 'Lock Ratio',
15 menu: 'Image Properties',
16 resetSize: 'Reset Size',
17 title: 'Image Properties',
18 titleButton: 'Image Button Properties',
19 upload: 'Upload',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/en-gb.js b/sources/plugins/image/lang/en-gb.js
new file mode 100644
index 0000000..dcf335e
--- /dev/null
+++ b/sources/plugins/image/lang/en-gb.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'en-gb', {
6 alt: 'Alternative Text',
7 border: 'Border',
8 btnUpload: 'Send it to the Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?',
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?',
12 infoTab: 'Image Info',
13 linkTab: 'Link',
14 lockRatio: 'Lock Ratio',
15 menu: 'Image Properties',
16 resetSize: 'Reset Size',
17 title: 'Image Properties',
18 titleButton: 'Image Button Properties',
19 upload: 'Upload',
20 urlMissing: 'Image source URL is missing.',
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.',
23 validateHSpace: 'HSpace must be a whole number.',
24 validateVSpace: 'VSpace must be a whole number.'
25} );
diff --git a/sources/plugins/image/lang/en.js b/sources/plugins/image/lang/en.js
new file mode 100644
index 0000000..4d0f50b
--- /dev/null
+++ b/sources/plugins/image/lang/en.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'en', {
6 alt: 'Alternative Text',
7 border: 'Border',
8 btnUpload: 'Send it to the Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?',
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?',
12 infoTab: 'Image Info',
13 linkTab: 'Link',
14 lockRatio: 'Lock Ratio',
15 menu: 'Image Properties',
16 resetSize: 'Reset Size',
17 title: 'Image Properties',
18 titleButton: 'Image Button Properties',
19 upload: 'Upload',
20 urlMissing: 'Image source URL is missing.',
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.',
23 validateHSpace: 'HSpace must be a whole number.',
24 validateVSpace: 'VSpace must be a whole number.'
25} );
diff --git a/sources/plugins/image/lang/eo.js b/sources/plugins/image/lang/eo.js
new file mode 100644
index 0000000..276ef33
--- /dev/null
+++ b/sources/plugins/image/lang/eo.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'eo', {
6 alt: 'Anstataŭiga Teksto',
7 border: 'Bordero',
8 btnUpload: 'Sendu al Servilo',
9 button2Img: 'Ĉu vi volas transformi la selektitan bildbutonon en simplan bildon?',
10 hSpace: 'Horizontala Spaco',
11 img2Button: 'Ĉu vi volas transformi la selektitan bildon en bildbutonon?',
12 infoTab: 'Informoj pri Bildo',
13 linkTab: 'Ligilo',
14 lockRatio: 'Konservi Proporcion',
15 menu: 'Atributoj de Bildo',
16 resetSize: 'Origina Grando',
17 title: 'Atributoj de Bildo',
18 titleButton: 'Bildbutonaj Atributoj',
19 upload: 'Alŝuti',
20 urlMissing: 'La fontretadreso de la bildo mankas.',
21 vSpace: 'Vertikala Spaco',
22 validateBorder: 'La bordero devas esti entjera nombro.',
23 validateHSpace: 'La horizontala spaco devas esti entjera nombro.',
24 validateVSpace: 'La vertikala spaco devas esti entjera nombro.'
25} );
diff --git a/sources/plugins/image/lang/es.js b/sources/plugins/image/lang/es.js
new file mode 100644
index 0000000..1302a19
--- /dev/null
+++ b/sources/plugins/image/lang/es.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'es', {
6 alt: 'Texto Alternativo',
7 border: 'Borde',
8 btnUpload: 'Enviar al Servidor',
9 button2Img: '¿Desea convertir el botón de imagen en una simple imagen?',
10 hSpace: 'Esp.Horiz',
11 img2Button: '¿Desea convertir la imagen en un botón de imagen?',
12 infoTab: 'Información de Imagen',
13 linkTab: 'Vínculo',
14 lockRatio: 'Proporcional',
15 menu: 'Propiedades de Imagen',
16 resetSize: 'Tamaño Original',
17 title: 'Propiedades de Imagen',
18 titleButton: 'Propiedades de Botón de Imagen',
19 upload: 'Cargar',
20 urlMissing: 'Debe indicar la URL de la imagen.',
21 vSpace: 'Esp.Vert',
22 validateBorder: 'El borde debe ser un número.',
23 validateHSpace: 'El espaciado horizontal debe ser un número.',
24 validateVSpace: 'El espaciado vertical debe ser un número.'
25} );
diff --git a/sources/plugins/image/lang/et.js b/sources/plugins/image/lang/et.js
new file mode 100644
index 0000000..4c7153a
--- /dev/null
+++ b/sources/plugins/image/lang/et.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'et', {
6 alt: 'Alternatiivne tekst',
7 border: 'Joon',
8 btnUpload: 'Saada serverisse',
9 button2Img: 'Kas tahad teisendada valitud pildiga nupu tavaliseks pildiks?',
10 hSpace: 'H. vaheruum',
11 img2Button: 'Kas tahad teisendada valitud tavalise pildi pildiga nupuks?',
12 infoTab: 'Pildi info',
13 linkTab: 'Link',
14 lockRatio: 'Lukusta kuvasuhe',
15 menu: 'Pildi omadused',
16 resetSize: 'Lähtesta suurus',
17 title: 'Pildi omadused',
18 titleButton: 'Piltnupu omadused',
19 upload: 'Lae üles',
20 urlMissing: 'Pildi lähte-URL on puudu.',
21 vSpace: 'V. vaheruum',
22 validateBorder: 'Äärise laius peab olema täisarv.',
23 validateHSpace: 'Horisontaalne vaheruum peab olema täisarv.',
24 validateVSpace: 'Vertikaalne vaheruum peab olema täisarv.'
25} );
diff --git a/sources/plugins/image/lang/eu.js b/sources/plugins/image/lang/eu.js
new file mode 100644
index 0000000..52f8289
--- /dev/null
+++ b/sources/plugins/image/lang/eu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'eu', {
6 alt: 'Ordezko testua',
7 border: 'Ertza',
8 btnUpload: 'Bidali zerbitzarira',
9 button2Img: 'Hautatutako irudi-botoia irudi arrunt bihurtu nahi duzu?',
10 hSpace: 'HSpace',
11 img2Button: 'Hautatutako irudia irudi-botoi bihurtu nahi duzu?',
12 infoTab: 'Irudiaren informazioa',
13 linkTab: 'Esteka',
14 lockRatio: 'Blokeatu erlazioa',
15 menu: 'Irudiaren propietateak',
16 resetSize: 'Berrezarri tamaina',
17 title: 'Irudiaren propietateak',
18 titleButton: 'Irudi-botoiaren propietateak',
19 upload: 'Kargatu',
20 urlMissing: 'Irudiaren iturburuaren URLa falta da.',
21 vSpace: 'VSpace',
22 validateBorder: 'Ertza zenbaki oso bat izan behar da.',
23 validateHSpace: 'HSpace zenbaki oso bat izan behar da.',
24 validateVSpace: 'VSpace zenbaki oso bat izan behar da.'
25} );
diff --git a/sources/plugins/image/lang/fa.js b/sources/plugins/image/lang/fa.js
new file mode 100644
index 0000000..6628e99
--- /dev/null
+++ b/sources/plugins/image/lang/fa.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'fa', {
6 alt: 'متن جایگزین',
7 border: 'لبه',
8 btnUpload: 'به سرور بفرست',
9 button2Img: 'آیا مایلید از یک تصویر ساده روی دکمه تصویری انتخاب شده استفاده کنید؟',
10 hSpace: 'فاصلهٴ افقی',
11 img2Button: 'آیا مایلید از یک دکمه تصویری روی تصویر انتخاب شده استفاده کنید؟',
12 infoTab: 'اطلاعات تصویر',
13 linkTab: 'پیوند',
14 lockRatio: 'قفل کردن نسبت',
15 menu: 'ویژگی​های تصویر',
16 resetSize: 'بازنشانی اندازه',
17 title: 'ویژگی​های تصویر',
18 titleButton: 'ویژگی​های دکمهٴ تصویری',
19 upload: 'انتقال به سرور',
20 urlMissing: 'آدرس URL اصلی تصویر یافت نشد.',
21 vSpace: 'فاصلهٴ عمودی',
22 validateBorder: 'مقدار خطوط باید یک عدد باشد.',
23 validateHSpace: 'مقدار فاصله گذاری افقی باید یک عدد باشد.',
24 validateVSpace: 'مقدار فاصله گذاری عمودی باید یک عدد باشد.'
25} );
diff --git a/sources/plugins/image/lang/fi.js b/sources/plugins/image/lang/fi.js
new file mode 100644
index 0000000..665b615
--- /dev/null
+++ b/sources/plugins/image/lang/fi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'fi', {
6 alt: 'Vaihtoehtoinen teksti',
7 border: 'Kehys',
8 btnUpload: 'Lähetä palvelimelle',
9 button2Img: 'Haluatko muuntaa valitun kuvanäppäimen kuvaksi?',
10 hSpace: 'Vaakatila',
11 img2Button: 'Haluatko muuntaa valitun kuvan kuvanäppäimeksi?',
12 infoTab: 'Kuvan tiedot',
13 linkTab: 'Linkki',
14 lockRatio: 'Lukitse suhteet',
15 menu: 'Kuvan ominaisuudet',
16 resetSize: 'Alkuperäinen koko',
17 title: 'Kuvan ominaisuudet',
18 titleButton: 'Kuvapainikkeen ominaisuudet',
19 upload: 'Lisää kuva',
20 urlMissing: 'Kuvan lähdeosoite puuttuu.',
21 vSpace: 'Pystytila',
22 validateBorder: 'Kehyksen täytyy olla kokonaisluku.',
23 validateHSpace: 'HSpace-määrityksen täytyy olla kokonaisluku.',
24 validateVSpace: 'VSpace-määrityksen täytyy olla kokonaisluku.'
25} );
diff --git a/sources/plugins/image/lang/fo.js b/sources/plugins/image/lang/fo.js
new file mode 100644
index 0000000..8332a38
--- /dev/null
+++ b/sources/plugins/image/lang/fo.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'fo', {
6 alt: 'Alternativur tekstur',
7 border: 'Bordi',
8 btnUpload: 'Send til ambætaran',
9 button2Img: 'Skal valdi myndaknøttur gerast til vanliga mynd?',
10 hSpace: 'Høgri breddi',
11 img2Button: 'Skal valda mynd gerast til myndaknøtt?',
12 infoTab: 'Myndaupplýsingar',
13 linkTab: 'Tilknýti',
14 lockRatio: 'Læs lutfallið',
15 menu: 'Myndaeginleikar',
16 resetSize: 'Upprunastødd',
17 title: 'Myndaeginleikar',
18 titleButton: 'Eginleikar fyri myndaknøtt',
19 upload: 'Send',
20 urlMissing: 'URL til mynd manglar.',
21 vSpace: 'Vinstri breddi',
22 validateBorder: 'Bordi má vera eitt heiltal.',
23 validateHSpace: 'HSpace má vera eitt heiltal.',
24 validateVSpace: 'VSpace má vera eitt heiltal.'
25} );
diff --git a/sources/plugins/image/lang/fr-ca.js b/sources/plugins/image/lang/fr-ca.js
new file mode 100644
index 0000000..644a9f3
--- /dev/null
+++ b/sources/plugins/image/lang/fr-ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'fr-ca', {
6 alt: 'Texte alternatif',
7 border: 'Bordure',
8 btnUpload: 'Envoyer sur le serveur',
9 button2Img: 'Désirez-vous transformer l\'image sélectionnée en image simple?',
10 hSpace: 'Espacement horizontal',
11 img2Button: 'Désirez-vous transformer l\'image sélectionnée en bouton image?',
12 infoTab: 'Informations sur l\'image',
13 linkTab: 'Lien',
14 lockRatio: 'Verrouiller les proportions',
15 menu: 'Propriétés de l\'image',
16 resetSize: 'Taille originale',
17 title: 'Propriétés de l\'image',
18 titleButton: 'Propriétés du bouton image',
19 upload: 'Téléverser',
20 urlMissing: 'L\'URL de la source de l\'image est manquant.',
21 vSpace: 'Espacement vertical',
22 validateBorder: 'La bordure doit être un entier.',
23 validateHSpace: 'L\'espacement horizontal doit être un entier.',
24 validateVSpace: 'L\'espacement vertical doit être un entier.'
25} );
diff --git a/sources/plugins/image/lang/fr.js b/sources/plugins/image/lang/fr.js
new file mode 100644
index 0000000..299c379
--- /dev/null
+++ b/sources/plugins/image/lang/fr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'fr', {
6 alt: 'Texte alternatif',
7 border: 'Bordure',
8 btnUpload: 'Envoyer sur le serveur',
9 button2Img: 'Voulez-vous transformer le bouton avec image sélectionné en simple image ?',
10 hSpace: 'Espacement horizontal',
11 img2Button: 'Voulez-vous transformer l\'image sélectionnée en bouton avec image ?',
12 infoTab: 'Informations sur l\'image',
13 linkTab: 'Lien',
14 lockRatio: 'Conserver les proportions',
15 menu: 'Propriétés de l\'image',
16 resetSize: 'Réinitialiser la taille',
17 title: 'Propriétés de l\'image',
18 titleButton: 'Propriétés du bouton avec image',
19 upload: 'Téléverser',
20 urlMissing: 'L\'URL source de l\'image est manquante.',
21 vSpace: 'Espacement vertical',
22 validateBorder: 'La bordure doit être un nombre entier.',
23 validateHSpace: 'L\'espacement horizontal doit être un nombre entier.',
24 validateVSpace: 'L\'espacement vertical doit être un nombre entier.'
25} );
diff --git a/sources/plugins/image/lang/gl.js b/sources/plugins/image/lang/gl.js
new file mode 100644
index 0000000..ba632b8
--- /dev/null
+++ b/sources/plugins/image/lang/gl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'gl', {
6 alt: 'Texto alternativo',
7 border: 'Bordo',
8 btnUpload: 'Enviar ao servidor',
9 button2Img: 'Quere converter o botón da imaxe seleccionada nunha imaxe sinxela?',
10 hSpace: 'Esp.Horiz.',
11 img2Button: 'Quere converter a imaxe seleccionada nun botón de imaxe?',
12 infoTab: 'Información da imaxe',
13 linkTab: 'Ligazón',
14 lockRatio: 'Proporcional',
15 menu: 'Propiedades da imaxe',
16 resetSize: 'Tamaño orixinal',
17 title: 'Propiedades da imaxe',
18 titleButton: 'Propiedades do botón de imaxe',
19 upload: 'Cargar',
20 urlMissing: 'Non se atopa o URL da imaxe.',
21 vSpace: 'Esp.Vert.',
22 validateBorder: 'O bordo debe ser un número.',
23 validateHSpace: 'O espazado horizontal debe ser un número.',
24 validateVSpace: 'O espazado vertical debe ser un número.'
25} );
diff --git a/sources/plugins/image/lang/gu.js b/sources/plugins/image/lang/gu.js
new file mode 100644
index 0000000..f70ae28
--- /dev/null
+++ b/sources/plugins/image/lang/gu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'gu', {
6 alt: 'ઑલ્ટર્નટ ટેક્સ્ટ',
7 border: 'બોર્ડર',
8 btnUpload: 'આ સર્વરને મોકલવું',
9 button2Img: 'તમારે ઈમેજ બટનને સાદી ઈમેજમાં બદલવું છે.',
10 hSpace: 'સમસ્તરીય જગ્યા',
11 img2Button: 'તમારે સાદી ઈમેજને ઈમેજ બટનમાં બદલવું છે.',
12 infoTab: 'ચિત્ર ની જાણકારી',
13 linkTab: 'લિંક',
14 lockRatio: 'લૉક ગુણોત્તર',
15 menu: 'ચિત્રના ગુણ',
16 resetSize: 'રીસેટ સાઇઝ',
17 title: 'ચિત્રના ગુણ',
18 titleButton: 'ચિત્ર બટનના ગુણ',
19 upload: 'અપલોડ',
20 urlMissing: 'ઈમેજની મૂળ URL છે નહી.',
21 vSpace: 'લંબરૂપ જગ્યા',
22 validateBorder: 'બોર્ડેર આંકડો હોવો જોઈએ.',
23 validateHSpace: 'HSpaceઆંકડો હોવો જોઈએ.',
24 validateVSpace: 'VSpace આંકડો હોવો જોઈએ. '
25} );
diff --git a/sources/plugins/image/lang/he.js b/sources/plugins/image/lang/he.js
new file mode 100644
index 0000000..41f207a
--- /dev/null
+++ b/sources/plugins/image/lang/he.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'he', {
6 alt: 'טקסט חלופי',
7 border: 'מסגרת',
8 btnUpload: 'שליחה לשרת',
9 button2Img: 'האם להפוך את תמונת הכפתור לתמונה פשוטה?',
10 hSpace: 'מרווח אופקי',
11 img2Button: 'האם להפוך את התמונה לכפתור תמונה?',
12 infoTab: 'מידע על התמונה',
13 linkTab: 'קישור',
14 lockRatio: 'נעילת היחס',
15 menu: 'תכונות התמונה',
16 resetSize: 'איפוס הגודל',
17 title: 'מאפייני התמונה',
18 titleButton: 'מאפיני כפתור תמונה',
19 upload: 'העלאה',
20 urlMissing: 'כתובת התמונה חסרה.',
21 vSpace: 'מרווח אנכי',
22 validateBorder: 'שדה המסגרת חייב להיות מספר שלם.',
23 validateHSpace: 'שדה המרווח האופקי חייב להיות מספר שלם.',
24 validateVSpace: 'שדה המרווח האנכי חייב להיות מספר שלם.'
25} );
diff --git a/sources/plugins/image/lang/hi.js b/sources/plugins/image/lang/hi.js
new file mode 100644
index 0000000..d4604b3
--- /dev/null
+++ b/sources/plugins/image/lang/hi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'hi', {
6 alt: 'वैकल्पिक टेक्स्ट',
7 border: 'बॉर्डर',
8 btnUpload: 'इसे सर्वर को भेजें',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'हॉरिज़ॉन्टल स्पेस',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'तस्वीर की जानकारी',
13 linkTab: 'लिंक',
14 lockRatio: 'लॉक अनुपात',
15 menu: 'तस्वीर प्रॉपर्टीज़',
16 resetSize: 'रीसॅट साइज़',
17 title: 'तस्वीर प्रॉपर्टीज़',
18 titleButton: 'तस्वीर बटन प्रॉपर्टीज़',
19 upload: 'अपलोड',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'वर्टिकल स्पेस',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/hr.js b/sources/plugins/image/lang/hr.js
new file mode 100644
index 0000000..8c272eb
--- /dev/null
+++ b/sources/plugins/image/lang/hr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'hr', {
6 alt: 'Alternativni tekst',
7 border: 'Okvir',
8 btnUpload: 'Pošalji na server',
9 button2Img: 'Želite li promijeniti odabrani gumb u jednostavnu sliku?',
10 hSpace: 'HSpace',
11 img2Button: 'Želite li promijeniti odabranu sliku u gumb?',
12 infoTab: 'Info slike',
13 linkTab: 'Link',
14 lockRatio: 'Zaključaj odnos',
15 menu: 'Svojstva slika',
16 resetSize: 'Obriši veličinu',
17 title: 'Svojstva slika',
18 titleButton: 'Image Button svojstva',
19 upload: 'Pošalji',
20 urlMissing: 'Nedostaje URL slike.',
21 vSpace: 'VSpace',
22 validateBorder: 'Okvir mora biti cijeli broj.',
23 validateHSpace: 'HSpace mora biti cijeli broj',
24 validateVSpace: 'VSpace mora biti cijeli broj.'
25} );
diff --git a/sources/plugins/image/lang/hu.js b/sources/plugins/image/lang/hu.js
new file mode 100644
index 0000000..5a9e990
--- /dev/null
+++ b/sources/plugins/image/lang/hu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'hu', {
6 alt: 'Alternatív szöveg',
7 border: 'Keret',
8 btnUpload: 'Küldés a szerverre',
9 button2Img: 'A kiválasztott képgombból sima képet szeretne csinálni?',
10 hSpace: 'Vízsz. táv',
11 img2Button: 'A kiválasztott képből képgombot szeretne csinálni?',
12 infoTab: 'Alaptulajdonságok',
13 linkTab: 'Hivatkozás',
14 lockRatio: 'Arány megtartása',
15 menu: 'Kép tulajdonságai',
16 resetSize: 'Eredeti méret',
17 title: 'Kép tulajdonságai',
18 titleButton: 'Képgomb tulajdonságai',
19 upload: 'Feltöltés',
20 urlMissing: 'Hiányzik a kép URL-je',
21 vSpace: 'Függ. táv',
22 validateBorder: 'A keret méretének egész számot kell beírni!',
23 validateHSpace: 'Vízszintes távolságnak egész számot kell beírni!',
24 validateVSpace: 'Függőleges távolságnak egész számot kell beírni!'
25} );
diff --git a/sources/plugins/image/lang/id.js b/sources/plugins/image/lang/id.js
new file mode 100644
index 0000000..8d27ad6
--- /dev/null
+++ b/sources/plugins/image/lang/id.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'id', {
6 alt: 'Teks alternatif',
7 border: 'Batas',
8 btnUpload: 'Kirim ke Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'HSpace', // MISSING
11 img2Button: 'Apakah anda ingin mengubah gambar yang dipilih pada tombol gambar?',
12 infoTab: 'Info Gambar',
13 linkTab: 'Tautan',
14 lockRatio: 'Lock Ratio', // MISSING
15 menu: 'Image Properties', // MISSING
16 resetSize: 'Atur Ulang Ukuran',
17 title: 'Image Properties', // MISSING
18 titleButton: 'Image Button Properties', // MISSING
19 upload: 'Unggah',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'VSpace',
22 validateBorder: 'Border harus berupa angka',
23 validateHSpace: 'HSpace harus berupa angka',
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/is.js b/sources/plugins/image/lang/is.js
new file mode 100644
index 0000000..fc02308
--- /dev/null
+++ b/sources/plugins/image/lang/is.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'is', {
6 alt: 'Baklægur texti',
7 border: 'Rammi',
8 btnUpload: 'Hlaða upp',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'Vinstri bil',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Almennt',
13 linkTab: 'Stikla',
14 lockRatio: 'Festa stærðarhlutfall',
15 menu: 'Eigindi myndar',
16 resetSize: 'Reikna stærð',
17 title: 'Eigindi myndar',
18 titleButton: 'Eigindi myndahnapps',
19 upload: 'Hlaða upp',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'Hægri bil',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/it.js b/sources/plugins/image/lang/it.js
new file mode 100644
index 0000000..7b066ca
--- /dev/null
+++ b/sources/plugins/image/lang/it.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'it', {
6 alt: 'Testo alternativo',
7 border: 'Bordo',
8 btnUpload: 'Invia al server',
9 button2Img: 'Vuoi trasformare il bottone immagine selezionato in un\'immagine semplice?',
10 hSpace: 'HSpace',
11 img2Button: 'Vuoi trasferomare l\'immagine selezionata in un bottone immagine?',
12 infoTab: 'Informazioni immagine',
13 linkTab: 'Collegamento',
14 lockRatio: 'Blocca rapporto',
15 menu: 'Proprietà immagine',
16 resetSize: 'Reimposta dimensione',
17 title: 'Proprietà immagine',
18 titleButton: 'Proprietà bottone immagine',
19 upload: 'Carica',
20 urlMissing: 'Manca l\'URL dell\'immagine.',
21 vSpace: 'VSpace',
22 validateBorder: 'Il campo Bordo deve essere un numero intero.',
23 validateHSpace: 'Il campo HSpace deve essere un numero intero.',
24 validateVSpace: 'Il campo VSpace deve essere un numero intero.'
25} );
diff --git a/sources/plugins/image/lang/ja.js b/sources/plugins/image/lang/ja.js
new file mode 100644
index 0000000..a2d500c
--- /dev/null
+++ b/sources/plugins/image/lang/ja.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ja', {
6 alt: '代替テキスト',
7 border: '枠線の幅',
8 btnUpload: 'サーバーに送信',
9 button2Img: '選択した画像ボタンを画像に変換しますか?',
10 hSpace: '水平間隔',
11 img2Button: '選択した画像を画像ボタンに変換しますか?',
12 infoTab: '画像情報',
13 linkTab: 'リンク',
14 lockRatio: '比率を固定',
15 menu: '画像のプロパティ',
16 resetSize: 'サイズをリセット',
17 title: '画像のプロパティ',
18 titleButton: '画像ボタンのプロパティ',
19 upload: 'アップロード',
20 urlMissing: '画像のURLを入力してください。',
21 vSpace: '垂直間隔',
22 validateBorder: '枠線の幅は数値で入力してください。',
23 validateHSpace: '水平間隔は数値で入力してください。',
24 validateVSpace: '垂直間隔は数値で入力してください。'
25} );
diff --git a/sources/plugins/image/lang/ka.js b/sources/plugins/image/lang/ka.js
new file mode 100644
index 0000000..0a634f0
--- /dev/null
+++ b/sources/plugins/image/lang/ka.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ka', {
6 alt: 'სანაცვლო ტექსტი',
7 border: 'ჩარჩო',
8 btnUpload: 'სერვერისთვის გაგზავნა',
9 button2Img: 'გსურთ არჩეული სურათიანი ღილაკის გადაქცევა ჩვეულებრივ ღილაკად?',
10 hSpace: 'ჰორიზონტალური სივრცე',
11 img2Button: 'გსურთ არჩეული ჩვეულებრივი ღილაკის გადაქცევა სურათიან ღილაკად?',
12 infoTab: 'სურათის ინფორმცია',
13 linkTab: 'ბმული',
14 lockRatio: 'პროპორციის შენარჩუნება',
15 menu: 'სურათის პარამეტრები',
16 resetSize: 'ზომის დაბრუნება',
17 title: 'სურათის პარამეტრები',
18 titleButton: 'სურათიანი ღილაკის პარამეტრები',
19 upload: 'ატვირთვა',
20 urlMissing: 'სურათის URL არაა შევსებული.',
21 vSpace: 'ვერტიკალური სივრცე',
22 validateBorder: 'ჩარჩო მთელი რიცხვი უნდა იყოს.',
23 validateHSpace: 'ჰორიზონტალური სივრცე მთელი რიცხვი უნდა იყოს.',
24 validateVSpace: 'ვერტიკალური სივრცე მთელი რიცხვი უნდა იყოს.'
25} );
diff --git a/sources/plugins/image/lang/km.js b/sources/plugins/image/lang/km.js
new file mode 100644
index 0000000..d60562a
--- /dev/null
+++ b/sources/plugins/image/lang/km.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'km', {
6 alt: 'អត្ថបទជំនួស',
7 border: 'ស៊ុម',
8 btnUpload: 'ផ្ញើ​ទៅ​ម៉ាស៊ីន​បម្រើ',
9 button2Img: 'តើ​អ្នក​ចង់​ផ្លាស់​ប្ដូរ​ប៊ូតុង​រូបភាព​ដែល​បាន​ជ្រើស នៅ​លើ​រូបភាព​ធម្មតា​មួយ​មែនទេ?',
10 hSpace: 'គម្លាត​ផ្ដេក',
11 img2Button: 'តើ​អ្នក​ចង់​ផ្លាស់​ប្ដូរ​រូបភាព​ដែល​បាន​ជ្រើស នៅ​លើ​ប៊ូតុង​រូបភាព​មែនទេ?',
12 infoTab: 'ពត៌មានអំពីរូបភាព',
13 linkTab: 'តំណ',
14 lockRatio: 'ចាក់​សោ​ផល​ធៀប',
15 menu: 'លក្ខណៈ​រូបភាព',
16 resetSize: 'កំណត់ទំហំឡើងវិញ',
17 title: 'លក្ខណៈ​រូបភាព',
18 titleButton: 'លក្ខណៈ​ប៊ូតុង​រូបភាព',
19 upload: 'ផ្ទុកឡើង',
20 urlMissing: 'ខ្វះ URL ប្រភព​រូប​ភាព។',
21 vSpace: 'គម្លាត​បញ្ឈរ',
22 validateBorder: 'ស៊ុម​ត្រូវ​តែ​ជា​លេខ។',
23 validateHSpace: 'គម្លាត​ផ្ដេក​ត្រូវ​តែ​ជា​លេខ។',
24 validateVSpace: 'គម្លាត​បញ្ឈរ​ត្រូវ​តែ​ជា​លេខ។'
25} );
diff --git a/sources/plugins/image/lang/ko.js b/sources/plugins/image/lang/ko.js
new file mode 100644
index 0000000..75e5252
--- /dev/null
+++ b/sources/plugins/image/lang/ko.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ko', {
6 alt: '대체 문자열',
7 border: '테두리',
8 btnUpload: '서버로 전송',
9 button2Img: '단순 이미지에서 선택한 이미지 버튼을 변환하시겠습니까?',
10 hSpace: '가로 여백',
11 img2Button: '이미지 버튼에 선택한 이미지를 변환하시겠습니까?',
12 infoTab: '이미지 정보',
13 linkTab: '링크',
14 lockRatio: '비율 유지',
15 menu: '이미지 속성',
16 resetSize: '원래 크기로',
17 title: '이미지 속성',
18 titleButton: '이미지 버튼 속성',
19 upload: '업로드',
20 urlMissing: '이미지 원본 주소(URL)가 없습니다.',
21 vSpace: '세로 여백',
22 validateBorder: '테두리 두께는 정수여야 합니다.',
23 validateHSpace: '가로 길이는 정수여야 합니다.',
24 validateVSpace: '세로 길이는 정수여야 합니다.'
25} );
diff --git a/sources/plugins/image/lang/ku.js b/sources/plugins/image/lang/ku.js
new file mode 100644
index 0000000..2b70145
--- /dev/null
+++ b/sources/plugins/image/lang/ku.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ku', {
6 alt: 'جێگرەوەی دەق',
7 border: 'پەراوێز',
8 btnUpload: 'ناردنی بۆ ڕاژه',
9 button2Img: 'تۆ دەتەوێت دوگمەی وێنەی دیاریکراو بگۆڕیت بۆ وێنەیەکی ئاسایی؟',
10 hSpace: 'بۆشایی ئاسۆیی',
11 img2Button: 'تۆ دەتەوێت وێنەی دیاریکراو بگۆڕیت بۆ دوگمەی وێنه؟',
12 infoTab: 'زانیاری وێنه',
13 linkTab: 'بەستەر',
14 lockRatio: 'داخستنی ڕێژه',
15 menu: 'خاسیەتی وێنه',
16 resetSize: 'ڕێکخستنەوەی قەباره',
17 title: 'خاسیەتی وێنه',
18 titleButton: 'خاسیەتی دوگمەی وێنه',
19 upload: 'بارکردن',
20 urlMissing: 'سەرچاوەی بەستەری وێنه بزره',
21 vSpace: 'بۆشایی ئەستونی',
22 validateBorder: 'پەراوێز دەبێت بەتەواوی تەنها ژماره بێت.',
23 validateHSpace: 'بۆشایی ئاسۆیی دەبێت بەتەواوی تەنها ژمارە بێت.',
24 validateVSpace: 'بۆشایی ئەستونی دەبێت بەتەواوی تەنها ژماره بێت.'
25} );
diff --git a/sources/plugins/image/lang/lt.js b/sources/plugins/image/lang/lt.js
new file mode 100644
index 0000000..2343934
--- /dev/null
+++ b/sources/plugins/image/lang/lt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'lt', {
6 alt: 'Alternatyvus Tekstas',
7 border: 'Rėmelis',
8 btnUpload: 'Siųsti į serverį',
9 button2Img: 'Ar norite mygtuką paversti paprastu paveiksliuku?',
10 hSpace: 'Hor.Erdvė',
11 img2Button: 'Ar norite paveiksliuką paversti mygtuku?',
12 infoTab: 'Vaizdo informacija',
13 linkTab: 'Nuoroda',
14 lockRatio: 'Išlaikyti proporciją',
15 menu: 'Vaizdo savybės',
16 resetSize: 'Atstatyti dydį',
17 title: 'Vaizdo savybės',
18 titleButton: 'Vaizdinio mygtuko savybės',
19 upload: 'Nusiųsti',
20 urlMissing: 'Paveiksliuko nuorodos nėra.',
21 vSpace: 'Vert.Erdvė',
22 validateBorder: 'Reikšmė turi būti sveikas skaičius.',
23 validateHSpace: 'Reikšmė turi būti sveikas skaičius.',
24 validateVSpace: 'Reikšmė turi būti sveikas skaičius.'
25} );
diff --git a/sources/plugins/image/lang/lv.js b/sources/plugins/image/lang/lv.js
new file mode 100644
index 0000000..cf20166
--- /dev/null
+++ b/sources/plugins/image/lang/lv.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'lv', {
6 alt: 'Alternatīvais teksts',
7 border: 'Rāmis',
8 btnUpload: 'Nosūtīt serverim',
9 button2Img: 'Vai vēlaties pārveidot izvēlēto attēla pogu uz attēla?',
10 hSpace: 'Horizontālā telpa',
11 img2Button: 'Vai vēlaties pārveidot izvēlēto attēlu uz attēla pogas?',
12 infoTab: 'Informācija par attēlu',
13 linkTab: 'Hipersaite',
14 lockRatio: 'Nemainīga Augstuma/Platuma attiecība',
15 menu: 'Attēla īpašības',
16 resetSize: 'Atjaunot sākotnējo izmēru',
17 title: 'Attēla īpašības',
18 titleButton: 'Attēlpogas īpašības',
19 upload: 'Augšupielādēt',
20 urlMissing: 'Trūkst attēla atrašanās adrese.',
21 vSpace: 'Vertikālā telpa',
22 validateBorder: 'Apmalei jābūt veselam skaitlim',
23 validateHSpace: 'HSpace jābūt veselam skaitlim',
24 validateVSpace: 'VSpace jābūt veselam skaitlim'
25} );
diff --git a/sources/plugins/image/lang/mk.js b/sources/plugins/image/lang/mk.js
new file mode 100644
index 0000000..9dd01cc
--- /dev/null
+++ b/sources/plugins/image/lang/mk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'mk', {
6 alt: 'Алтернативен текст',
7 border: 'Раб',
8 btnUpload: 'Прикачи на сервер',
9 button2Img: 'Дали сакате да направите сликата-копче да биде само слика?',
10 hSpace: 'Хоризонтален простор',
11 img2Button: 'Дали сакате да ја претворите сликата во слика-копче?',
12 infoTab: 'Информации за сликата',
13 linkTab: 'Врска',
14 lockRatio: 'Зачувај пропорција',
15 menu: 'Својства на сликата',
16 resetSize: 'Ресетирај големина',
17 title: 'Својства на сликата',
18 titleButton: 'Својства на копче-сликата',
19 upload: 'Прикачи',
20 urlMissing: 'Недостасува URL-то на сликата.',
21 vSpace: 'Вертикален простор',
22 validateBorder: 'Работ мора да биде цел број.',
23 validateHSpace: 'Хор. простор мора да биде цел број.',
24 validateVSpace: 'Верт. простор мора да биде цел број.'
25} );
diff --git a/sources/plugins/image/lang/mn.js b/sources/plugins/image/lang/mn.js
new file mode 100644
index 0000000..4daf38a
--- /dev/null
+++ b/sources/plugins/image/lang/mn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'mn', {
6 alt: 'Зургийг орлох бичвэр',
7 border: 'Хүрээ',
8 btnUpload: 'Үүнийг сервэррүү илгээ',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'Хөндлөн зай',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Зурагны мэдээлэл',
13 linkTab: 'Холбоос',
14 lockRatio: 'Радио түгжих',
15 menu: 'Зураг',
16 resetSize: 'хэмжээ дахин оноох',
17 title: 'Зураг',
18 titleButton: 'Зурган товчны шинж чанар',
19 upload: 'Хуулах',
20 urlMissing: 'Зургийн эх сурвалжийн хаяг (URL) байхгүй байна.',
21 vSpace: 'Босоо зай',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/ms.js b/sources/plugins/image/lang/ms.js
new file mode 100644
index 0000000..28511d0
--- /dev/null
+++ b/sources/plugins/image/lang/ms.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ms', {
6 alt: 'Text Alternatif',
7 border: 'Border',
8 btnUpload: 'Hantar ke Server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'Ruang Melintang',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Info Imej',
13 linkTab: 'Sambungan',
14 lockRatio: 'Tetapkan Nisbah',
15 menu: 'Ciri-ciri Imej',
16 resetSize: 'Saiz Set Semula',
17 title: 'Ciri-ciri Imej',
18 titleButton: 'Ciri-ciri Butang Bergambar',
19 upload: 'Muat Naik',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'Ruang Menegak',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/nb.js b/sources/plugins/image/lang/nb.js
new file mode 100644
index 0000000..87208af
--- /dev/null
+++ b/sources/plugins/image/lang/nb.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'nb', {
6 alt: 'Alternativ tekst',
7 border: 'Ramme',
8 btnUpload: 'Send det til serveren',
9 button2Img: 'Vil du endre den valgte bildeknappen til et vanlig bilde?',
10 hSpace: 'HMarg',
11 img2Button: 'Vil du endre det valgte bildet til en bildeknapp?',
12 infoTab: 'Bildeinformasjon',
13 linkTab: 'Lenke',
14 lockRatio: 'Lås forhold',
15 menu: 'Bildeegenskaper',
16 resetSize: 'Tilbakestill størrelse',
17 title: 'Bildeegenskaper',
18 titleButton: 'Egenskaper for bildeknapp',
19 upload: 'Last opp',
20 urlMissing: 'Bildets adresse mangler.',
21 vSpace: 'VMarg',
22 validateBorder: 'Ramme må være et heltall.',
23 validateHSpace: 'HMarg må være et heltall.',
24 validateVSpace: 'VMarg må være et heltall.'
25} );
diff --git a/sources/plugins/image/lang/nl.js b/sources/plugins/image/lang/nl.js
new file mode 100644
index 0000000..bbe4943
--- /dev/null
+++ b/sources/plugins/image/lang/nl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'nl', {
6 alt: 'Alternatieve tekst',
7 border: 'Rand',
8 btnUpload: 'Naar server verzenden',
9 button2Img: 'Wilt u de geselecteerde afbeeldingsknop vervangen door een eenvoudige afbeelding?',
10 hSpace: 'HSpace',
11 img2Button: 'Wilt u de geselecteerde afbeelding vervangen door een afbeeldingsknop?',
12 infoTab: 'Informatie afbeelding',
13 linkTab: 'Link',
14 lockRatio: 'Afmetingen vergrendelen',
15 menu: 'Eigenschappen afbeelding',
16 resetSize: 'Afmetingen resetten',
17 title: 'Eigenschappen afbeelding',
18 titleButton: 'Eigenschappen afbeeldingsknop',
19 upload: 'Upload',
20 urlMissing: 'De URL naar de afbeelding ontbreekt.',
21 vSpace: 'VSpace',
22 validateBorder: 'Rand moet een heel nummer zijn.',
23 validateHSpace: 'HSpace moet een heel nummer zijn.',
24 validateVSpace: 'VSpace moet een heel nummer zijn.'
25} );
diff --git a/sources/plugins/image/lang/no.js b/sources/plugins/image/lang/no.js
new file mode 100644
index 0000000..9d4898a
--- /dev/null
+++ b/sources/plugins/image/lang/no.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'no', {
6 alt: 'Alternativ tekst',
7 border: 'Ramme',
8 btnUpload: 'Send det til serveren',
9 button2Img: 'Vil du endre den valgte bildeknappen til et vanlig bilde?',
10 hSpace: 'HMarg',
11 img2Button: 'Vil du endre det valgte bildet til en bildeknapp?',
12 infoTab: 'Bildeinformasjon',
13 linkTab: 'Lenke',
14 lockRatio: 'Lås forhold',
15 menu: 'Bildeegenskaper',
16 resetSize: 'Tilbakestill størrelse',
17 title: 'Bildeegenskaper',
18 titleButton: 'Egenskaper for bildeknapp',
19 upload: 'Last opp',
20 urlMissing: 'Bildets adresse mangler.',
21 vSpace: 'VMarg',
22 validateBorder: 'Ramme må være et heltall.',
23 validateHSpace: 'HMarg må være et heltall.',
24 validateVSpace: 'VMarg må være et heltall.'
25} );
diff --git a/sources/plugins/image/lang/oc.js b/sources/plugins/image/lang/oc.js
new file mode 100644
index 0000000..fa595c6
--- /dev/null
+++ b/sources/plugins/image/lang/oc.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'oc', {
6 alt: 'Tèxte alternatiu',
7 border: 'Bordadura',
8 btnUpload: 'Mandar sul servidor',
9 button2Img: 'Volètz transformar lo boton amb imatge seleccionat en imatge simple ?',
10 hSpace: 'Espaçament orizontal',
11 img2Button: 'Volètz transformar l\'imatge seleccionat en boton amb imatge ?',
12 infoTab: 'Informacions sus l\'imatge',
13 linkTab: 'Ligam',
14 lockRatio: 'Conservar las proporcions',
15 menu: 'Proprietats de l\'imatge',
16 resetSize: 'Reïnicializar la talha',
17 title: 'Proprietats de l\'imatge',
18 titleButton: 'Proprietats del boton amb imatge',
19 upload: 'Mandar',
20 urlMissing: 'L\'URL font de l\'imatge es mancanta.',
21 vSpace: 'Espaçament vertical',
22 validateBorder: 'La bordadura deu èsser un nombre entièr.',
23 validateHSpace: 'L\'espaçament orizontal deu èsser un nombre entièr.',
24 validateVSpace: 'L\'espaçament vertical deu èsser un nombre entièr.'
25} );
diff --git a/sources/plugins/image/lang/pl.js b/sources/plugins/image/lang/pl.js
new file mode 100644
index 0000000..93afb85
--- /dev/null
+++ b/sources/plugins/image/lang/pl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'pl', {
6 alt: 'Tekst zastępczy',
7 border: 'Obramowanie',
8 btnUpload: 'Wyślij',
9 button2Img: 'Czy chcesz przekonwertować zaznaczony przycisk graficzny do zwykłego obrazka?',
10 hSpace: 'Odstęp poziomy',
11 img2Button: 'Czy chcesz przekonwertować zaznaczony obrazek do przycisku graficznego?',
12 infoTab: 'Informacje o obrazku',
13 linkTab: 'Hiperłącze',
14 lockRatio: 'Zablokuj proporcje',
15 menu: 'Właściwości obrazka',
16 resetSize: 'Przywróć rozmiar',
17 title: 'Właściwości obrazka',
18 titleButton: 'Właściwości przycisku graficznego',
19 upload: 'Wyślij',
20 urlMissing: 'Podaj adres URL obrazka.',
21 vSpace: 'Odstęp pionowy',
22 validateBorder: 'Wartość obramowania musi być liczbą całkowitą.',
23 validateHSpace: 'Wartość odstępu poziomego musi być liczbą całkowitą.',
24 validateVSpace: 'Wartość odstępu pionowego musi być liczbą całkowitą.'
25} );
diff --git a/sources/plugins/image/lang/pt-br.js b/sources/plugins/image/lang/pt-br.js
new file mode 100644
index 0000000..0d13a9a
--- /dev/null
+++ b/sources/plugins/image/lang/pt-br.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'pt-br', {
6 alt: 'Texto Alternativo',
7 border: 'Borda',
8 btnUpload: 'Enviar para o Servidor',
9 button2Img: 'Deseja transformar o botão de imagem em uma imagem comum?',
10 hSpace: 'HSpace',
11 img2Button: 'Deseja transformar a imagem em um botão de imagem?',
12 infoTab: 'Informações da Imagem',
13 linkTab: 'Link',
14 lockRatio: 'Travar Proporções',
15 menu: 'Formatar Imagem',
16 resetSize: 'Redefinir para o Tamanho Original',
17 title: 'Formatar Imagem',
18 titleButton: 'Formatar Botão de Imagem',
19 upload: 'Enviar',
20 urlMissing: 'URL da imagem está faltando.',
21 vSpace: 'VSpace',
22 validateBorder: 'A borda deve ser um número inteiro.',
23 validateHSpace: 'O HSpace deve ser um número inteiro.',
24 validateVSpace: 'O VSpace deve ser um número inteiro.'
25} );
diff --git a/sources/plugins/image/lang/pt.js b/sources/plugins/image/lang/pt.js
new file mode 100644
index 0000000..2b8f50c
--- /dev/null
+++ b/sources/plugins/image/lang/pt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'pt', {
6 alt: 'Texto alternativo',
7 border: 'Limite',
8 btnUpload: 'Enviar para o servidor',
9 button2Img: 'Deseja transformar o botão com imagem selecionado em uma imagem?',
10 hSpace: 'Esp. Horiz',
11 img2Button: 'Deseja transformar a imagem selecionada em um botão com imagem?',
12 infoTab: 'Informação da imagem',
13 linkTab: 'Hiperligação',
14 lockRatio: 'Proporcional',
15 menu: 'Propriedades da Imagem',
16 resetSize: 'Tamanho original',
17 title: 'Propriedades da imagem',
18 titleButton: 'Propriedades do botão de imagem',
19 upload: 'Carregar',
20 urlMissing: 'O URL da fonte da imagem está em falta.',
21 vSpace: 'Esp. Vert',
22 validateBorder: 'A borda tem de ser um numero.',
23 validateHSpace: 'HSpace tem de ser um numero.',
24 validateVSpace: 'VSpace tem de ser um numero.'
25} );
diff --git a/sources/plugins/image/lang/ro.js b/sources/plugins/image/lang/ro.js
new file mode 100644
index 0000000..067dee2
--- /dev/null
+++ b/sources/plugins/image/lang/ro.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ro', {
6 alt: 'Text alternativ',
7 border: 'Margine',
8 btnUpload: 'Trimite la server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Informaţii despre imagine',
13 linkTab: 'Link (Legătură web)',
14 lockRatio: 'Păstrează proporţiile',
15 menu: 'Proprietăţile imaginii',
16 resetSize: 'Resetează mărimea',
17 title: 'Proprietăţile imaginii',
18 titleButton: 'Proprietăţi buton imagine (Image Button)',
19 upload: 'Încarcă',
20 urlMissing: 'Sursa URL a imaginii lipsește.',
21 vSpace: 'VSpace',
22 validateBorder: 'Bordura trebuie să fie un număr întreg.',
23 validateHSpace: 'Hspace trebuie să fie un număr întreg.',
24 validateVSpace: 'Vspace trebuie să fie un număr întreg.'
25} );
diff --git a/sources/plugins/image/lang/ru.js b/sources/plugins/image/lang/ru.js
new file mode 100644
index 0000000..cb937c9
--- /dev/null
+++ b/sources/plugins/image/lang/ru.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ru', {
6 alt: 'Альтернативный текст',
7 border: 'Граница',
8 btnUpload: 'Загрузить на сервер',
9 button2Img: 'Вы желаете преобразовать это изображение-кнопку в обычное изображение?',
10 hSpace: 'Гориз. отступ',
11 img2Button: 'Вы желаете преобразовать это обычное изображение в изображение-кнопку?',
12 infoTab: 'Данные об изображении',
13 linkTab: 'Ссылка',
14 lockRatio: 'Сохранять пропорции',
15 menu: 'Свойства изображения',
16 resetSize: 'Вернуть обычные размеры',
17 title: 'Свойства изображения',
18 titleButton: 'Свойства изображения-кнопки',
19 upload: 'Загрузить',
20 urlMissing: 'Не указана ссылка на изображение.',
21 vSpace: 'Вертик. отступ',
22 validateBorder: 'Размер границ должен быть задан числом.',
23 validateHSpace: 'Горизонтальный отступ должен быть задан числом.',
24 validateVSpace: 'Вертикальный отступ должен быть задан числом.'
25} );
diff --git a/sources/plugins/image/lang/si.js b/sources/plugins/image/lang/si.js
new file mode 100644
index 0000000..84cbace
--- /dev/null
+++ b/sources/plugins/image/lang/si.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'si', {
6 alt: 'විකල්ප ',
7 border: 'සීමාවවල ',
8 btnUpload: 'සේවාදායකය වෙත යොමුකිරිම',
9 button2Img: 'ඔබට තෝරන ලද රුපය පරිවර්තනය කිරීමට අවශ්‍යද?',
10 hSpace: 'HSpace',
11 img2Button: 'ඔබට තෝරන ලද රුපය පරිවර්තනය කිරීමට අවශ්‍යද?',
12 infoTab: 'රුපයේ තොරතුරු',
13 linkTab: 'සබැඳිය',
14 lockRatio: 'නවතන අනුපාතය ',
15 menu: 'රුපයේ ගුණ',
16 resetSize: 'නැවතත් විශාලත්වය වෙනස් කිරීම',
17 title: 'රුපයේ ',
18 titleButton: 'රුප බොත්තමේ ගුණ',
19 upload: 'උඩුගතකිරීම',
20 urlMissing: 'රුප මුලාශ්‍ර URL නැත.',
21 vSpace: 'VSpace',
22 validateBorder: 'මාඉම් සම්පුර්ණ සංක්‍යාවක් විය යුතුය.',
23 validateHSpace: 'HSpace සම්පුර්ණ සංක්‍යාවක් විය යුතුය',
24 validateVSpace: 'VSpace සම්පුර්ණ සංක්‍යාවක් විය යුතුය.'
25} );
diff --git a/sources/plugins/image/lang/sk.js b/sources/plugins/image/lang/sk.js
new file mode 100644
index 0000000..38bc38a
--- /dev/null
+++ b/sources/plugins/image/lang/sk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sk', {
6 alt: 'Alternatívny text',
7 border: 'Rám (border)',
8 btnUpload: 'Odoslať to na server',
9 button2Img: 'Chcete zmeniť vybrané obrázkové tlačidlo na jednoduchý obrázok?',
10 hSpace: 'H-medzera',
11 img2Button: 'Chcete zmeniť vybraný obrázok na obrázkové tlačidlo?',
12 infoTab: 'Informácie o obrázku',
13 linkTab: 'Odkaz',
14 lockRatio: 'Pomer zámky',
15 menu: 'Vlastnosti obrázka',
16 resetSize: 'Pôvodná veľkosť',
17 title: 'Vlastnosti obrázka',
18 titleButton: 'Vlastnosti obrázkového tlačidla',
19 upload: 'Nahrať',
20 urlMissing: 'Chýba URL zdroja obrázka.',
21 vSpace: 'V-medzera',
22 validateBorder: 'Rám (border) musí byť celé číslo.',
23 validateHSpace: 'H-medzera musí byť celé číslo.',
24 validateVSpace: 'V-medzera musí byť celé číslo.'
25} );
diff --git a/sources/plugins/image/lang/sl.js b/sources/plugins/image/lang/sl.js
new file mode 100644
index 0000000..29c440f
--- /dev/null
+++ b/sources/plugins/image/lang/sl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sl', {
6 alt: 'Nadomestno besedilo',
7 border: 'Obroba',
8 btnUpload: 'Pošlji na strežnik',
9 button2Img: 'Želite pretvoriti izbrani gumb s sliko v preprosto sliko?',
10 hSpace: 'Vodoravni odmik',
11 img2Button: 'Želite pretvoriti izbrano sliko v gumb s sliko?',
12 infoTab: 'Podatki o sliki',
13 linkTab: 'Povezava',
14 lockRatio: 'Zakleni razmerje',
15 menu: 'Lastnosti slike',
16 resetSize: 'Ponastavi velikost',
17 title: 'Lastnosti slike',
18 titleButton: 'Lastnosti gumba s sliko',
19 upload: 'Naloži',
20 urlMissing: 'Manjka URL vira slike.',
21 vSpace: 'Navpični odmik',
22 validateBorder: 'Meja mora biti celo število.',
23 validateHSpace: 'Vodoravni odmik mora biti celo število.',
24 validateVSpace: 'VSpace mora biti celo število.'
25} );
diff --git a/sources/plugins/image/lang/sq.js b/sources/plugins/image/lang/sq.js
new file mode 100644
index 0000000..072a96d
--- /dev/null
+++ b/sources/plugins/image/lang/sq.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sq', {
6 alt: 'Tekst Alternativ',
7 border: 'Korniza',
8 btnUpload: 'Dërgo në server',
9 button2Img: 'Dëshironi të e ndërroni pullën e fotos së selektuar në një foto të thjeshtë?',
10 hSpace: 'HSpace',
11 img2Button: 'Dëshironi të ndryshoni foton e përzgjedhur në pullë?',
12 infoTab: 'Informacione mbi Fotografinë',
13 linkTab: 'Nyja',
14 lockRatio: 'Mbyll Racionin',
15 menu: 'Karakteristikat e Fotografisë',
16 resetSize: 'Rikthe Madhësinë',
17 title: 'Karakteristikat e Fotografisë',
18 titleButton: 'Karakteristikat e Pullës së Fotografisë',
19 upload: 'Ngarko',
20 urlMissing: 'Mungon URL e burimit të fotografisë.',
21 vSpace: 'Hapësira Vertikale',
22 validateBorder: 'Korniza duhet të jetë numër i plotë.',
23 validateHSpace: 'Hapësira horizontale duhet të jetë numër i plotë.',
24 validateVSpace: 'Hapësira vertikale duhet të jetë numër i plotë.'
25} );
diff --git a/sources/plugins/image/lang/sr-latn.js b/sources/plugins/image/lang/sr-latn.js
new file mode 100644
index 0000000..b3c2a98
--- /dev/null
+++ b/sources/plugins/image/lang/sr-latn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sr-latn', {
6 alt: 'Alternativni tekst',
7 border: 'Okvir',
8 btnUpload: 'Pošalji na server',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'HSpace',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Info slike',
13 linkTab: 'Link',
14 lockRatio: 'Zaključaj odnos',
15 menu: 'Osobine slika',
16 resetSize: 'Resetuj veličinu',
17 title: 'Osobine slika',
18 titleButton: 'Osobine dugmeta sa slikom',
19 upload: 'Pošalji',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'VSpace',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/sr.js b/sources/plugins/image/lang/sr.js
new file mode 100644
index 0000000..4a269d9
--- /dev/null
+++ b/sources/plugins/image/lang/sr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sr', {
6 alt: 'Алтернативни текст',
7 border: 'Оквир',
8 btnUpload: 'Пошаљи на сервер',
9 button2Img: 'Да ли желите да промените одабрану слику дугмета као једноставну слику?',
10 hSpace: 'HSpace',
11 img2Button: 'Да ли желите да промените одабрану слику у слику дугмета?',
12 infoTab: 'Инфо слике',
13 linkTab: 'Линк',
14 lockRatio: 'Закључај однос',
15 menu: 'Особине слика',
16 resetSize: 'Ресетуј величину',
17 title: 'Особине слика',
18 titleButton: 'Особине дугмета са сликом',
19 upload: 'Пошаљи',
20 urlMissing: 'Недостаје УРЛ слике.',
21 vSpace: 'VSpace',
22 validateBorder: 'Ивица треба да буде цифра.',
23 validateHSpace: 'HSpace треба да буде цифра.',
24 validateVSpace: 'VSpace треба да буде цифра.'
25} );
diff --git a/sources/plugins/image/lang/sv.js b/sources/plugins/image/lang/sv.js
new file mode 100644
index 0000000..db07c37
--- /dev/null
+++ b/sources/plugins/image/lang/sv.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'sv', {
6 alt: 'Alternativ text',
7 border: 'Kant',
8 btnUpload: 'Skicka till server',
9 button2Img: 'Vill du omvandla den valda bildknappen på en enkel bild?',
10 hSpace: 'Horis. marginal',
11 img2Button: 'Vill du omvandla den valda bildknappen på en enkel bild?',
12 infoTab: 'Bildinformation',
13 linkTab: 'Länk',
14 lockRatio: 'Lås höjd/bredd förhållanden',
15 menu: 'Bildegenskaper',
16 resetSize: 'Återställ storlek',
17 title: 'Bildegenskaper',
18 titleButton: 'Egenskaper för bildknapp',
19 upload: 'Ladda upp',
20 urlMissing: 'Bildkällans URL saknas.',
21 vSpace: 'Vert. marginal',
22 validateBorder: 'Kantlinje måste vara ett heltal.',
23 validateHSpace: 'HSpace måste vara ett heltal.',
24 validateVSpace: 'VSpace måste vara ett heltal.'
25} );
diff --git a/sources/plugins/image/lang/th.js b/sources/plugins/image/lang/th.js
new file mode 100644
index 0000000..0d33bb3
--- /dev/null
+++ b/sources/plugins/image/lang/th.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'th', {
6 alt: 'คำประกอบรูปภาพ',
7 border: 'ขนาดขอบรูป',
8 btnUpload: 'อัพโหลดไฟล์ไปเก็บไว้ที่เครื่องแม่ข่าย (เซิร์ฟเวอร์)',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'ระยะแนวนอน',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'ข้อมูลของรูปภาพ',
13 linkTab: 'ลิ้งค์',
14 lockRatio: 'กำหนดอัตราส่วน กว้าง-สูง แบบคงที่',
15 menu: 'คุณสมบัติของ รูปภาพ',
16 resetSize: 'กำหนดรูปเท่าขนาดจริง',
17 title: 'คุณสมบัติของ รูปภาพ',
18 titleButton: 'คุณสมบัติของ ปุ่มแบบรูปภาพ',
19 upload: 'อัพโหลดไฟล์',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'ระยะแนวตั้ง',
22 validateBorder: 'Border must be a whole number.', // MISSING
23 validateHSpace: 'HSpace must be a whole number.', // MISSING
24 validateVSpace: 'VSpace must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/image/lang/tr.js b/sources/plugins/image/lang/tr.js
new file mode 100644
index 0000000..2f707a1
--- /dev/null
+++ b/sources/plugins/image/lang/tr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'tr', {
6 alt: 'Alternatif Yazı',
7 border: 'Kenar',
8 btnUpload: 'Sunucuya Yolla',
9 button2Img: 'Seçili resim butonunu basit resime çevirmek istermisiniz?',
10 hSpace: 'Yatay Boşluk',
11 img2Button: 'Seçili olan resimi, resimli butona çevirmek istermisiniz?',
12 infoTab: 'Resim Bilgisi',
13 linkTab: 'Köprü',
14 lockRatio: 'Oranı Kilitle',
15 menu: 'Resim Özellikleri',
16 resetSize: 'Boyutu Başa Döndür',
17 title: 'Resim Özellikleri',
18 titleButton: 'Resimli Düğme Özellikleri',
19 upload: 'Karşıya Yükle',
20 urlMissing: 'Resmin URL kaynağı eksiktir.',
21 vSpace: 'Dikey Boşluk',
22 validateBorder: 'Çerçeve tam sayı olmalıdır.',
23 validateHSpace: 'HSpace tam sayı olmalıdır.',
24 validateVSpace: 'VSpace tam sayı olmalıdır.'
25} );
diff --git a/sources/plugins/image/lang/tt.js b/sources/plugins/image/lang/tt.js
new file mode 100644
index 0000000..e659066
--- /dev/null
+++ b/sources/plugins/image/lang/tt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'tt', {
6 alt: 'Альтернатив текст',
7 border: 'Чик',
8 btnUpload: 'Серверга җибәрү',
9 button2Img: 'Do you want to transform the selected image button on a simple image?', // MISSING
10 hSpace: 'Горизонталь ара',
11 img2Button: 'Do you want to transform the selected image on a image button?', // MISSING
12 infoTab: 'Рәсем тасвирламасы',
13 linkTab: 'Сылталама',
14 lockRatio: 'Lock Ratio', // MISSING
15 menu: 'Рәсем үзлекләре',
16 resetSize: 'Баштагы зурлык',
17 title: 'Рәсем үзлекләре',
18 titleButton: 'Рәсемле төймə үзлекләре',
19 upload: 'Йөкләү',
20 urlMissing: 'Image source URL is missing.', // MISSING
21 vSpace: 'Вертикаль ара',
22 validateBorder: 'Чик киңлеге сан булырга тиеш.',
23 validateHSpace: 'Горизонталь ара бөтен сан булырга тиеш.',
24 validateVSpace: 'Вертикаль ара бөтен сан булырга тиеш.'
25} );
diff --git a/sources/plugins/image/lang/ug.js b/sources/plugins/image/lang/ug.js
new file mode 100644
index 0000000..d2a28ef
--- /dev/null
+++ b/sources/plugins/image/lang/ug.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'ug', {
6 alt: 'تېكىست ئالماشتۇر',
7 border: 'گىرۋەك چوڭلۇقى',
8 btnUpload: 'مۇلازىمېتىرغا يۈكلە',
9 button2Img: 'نۆۋەتتىكى توپچىنى سۈرەتكە ئۆزگەرتەمسىز؟',
10 hSpace: 'توغرىسىغا ئارىلىقى',
11 img2Button: 'نۆۋەتتىكى سۈرەتنى توپچىغا ئۆزگەرتەمسىز؟',
12 infoTab: 'سۈرەت',
13 linkTab: 'ئۇلانما',
14 lockRatio: 'نىسبەتنى قۇلۇپلا',
15 menu: 'سۈرەت خاسلىقى',
16 resetSize: 'ئەسلى چوڭلۇق',
17 title: 'سۈرەت خاسلىقى',
18 titleButton: 'سۈرەت دائىرە خاسلىقى',
19 upload: 'يۈكلە',
20 urlMissing: 'سۈرەتنىڭ ئەسلى ھۆججەت ئادرېسى كەم',
21 vSpace: 'بويىغا ئارىلىقى',
22 validateBorder: 'گىرۋەك چوڭلۇقى چوقۇم سان بولىدۇ',
23 validateHSpace: 'توغرىسىغا ئارىلىق چوقۇم پۈتۈن سان بولىدۇ',
24 validateVSpace: 'بويىغا ئارىلىق چوقۇم پۈتۈن سان بولىدۇ'
25} );
diff --git a/sources/plugins/image/lang/uk.js b/sources/plugins/image/lang/uk.js
new file mode 100644
index 0000000..ace2eea
--- /dev/null
+++ b/sources/plugins/image/lang/uk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'uk', {
6 alt: 'Альтернативний текст',
7 border: 'Рамка',
8 btnUpload: 'Надіслати на сервер',
9 button2Img: 'Бажаєте перетворити обрану кнопку-зображення на просте зображення?',
10 hSpace: 'Гориз. відступ',
11 img2Button: 'Бажаєте перетворити обране зображення на кнопку-зображення?',
12 infoTab: 'Інформація про зображення',
13 linkTab: 'Посилання',
14 lockRatio: 'Зберегти пропорції',
15 menu: 'Властивості зображення',
16 resetSize: 'Очистити поля розмірів',
17 title: 'Властивості зображення',
18 titleButton: 'Властивості кнопки із зображенням',
19 upload: 'Надіслати',
20 urlMissing: 'Вкажіть URL зображення.',
21 vSpace: 'Верт. відступ',
22 validateBorder: 'Ширина рамки повинна бути цілим числом.',
23 validateHSpace: 'Гориз. відступ повинен бути цілим числом.',
24 validateVSpace: 'Верт. відступ повинен бути цілим числом.'
25} );
diff --git a/sources/plugins/image/lang/vi.js b/sources/plugins/image/lang/vi.js
new file mode 100644
index 0000000..4c33fd5
--- /dev/null
+++ b/sources/plugins/image/lang/vi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'vi', {
6 alt: 'Chú thích ảnh',
7 border: 'Đường viền',
8 btnUpload: 'Tải lên máy chủ',
9 button2Img: 'Bạn có muốn chuyển nút bấm bằng ảnh được chọn thành ảnh?',
10 hSpace: 'Khoảng đệm ngang',
11 img2Button: 'Bạn có muốn chuyển đổi ảnh được chọn thành nút bấm bằng ảnh?',
12 infoTab: 'Thông tin của ảnh',
13 linkTab: 'Tab liên kết',
14 lockRatio: 'Giữ nguyên tỷ lệ',
15 menu: 'Thuộc tính của ảnh',
16 resetSize: 'Kích thước gốc',
17 title: 'Thuộc tính của ảnh',
18 titleButton: 'Thuộc tính nút của ảnh',
19 upload: 'Tải lên',
20 urlMissing: 'Thiếu đường dẫn hình ảnh',
21 vSpace: 'Khoảng đệm dọc',
22 validateBorder: 'Chiều rộng của đường viền phải là một số nguyên dương',
23 validateHSpace: 'Khoảng đệm ngang phải là một số nguyên dương',
24 validateVSpace: 'Khoảng đệm dọc phải là một số nguyên dương'
25} );
diff --git a/sources/plugins/image/lang/zh-cn.js b/sources/plugins/image/lang/zh-cn.js
new file mode 100644
index 0000000..287a362
--- /dev/null
+++ b/sources/plugins/image/lang/zh-cn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'zh-cn', {
6 alt: '替换文本',
7 border: '边框大小',
8 btnUpload: '上传到服务器',
9 button2Img: '确定要把当前图像按钮转换为普通图像吗?',
10 hSpace: '水平间距',
11 img2Button: '确定要把当前图像改变为图像按钮吗?',
12 infoTab: '图像信息',
13 linkTab: '链接',
14 lockRatio: '锁定比例',
15 menu: '图像属性',
16 resetSize: '原始尺寸',
17 title: '图像属性',
18 titleButton: '图像域属性',
19 upload: '上传',
20 urlMissing: '缺少图像源文件地址',
21 vSpace: '垂直间距',
22 validateBorder: '边框大小必须为整数格式',
23 validateHSpace: '水平间距必须为整数格式',
24 validateVSpace: '垂直间距必须为整数格式'
25} );
diff --git a/sources/plugins/image/lang/zh.js b/sources/plugins/image/lang/zh.js
new file mode 100644
index 0000000..920b554
--- /dev/null
+++ b/sources/plugins/image/lang/zh.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'image', 'zh', {
6 alt: '替代文字',
7 border: '框線',
8 btnUpload: '傳送到伺服器',
9 button2Img: '請問您確定要將「圖片按鈕」轉換成「圖片」嗎?',
10 hSpace: 'HSpace',
11 img2Button: '請問您確定要將「圖片」轉換成「圖片按鈕」嗎?',
12 infoTab: '影像資訊',
13 linkTab: '連結',
14 lockRatio: '固定比例',
15 menu: '影像屬性',
16 resetSize: '重設大小',
17 title: '影像屬性',
18 titleButton: '影像按鈕屬性',
19 upload: '上傳',
20 urlMissing: '遺失圖片來源之 URL ',
21 vSpace: 'VSpace',
22 validateBorder: '框線必須是整數。',
23 validateHSpace: 'HSpace 必須是整數。',
24 validateVSpace: 'VSpace 必須是整數。'
25} );
diff --git a/sources/plugins/image/plugin.js b/sources/plugins/image/plugin.js
new file mode 100644
index 0000000..1394510
--- /dev/null
+++ b/sources/plugins/image/plugin.js
@@ -0,0 +1,183 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The Image plugin.
8 */
9
10( function() {
11
12 CKEDITOR.plugins.add( 'image', {
13 requires: 'dialog',
14 // jscs:disable maximumLineLength
15 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
16 // jscs:enable maximumLineLength
17 icons: 'image', // %REMOVE_LINE_CORE%
18 hidpi: true, // %REMOVE_LINE_CORE%
19 init: function( editor ) {
20 // Abort when Image2 is to be loaded since both plugins
21 // share the same button, command, etc. names (#11222).
22 if ( editor.plugins.image2 )
23 return;
24
25 var pluginName = 'image';
26
27 // Register the dialog.
28 CKEDITOR.dialog.add( pluginName, this.path + 'dialogs/image.js' );
29
30 var allowed = 'img[alt,!src]{border-style,border-width,float,height,margin,margin-bottom,margin-left,margin-right,margin-top,width}',
31 required = 'img[alt,src]';
32
33 if ( CKEDITOR.dialog.isTabEnabled( editor, pluginName, 'advanced' ) )
34 allowed = 'img[alt,dir,id,lang,longdesc,!src,title]{*}(*)';
35
36 // Register the command.
37 editor.addCommand( pluginName, new CKEDITOR.dialogCommand( pluginName, {
38 allowedContent: allowed,
39 requiredContent: required,
40 contentTransformations: [
41 [ 'img{width}: sizeToStyle', 'img[width]: sizeToAttribute' ],
42 [ 'img{float}: alignmentToStyle', 'img[align]: alignmentToAttribute' ]
43 ]
44 } ) );
45
46 // Register the toolbar button.
47 editor.ui.addButton && editor.ui.addButton( 'Image', {
48 label: editor.lang.common.image,
49 command: pluginName,
50 toolbar: 'insert,10'
51 } );
52
53 editor.on( 'doubleclick', function( evt ) {
54 var element = evt.data.element;
55
56 if ( element.is( 'img' ) && !element.data( 'cke-realelement' ) && !element.isReadOnly() )
57 evt.data.dialog = 'image';
58 } );
59
60 // If the "menu" plugin is loaded, register the menu items.
61 if ( editor.addMenuItems ) {
62 editor.addMenuItems( {
63 image: {
64 label: editor.lang.image.menu,
65 command: 'image',
66 group: 'image'
67 }
68 } );
69 }
70
71 // If the "contextmenu" plugin is loaded, register the listeners.
72 if ( editor.contextMenu ) {
73 editor.contextMenu.addListener( function( element ) {
74 if ( getSelectedImage( editor, element ) )
75 return { image: CKEDITOR.TRISTATE_OFF };
76 } );
77 }
78 },
79 afterInit: function( editor ) {
80 // Abort when Image2 is to be loaded since both plugins
81 // share the same button, command, etc. names (#11222).
82 if ( editor.plugins.image2 )
83 return;
84
85 // Customize the behavior of the alignment commands. (#7430)
86 setupAlignCommand( 'left' );
87 setupAlignCommand( 'right' );
88 setupAlignCommand( 'center' );
89 setupAlignCommand( 'block' );
90
91 function setupAlignCommand( value ) {
92 var command = editor.getCommand( 'justify' + value );
93 if ( command ) {
94 if ( value == 'left' || value == 'right' ) {
95 command.on( 'exec', function( evt ) {
96 var img = getSelectedImage( editor ),
97 align;
98 if ( img ) {
99 align = getImageAlignment( img );
100 if ( align == value ) {
101 img.removeStyle( 'float' );
102
103 // Remove "align" attribute when necessary.
104 if ( value == getImageAlignment( img ) )
105 img.removeAttribute( 'align' );
106 } else {
107 img.setStyle( 'float', value );
108 }
109
110 evt.cancel();
111 }
112 } );
113 }
114
115 command.on( 'refresh', function( evt ) {
116 var img = getSelectedImage( editor ),
117 align;
118 if ( img ) {
119 align = getImageAlignment( img );
120
121 this.setState(
122 ( align == value ) ? CKEDITOR.TRISTATE_ON : ( value == 'right' || value == 'left' ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
123
124 evt.cancel();
125 }
126 } );
127 }
128 }
129 }
130 } );
131
132 function getSelectedImage( editor, element ) {
133 if ( !element ) {
134 var sel = editor.getSelection();
135 element = sel.getSelectedElement();
136 }
137
138 if ( element && element.is( 'img' ) && !element.data( 'cke-realelement' ) && !element.isReadOnly() )
139 return element;
140 }
141
142 function getImageAlignment( element ) {
143 var align = element.getStyle( 'float' );
144
145 if ( align == 'inherit' || align == 'none' )
146 align = 0;
147
148 if ( !align )
149 align = element.getAttribute( 'align' );
150
151 return align;
152 }
153
154} )();
155
156/**
157 * Determines whether dimension inputs should be automatically filled when the image URL changes in the Image plugin dialog window.
158 *
159 * config.image_prefillDimensions = false;
160 *
161 * @since 4.5
162 * @cfg {Boolean} [image_prefillDimensions=true]
163 * @member CKEDITOR.config
164 */
165
166/**
167 * Whether to remove links when emptying the link URL field in the Image dialog window.
168 *
169 * config.image_removeLinkByEmptyURL = false;
170 *
171 * @cfg {Boolean} [image_removeLinkByEmptyURL=true]
172 * @member CKEDITOR.config
173 */
174CKEDITOR.config.image_removeLinkByEmptyURL = true;
175
176/**
177 * Padding text to set off the image in the preview area.
178 *
179 * config.image_previewText = CKEDITOR.tools.repeat( '___ ', 100 );
180 *
181 * @cfg {String} [image_previewText='Lorem ipsum dolor...' (placeholder text)]
182 * @member CKEDITOR.config
183 */
diff --git a/sources/plugins/indent/dev/indent.html b/sources/plugins/indent/dev/indent.html
new file mode 100644
index 0000000..8b935ae
--- /dev/null
+++ b/sources/plugins/indent/dev/indent.html
@@ -0,0 +1,284 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Indent DEV sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <style>
12 body {
13 padding: 20px;
14 margin: 0;
15 }
16 .editors {
17 display: block;
18 overflow: hidden;
19 width: 100%;
20 margin: 0px auto;
21 list-style-type: none;
22 margin: 0;
23 padding: 0;
24
25 box-sizing: content-box;
26
27 background: #eee;
28 }
29 .editors li {
30 width: 50%;
31 margin: 0;
32 padding: 10px;
33 float: left;
34
35 box-sizing: border-box;
36 }
37 .editors li:nth-child(2n) {
38 background: #D4E59A;
39 }
40 #menu {
41 position: fixed;
42 top: 0;
43 right: 20px;
44 padding: 5px;
45 border: 1px solid #aaa;
46 background: #eee;
47 }
48
49 </style>
50</head>
51<body>
52 <p id="menu">
53 <a href="#listnblock">List &amp; Block</a>,
54 <a href="#classes">Classes</a>,
55 <a href="#list">List</a>,
56 <a href="#block">Block</a>,
57 <a href="#br">ENTER_BR</a>
58 </p>
59
60 <h1 class="samples">Indent DEV sample</h1>
61 <h2 id="listnblock">List &amp; Block</h2>
62 <ul class="editors">
63 <li>
64 <textarea cols="80" id="editor1" rows="10">
65 <p>xx</p>
66 <ul>
67 <li>x</li>
68 <li>y</li>
69 </ul>
70 <p>xx</p>
71
72 <br>
73
74 <ul><li><ol><li>xx</li></ol></li><li>yy</li></ul>
75 </textarea>
76 </li>
77 <li>
78 <pre id="editor1_out"></pre>
79 </li>
80 </ul>
81
82 <h2 id="classes">Indent classes</h2>
83 <ul class="editors">
84 <li>
85 <textarea cols="80" id="editor2" rows="10">
86 <ul>
87 <li>a</li>
88 <li>
89 b
90 <ol>
91 <li>inner</li>
92 </ol>
93 </li>
94 <li>c</li>
95 </ul>
96 <p>moo</p>
97 </textarea>
98 </li>
99 <li>
100 <pre id="editor2_out"></pre>
101 </li>
102 </ul>
103
104 <h2 id="list">List only</h2>
105 <ul class="editors">
106 <li>
107 <textarea cols="80" id="editor3" rows="10">
108 <ul>
109 <li>a</li>
110 <li>
111 b
112 <ol>
113 <li>inner</li>
114 </ol>
115 </li>
116 <li>c</li>
117 </ul>
118 <p>moo</p>
119 </textarea>
120 </li>
121 <li>
122 <pre id="editor3_out"></pre>
123 </li>
124 </ul>
125
126 <h2 id="block">Block only</h2>
127 <ul class="editors">
128 <li>
129 <textarea cols="80" id="editor4" rows="10">
130 <ul>
131 <li>a</li>
132 <li>
133 b
134 <ol>
135 <li>inner</li>
136 </ol>
137 </li>
138 <li>c</li>
139 </ul>
140 <p>moo</p>
141 </textarea>
142 </li>
143 <li>
144 <pre id="editor4_out"></pre>
145 </li>
146 </ul>
147
148 <h2 id="br">CKEDITOR.ENTER_BR</h2>
149 <ul class="editors">
150 <li>
151 <textarea cols="80" id="editor5" rows="10">
152 Text
153 <br>
154 <ul>
155 <li>a</li>
156 <li>b</li>
157 </ul>
158 </textarea>
159 </li>
160 <li>
161 <pre id="editor5_out"></pre>
162 </li>
163 </ul>
164 <script>
165
166 var plugins = 'enterkey,toolbar,htmlwriter,wysiwygarea,undo,sourcearea,clipboard,list,justify,indent,indentlist,indentblock';
167
168 CKEDITOR.config.indentOffset = 10;
169 CKEDITOR.addCss( '\
170 .i1{ margin-left: 10px}\
171 .i2{ margin-left: 20px}\
172 .i3{ margin-left: 30px}' );
173
174 function showData( event ) {
175 CKEDITOR.document.getById( this.name + '_out' ).setText( getHtmlWithSelection( this ) );
176 }
177
178 function browserHtmlFix( html ) {
179 if ( CKEDITOR.env.ie && ( document.documentMode || CKEDITOR.env.version ) < 9 ) {
180 // Fix output base href on anchored link.
181 html = html.replace( /href="(.*?)#(.*?)"/gi,
182 function( m, base, anchor ) {
183 if ( base == window.location.href.replace( window.location.hash, '' ) )
184 return 'href="#' + anchor + '"';
185
186 return m;
187 } );
188
189 // Fix output line break after HR.
190 html = html.replace( /(<HR>)\r\n/gi, function( m, hr ) { return hr; } );
191 }
192
193 return html;
194 }
195
196 function getHtmlWithSelection( editorOrElement, root ) {
197 var isEditor = editorOrElement instanceof CKEDITOR.editor,
198 element = isEditor ? editorOrElement.editable() : editorOrElement;
199
200 root = isEditor ? element :
201 root instanceof CKEDITOR.dom.document ?
202 root.getBody() : root || CKEDITOR.document.getBody();
203
204 function replaceWithBookmark( match, startOrEnd ) {
205 var bookmark;
206 switch( startOrEnd ) {
207 case 'S' :
208 bookmark = '[';
209 break;
210 case 'E' :
211 bookmark = ']';
212 break;
213 case 'C' :
214 bookmark = '^';
215 break;
216 }
217 return bookmark;
218 }
219
220 // Hack: force remove the filling char hack in Webkit.
221 isEditor && CKEDITOR.env.webkit && editorOrElement.fire( 'beforeSetMode' );
222
223 var sel = isEditor ? editorOrElement.getSelection()
224 : new CKEDITOR.dom.selection( root );
225
226 var doc = sel.document;
227 var ranges = sel.getRanges(),
228 range;
229
230 var bms = [];
231 var iter = ranges.createIterator();
232 while( range = iter.getNextRange() )
233 bms.push( range.createBookmark( 1 ) );
234
235 var html = browserHtmlFix( isEditor ? editorOrElement.getData() : element.getHtml() );
236 html = html.replace( /<span\b[^>]*?id="?cke_bm_\d+(\w)"?\b[^>]*?>.*?<\/span>/gi,
237 replaceWithBookmark );
238
239 for ( var i = 0, bm; i < bms.length; i++ ) {
240 bm = bms[ i ];
241 var start = doc.getById( bm.startNode ),
242 end = doc.getById( bm.endNode );
243
244 start && start.remove();
245 end && end.remove();
246 }
247
248 return html;
249 }
250
251 CKEDITOR.on( 'instanceReady', function ( event ) {
252 var editor = event.editor;
253
254 showData.call( editor );
255
256 editor.on( 'afterCommandExec', showData, editor );
257 });
258
259 CKEDITOR.replace( 'editor1', {
260 plugins: plugins
261 } );
262
263 CKEDITOR.replace( 'editor2', {
264 plugins: plugins,
265 indentClasses: [ 'i1', 'i2', 'i3' ]
266 } );
267
268 CKEDITOR.replace( 'editor3', {
269 plugins: plugins,
270 removePlugins: 'indentblock'
271 } );
272
273 CKEDITOR.replace( 'editor4', {
274 plugins: plugins,
275 removePlugins: 'indentlist'
276 } );
277
278 CKEDITOR.replace( 'editor5', {
279 plugins: plugins,
280 enterMode: CKEDITOR.ENTER_BR
281 } );
282 </script>
283</body>
284</html>
diff --git a/sources/plugins/indent/icons/hidpi/indent-rtl.png b/sources/plugins/indent/icons/hidpi/indent-rtl.png
new file mode 100644
index 0000000..72bf567
--- /dev/null
+++ b/sources/plugins/indent/icons/hidpi/indent-rtl.png
Binary files differ
diff --git a/sources/plugins/indent/icons/hidpi/indent.png b/sources/plugins/indent/icons/hidpi/indent.png
new file mode 100644
index 0000000..6381b23
--- /dev/null
+++ b/sources/plugins/indent/icons/hidpi/indent.png
Binary files differ
diff --git a/sources/plugins/indent/icons/hidpi/outdent-rtl.png b/sources/plugins/indent/icons/hidpi/outdent-rtl.png
new file mode 100644
index 0000000..441e204
--- /dev/null
+++ b/sources/plugins/indent/icons/hidpi/outdent-rtl.png
Binary files differ
diff --git a/sources/plugins/indent/icons/hidpi/outdent.png b/sources/plugins/indent/icons/hidpi/outdent.png
new file mode 100644
index 0000000..8fa4e5e
--- /dev/null
+++ b/sources/plugins/indent/icons/hidpi/outdent.png
Binary files differ
diff --git a/sources/plugins/indent/icons/indent-rtl.png b/sources/plugins/indent/icons/indent-rtl.png
new file mode 100644
index 0000000..0327578
--- /dev/null
+++ b/sources/plugins/indent/icons/indent-rtl.png
Binary files differ
diff --git a/sources/plugins/indent/icons/indent.png b/sources/plugins/indent/icons/indent.png
new file mode 100644
index 0000000..0a5d293
--- /dev/null
+++ b/sources/plugins/indent/icons/indent.png
Binary files differ
diff --git a/sources/plugins/indent/icons/outdent-rtl.png b/sources/plugins/indent/icons/outdent-rtl.png
new file mode 100644
index 0000000..ce9ce08
--- /dev/null
+++ b/sources/plugins/indent/icons/outdent-rtl.png
Binary files differ
diff --git a/sources/plugins/indent/icons/outdent.png b/sources/plugins/indent/icons/outdent.png
new file mode 100644
index 0000000..351f05d
--- /dev/null
+++ b/sources/plugins/indent/icons/outdent.png
Binary files differ
diff --git a/sources/plugins/indent/lang/af.js b/sources/plugins/indent/lang/af.js
new file mode 100644
index 0000000..14fff63
--- /dev/null
+++ b/sources/plugins/indent/lang/af.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'af', {
6 indent: 'Vergroot inspring',
7 outdent: 'Verklein inspring'
8} );
diff --git a/sources/plugins/indent/lang/ar.js b/sources/plugins/indent/lang/ar.js
new file mode 100644
index 0000000..fe078cb
--- /dev/null
+++ b/sources/plugins/indent/lang/ar.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ar', {
6 indent: 'زيادة المسافة البادئة',
7 outdent: 'إنقاص المسافة البادئة'
8} );
diff --git a/sources/plugins/indent/lang/az.js b/sources/plugins/indent/lang/az.js
new file mode 100644
index 0000000..389d1d9
--- /dev/null
+++ b/sources/plugins/indent/lang/az.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'az', {
6 indent: 'Sol boşluqu artır',
7 outdent: 'Sol boşluqu azalt'
8} );
diff --git a/sources/plugins/indent/lang/bg.js b/sources/plugins/indent/lang/bg.js
new file mode 100644
index 0000000..f4e0163
--- /dev/null
+++ b/sources/plugins/indent/lang/bg.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'bg', {
6 indent: 'Увеличаване на отстъпа',
7 outdent: 'Намаляване на отстъпа'
8} );
diff --git a/sources/plugins/indent/lang/bn.js b/sources/plugins/indent/lang/bn.js
new file mode 100644
index 0000000..88a3393
--- /dev/null
+++ b/sources/plugins/indent/lang/bn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'bn', {
6 indent: 'ইনডেন্ট বাড়াই',
7 outdent: 'ইনডেন্ট কমাও'
8} );
diff --git a/sources/plugins/indent/lang/bs.js b/sources/plugins/indent/lang/bs.js
new file mode 100644
index 0000000..62df508
--- /dev/null
+++ b/sources/plugins/indent/lang/bs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'bs', {
6 indent: 'Poveæaj uvod',
7 outdent: 'Smanji uvod'
8} );
diff --git a/sources/plugins/indent/lang/ca.js b/sources/plugins/indent/lang/ca.js
new file mode 100644
index 0000000..38f299a
--- /dev/null
+++ b/sources/plugins/indent/lang/ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ca', {
6 indent: 'Augmenta el sagnat',
7 outdent: 'Redueix el sagnat'
8} );
diff --git a/sources/plugins/indent/lang/cs.js b/sources/plugins/indent/lang/cs.js
new file mode 100644
index 0000000..854aac8
--- /dev/null
+++ b/sources/plugins/indent/lang/cs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'cs', {
6 indent: 'Zvětšit odsazení',
7 outdent: 'Zmenšit odsazení'
8} );
diff --git a/sources/plugins/indent/lang/cy.js b/sources/plugins/indent/lang/cy.js
new file mode 100644
index 0000000..d1df873
--- /dev/null
+++ b/sources/plugins/indent/lang/cy.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'cy', {
6 indent: 'Cynyddu\'r Mewnoliad',
7 outdent: 'Lleihau\'r Mewnoliad'
8} );
diff --git a/sources/plugins/indent/lang/da.js b/sources/plugins/indent/lang/da.js
new file mode 100644
index 0000000..27e5731
--- /dev/null
+++ b/sources/plugins/indent/lang/da.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'da', {
6 indent: 'Forøg indrykning',
7 outdent: 'Formindsk indrykning'
8} );
diff --git a/sources/plugins/indent/lang/de-ch.js b/sources/plugins/indent/lang/de-ch.js
new file mode 100644
index 0000000..0696275
--- /dev/null
+++ b/sources/plugins/indent/lang/de-ch.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'de-ch', {
6 indent: 'Einzug erhöhen',
7 outdent: 'Einzug verringern'
8} );
diff --git a/sources/plugins/indent/lang/de.js b/sources/plugins/indent/lang/de.js
new file mode 100644
index 0000000..3f7a53c
--- /dev/null
+++ b/sources/plugins/indent/lang/de.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'de', {
6 indent: 'Einzug erhöhen',
7 outdent: 'Einzug verringern'
8} );
diff --git a/sources/plugins/indent/lang/el.js b/sources/plugins/indent/lang/el.js
new file mode 100644
index 0000000..57ac0f5
--- /dev/null
+++ b/sources/plugins/indent/lang/el.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'el', {
6 indent: 'Αύξηση Εσοχής',
7 outdent: 'Μείωση Εσοχής'
8} );
diff --git a/sources/plugins/indent/lang/en-au.js b/sources/plugins/indent/lang/en-au.js
new file mode 100644
index 0000000..6fd80ea
--- /dev/null
+++ b/sources/plugins/indent/lang/en-au.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'en-au', {
6 indent: 'Increase Indent',
7 outdent: 'Decrease Indent'
8} );
diff --git a/sources/plugins/indent/lang/en-ca.js b/sources/plugins/indent/lang/en-ca.js
new file mode 100644
index 0000000..b103510
--- /dev/null
+++ b/sources/plugins/indent/lang/en-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'en-ca', {
6 indent: 'Increase Indent',
7 outdent: 'Decrease Indent'
8} );
diff --git a/sources/plugins/indent/lang/en-gb.js b/sources/plugins/indent/lang/en-gb.js
new file mode 100644
index 0000000..0d2edf3
--- /dev/null
+++ b/sources/plugins/indent/lang/en-gb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'en-gb', {
6 indent: 'Increase Indent',
7 outdent: 'Decrease Indent'
8} );
diff --git a/sources/plugins/indent/lang/en.js b/sources/plugins/indent/lang/en.js
new file mode 100644
index 0000000..c5dba75
--- /dev/null
+++ b/sources/plugins/indent/lang/en.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'en', {
6 indent: 'Increase Indent',
7 outdent: 'Decrease Indent'
8} );
diff --git a/sources/plugins/indent/lang/eo.js b/sources/plugins/indent/lang/eo.js
new file mode 100644
index 0000000..eb8b8ea
--- /dev/null
+++ b/sources/plugins/indent/lang/eo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'eo', {
6 indent: 'Pligrandigi Krommarĝenon',
7 outdent: 'Malpligrandigi Krommarĝenon'
8} );
diff --git a/sources/plugins/indent/lang/es.js b/sources/plugins/indent/lang/es.js
new file mode 100644
index 0000000..d7b01c6
--- /dev/null
+++ b/sources/plugins/indent/lang/es.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'es', {
6 indent: 'Aumentar Sangría',
7 outdent: 'Disminuir Sangría'
8} );
diff --git a/sources/plugins/indent/lang/et.js b/sources/plugins/indent/lang/et.js
new file mode 100644
index 0000000..ce10b13
--- /dev/null
+++ b/sources/plugins/indent/lang/et.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'et', {
6 indent: 'Taande suurendamine',
7 outdent: 'Taande vähendamine'
8} );
diff --git a/sources/plugins/indent/lang/eu.js b/sources/plugins/indent/lang/eu.js
new file mode 100644
index 0000000..7934a48
--- /dev/null
+++ b/sources/plugins/indent/lang/eu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'eu', {
6 indent: 'Handitu koska',
7 outdent: 'Txikitu koska'
8} );
diff --git a/sources/plugins/indent/lang/fa.js b/sources/plugins/indent/lang/fa.js
new file mode 100644
index 0000000..932734a
--- /dev/null
+++ b/sources/plugins/indent/lang/fa.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'fa', {
6 indent: 'افزایش تورفتگی',
7 outdent: 'کاهش تورفتگی'
8} );
diff --git a/sources/plugins/indent/lang/fi.js b/sources/plugins/indent/lang/fi.js
new file mode 100644
index 0000000..c6a5b21
--- /dev/null
+++ b/sources/plugins/indent/lang/fi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'fi', {
6 indent: 'Suurenna sisennystä',
7 outdent: 'Pienennä sisennystä'
8} );
diff --git a/sources/plugins/indent/lang/fo.js b/sources/plugins/indent/lang/fo.js
new file mode 100644
index 0000000..f6e6671
--- /dev/null
+++ b/sources/plugins/indent/lang/fo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'fo', {
6 indent: 'Økja reglubrotarinntriv',
7 outdent: 'Minka reglubrotarinntriv'
8} );
diff --git a/sources/plugins/indent/lang/fr-ca.js b/sources/plugins/indent/lang/fr-ca.js
new file mode 100644
index 0000000..74bbed5
--- /dev/null
+++ b/sources/plugins/indent/lang/fr-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'fr-ca', {
6 indent: 'Augmenter le retrait',
7 outdent: 'Diminuer le retrait'
8} );
diff --git a/sources/plugins/indent/lang/fr.js b/sources/plugins/indent/lang/fr.js
new file mode 100644
index 0000000..0fb1347
--- /dev/null
+++ b/sources/plugins/indent/lang/fr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'fr', {
6 indent: 'Augmenter le retrait',
7 outdent: 'Diminuer le retrait'
8} );
diff --git a/sources/plugins/indent/lang/gl.js b/sources/plugins/indent/lang/gl.js
new file mode 100644
index 0000000..832b0ad
--- /dev/null
+++ b/sources/plugins/indent/lang/gl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'gl', {
6 indent: 'Aumentar a sangría',
7 outdent: 'Reducir a sangría'
8} );
diff --git a/sources/plugins/indent/lang/gu.js b/sources/plugins/indent/lang/gu.js
new file mode 100644
index 0000000..e69a3ce
--- /dev/null
+++ b/sources/plugins/indent/lang/gu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'gu', {
6 indent: 'ઇન્ડેન્ટ, લીટીના આરંભમાં જગ્યા વધારવી',
7 outdent: 'ઇન્ડેન્ટ લીટીના આરંભમાં જગ્યા ઘટાડવી'
8} );
diff --git a/sources/plugins/indent/lang/he.js b/sources/plugins/indent/lang/he.js
new file mode 100644
index 0000000..6fa5ed7
--- /dev/null
+++ b/sources/plugins/indent/lang/he.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'he', {
6 indent: 'הגדלת הזחה',
7 outdent: 'הקטנת הזחה'
8} );
diff --git a/sources/plugins/indent/lang/hi.js b/sources/plugins/indent/lang/hi.js
new file mode 100644
index 0000000..a3c39d8
--- /dev/null
+++ b/sources/plugins/indent/lang/hi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'hi', {
6 indent: 'इन्डॅन्ट बढ़ायें',
7 outdent: 'इन्डॅन्ट कम करें'
8} );
diff --git a/sources/plugins/indent/lang/hr.js b/sources/plugins/indent/lang/hr.js
new file mode 100644
index 0000000..dfa90d4
--- /dev/null
+++ b/sources/plugins/indent/lang/hr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'hr', {
6 indent: 'Pomakni udesno',
7 outdent: 'Pomakni ulijevo'
8} );
diff --git a/sources/plugins/indent/lang/hu.js b/sources/plugins/indent/lang/hu.js
new file mode 100644
index 0000000..22cd8e0
--- /dev/null
+++ b/sources/plugins/indent/lang/hu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'hu', {
6 indent: 'Behúzás növelése',
7 outdent: 'Behúzás csökkentése'
8} );
diff --git a/sources/plugins/indent/lang/id.js b/sources/plugins/indent/lang/id.js
new file mode 100644
index 0000000..2c66b70
--- /dev/null
+++ b/sources/plugins/indent/lang/id.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'id', {
6 indent: 'Tingkatkan Lekuk',
7 outdent: 'Kurangi Lekuk'
8} );
diff --git a/sources/plugins/indent/lang/is.js b/sources/plugins/indent/lang/is.js
new file mode 100644
index 0000000..71f80b1
--- /dev/null
+++ b/sources/plugins/indent/lang/is.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'is', {
6 indent: 'Minnka inndrátt',
7 outdent: 'Auka inndrátt'
8} );
diff --git a/sources/plugins/indent/lang/it.js b/sources/plugins/indent/lang/it.js
new file mode 100644
index 0000000..36e0922
--- /dev/null
+++ b/sources/plugins/indent/lang/it.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'it', {
6 indent: 'Aumenta rientro',
7 outdent: 'Riduci rientro'
8} );
diff --git a/sources/plugins/indent/lang/ja.js b/sources/plugins/indent/lang/ja.js
new file mode 100644
index 0000000..838f4cb
--- /dev/null
+++ b/sources/plugins/indent/lang/ja.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ja', {
6 indent: 'インデント',
7 outdent: 'インデント解除'
8} );
diff --git a/sources/plugins/indent/lang/ka.js b/sources/plugins/indent/lang/ka.js
new file mode 100644
index 0000000..a0ce0e8
--- /dev/null
+++ b/sources/plugins/indent/lang/ka.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ka', {
6 indent: 'მეტად შეწევა',
7 outdent: 'ნაკლებად შეწევა'
8} );
diff --git a/sources/plugins/indent/lang/km.js b/sources/plugins/indent/lang/km.js
new file mode 100644
index 0000000..514fba2
--- /dev/null
+++ b/sources/plugins/indent/lang/km.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'km', {
6 indent: 'បន្ថែមការចូលបន្ទាត់',
7 outdent: 'បន្ថយការចូលបន្ទាត់'
8} );
diff --git a/sources/plugins/indent/lang/ko.js b/sources/plugins/indent/lang/ko.js
new file mode 100644
index 0000000..c77afbd
--- /dev/null
+++ b/sources/plugins/indent/lang/ko.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ko', {
6 indent: '들여쓰기',
7 outdent: '내어쓰기'
8} );
diff --git a/sources/plugins/indent/lang/ku.js b/sources/plugins/indent/lang/ku.js
new file mode 100644
index 0000000..728bfe3
--- /dev/null
+++ b/sources/plugins/indent/lang/ku.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ku', {
6 indent: 'زیادکردنی بۆشایی',
7 outdent: 'کەمکردنەوەی بۆشایی'
8} );
diff --git a/sources/plugins/indent/lang/lt.js b/sources/plugins/indent/lang/lt.js
new file mode 100644
index 0000000..4458598
--- /dev/null
+++ b/sources/plugins/indent/lang/lt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'lt', {
6 indent: 'Padidinti įtrauką',
7 outdent: 'Sumažinti įtrauką'
8} );
diff --git a/sources/plugins/indent/lang/lv.js b/sources/plugins/indent/lang/lv.js
new file mode 100644
index 0000000..74d36a4
--- /dev/null
+++ b/sources/plugins/indent/lang/lv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'lv', {
6 indent: 'Palielināt atkāpi',
7 outdent: 'Samazināt atkāpi'
8} );
diff --git a/sources/plugins/indent/lang/mk.js b/sources/plugins/indent/lang/mk.js
new file mode 100644
index 0000000..440995e
--- /dev/null
+++ b/sources/plugins/indent/lang/mk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'mk', {
6 indent: 'Increase Indent', // MISSING
7 outdent: 'Decrease Indent' // MISSING
8} );
diff --git a/sources/plugins/indent/lang/mn.js b/sources/plugins/indent/lang/mn.js
new file mode 100644
index 0000000..d9c74ba
--- /dev/null
+++ b/sources/plugins/indent/lang/mn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'mn', {
6 indent: 'Догол мөр хасах',
7 outdent: 'Догол мөр нэмэх'
8} );
diff --git a/sources/plugins/indent/lang/ms.js b/sources/plugins/indent/lang/ms.js
new file mode 100644
index 0000000..5fd53e2
--- /dev/null
+++ b/sources/plugins/indent/lang/ms.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ms', {
6 indent: 'Tambahkan Inden',
7 outdent: 'Kurangkan Inden'
8} );
diff --git a/sources/plugins/indent/lang/nb.js b/sources/plugins/indent/lang/nb.js
new file mode 100644
index 0000000..e69a947
--- /dev/null
+++ b/sources/plugins/indent/lang/nb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'nb', {
6 indent: 'Øk innrykk',
7 outdent: 'Reduser innrykk'
8} );
diff --git a/sources/plugins/indent/lang/nl.js b/sources/plugins/indent/lang/nl.js
new file mode 100644
index 0000000..8979f8f
--- /dev/null
+++ b/sources/plugins/indent/lang/nl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'nl', {
6 indent: 'Inspringing vergroten',
7 outdent: 'Inspringing verkleinen'
8} );
diff --git a/sources/plugins/indent/lang/no.js b/sources/plugins/indent/lang/no.js
new file mode 100644
index 0000000..a01c1bb
--- /dev/null
+++ b/sources/plugins/indent/lang/no.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'no', {
6 indent: 'Øk innrykk',
7 outdent: 'Reduser innrykk'
8} );
diff --git a/sources/plugins/indent/lang/oc.js b/sources/plugins/indent/lang/oc.js
new file mode 100644
index 0000000..00e9cf9
--- /dev/null
+++ b/sources/plugins/indent/lang/oc.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'oc', {
6 indent: 'Aumentar l\'alinèa',
7 outdent: 'Dmesir l\'alinèa'
8} );
diff --git a/sources/plugins/indent/lang/pl.js b/sources/plugins/indent/lang/pl.js
new file mode 100644
index 0000000..ef78a2e
--- /dev/null
+++ b/sources/plugins/indent/lang/pl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'pl', {
6 indent: 'Zwiększ wcięcie',
7 outdent: 'Zmniejsz wcięcie'
8} );
diff --git a/sources/plugins/indent/lang/pt-br.js b/sources/plugins/indent/lang/pt-br.js
new file mode 100644
index 0000000..45ae5e6
--- /dev/null
+++ b/sources/plugins/indent/lang/pt-br.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'pt-br', {
6 indent: 'Aumentar Recuo',
7 outdent: 'Diminuir Recuo'
8} );
diff --git a/sources/plugins/indent/lang/pt.js b/sources/plugins/indent/lang/pt.js
new file mode 100644
index 0000000..6d26cb2
--- /dev/null
+++ b/sources/plugins/indent/lang/pt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'pt', {
6 indent: 'Aumentar avanço',
7 outdent: 'Diminuir avanço'
8} );
diff --git a/sources/plugins/indent/lang/ro.js b/sources/plugins/indent/lang/ro.js
new file mode 100644
index 0000000..708b09d
--- /dev/null
+++ b/sources/plugins/indent/lang/ro.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ro', {
6 indent: 'Creşte indentarea',
7 outdent: 'Scade indentarea'
8} );
diff --git a/sources/plugins/indent/lang/ru.js b/sources/plugins/indent/lang/ru.js
new file mode 100644
index 0000000..aa21b7a
--- /dev/null
+++ b/sources/plugins/indent/lang/ru.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ru', {
6 indent: 'Увеличить отступ',
7 outdent: 'Уменьшить отступ'
8} );
diff --git a/sources/plugins/indent/lang/si.js b/sources/plugins/indent/lang/si.js
new file mode 100644
index 0000000..98b8dd3
--- /dev/null
+++ b/sources/plugins/indent/lang/si.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'si', {
6 indent: 'අතර පරතරය වැඩිකරන්න',
7 outdent: 'අතර පරතරය අඩුකරන්න'
8} );
diff --git a/sources/plugins/indent/lang/sk.js b/sources/plugins/indent/lang/sk.js
new file mode 100644
index 0000000..3135f4f
--- /dev/null
+++ b/sources/plugins/indent/lang/sk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sk', {
6 indent: 'Zväčšiť odsadenie',
7 outdent: 'Zmenšiť odsadenie'
8} );
diff --git a/sources/plugins/indent/lang/sl.js b/sources/plugins/indent/lang/sl.js
new file mode 100644
index 0000000..15be2f7
--- /dev/null
+++ b/sources/plugins/indent/lang/sl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sl', {
6 indent: 'Povečaj zamik',
7 outdent: 'Zmanjšaj zamik'
8} );
diff --git a/sources/plugins/indent/lang/sq.js b/sources/plugins/indent/lang/sq.js
new file mode 100644
index 0000000..9a2dd63
--- /dev/null
+++ b/sources/plugins/indent/lang/sq.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sq', {
6 indent: 'Rrite Identin',
7 outdent: 'Zvogëlo Identin'
8} );
diff --git a/sources/plugins/indent/lang/sr-latn.js b/sources/plugins/indent/lang/sr-latn.js
new file mode 100644
index 0000000..ca5a140
--- /dev/null
+++ b/sources/plugins/indent/lang/sr-latn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sr-latn', {
6 indent: 'Uvećaj levu marginu',
7 outdent: 'Smanji levu marginu'
8} );
diff --git a/sources/plugins/indent/lang/sr.js b/sources/plugins/indent/lang/sr.js
new file mode 100644
index 0000000..f7498be
--- /dev/null
+++ b/sources/plugins/indent/lang/sr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sr', {
6 indent: 'Увећај леву маргину',
7 outdent: 'Смањи леву маргину'
8} );
diff --git a/sources/plugins/indent/lang/sv.js b/sources/plugins/indent/lang/sv.js
new file mode 100644
index 0000000..46b0692
--- /dev/null
+++ b/sources/plugins/indent/lang/sv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'sv', {
6 indent: 'Öka indrag',
7 outdent: 'Minska indrag'
8} );
diff --git a/sources/plugins/indent/lang/th.js b/sources/plugins/indent/lang/th.js
new file mode 100644
index 0000000..2f60e53
--- /dev/null
+++ b/sources/plugins/indent/lang/th.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'th', {
6 indent: 'เพิ่มระยะย่อหน้า',
7 outdent: 'ลดระยะย่อหน้า'
8} );
diff --git a/sources/plugins/indent/lang/tr.js b/sources/plugins/indent/lang/tr.js
new file mode 100644
index 0000000..21520b6
--- /dev/null
+++ b/sources/plugins/indent/lang/tr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'tr', {
6 indent: 'Sekme Arttır',
7 outdent: 'Sekme Azalt'
8} );
diff --git a/sources/plugins/indent/lang/tt.js b/sources/plugins/indent/lang/tt.js
new file mode 100644
index 0000000..604bbba
--- /dev/null
+++ b/sources/plugins/indent/lang/tt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'tt', {
6 indent: 'Отступны арттыру',
7 outdent: 'Отступны кечерәйтү'
8} );
diff --git a/sources/plugins/indent/lang/ug.js b/sources/plugins/indent/lang/ug.js
new file mode 100644
index 0000000..6fec573
--- /dev/null
+++ b/sources/plugins/indent/lang/ug.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'ug', {
6 indent: 'تارايت',
7 outdent: 'كەڭەيت'
8} );
diff --git a/sources/plugins/indent/lang/uk.js b/sources/plugins/indent/lang/uk.js
new file mode 100644
index 0000000..c68ca96
--- /dev/null
+++ b/sources/plugins/indent/lang/uk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'uk', {
6 indent: 'Збільшити відступ',
7 outdent: 'Зменшити відступ'
8} );
diff --git a/sources/plugins/indent/lang/vi.js b/sources/plugins/indent/lang/vi.js
new file mode 100644
index 0000000..7f44c5d
--- /dev/null
+++ b/sources/plugins/indent/lang/vi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'vi', {
6 indent: 'Dịch vào trong',
7 outdent: 'Dịch ra ngoài'
8} );
diff --git a/sources/plugins/indent/lang/zh-cn.js b/sources/plugins/indent/lang/zh-cn.js
new file mode 100644
index 0000000..2c9c383
--- /dev/null
+++ b/sources/plugins/indent/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'zh-cn', {
6 indent: '增加缩进量',
7 outdent: '减少缩进量'
8} );
diff --git a/sources/plugins/indent/lang/zh.js b/sources/plugins/indent/lang/zh.js
new file mode 100644
index 0000000..ee681cb
--- /dev/null
+++ b/sources/plugins/indent/lang/zh.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'indent', 'zh', {
6 indent: '增加縮排',
7 outdent: '減少縮排'
8} );
diff --git a/sources/plugins/indent/plugin.js b/sources/plugins/indent/plugin.js
new file mode 100644
index 0000000..0e887cf
--- /dev/null
+++ b/sources/plugins/indent/plugin.js
@@ -0,0 +1,461 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Increase and Decrease Indent commands.
8 */
9
10( function() {
11 'use strict';
12
13 var TRISTATE_DISABLED = CKEDITOR.TRISTATE_DISABLED,
14 TRISTATE_OFF = CKEDITOR.TRISTATE_OFF;
15
16 CKEDITOR.plugins.add( 'indent', {
17 // jscs:disable maximumLineLength
18 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
19 // jscs:enable maximumLineLength
20 icons: 'indent,indent-rtl,outdent,outdent-rtl', // %REMOVE_LINE_CORE%
21 hidpi: true, // %REMOVE_LINE_CORE%
22
23 init: function( editor ) {
24 var genericDefinition = CKEDITOR.plugins.indent.genericDefinition;
25
26 // Register generic commands.
27 setupGenericListeners( editor, editor.addCommand( 'indent', new genericDefinition( true ) ) );
28 setupGenericListeners( editor, editor.addCommand( 'outdent', new genericDefinition() ) );
29
30 // Create and register toolbar button if possible.
31 if ( editor.ui.addButton ) {
32 editor.ui.addButton( 'Indent', {
33 label: editor.lang.indent.indent,
34 command: 'indent',
35 directional: true,
36 toolbar: 'indent,20'
37 } );
38
39 editor.ui.addButton( 'Outdent', {
40 label: editor.lang.indent.outdent,
41 command: 'outdent',
42 directional: true,
43 toolbar: 'indent,10'
44 } );
45 }
46
47 // Register dirChanged listener.
48 editor.on( 'dirChanged', function( evt ) {
49 var range = editor.createRange(),
50 dataNode = evt.data.node;
51
52 range.setStartBefore( dataNode );
53 range.setEndAfter( dataNode );
54
55 var walker = new CKEDITOR.dom.walker( range ),
56 node;
57
58 while ( ( node = walker.next() ) ) {
59 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
60 // A child with the defined dir is to be ignored.
61 if ( !node.equals( dataNode ) && node.getDirection() ) {
62 range.setStartAfter( node );
63 walker = new CKEDITOR.dom.walker( range );
64 continue;
65 }
66
67 // Switch alignment classes.
68 var classes = editor.config.indentClasses;
69 if ( classes ) {
70 var suffix = ( evt.data.dir == 'ltr' ) ? [ '_rtl', '' ] : [ '', '_rtl' ];
71 for ( var i = 0; i < classes.length; i++ ) {
72 if ( node.hasClass( classes[ i ] + suffix[ 0 ] ) ) {
73 node.removeClass( classes[ i ] + suffix[ 0 ] );
74 node.addClass( classes[ i ] + suffix[ 1 ] );
75 }
76 }
77 }
78
79 // Switch the margins.
80 var marginLeft = node.getStyle( 'margin-right' ),
81 marginRight = node.getStyle( 'margin-left' );
82
83 marginLeft ? node.setStyle( 'margin-left', marginLeft ) : node.removeStyle( 'margin-left' );
84 marginRight ? node.setStyle( 'margin-right', marginRight ) : node.removeStyle( 'margin-right' );
85 }
86 }
87 } );
88 }
89 } );
90
91 /**
92 * Global command class definitions and global helpers.
93 *
94 * @class
95 * @singleton
96 */
97 CKEDITOR.plugins.indent = {
98 /**
99 * A base class for a generic command definition, responsible mainly for creating
100 * Increase Indent and Decrease Indent toolbar buttons as well as for refreshing
101 * UI states.
102 *
103 * Commands of this class do not perform any indentation by themselves. They
104 * delegate this job to content-specific indentation commands (i.e. indentlist).
105 *
106 * @class CKEDITOR.plugins.indent.genericDefinition
107 * @extends CKEDITOR.commandDefinition
108 * @param {CKEDITOR.editor} editor The editor instance this command will be
109 * applied to.
110 * @param {String} name The name of the command.
111 * @param {Boolean} [isIndent] Defines the command as indenting or outdenting.
112 */
113 genericDefinition: function( isIndent ) {
114 /**
115 * Determines whether the command belongs to the indentation family.
116 * Otherwise it is assumed to be an outdenting command.
117 *
118 * @readonly
119 * @property {Boolean} [=false]
120 */
121 this.isIndent = !!isIndent;
122
123 // Mimic naive startDisabled behavior for outdent.
124 this.startDisabled = !this.isIndent;
125 },
126
127 /**
128 * A base class for specific indentation command definitions responsible for
129 * handling a pre-defined set of elements i.e. indentlist for lists or
130 * indentblock for text block elements.
131 *
132 * Commands of this class perform indentation operations and modify the DOM structure.
133 * They listen for events fired by {@link CKEDITOR.plugins.indent.genericDefinition}
134 * and execute defined actions.
135 *
136 * **NOTE**: This is not an {@link CKEDITOR.command editor command}.
137 * Context-specific commands are internal, for indentation system only.
138 *
139 * @class CKEDITOR.plugins.indent.specificDefinition
140 * @param {CKEDITOR.editor} editor The editor instance this command will be
141 * applied to.
142 * @param {String} name The name of the command.
143 * @param {Boolean} [isIndent] Defines the command as indenting or outdenting.
144 */
145 specificDefinition: function( editor, name, isIndent ) {
146 this.name = name;
147 this.editor = editor;
148
149 /**
150 * An object of jobs handled by the command. Each job consists
151 * of two functions: `refresh` and `exec` as well as the execution priority.
152 *
153 * * The `refresh` function determines whether a job is doable for
154 * a particular context. These functions are executed in the
155 * order of priorities, one by one, for all plugins that registered
156 * jobs. As jobs are related to generic commands, refreshing
157 * occurs when the global command is firing the `refresh` event.
158 *
159 * **Note**: This function must return either {@link CKEDITOR#TRISTATE_DISABLED}
160 * or {@link CKEDITOR#TRISTATE_OFF}.
161 *
162 * * The `exec` function modifies the DOM if possible. Just like
163 * `refresh`, `exec` functions are executed in the order of priorities
164 * while the generic command is executed. This function is not executed
165 * if `refresh` for this job returned {@link CKEDITOR#TRISTATE_DISABLED}.
166 *
167 * **Note**: This function must return a Boolean value, indicating whether it
168 * was successful. If a job was successful, then no other jobs are being executed.
169 *
170 * Sample definition:
171 *
172 * command.jobs = {
173 * // Priority = 20.
174 * '20': {
175 * refresh( editor, path ) {
176 * if ( condition )
177 * return CKEDITOR.TRISTATE_OFF;
178 * else
179 * return CKEDITOR.TRISTATE_DISABLED;
180 * },
181 * exec( editor ) {
182 * // DOM modified! This was OK.
183 * return true;
184 * }
185 * },
186 * // Priority = 60. This job is done later.
187 * '60': {
188 * // Another job.
189 * }
190 * };
191 *
192 * For additional information, please check comments for
193 * the `setupGenericListeners` function.
194 *
195 * @readonly
196 * @property {Object} [={}]
197 */
198 this.jobs = {};
199
200 /**
201 * Determines whether the editor that the command belongs to has
202 * {@link CKEDITOR.config#enterMode config.enterMode} set to {@link CKEDITOR#ENTER_BR}.
203 *
204 * @readonly
205 * @see CKEDITOR.config#enterMode
206 * @property {Boolean} [=false]
207 */
208 this.enterBr = editor.config.enterMode == CKEDITOR.ENTER_BR;
209
210 /**
211 * Determines whether the command belongs to the indentation family.
212 * Otherwise it is assumed to be an outdenting command.
213 *
214 * @readonly
215 * @property {Boolean} [=false]
216 */
217 this.isIndent = !!isIndent;
218
219 /**
220 * The name of the global command related to this one.
221 *
222 * @readonly
223 */
224 this.relatedGlobal = isIndent ? 'indent' : 'outdent';
225
226 /**
227 * A keystroke associated with this command (*Tab* or *Shift+Tab*).
228 *
229 * @readonly
230 */
231 this.indentKey = isIndent ? 9 : CKEDITOR.SHIFT + 9;
232
233 /**
234 * Stores created markers for the command so they can eventually be
235 * purged after the `exec` function is run.
236 */
237 this.database = {};
238 },
239
240 /**
241 * Registers content-specific commands as a part of the indentation system
242 * directed by generic commands. Once a command is registered,
243 * it listens for events of a related generic command.
244 *
245 * CKEDITOR.plugins.indent.registerCommands( editor, {
246 * 'indentlist': new indentListCommand( editor, 'indentlist' ),
247 * 'outdentlist': new indentListCommand( editor, 'outdentlist' )
248 * } );
249 *
250 * Content-specific commands listen for the generic command's `exec` and
251 * try to execute their own jobs, one after another. If some execution is
252 * successful, `evt.data.done` is set so no more jobs (commands) are involved.
253 *
254 * Content-specific commands also listen for the generic command's `refresh`
255 * and fill the `evt.data.states` object with states of jobs. A generic command
256 * uses this data to determine its own state and to update the UI.
257 *
258 * @member CKEDITOR.plugins.indent
259 * @param {CKEDITOR.editor} editor The editor instance this command is
260 * applied to.
261 * @param {Object} commands An object of {@link CKEDITOR.command}.
262 */
263 registerCommands: function( editor, commands ) {
264 editor.on( 'pluginsLoaded', function() {
265 for ( var name in commands ) {
266 ( function( editor, command ) {
267 var relatedGlobal = editor.getCommand( command.relatedGlobal );
268
269 for ( var priority in command.jobs ) {
270 // Observe generic exec event and execute command when necessary.
271 // If the command was successfully handled by the command and
272 // DOM has been modified, stop event propagation so no other plugin
273 // will bother. Job is done.
274 relatedGlobal.on( 'exec', function( evt ) {
275 if ( evt.data.done )
276 return;
277
278 // Make sure that anything this command will do is invisible
279 // for undoManager. What undoManager only can see and
280 // remember is the execution of the global command (relatedGlobal).
281 editor.fire( 'lockSnapshot' );
282
283 if ( command.execJob( editor, priority ) )
284 evt.data.done = true;
285
286 editor.fire( 'unlockSnapshot' );
287
288 // Clean up the markers.
289 CKEDITOR.dom.element.clearAllMarkers( command.database );
290 }, this, null, priority );
291
292 // Observe generic refresh event and force command refresh.
293 // Once refreshed, save command state in event data
294 // so generic command plugin can update its own state and UI.
295 relatedGlobal.on( 'refresh', function( evt ) {
296 if ( !evt.data.states )
297 evt.data.states = {};
298
299 evt.data.states[ command.name + '@' + priority ] =
300 command.refreshJob( editor, priority, evt.data.path );
301 }, this, null, priority );
302 }
303
304 // Since specific indent commands have no UI elements,
305 // they need to be manually registered as a editor feature.
306 editor.addFeature( command );
307 } )( this, commands[ name ] );
308 }
309 } );
310 }
311 };
312
313 CKEDITOR.plugins.indent.genericDefinition.prototype = {
314 context: 'p',
315
316 exec: function() {}
317 };
318
319 CKEDITOR.plugins.indent.specificDefinition.prototype = {
320 /**
321 * Executes the content-specific procedure if the context is correct.
322 * It calls the `exec` function of a job of the given `priority`
323 * that modifies the DOM.
324 *
325 * @param {CKEDITOR.editor} editor The editor instance this command
326 * will be applied to.
327 * @param {Number} priority The priority of the job to be executed.
328 * @returns {Boolean} Indicates whether the job was successful.
329 */
330 execJob: function( editor, priority ) {
331 var job = this.jobs[ priority ];
332
333 if ( job.state != TRISTATE_DISABLED )
334 return job.exec.call( this, editor );
335 },
336
337 /**
338 * Calls the `refresh` function of a job of the given `priority`.
339 * The function returns the state of the job which can be either
340 * {@link CKEDITOR#TRISTATE_DISABLED} or {@link CKEDITOR#TRISTATE_OFF}.
341 *
342 * @param {CKEDITOR.editor} editor The editor instance this command
343 * will be applied to.
344 * @param {Number} priority The priority of the job to be executed.
345 * @returns {Number} The state of the job.
346 */
347 refreshJob: function( editor, priority, path ) {
348 var job = this.jobs[ priority ];
349
350 if ( !editor.activeFilter.checkFeature( this ) )
351 job.state = TRISTATE_DISABLED;
352 else
353 job.state = job.refresh.call( this, editor, path );
354
355 return job.state;
356 },
357
358 /**
359 * Checks if the element path contains the element handled
360 * by this indentation command.
361 *
362 * @param {CKEDITOR.dom.elementPath} node A path to be checked.
363 * @returns {CKEDITOR.dom.element}
364 */
365 getContext: function( path ) {
366 return path.contains( this.context );
367 }
368 };
369
370 /**
371 * Attaches event listeners for this generic command. Since the indentation
372 * system is event-oriented, generic commands communicate with
373 * content-specific commands using the `exec` and `refresh` events.
374 *
375 * Listener priorities are crucial. Different indentation phases
376 * are executed with different priorities.
377 *
378 * For the `exec` event:
379 *
380 * * 0: Selection and bookmarks are saved by the generic command.
381 * * 1-99: Content-specific commands try to indent the code by executing
382 * their own jobs ({@link CKEDITOR.plugins.indent.specificDefinition#jobs}).
383 * * 100: Bookmarks are re-selected by the generic command.
384 *
385 * The visual interpretation looks as follows:
386 *
387 * +------------------+
388 * | Exec event fired |
389 * +------ + ---------+
390 * |
391 * 0 -<----------+ Selection and bookmarks saved.
392 * |
393 * |
394 * 25 -<---+ Exec 1st job of plugin#1 (return false, continuing...).
395 * |
396 * |
397 * 50 -<---+ Exec 1st job of plugin#2 (return false, continuing...).
398 * |
399 * |
400 * 75 -<---+ Exec 2nd job of plugin#1 (only if plugin#2 failed).
401 * |
402 * |
403 * 100 -<-----------+ Re-select bookmarks, clean-up.
404 * |
405 * +-------- v ----------+
406 * | Exec event finished |
407 * +---------------------+
408 *
409 * For the `refresh` event:
410 *
411 * * <100: Content-specific commands refresh their job states according
412 * to the given path. Jobs save their states in the `evt.data.states` object
413 * passed along with the event. This can be either {@link CKEDITOR#TRISTATE_DISABLED}
414 * or {@link CKEDITOR#TRISTATE_OFF}.
415 * * 100: Command state is determined according to what states
416 * have been returned by content-specific jobs (`evt.data.states`).
417 * UI elements are updated at this stage.
418 *
419 * **Note**: If there is at least one job with the {@link CKEDITOR#TRISTATE_OFF} state,
420 * then the generic command state is also {@link CKEDITOR#TRISTATE_OFF}. Otherwise,
421 * the command state is {@link CKEDITOR#TRISTATE_DISABLED}.
422 *
423 * @param {CKEDITOR.command} command The command to be set up.
424 * @private
425 */
426 function setupGenericListeners( editor, command ) {
427 var selection, bookmarks;
428
429 // Set the command state according to content-specific
430 // command states.
431 command.on( 'refresh', function( evt ) {
432 // If no state comes with event data, disable command.
433 var states = [ TRISTATE_DISABLED ];
434
435 for ( var s in evt.data.states )
436 states.push( evt.data.states[ s ] );
437
438 this.setState( CKEDITOR.tools.search( states, TRISTATE_OFF ) ? TRISTATE_OFF : TRISTATE_DISABLED );
439 }, command, null, 100 );
440
441 // Initialization. Save bookmarks and mark event as not handled
442 // by any plugin (command) yet.
443 command.on( 'exec', function( evt ) {
444 selection = editor.getSelection();
445 bookmarks = selection.createBookmarks( 1 );
446
447 // Mark execution as not handled yet.
448 if ( !evt.data )
449 evt.data = {};
450
451 evt.data.done = false;
452 }, command, null, 0 );
453
454 // Housekeeping. Make sure selectionChange will be called.
455 // Also re-select previously saved bookmarks.
456 command.on( 'exec', function() {
457 editor.forceNextSelectionCheck();
458 selection.selectBookmarks( bookmarks );
459 }, command, null, 100 );
460 }
461} )();
diff --git a/sources/plugins/indentblock/plugin.js b/sources/plugins/indentblock/plugin.js
new file mode 100644
index 0000000..b39fd73
--- /dev/null
+++ b/sources/plugins/indentblock/plugin.js
@@ -0,0 +1,312 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Handles the indentation of block elements.
8 */
9
10( function() {
11 'use strict';
12
13 var $listItem = CKEDITOR.dtd.$listItem,
14 $list = CKEDITOR.dtd.$list,
15 TRISTATE_DISABLED = CKEDITOR.TRISTATE_DISABLED,
16 TRISTATE_OFF = CKEDITOR.TRISTATE_OFF;
17
18 CKEDITOR.plugins.add( 'indentblock', {
19 requires: 'indent',
20 init: function( editor ) {
21 var globalHelpers = CKEDITOR.plugins.indent,
22 classes = editor.config.indentClasses;
23
24 // Register commands.
25 globalHelpers.registerCommands( editor, {
26 indentblock: new commandDefinition( editor, 'indentblock', true ),
27 outdentblock: new commandDefinition( editor, 'outdentblock' )
28 } );
29
30 function commandDefinition() {
31 globalHelpers.specificDefinition.apply( this, arguments );
32
33 this.allowedContent = {
34 'div h1 h2 h3 h4 h5 h6 ol p pre ul': {
35 // Do not add elements, but only text-align style if element is validated by other rule.
36 propertiesOnly: true,
37 styles: !classes ? 'margin-left,margin-right' : null,
38 classes: classes || null
39 }
40 };
41
42 this.contentTransformations = [
43 [ 'div: splitMarginShorthand' ],
44 [ 'h1: splitMarginShorthand' ],
45 [ 'h2: splitMarginShorthand' ],
46 [ 'h3: splitMarginShorthand' ],
47 [ 'h4: splitMarginShorthand' ],
48 [ 'h5: splitMarginShorthand' ],
49 [ 'h6: splitMarginShorthand' ],
50 [ 'ol: splitMarginShorthand' ],
51 [ 'p: splitMarginShorthand' ],
52 [ 'pre: splitMarginShorthand' ],
53 [ 'ul: splitMarginShorthand' ]
54 ];
55
56 if ( this.enterBr )
57 this.allowedContent.div = true;
58
59 this.requiredContent = ( this.enterBr ? 'div' : 'p' ) +
60 ( classes ? '(' + classes.join( ',' ) + ')' : '{margin-left}' );
61
62 this.jobs = {
63 '20': {
64 refresh: function( editor, path ) {
65 var firstBlock = path.block || path.blockLimit;
66
67 // Switch context from somewhere inside list item to list item,
68 // if not found just assign self (doing nothing).
69 if ( !firstBlock.is( $listItem ) ) {
70 var ascendant = firstBlock.getAscendant( $listItem );
71
72 firstBlock = ( ascendant && path.contains( ascendant ) ) || firstBlock;
73 }
74
75 // Switch context from list item to list
76 // because indentblock can indent entire list
77 // but not a single list element.
78
79 if ( firstBlock.is( $listItem ) )
80 firstBlock = firstBlock.getParent();
81
82 // [-] Context in the path or ENTER_BR
83 //
84 // Don't try to indent if the element is out of
85 // this plugin's scope. This assertion is omitted
86 // if ENTER_BR is in use since there may be no block
87 // in the path.
88
89 if ( !this.enterBr && !this.getContext( path ) )
90 return TRISTATE_DISABLED;
91
92 else if ( classes ) {
93
94 // [+] Context in the path or ENTER_BR
95 // [+] IndentClasses
96 //
97 // If there are indentation classes, check if reached
98 // the highest level of indentation. If so, disable
99 // the command.
100
101 if ( indentClassLeft.call( this, firstBlock, classes ) )
102 return TRISTATE_OFF;
103 else
104 return TRISTATE_DISABLED;
105 } else {
106
107 // [+] Context in the path or ENTER_BR
108 // [-] IndentClasses
109 // [+] Indenting
110 //
111 // No indent-level limitations due to indent classes.
112 // Indent-like command can always be executed.
113
114 if ( this.isIndent )
115 return TRISTATE_OFF;
116
117 // [+] Context in the path or ENTER_BR
118 // [-] IndentClasses
119 // [-] Indenting
120 // [-] Block in the path
121 //
122 // No block in path. There's no element to apply indentation
123 // so disable the command.
124
125 else if ( !firstBlock )
126 return TRISTATE_DISABLED;
127
128 // [+] Context in the path or ENTER_BR
129 // [-] IndentClasses
130 // [-] Indenting
131 // [+] Block in path.
132 //
133 // Not using indentClasses but there is firstBlock.
134 // We can calculate current indentation level and
135 // try to increase/decrease it.
136
137 else {
138 return CKEDITOR[
139 ( getIndent( firstBlock ) || 0 ) <= 0 ? 'TRISTATE_DISABLED' : 'TRISTATE_OFF'
140 ];
141 }
142 }
143 },
144
145 exec: function( editor ) {
146 var selection = editor.getSelection(),
147 range = selection && selection.getRanges()[ 0 ],
148 nearestListBlock;
149
150 // If there's some list in the path, then it will be
151 // a full-list indent by increasing or decreasing margin property.
152 if ( ( nearestListBlock = editor.elementPath().contains( $list ) ) )
153 indentElement.call( this, nearestListBlock, classes );
154
155 // If no list in the path, use iterator to indent all the possible
156 // paragraphs in the range, creating them if necessary.
157 else {
158 var iterator = range.createIterator(),
159 enterMode = editor.config.enterMode,
160 block;
161
162 iterator.enforceRealBlocks = true;
163 iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
164
165 while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) {
166 if ( !block.isReadOnly() )
167 indentElement.call( this, block, classes );
168 }
169 }
170
171 return true;
172 }
173 }
174 };
175 }
176
177 CKEDITOR.tools.extend( commandDefinition.prototype, globalHelpers.specificDefinition.prototype, {
178 // Elements that, if in an elementpath, will be handled by this
179 // command. They restrict the scope of the plugin.
180 context: { div: 1, dl: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, ul: 1, ol: 1, p: 1, pre: 1, table: 1 },
181
182 // A regex built on config#indentClasses to detect whether an
183 // element has some indentClass or not.
184 classNameRegex: classes ? new RegExp( '(?:^|\\s+)(' + classes.join( '|' ) + ')(?=$|\\s)' ) : null
185 } );
186 }
187 } );
188
189 // Generic indentation procedure for indentation of any element
190 // either with margin property or config#indentClass.
191 function indentElement( element, classes, dir ) {
192 if ( element.getCustomData( 'indent_processed' ) )
193 return;
194
195 var editor = this.editor,
196 isIndent = this.isIndent;
197
198 if ( classes ) {
199 // Transform current class f to indent step index.
200 var indentClass = element.$.className.match( this.classNameRegex ),
201 indentStep = 0;
202
203 if ( indentClass ) {
204 indentClass = indentClass[ 1 ];
205 indentStep = CKEDITOR.tools.indexOf( classes, indentClass ) + 1;
206 }
207
208 // Operate on indent step index, transform indent step index
209 // back to class name.
210 if ( ( indentStep += isIndent ? 1 : -1 ) < 0 )
211 return;
212
213 indentStep = Math.min( indentStep, classes.length );
214 indentStep = Math.max( indentStep, 0 );
215 element.$.className = CKEDITOR.tools.ltrim( element.$.className.replace( this.classNameRegex, '' ) );
216
217 if ( indentStep > 0 )
218 element.addClass( classes[ indentStep - 1 ] );
219 } else {
220 var indentCssProperty = getIndentCss( element, dir ),
221 currentOffset = parseInt( element.getStyle( indentCssProperty ), 10 ),
222 indentOffset = editor.config.indentOffset || 40;
223
224 if ( isNaN( currentOffset ) )
225 currentOffset = 0;
226
227 currentOffset += ( isIndent ? 1 : -1 ) * indentOffset;
228
229 if ( currentOffset < 0 )
230 return;
231
232 currentOffset = Math.max( currentOffset, 0 );
233 currentOffset = Math.ceil( currentOffset / indentOffset ) * indentOffset;
234
235 element.setStyle(
236 indentCssProperty,
237 currentOffset ? currentOffset + ( editor.config.indentUnit || 'px' ) : ''
238 );
239
240 if ( element.getAttribute( 'style' ) === '' )
241 element.removeAttribute( 'style' );
242 }
243
244 CKEDITOR.dom.element.setMarker( this.database, element, 'indent_processed', 1 );
245
246 return;
247 }
248
249 // Method that checks if current indentation level for an element
250 // reached the limit determined by config#indentClasses.
251 function indentClassLeft( node, classes ) {
252 var indentClass = node.$.className.match( this.classNameRegex ),
253 isIndent = this.isIndent;
254
255 // If node has one of the indentClasses:
256 // * If it holds the topmost indentClass, then
257 // no more classes have left.
258 // * If it holds any other indentClass, it can use the next one
259 // or the previous one.
260 // * Outdent is always possible. We can remove indentClass.
261 if ( indentClass )
262 return isIndent ? indentClass[ 1 ] != classes.slice( -1 ) : true;
263
264 // If node has no class which belongs to indentClasses,
265 // then it is at 0-level. It can be indented but not outdented.
266 else
267 return isIndent;
268 }
269
270 // Determines indent CSS property for an element according to
271 // what is the direction of such element. It can be either `margin-left`
272 // or `margin-right`.
273 function getIndentCss( element, dir ) {
274 return ( dir || element.getComputedStyle( 'direction' ) ) == 'ltr' ? 'margin-left' : 'margin-right';
275 }
276
277 // Return the numerical indent value of margin-left|right of an element,
278 // considering element's direction. If element has no margin specified,
279 // NaN is returned.
280 function getIndent( element ) {
281 return parseInt( element.getStyle( getIndentCss( element ) ), 10 );
282 }
283} )();
284
285/**
286 * A list of classes to use for indenting the contents. If set to `null`, no classes will be used
287 * and instead the {@link #indentUnit} and {@link #indentOffset} properties will be used.
288 *
289 * // Use the 'Indent1', 'Indent2', 'Indent3' classes.
290 * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];
291 *
292 * @cfg {Array} [indentClasses=null]
293 * @member CKEDITOR.config
294 */
295
296/**
297 * The size in {@link CKEDITOR.config#indentUnit indentation units} of each indentation step.
298 *
299 * config.indentOffset = 4;
300 *
301 * @cfg {Number} [indentOffset=40]
302 * @member CKEDITOR.config
303 */
304
305/**
306 * The unit used for {@link CKEDITOR.config#indentOffset indentation offset}.
307 *
308 * config.indentUnit = 'em';
309 *
310 * @cfg {String} [indentUnit='px']
311 * @member CKEDITOR.config
312 */
diff --git a/sources/plugins/indentlist/plugin.js b/sources/plugins/indentlist/plugin.js
new file mode 100644
index 0000000..15c661f
--- /dev/null
+++ b/sources/plugins/indentlist/plugin.js
@@ -0,0 +1,318 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Handles the indentation of lists.
8 */
9
10( function() {
11 'use strict';
12
13 var isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
14 isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ),
15 TRISTATE_DISABLED = CKEDITOR.TRISTATE_DISABLED,
16 TRISTATE_OFF = CKEDITOR.TRISTATE_OFF;
17
18 CKEDITOR.plugins.add( 'indentlist', {
19 requires: 'indent',
20 init: function( editor ) {
21 var globalHelpers = CKEDITOR.plugins.indent;
22
23 // Register commands.
24 globalHelpers.registerCommands( editor, {
25 indentlist: new commandDefinition( editor, 'indentlist', true ),
26 outdentlist: new commandDefinition( editor, 'outdentlist' )
27 } );
28
29 function commandDefinition( editor ) {
30 globalHelpers.specificDefinition.apply( this, arguments );
31
32 // Require ul OR ol list.
33 this.requiredContent = [ 'ul', 'ol' ];
34
35 // Indent and outdent lists with TAB/SHIFT+TAB key. Indenting can
36 // be done for any list item that isn't the first child of the parent.
37 editor.on( 'key', function( evt ) {
38 if ( editor.mode != 'wysiwyg' )
39 return;
40
41 if ( evt.data.keyCode == this.indentKey ) {
42 var list = this.getContext( editor.elementPath() );
43
44 if ( list ) {
45 // Don't indent if in first list item of the parent.
46 // Outdent, however, can always be done to collapse
47 // the list into a paragraph (div).
48 if ( this.isIndent && CKEDITOR.plugins.indentList.firstItemInPath( this.context, editor.elementPath(), list ) )
49 return;
50
51 // Exec related global indentation command. Global
52 // commands take care of bookmarks and selection,
53 // so it's much easier to use them instead of
54 // content-specific commands.
55 editor.execCommand( this.relatedGlobal );
56
57 // Cancel the key event so editor doesn't lose focus.
58 evt.cancel();
59 }
60 }
61 }, this );
62
63 // There are two different jobs for this plugin:
64 //
65 // * Indent job (priority=10), before indentblock.
66 //
67 // This job is before indentblock because, if this plugin is
68 // loaded it has higher priority over indentblock. It means that,
69 // if possible, nesting is performed, and then block manipulation,
70 // if necessary.
71 //
72 // * Outdent job (priority=30), after outdentblock.
73 //
74 // This job got to be after outdentblock because in some cases
75 // (margin, config#indentClass on list) outdent must be done on
76 // block-level.
77
78 this.jobs[ this.isIndent ? 10 : 30 ] = {
79 refresh: this.isIndent ?
80 function( editor, path ) {
81 var list = this.getContext( path ),
82 inFirstListItem = CKEDITOR.plugins.indentList.firstItemInPath( this.context, path, list );
83
84 if ( !list || !this.isIndent || inFirstListItem )
85 return TRISTATE_DISABLED;
86
87 return TRISTATE_OFF;
88 } : function( editor, path ) {
89 var list = this.getContext( path );
90
91 if ( !list || this.isIndent )
92 return TRISTATE_DISABLED;
93
94 return TRISTATE_OFF;
95 },
96
97 exec: CKEDITOR.tools.bind( indentList, this )
98 };
99 }
100
101 CKEDITOR.tools.extend( commandDefinition.prototype, globalHelpers.specificDefinition.prototype, {
102 // Elements that, if in an elementpath, will be handled by this
103 // command. They restrict the scope of the plugin.
104 context: { ol: 1, ul: 1 }
105 } );
106 }
107 } );
108
109 function indentList( editor ) {
110 var that = this,
111 database = this.database,
112 context = this.context;
113
114 function indent( listNode ) {
115 // Our starting and ending points of the range might be inside some blocks under a list item...
116 // So before playing with the iterator, we need to expand the block to include the list items.
117 var startContainer = range.startContainer,
118 endContainer = range.endContainer;
119 while ( startContainer && !startContainer.getParent().equals( listNode ) )
120 startContainer = startContainer.getParent();
121 while ( endContainer && !endContainer.getParent().equals( listNode ) )
122 endContainer = endContainer.getParent();
123
124 if ( !startContainer || !endContainer )
125 return false;
126
127 // Now we can iterate over the individual items on the same tree depth.
128 var block = startContainer,
129 itemsToMove = [],
130 stopFlag = false;
131
132 while ( !stopFlag ) {
133 if ( block.equals( endContainer ) )
134 stopFlag = true;
135
136 itemsToMove.push( block );
137 block = block.getNext();
138 }
139
140 if ( itemsToMove.length < 1 )
141 return false;
142
143 // Do indent or outdent operations on the array model of the list, not the
144 // list's DOM tree itself. The array model demands that it knows as much as
145 // possible about the surrounding lists, we need to feed it the further
146 // ancestor node that is still a list.
147 var listParents = listNode.getParents( true );
148 for ( var i = 0; i < listParents.length; i++ ) {
149 if ( listParents[ i ].getName && context[ listParents[ i ].getName() ] ) {
150 listNode = listParents[ i ];
151 break;
152 }
153 }
154
155 var indentOffset = that.isIndent ? 1 : -1,
156 startItem = itemsToMove[ 0 ],
157 lastItem = itemsToMove[ itemsToMove.length - 1 ],
158
159 // Convert the list DOM tree into a one dimensional array.
160 listArray = CKEDITOR.plugins.list.listToArray( listNode, database ),
161
162 // Apply indenting or outdenting on the array.
163 baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
164
165 for ( i = startItem.getCustomData( 'listarray_index' ); i <= lastItem.getCustomData( 'listarray_index' ); i++ ) {
166 listArray[ i ].indent += indentOffset;
167 // Make sure the newly created sublist get a brand-new element of the same type. (#5372)
168 if ( indentOffset > 0 ) {
169 var listRoot = listArray[ i ].parent;
170 listArray[ i ].parent = new CKEDITOR.dom.element( listRoot.getName(), listRoot.getDocument() );
171 }
172 }
173
174 for ( i = lastItem.getCustomData( 'listarray_index' ) + 1; i < listArray.length && listArray[ i ].indent > baseIndent; i++ )
175 listArray[ i ].indent += indentOffset;
176
177 // Convert the array back to a DOM forest (yes we might have a few subtrees now).
178 // And replace the old list with the new forest.
179 var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, listNode.getDirection() );
180
181 // Avoid nested <li> after outdent even they're visually same,
182 // recording them for later refactoring.(#3982)
183 if ( !that.isIndent ) {
184 var parentLiElement;
185 if ( ( parentLiElement = listNode.getParent() ) && parentLiElement.is( 'li' ) ) {
186 var children = newList.listNode.getChildren(),
187 pendingLis = [],
188 count = children.count(),
189 child;
190
191 for ( i = count - 1; i >= 0; i-- ) {
192 if ( ( child = children.getItem( i ) ) && child.is && child.is( 'li' ) )
193 pendingLis.push( child );
194 }
195 }
196 }
197
198 if ( newList )
199 newList.listNode.replace( listNode );
200
201 // Move the nested <li> to be appeared after the parent.
202 if ( pendingLis && pendingLis.length ) {
203 for ( i = 0; i < pendingLis.length; i++ ) {
204 var li = pendingLis[ i ],
205 followingList = li;
206
207 // Nest preceding <ul>/<ol> inside current <li> if any.
208 while ( ( followingList = followingList.getNext() ) && followingList.is && followingList.getName() in context ) {
209 // IE requires a filler NBSP for nested list inside empty list item,
210 // otherwise the list item will be inaccessiable. (#4476)
211 if ( CKEDITOR.env.needsNbspFiller && !li.getFirst( neitherWhitespacesNorBookmark ) )
212 li.append( range.document.createText( '\u00a0' ) );
213
214 li.append( followingList );
215 }
216
217 li.insertAfter( parentLiElement );
218 }
219 }
220
221 if ( newList )
222 editor.fire( 'contentDomInvalidated' );
223
224 return true;
225 }
226
227 var selection = editor.getSelection(),
228 ranges = selection && selection.getRanges(),
229 iterator = ranges.createIterator(),
230 range;
231
232 while ( ( range = iterator.getNextRange() ) ) {
233 var nearestListBlock = range.getCommonAncestor();
234
235 while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT && context[ nearestListBlock.getName() ] ) ) {
236 // Avoid having plugin propagate to parent of editor in inline mode by canceling the indentation. (#12796)
237 if ( editor.editable().equals( nearestListBlock ) ) {
238 nearestListBlock = false;
239 break;
240 }
241 nearestListBlock = nearestListBlock.getParent();
242 }
243
244 // Avoid having selection boundaries out of the list.
245 // <ul><li>[...</li></ul><p>...]</p> => <ul><li>[...]</li></ul><p>...</p>
246 if ( !nearestListBlock ) {
247 if ( ( nearestListBlock = range.startPath().contains( context ) ) )
248 range.setEndAt( nearestListBlock, CKEDITOR.POSITION_BEFORE_END );
249 }
250
251 // Avoid having selection enclose the entire list. (#6138)
252 // [<ul><li>...</li></ul>] =><ul><li>[...]</li></ul>
253 if ( !nearestListBlock ) {
254 var selectedNode = range.getEnclosedNode();
255 if ( selectedNode && selectedNode.type == CKEDITOR.NODE_ELEMENT && selectedNode.getName() in context ) {
256 range.setStartAt( selectedNode, CKEDITOR.POSITION_AFTER_START );
257 range.setEndAt( selectedNode, CKEDITOR.POSITION_BEFORE_END );
258 nearestListBlock = selectedNode;
259 }
260 }
261
262 // Avoid selection anchors under list root.
263 // <ul>[<li>...</li>]</ul> => <ul><li>[...]</li></ul>
264 if ( nearestListBlock && range.startContainer.type == CKEDITOR.NODE_ELEMENT && range.startContainer.getName() in context ) {
265 var walker = new CKEDITOR.dom.walker( range );
266 walker.evaluator = listItem;
267 range.startContainer = walker.next();
268 }
269
270 if ( nearestListBlock && range.endContainer.type == CKEDITOR.NODE_ELEMENT && range.endContainer.getName() in context ) {
271 walker = new CKEDITOR.dom.walker( range );
272 walker.evaluator = listItem;
273 range.endContainer = walker.previous();
274 }
275
276 if ( nearestListBlock )
277 return indent( nearestListBlock );
278 }
279 return 0;
280 }
281
282 // Determines whether a node is a list <li> element.
283 function listItem( node ) {
284 return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );
285 }
286
287 function neitherWhitespacesNorBookmark( node ) {
288 return isNotWhitespaces( node ) && isNotBookmark( node );
289 }
290
291 /**
292 * Global namespace for methods exposed by the Indent List plugin.
293 *
294 * @singleton
295 * @class
296 */
297 CKEDITOR.plugins.indentList = {};
298
299 /**
300 * Checks whether the first child of the list is in the path.
301 * The list can be extracted from the path or given explicitly
302 * e.g. for better performance if cached.
303 *
304 * @since 4.4.6
305 * @param {Object} query See the {@link CKEDITOR.dom.elementPath#contains} method arguments.
306 * @param {CKEDITOR.dom.elementPath} path
307 * @param {CKEDITOR.dom.element} [list]
308 * @returns {Boolean}
309 * @member CKEDITOR.plugins.indentList
310 */
311 CKEDITOR.plugins.indentList.firstItemInPath = function( query, path, list ) {
312 var firstListItemInPath = path.contains( listItem );
313 if ( !list )
314 list = path.contains( query );
315
316 return list && firstListItemInPath && firstListItemInPath.equals( list.getFirst( listItem ) );
317 };
318} )();
diff --git a/sources/plugins/justify/icons/hidpi/justifyblock.png b/sources/plugins/justify/icons/hidpi/justifyblock.png
new file mode 100644
index 0000000..5c0cf43
--- /dev/null
+++ b/sources/plugins/justify/icons/hidpi/justifyblock.png
Binary files differ
diff --git a/sources/plugins/justify/icons/hidpi/justifycenter.png b/sources/plugins/justify/icons/hidpi/justifycenter.png
new file mode 100644
index 0000000..fd751be
--- /dev/null
+++ b/sources/plugins/justify/icons/hidpi/justifycenter.png
Binary files differ
diff --git a/sources/plugins/justify/icons/hidpi/justifyleft.png b/sources/plugins/justify/icons/hidpi/justifyleft.png
new file mode 100644
index 0000000..a109ad3
--- /dev/null
+++ b/sources/plugins/justify/icons/hidpi/justifyleft.png
Binary files differ
diff --git a/sources/plugins/justify/icons/hidpi/justifyright.png b/sources/plugins/justify/icons/hidpi/justifyright.png
new file mode 100644
index 0000000..5125d56
--- /dev/null
+++ b/sources/plugins/justify/icons/hidpi/justifyright.png
Binary files differ
diff --git a/sources/plugins/justify/icons/justifyblock.png b/sources/plugins/justify/icons/justifyblock.png
new file mode 100644
index 0000000..ffe0620
--- /dev/null
+++ b/sources/plugins/justify/icons/justifyblock.png
Binary files differ
diff --git a/sources/plugins/justify/icons/justifycenter.png b/sources/plugins/justify/icons/justifycenter.png
new file mode 100644
index 0000000..8b5b40f
--- /dev/null
+++ b/sources/plugins/justify/icons/justifycenter.png
Binary files differ
diff --git a/sources/plugins/justify/icons/justifyleft.png b/sources/plugins/justify/icons/justifyleft.png
new file mode 100644
index 0000000..a60d079
--- /dev/null
+++ b/sources/plugins/justify/icons/justifyleft.png
Binary files differ
diff --git a/sources/plugins/justify/icons/justifyright.png b/sources/plugins/justify/icons/justifyright.png
new file mode 100644
index 0000000..21de814
--- /dev/null
+++ b/sources/plugins/justify/icons/justifyright.png
Binary files differ
diff --git a/sources/plugins/justify/lang/af.js b/sources/plugins/justify/lang/af.js
new file mode 100644
index 0000000..9f5c303
--- /dev/null
+++ b/sources/plugins/justify/lang/af.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'af', {
6 block: 'Uitvul',
7 center: 'Sentreer',
8 left: 'Links oplyn',
9 right: 'Regs oplyn'
10} );
diff --git a/sources/plugins/justify/lang/ar.js b/sources/plugins/justify/lang/ar.js
new file mode 100644
index 0000000..6c414be
--- /dev/null
+++ b/sources/plugins/justify/lang/ar.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ar', {
6 block: 'ضبط',
7 center: 'توسيط',
8 left: 'محاذاة إلى اليسار',
9 right: 'محاذاة إلى اليمين'
10} );
diff --git a/sources/plugins/justify/lang/az.js b/sources/plugins/justify/lang/az.js
new file mode 100644
index 0000000..9360568
--- /dev/null
+++ b/sources/plugins/justify/lang/az.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'az', {
6 block: 'Eninə görə',
7 center: 'Mərkəz',
8 left: 'Soldan düzləndir',
9 right: 'Sağdan düzləndir'
10} );
diff --git a/sources/plugins/justify/lang/bg.js b/sources/plugins/justify/lang/bg.js
new file mode 100644
index 0000000..1724947
--- /dev/null
+++ b/sources/plugins/justify/lang/bg.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'bg', {
6 block: 'Двустранно подравняване',
7 center: 'Център',
8 left: 'Подравни в ляво',
9 right: 'Подравни в дясно'
10} );
diff --git a/sources/plugins/justify/lang/bn.js b/sources/plugins/justify/lang/bn.js
new file mode 100644
index 0000000..002a633
--- /dev/null
+++ b/sources/plugins/justify/lang/bn.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'bn', {
6 block: 'যাচাই করি',
7 center: 'মাঝ বরাবর ঘেষা',
8 left: 'বা দিকে ঘেঁষা',
9 right: 'ডান দিকে ঘেঁষা'
10} );
diff --git a/sources/plugins/justify/lang/bs.js b/sources/plugins/justify/lang/bs.js
new file mode 100644
index 0000000..0fbedfc
--- /dev/null
+++ b/sources/plugins/justify/lang/bs.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'bs', {
6 block: 'Puno poravnanje',
7 center: 'Centralno poravnanje',
8 left: 'Lijevo poravnanje',
9 right: 'Desno poravnanje'
10} );
diff --git a/sources/plugins/justify/lang/ca.js b/sources/plugins/justify/lang/ca.js
new file mode 100644
index 0000000..afb7adb
--- /dev/null
+++ b/sources/plugins/justify/lang/ca.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ca', {
6 block: 'Justificat',
7 center: 'Centrat',
8 left: 'Alinea a l\'esquerra',
9 right: 'Alinea a la dreta'
10} );
diff --git a/sources/plugins/justify/lang/cs.js b/sources/plugins/justify/lang/cs.js
new file mode 100644
index 0000000..467ae6f
--- /dev/null
+++ b/sources/plugins/justify/lang/cs.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'cs', {
6 block: 'Zarovnat do bloku',
7 center: 'Zarovnat na střed',
8 left: 'Zarovnat vlevo',
9 right: 'Zarovnat vpravo'
10} );
diff --git a/sources/plugins/justify/lang/cy.js b/sources/plugins/justify/lang/cy.js
new file mode 100644
index 0000000..6b39beb
--- /dev/null
+++ b/sources/plugins/justify/lang/cy.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'cy', {
6 block: 'Unioni',
7 center: 'Alinio i\'r Canol',
8 left: 'Alinio i\'r Chwith',
9 right: 'Alinio i\'r Dde'
10} );
diff --git a/sources/plugins/justify/lang/da.js b/sources/plugins/justify/lang/da.js
new file mode 100644
index 0000000..ac8ee29
--- /dev/null
+++ b/sources/plugins/justify/lang/da.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'da', {
6 block: 'Lige margener',
7 center: 'Centreret',
8 left: 'Venstrestillet',
9 right: 'Højrestillet'
10} );
diff --git a/sources/plugins/justify/lang/de-ch.js b/sources/plugins/justify/lang/de-ch.js
new file mode 100644
index 0000000..a2c24eb
--- /dev/null
+++ b/sources/plugins/justify/lang/de-ch.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'de-ch', {
6 block: 'Blocksatz',
7 center: 'Zentriert',
8 left: 'Linksbündig',
9 right: 'Rechtsbündig'
10} );
diff --git a/sources/plugins/justify/lang/de.js b/sources/plugins/justify/lang/de.js
new file mode 100644
index 0000000..4db8725
--- /dev/null
+++ b/sources/plugins/justify/lang/de.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'de', {
6 block: 'Blocksatz',
7 center: 'Zentriert',
8 left: 'Linksbündig',
9 right: 'Rechtsbündig'
10} );
diff --git a/sources/plugins/justify/lang/el.js b/sources/plugins/justify/lang/el.js
new file mode 100644
index 0000000..1bdc64f
--- /dev/null
+++ b/sources/plugins/justify/lang/el.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'el', {
6 block: 'Πλήρης Στοίχιση',
7 center: 'Στο Κέντρο',
8 left: 'Στοίχιση Αριστερά',
9 right: 'Στοίχιση Δεξιά'
10} );
diff --git a/sources/plugins/justify/lang/en-au.js b/sources/plugins/justify/lang/en-au.js
new file mode 100644
index 0000000..68eb09c
--- /dev/null
+++ b/sources/plugins/justify/lang/en-au.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'en-au', {
6 block: 'Justify',
7 center: 'Centre',
8 left: 'Align Left',
9 right: 'Align Right'
10} );
diff --git a/sources/plugins/justify/lang/en-ca.js b/sources/plugins/justify/lang/en-ca.js
new file mode 100644
index 0000000..27718a2
--- /dev/null
+++ b/sources/plugins/justify/lang/en-ca.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'en-ca', {
6 block: 'Justify',
7 center: 'Centre',
8 left: 'Align Left',
9 right: 'Align Right'
10} );
diff --git a/sources/plugins/justify/lang/en-gb.js b/sources/plugins/justify/lang/en-gb.js
new file mode 100644
index 0000000..d6db4ff
--- /dev/null
+++ b/sources/plugins/justify/lang/en-gb.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'en-gb', {
6 block: 'Justify',
7 center: 'Centre',
8 left: 'Align Left',
9 right: 'Align Right'
10} );
diff --git a/sources/plugins/justify/lang/en.js b/sources/plugins/justify/lang/en.js
new file mode 100644
index 0000000..8a72e85
--- /dev/null
+++ b/sources/plugins/justify/lang/en.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'en', {
6 block: 'Justify',
7 center: 'Center',
8 left: 'Align Left',
9 right: 'Align Right'
10} );
diff --git a/sources/plugins/justify/lang/eo.js b/sources/plugins/justify/lang/eo.js
new file mode 100644
index 0000000..7531dde
--- /dev/null
+++ b/sources/plugins/justify/lang/eo.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'eo', {
6 block: 'Ĝisrandigi Ambaŭflanke',
7 center: 'Centrigi',
8 left: 'Ĝisrandigi maldekstren',
9 right: 'Ĝisrandigi dekstren'
10} );
diff --git a/sources/plugins/justify/lang/es.js b/sources/plugins/justify/lang/es.js
new file mode 100644
index 0000000..2e89bc0
--- /dev/null
+++ b/sources/plugins/justify/lang/es.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'es', {
6 block: 'Justificado',
7 center: 'Centrar',
8 left: 'Alinear a Izquierda',
9 right: 'Alinear a Derecha'
10} );
diff --git a/sources/plugins/justify/lang/et.js b/sources/plugins/justify/lang/et.js
new file mode 100644
index 0000000..0fc4915
--- /dev/null
+++ b/sources/plugins/justify/lang/et.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'et', {
6 block: 'Rööpjoondus',
7 center: 'Keskjoondus',
8 left: 'Vasakjoondus',
9 right: 'Paremjoondus'
10} );
diff --git a/sources/plugins/justify/lang/eu.js b/sources/plugins/justify/lang/eu.js
new file mode 100644
index 0000000..f7d291e
--- /dev/null
+++ b/sources/plugins/justify/lang/eu.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'eu', {
6 block: 'Justifikatu',
7 center: 'Erdian',
8 left: 'Lerrokatu ezkerrean',
9 right: 'Lerrokatu eskuinean'
10} );
diff --git a/sources/plugins/justify/lang/fa.js b/sources/plugins/justify/lang/fa.js
new file mode 100644
index 0000000..03c3c6b
--- /dev/null
+++ b/sources/plugins/justify/lang/fa.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'fa', {
6 block: 'بلوک چین',
7 center: 'میان چین',
8 left: 'چپ چین',
9 right: 'راست چین'
10} );
diff --git a/sources/plugins/justify/lang/fi.js b/sources/plugins/justify/lang/fi.js
new file mode 100644
index 0000000..6993f10
--- /dev/null
+++ b/sources/plugins/justify/lang/fi.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'fi', {
6 block: 'Tasaa molemmat reunat',
7 center: 'Keskitä',
8 left: 'Tasaa vasemmat reunat',
9 right: 'Tasaa oikeat reunat'
10} );
diff --git a/sources/plugins/justify/lang/fo.js b/sources/plugins/justify/lang/fo.js
new file mode 100644
index 0000000..f11a575
--- /dev/null
+++ b/sources/plugins/justify/lang/fo.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'fo', {
6 block: 'Javnir tekstkantar',
7 center: 'Miðsett',
8 left: 'Vinstrasett',
9 right: 'Høgrasett'
10} );
diff --git a/sources/plugins/justify/lang/fr-ca.js b/sources/plugins/justify/lang/fr-ca.js
new file mode 100644
index 0000000..8d59e5e
--- /dev/null
+++ b/sources/plugins/justify/lang/fr-ca.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'fr-ca', {
6 block: 'Justifié',
7 center: 'Centré',
8 left: 'Aligner à gauche',
9 right: 'Aligner à Droite'
10} );
diff --git a/sources/plugins/justify/lang/fr.js b/sources/plugins/justify/lang/fr.js
new file mode 100644
index 0000000..e44df52
--- /dev/null
+++ b/sources/plugins/justify/lang/fr.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'fr', {
6 block: 'Justifier',
7 center: 'Centrer',
8 left: 'Aligner à gauche',
9 right: 'Aligner à droite'
10} );
diff --git a/sources/plugins/justify/lang/gl.js b/sources/plugins/justify/lang/gl.js
new file mode 100644
index 0000000..1995e8c
--- /dev/null
+++ b/sources/plugins/justify/lang/gl.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'gl', {
6 block: 'Xustificado',
7 center: 'Centrado',
8 left: 'Aliñar á esquerda',
9 right: 'Aliñar á dereita'
10} );
diff --git a/sources/plugins/justify/lang/gu.js b/sources/plugins/justify/lang/gu.js
new file mode 100644
index 0000000..d491684
--- /dev/null
+++ b/sources/plugins/justify/lang/gu.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'gu', {
6 block: 'બ્લૉક, અંતરાય જસ્ટિફાઇ',
7 center: 'સંકેંદ્રણ/સેંટરિંગ',
8 left: 'ડાબી બાજુએ/બાજુ તરફ',
9 right: 'જમણી બાજુએ/બાજુ તરફ'
10} );
diff --git a/sources/plugins/justify/lang/he.js b/sources/plugins/justify/lang/he.js
new file mode 100644
index 0000000..ab5c759
--- /dev/null
+++ b/sources/plugins/justify/lang/he.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'he', {
6 block: 'יישור לשוליים',
7 center: 'מרכוז',
8 left: 'יישור לשמאל',
9 right: 'יישור לימין'
10} );
diff --git a/sources/plugins/justify/lang/hi.js b/sources/plugins/justify/lang/hi.js
new file mode 100644
index 0000000..6a4fae8
--- /dev/null
+++ b/sources/plugins/justify/lang/hi.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'hi', {
6 block: 'ब्लॉक जस्टीफ़ाई',
7 center: 'बीच में',
8 left: 'बायीं तरफ',
9 right: 'दायीं तरफ'
10} );
diff --git a/sources/plugins/justify/lang/hr.js b/sources/plugins/justify/lang/hr.js
new file mode 100644
index 0000000..852c686
--- /dev/null
+++ b/sources/plugins/justify/lang/hr.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'hr', {
6 block: 'Blok poravnanje',
7 center: 'Središnje poravnanje',
8 left: 'Lijevo poravnanje',
9 right: 'Desno poravnanje'
10} );
diff --git a/sources/plugins/justify/lang/hu.js b/sources/plugins/justify/lang/hu.js
new file mode 100644
index 0000000..c7b8dad
--- /dev/null
+++ b/sources/plugins/justify/lang/hu.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'hu', {
6 block: 'Sorkizárt',
7 center: 'Középre',
8 left: 'Balra',
9 right: 'Jobbra'
10} );
diff --git a/sources/plugins/justify/lang/id.js b/sources/plugins/justify/lang/id.js
new file mode 100644
index 0000000..d67247c
--- /dev/null
+++ b/sources/plugins/justify/lang/id.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'id', {
6 block: 'Rata kiri-kanan',
7 center: 'Pusat',
8 left: 'Align Left', // MISSING
9 right: 'Align Right' // MISSING
10} );
diff --git a/sources/plugins/justify/lang/is.js b/sources/plugins/justify/lang/is.js
new file mode 100644
index 0000000..d01a43a
--- /dev/null
+++ b/sources/plugins/justify/lang/is.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'is', {
6 block: 'Jafna báðum megin',
7 center: 'Miðja texta',
8 left: 'Vinstrijöfnun',
9 right: 'Hægrijöfnun'
10} );
diff --git a/sources/plugins/justify/lang/it.js b/sources/plugins/justify/lang/it.js
new file mode 100644
index 0000000..fd4ae51
--- /dev/null
+++ b/sources/plugins/justify/lang/it.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'it', {
6 block: 'Giustifica',
7 center: 'Centra',
8 left: 'Allinea a sinistra',
9 right: 'Allinea a destra'
10} );
diff --git a/sources/plugins/justify/lang/ja.js b/sources/plugins/justify/lang/ja.js
new file mode 100644
index 0000000..6c71c86
--- /dev/null
+++ b/sources/plugins/justify/lang/ja.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ja', {
6 block: '両端揃え',
7 center: '中央揃え',
8 left: '左揃え',
9 right: '右揃え'
10} );
diff --git a/sources/plugins/justify/lang/ka.js b/sources/plugins/justify/lang/ka.js
new file mode 100644
index 0000000..4ba0bcb
--- /dev/null
+++ b/sources/plugins/justify/lang/ka.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ka', {
6 block: 'გადასწორება',
7 center: 'შუაში სწორება',
8 left: 'მარცხნივ სწორება',
9 right: 'მარჯვნივ სწორება'
10} );
diff --git a/sources/plugins/justify/lang/km.js b/sources/plugins/justify/lang/km.js
new file mode 100644
index 0000000..a7546c3
--- /dev/null
+++ b/sources/plugins/justify/lang/km.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'km', {
6 block: 'តម្រឹម​ពេញ',
7 center: 'កណ្ដាល',
8 left: 'តម្រឹម​ឆ្វេង',
9 right: 'តម្រឹម​ស្ដាំ'
10} );
diff --git a/sources/plugins/justify/lang/ko.js b/sources/plugins/justify/lang/ko.js
new file mode 100644
index 0000000..346405d
--- /dev/null
+++ b/sources/plugins/justify/lang/ko.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ko', {
6 block: '양쪽 맞춤',
7 center: '가운데 정렬',
8 left: '왼쪽 정렬',
9 right: '오른쪽 정렬'
10} );
diff --git a/sources/plugins/justify/lang/ku.js b/sources/plugins/justify/lang/ku.js
new file mode 100644
index 0000000..24ed914
--- /dev/null
+++ b/sources/plugins/justify/lang/ku.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ku', {
6 block: 'هاوستوونی',
7 center: 'ناوەڕاست',
8 left: 'بەهێڵ کردنی چەپ',
9 right: 'بەهێڵ کردنی ڕاست'
10} );
diff --git a/sources/plugins/justify/lang/lt.js b/sources/plugins/justify/lang/lt.js
new file mode 100644
index 0000000..08202cb
--- /dev/null
+++ b/sources/plugins/justify/lang/lt.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'lt', {
6 block: 'Lygiuoti abi puses',
7 center: 'Centruoti',
8 left: 'Lygiuoti kairę',
9 right: 'Lygiuoti dešinę'
10} );
diff --git a/sources/plugins/justify/lang/lv.js b/sources/plugins/justify/lang/lv.js
new file mode 100644
index 0000000..8c729c9
--- /dev/null
+++ b/sources/plugins/justify/lang/lv.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'lv', {
6 block: 'Izlīdzināt malas',
7 center: 'Izlīdzināt pret centru',
8 left: 'Izlīdzināt pa kreisi',
9 right: 'Izlīdzināt pa labi'
10} );
diff --git a/sources/plugins/justify/lang/mk.js b/sources/plugins/justify/lang/mk.js
new file mode 100644
index 0000000..f45fb19
--- /dev/null
+++ b/sources/plugins/justify/lang/mk.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'mk', {
6 block: 'Justify', // MISSING
7 center: 'Во средина',
8 left: 'Align Left', // MISSING
9 right: 'Align Right' // MISSING
10} );
diff --git a/sources/plugins/justify/lang/mn.js b/sources/plugins/justify/lang/mn.js
new file mode 100644
index 0000000..850e474
--- /dev/null
+++ b/sources/plugins/justify/lang/mn.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'mn', {
6 block: 'Тэгшлэх',
7 center: 'Голлуулах',
8 left: 'Зүүн талд тулгах',
9 right: 'Баруун талд тулгах'
10} );
diff --git a/sources/plugins/justify/lang/ms.js b/sources/plugins/justify/lang/ms.js
new file mode 100644
index 0000000..323f8e9
--- /dev/null
+++ b/sources/plugins/justify/lang/ms.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ms', {
6 block: 'Jajaran Blok',
7 center: 'Jajaran Tengah',
8 left: 'Jajaran Kiri',
9 right: 'Jajaran Kanan'
10} );
diff --git a/sources/plugins/justify/lang/nb.js b/sources/plugins/justify/lang/nb.js
new file mode 100644
index 0000000..98a3c44
--- /dev/null
+++ b/sources/plugins/justify/lang/nb.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'nb', {
6 block: 'Blokkjuster',
7 center: 'Midtstill',
8 left: 'Venstrejuster',
9 right: 'Høyrejuster'
10} );
diff --git a/sources/plugins/justify/lang/nl.js b/sources/plugins/justify/lang/nl.js
new file mode 100644
index 0000000..972bf82
--- /dev/null
+++ b/sources/plugins/justify/lang/nl.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'nl', {
6 block: 'Uitvullen',
7 center: 'Centreren',
8 left: 'Links uitlijnen',
9 right: 'Rechts uitlijnen'
10} );
diff --git a/sources/plugins/justify/lang/no.js b/sources/plugins/justify/lang/no.js
new file mode 100644
index 0000000..cfcd72a
--- /dev/null
+++ b/sources/plugins/justify/lang/no.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'no', {
6 block: 'Blokkjuster',
7 center: 'Midtstill',
8 left: 'Venstrejuster',
9 right: 'Høyrejuster'
10} );
diff --git a/sources/plugins/justify/lang/oc.js b/sources/plugins/justify/lang/oc.js
new file mode 100644
index 0000000..a13e528
--- /dev/null
+++ b/sources/plugins/justify/lang/oc.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'oc', {
6 block: 'Justificar',
7 center: 'Centrar',
8 left: 'Alinhar a esquèrra',
9 right: 'Alinhar a dreita'
10} );
diff --git a/sources/plugins/justify/lang/pl.js b/sources/plugins/justify/lang/pl.js
new file mode 100644
index 0000000..60922b9
--- /dev/null
+++ b/sources/plugins/justify/lang/pl.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'pl', {
6 block: 'Wyjustuj',
7 center: 'Wyśrodkuj',
8 left: 'Wyrównaj do lewej',
9 right: 'Wyrównaj do prawej'
10} );
diff --git a/sources/plugins/justify/lang/pt-br.js b/sources/plugins/justify/lang/pt-br.js
new file mode 100644
index 0000000..cf40ad0
--- /dev/null
+++ b/sources/plugins/justify/lang/pt-br.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'pt-br', {
6 block: 'Justificado',
7 center: 'Centralizar',
8 left: 'Alinhar Esquerda',
9 right: 'Alinhar Direita'
10} );
diff --git a/sources/plugins/justify/lang/pt.js b/sources/plugins/justify/lang/pt.js
new file mode 100644
index 0000000..46ac43b
--- /dev/null
+++ b/sources/plugins/justify/lang/pt.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'pt', {
6 block: 'Justificado',
7 center: 'Alinhar ao centro',
8 left: 'Alinhar à esquerda',
9 right: 'Alinhar à direita'
10} );
diff --git a/sources/plugins/justify/lang/ro.js b/sources/plugins/justify/lang/ro.js
new file mode 100644
index 0000000..21caeca
--- /dev/null
+++ b/sources/plugins/justify/lang/ro.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ro', {
6 block: 'Aliniere în bloc (Block Justify)',
7 center: 'Aliniere centrală',
8 left: 'Aliniere la stânga',
9 right: 'Aliniere la dreapta'
10} );
diff --git a/sources/plugins/justify/lang/ru.js b/sources/plugins/justify/lang/ru.js
new file mode 100644
index 0000000..47c98bb
--- /dev/null
+++ b/sources/plugins/justify/lang/ru.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ru', {
6 block: 'По ширине',
7 center: 'По центру',
8 left: 'По левому краю',
9 right: 'По правому краю'
10} );
diff --git a/sources/plugins/justify/lang/si.js b/sources/plugins/justify/lang/si.js
new file mode 100644
index 0000000..6d9f373
--- /dev/null
+++ b/sources/plugins/justify/lang/si.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'si', {
6 block: 'Justify', // MISSING
7 center: 'මධ්‍ය',
8 left: 'Align Left', // MISSING
9 right: 'Align Right' // MISSING
10} );
diff --git a/sources/plugins/justify/lang/sk.js b/sources/plugins/justify/lang/sk.js
new file mode 100644
index 0000000..08c3991
--- /dev/null
+++ b/sources/plugins/justify/lang/sk.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sk', {
6 block: 'Zarovnať do bloku',
7 center: 'Zarovnať na stred',
8 left: 'Zarovnať vľavo',
9 right: 'Zarovnať vpravo'
10} );
diff --git a/sources/plugins/justify/lang/sl.js b/sources/plugins/justify/lang/sl.js
new file mode 100644
index 0000000..d776354
--- /dev/null
+++ b/sources/plugins/justify/lang/sl.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sl', {
6 block: 'Obojestranska poravnava',
7 center: 'Sredinska poravnava',
8 left: 'Leva poravnava',
9 right: 'Desna poravnava'
10} );
diff --git a/sources/plugins/justify/lang/sq.js b/sources/plugins/justify/lang/sq.js
new file mode 100644
index 0000000..1ed002c
--- /dev/null
+++ b/sources/plugins/justify/lang/sq.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sq', {
6 block: 'Zgjero',
7 center: 'Qendër',
8 left: 'Rreshto majtas',
9 right: 'Rreshto Djathtas'
10} );
diff --git a/sources/plugins/justify/lang/sr-latn.js b/sources/plugins/justify/lang/sr-latn.js
new file mode 100644
index 0000000..7fdba23
--- /dev/null
+++ b/sources/plugins/justify/lang/sr-latn.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sr-latn', {
6 block: 'Obostrano ravnanje',
7 center: 'Centriran tekst',
8 left: 'Levo ravnanje',
9 right: 'Desno ravnanje'
10} );
diff --git a/sources/plugins/justify/lang/sr.js b/sources/plugins/justify/lang/sr.js
new file mode 100644
index 0000000..2314a96
--- /dev/null
+++ b/sources/plugins/justify/lang/sr.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sr', {
6 block: 'Обострано равнање',
7 center: 'Центриран текст',
8 left: 'Лево равнање',
9 right: 'Десно равнање'
10} );
diff --git a/sources/plugins/justify/lang/sv.js b/sources/plugins/justify/lang/sv.js
new file mode 100644
index 0000000..cac94c0
--- /dev/null
+++ b/sources/plugins/justify/lang/sv.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'sv', {
6 block: 'Justera till marginaler',
7 center: 'Centrera',
8 left: 'Vänsterjustera',
9 right: 'Högerjustera'
10} );
diff --git a/sources/plugins/justify/lang/th.js b/sources/plugins/justify/lang/th.js
new file mode 100644
index 0000000..4a9d4f9
--- /dev/null
+++ b/sources/plugins/justify/lang/th.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'th', {
6 block: 'จัดพอดีหน้ากระดาษ',
7 center: 'จัดกึ่งกลาง',
8 left: 'จัดชิดซ้าย',
9 right: 'จัดชิดขวา'
10} );
diff --git a/sources/plugins/justify/lang/tr.js b/sources/plugins/justify/lang/tr.js
new file mode 100644
index 0000000..fbc512f
--- /dev/null
+++ b/sources/plugins/justify/lang/tr.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'tr', {
6 block: 'İki Kenara Yaslanmış',
7 center: 'Ortalanmış',
8 left: 'Sola Dayalı',
9 right: 'Sağa Dayalı'
10} );
diff --git a/sources/plugins/justify/lang/tt.js b/sources/plugins/justify/lang/tt.js
new file mode 100644
index 0000000..b36f69c
--- /dev/null
+++ b/sources/plugins/justify/lang/tt.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'tt', {
6 block: 'Киңлеккә карап тигезләү',
7 center: 'Үзәккә тигезләү',
8 left: 'Сул як кырыйдан тигезләү',
9 right: 'Уң як кырыйдан тигезләү'
10} );
diff --git a/sources/plugins/justify/lang/ug.js b/sources/plugins/justify/lang/ug.js
new file mode 100644
index 0000000..e5861f5
--- /dev/null
+++ b/sources/plugins/justify/lang/ug.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'ug', {
6 block: 'ئىككى تەرەپتىن توغرىلا',
7 center: 'ئوتتۇرىغا توغرىلا',
8 left: 'سولغا توغرىلا',
9 right: 'ئوڭغا توغرىلا'
10} );
diff --git a/sources/plugins/justify/lang/uk.js b/sources/plugins/justify/lang/uk.js
new file mode 100644
index 0000000..5807f25
--- /dev/null
+++ b/sources/plugins/justify/lang/uk.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'uk', {
6 block: 'По ширині',
7 center: 'По центру',
8 left: 'По лівому краю',
9 right: 'По правому краю'
10} );
diff --git a/sources/plugins/justify/lang/vi.js b/sources/plugins/justify/lang/vi.js
new file mode 100644
index 0000000..de0c170
--- /dev/null
+++ b/sources/plugins/justify/lang/vi.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'vi', {
6 block: 'Canh đều',
7 center: 'Canh giữa',
8 left: 'Canh trái',
9 right: 'Canh phải'
10} );
diff --git a/sources/plugins/justify/lang/zh-cn.js b/sources/plugins/justify/lang/zh-cn.js
new file mode 100644
index 0000000..4c19627
--- /dev/null
+++ b/sources/plugins/justify/lang/zh-cn.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'zh-cn', {
6 block: '两端对齐',
7 center: '居中',
8 left: '左对齐',
9 right: '右对齐'
10} );
diff --git a/sources/plugins/justify/lang/zh.js b/sources/plugins/justify/lang/zh.js
new file mode 100644
index 0000000..0865d51
--- /dev/null
+++ b/sources/plugins/justify/lang/zh.js
@@ -0,0 +1,10 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'justify', 'zh', {
6 block: '左右對齊',
7 center: '置中',
8 left: '靠左對齊',
9 right: '靠右對齊'
10} );
diff --git a/sources/plugins/justify/plugin.js b/sources/plugins/justify/plugin.js
new file mode 100644
index 0000000..ce5cab3
--- /dev/null
+++ b/sources/plugins/justify/plugin.js
@@ -0,0 +1,245 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Justify commands.
8 */
9
10( function() {
11 function getAlignment( element, useComputedState ) {
12 useComputedState = useComputedState === undefined || useComputedState;
13
14 var align;
15 if ( useComputedState )
16 align = element.getComputedStyle( 'text-align' );
17 else {
18 while ( !element.hasAttribute || !( element.hasAttribute( 'align' ) || element.getStyle( 'text-align' ) ) ) {
19 var parent = element.getParent();
20 if ( !parent )
21 break;
22 element = parent;
23 }
24 align = element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || '';
25 }
26
27 // Sometimes computed values doesn't tell.
28 align && ( align = align.replace( /(?:-(?:moz|webkit)-)?(?:start|auto)/i, '' ) );
29
30 !align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' );
31
32 return align;
33 }
34
35 function justifyCommand( editor, name, value ) {
36 this.editor = editor;
37 this.name = name;
38 this.value = value;
39 this.context = 'p';
40
41 var classes = editor.config.justifyClasses,
42 blockTag = editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div';
43
44 if ( classes ) {
45 switch ( value ) {
46 case 'left':
47 this.cssClassName = classes[ 0 ];
48 break;
49 case 'center':
50 this.cssClassName = classes[ 1 ];
51 break;
52 case 'right':
53 this.cssClassName = classes[ 2 ];
54 break;
55 case 'justify':
56 this.cssClassName = classes[ 3 ];
57 break;
58 }
59
60 this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' );
61 this.requiredContent = blockTag + '(' + this.cssClassName + ')';
62 }
63 else {
64 this.requiredContent = blockTag + '{text-align}';
65 }
66
67 this.allowedContent = {
68 'caption div h1 h2 h3 h4 h5 h6 p pre td th li': {
69 // Do not add elements, but only text-align style if element is validated by other rule.
70 propertiesOnly: true,
71 styles: this.cssClassName ? null : 'text-align',
72 classes: this.cssClassName || null
73 }
74 };
75
76 // In enter mode BR we need to allow here for div, because when non other
77 // feature allows div justify is the only plugin that uses it.
78 if ( editor.config.enterMode == CKEDITOR.ENTER_BR )
79 this.allowedContent.div = true;
80 }
81
82 function onDirChanged( e ) {
83 var editor = e.editor;
84
85 var range = editor.createRange();
86 range.setStartBefore( e.data.node );
87 range.setEndAfter( e.data.node );
88
89 var walker = new CKEDITOR.dom.walker( range ),
90 node;
91
92 while ( ( node = walker.next() ) ) {
93 if ( node.type == CKEDITOR.NODE_ELEMENT ) {
94 // A child with the defined dir is to be ignored.
95 if ( !node.equals( e.data.node ) && node.getDirection() ) {
96 range.setStartAfter( node );
97 walker = new CKEDITOR.dom.walker( range );
98 continue;
99 }
100
101 // Switch the alignment.
102 var classes = editor.config.justifyClasses;
103 if ( classes ) {
104 // The left align class.
105 if ( node.hasClass( classes[ 0 ] ) ) {
106 node.removeClass( classes[ 0 ] );
107 node.addClass( classes[ 2 ] );
108 }
109 // The right align class.
110 else if ( node.hasClass( classes[ 2 ] ) ) {
111 node.removeClass( classes[ 2 ] );
112 node.addClass( classes[ 0 ] );
113 }
114 }
115
116 // Always switch CSS margins.
117 var style = 'text-align';
118 var align = node.getStyle( style );
119
120 if ( align == 'left' )
121 node.setStyle( style, 'right' );
122 else if ( align == 'right' )
123 node.setStyle( style, 'left' );
124 }
125 }
126 }
127
128 justifyCommand.prototype = {
129 exec: function( editor ) {
130 var selection = editor.getSelection(),
131 enterMode = editor.config.enterMode;
132
133 if ( !selection )
134 return;
135
136 var bookmarks = selection.createBookmarks(),
137 ranges = selection.getRanges();
138
139 var cssClassName = this.cssClassName,
140 iterator, block;
141
142 var useComputedState = editor.config.useComputedState;
143 useComputedState = useComputedState === undefined || useComputedState;
144
145 for ( var i = ranges.length - 1; i >= 0; i-- ) {
146 iterator = ranges[ i ].createIterator();
147 iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
148
149 while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) {
150 if ( block.isReadOnly() )
151 continue;
152
153 block.removeAttribute( 'align' );
154 block.removeStyle( 'text-align' );
155
156 // Remove any of the alignment classes from the className.
157 var className = cssClassName && ( block.$.className = CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) );
158
159 var apply = ( this.state == CKEDITOR.TRISTATE_OFF ) && ( !useComputedState || ( getAlignment( block, true ) != this.value ) );
160
161 if ( cssClassName ) {
162 // Append the desired class name.
163 if ( apply )
164 block.addClass( cssClassName );
165 else if ( !className )
166 block.removeAttribute( 'class' );
167 } else if ( apply ) {
168 block.setStyle( 'text-align', this.value );
169 }
170 }
171
172 }
173
174 editor.focus();
175 editor.forceNextSelectionCheck();
176 selection.selectBookmarks( bookmarks );
177 },
178
179 refresh: function( editor, path ) {
180 var firstBlock = path.block || path.blockLimit;
181
182 this.setState( firstBlock.getName() != 'body' && getAlignment( firstBlock, this.editor.config.useComputedState ) == this.value ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
183 }
184 };
185
186 CKEDITOR.plugins.add( 'justify', {
187 // jscs:disable maximumLineLength
188 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
189 // jscs:enable maximumLineLength
190 icons: 'justifyblock,justifycenter,justifyleft,justifyright', // %REMOVE_LINE_CORE%
191 hidpi: true, // %REMOVE_LINE_CORE%
192 init: function( editor ) {
193 if ( editor.blockless )
194 return;
195
196 var left = new justifyCommand( editor, 'justifyleft', 'left' ),
197 center = new justifyCommand( editor, 'justifycenter', 'center' ),
198 right = new justifyCommand( editor, 'justifyright', 'right' ),
199 justify = new justifyCommand( editor, 'justifyblock', 'justify' );
200
201 editor.addCommand( 'justifyleft', left );
202 editor.addCommand( 'justifycenter', center );
203 editor.addCommand( 'justifyright', right );
204 editor.addCommand( 'justifyblock', justify );
205
206 if ( editor.ui.addButton ) {
207 editor.ui.addButton( 'JustifyLeft', {
208 label: editor.lang.justify.left,
209 command: 'justifyleft',
210 toolbar: 'align,10'
211 } );
212 editor.ui.addButton( 'JustifyCenter', {
213 label: editor.lang.justify.center,
214 command: 'justifycenter',
215 toolbar: 'align,20'
216 } );
217 editor.ui.addButton( 'JustifyRight', {
218 label: editor.lang.justify.right,
219 command: 'justifyright',
220 toolbar: 'align,30'
221 } );
222 editor.ui.addButton( 'JustifyBlock', {
223 label: editor.lang.justify.block,
224 command: 'justifyblock',
225 toolbar: 'align,40'
226 } );
227 }
228
229 editor.on( 'dirChanged', onDirChanged );
230 }
231 } );
232} )();
233
234/**
235 * List of classes to use for aligning the contents. If it's `null`, no classes will be used
236 * and instead the corresponding CSS values will be used.
237 *
238 * The array should contain 4 members, in the following order: left, center, right, justify.
239 *
240 * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'
241 * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];
242 *
243 * @cfg {Array} [justifyClasses=null]
244 * @member CKEDITOR.config
245 */
diff --git a/sources/plugins/lineutils/dev/dnd.html b/sources/plugins/lineutils/dev/dnd.html
new file mode 100644
index 0000000..7293daa
--- /dev/null
+++ b/sources/plugins/lineutils/dev/dnd.html
@@ -0,0 +1,172 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Widget Drag &amp; Drop with Lineutils &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <script>
12 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
13 CKEDITOR.tools.enableHtml5Elements( document );
14 </script>
15 <link href="../../../samples/old/sample.css" rel="stylesheet">
16 <link href="../../image2/samples/contents.css" rel="stylesheet">
17</head>
18<body>
19 <h1 class="samples">
20 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Widget Drag &amp; Drop with Lineutils
21 </h1>
22
23 <h3>Classic (iframe-based) Editor</h3>
24
25 <textarea id="editor1" cols="10" rows="10">
26 <h1>Apollo 11</h1>
27
28 <figure class="caption" style="float:right"><img alt="Saturn V" src="../../image2/samples/assets/image1.jpg" width="200" />
29 <figcaption>Roll out of Saturn V on launch pad</figcaption>
30 </figure>
31
32 <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p>
33
34 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
35
36 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
37
38 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
39
40 <blockquote>
41 <p>One small step for [a] man, one giant leap for mankind.</p>
42 </blockquote>
43
44 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
45
46 <div style="text-align:center">
47 <figure class="caption" style="display:inline-block"><img alt="The Eagle" height="123" src="../../image2/samples/assets/image2.jpg" width="136" />
48 <figcaption>The Eagle in lunar orbit</figcaption>
49 </figure>
50 </div>
51
52 <blockquote>
53 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
54 </blockquote>
55
56 <figure class="caption" style="float:right"><img alt="The Eagle" src="../../image2/samples/assets/image2.jpg" width="200" />
57 <figcaption>The Eagle in lunar orbit</figcaption>
58 </figure>
59
60 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
61
62 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
63
64 <ol>
65 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
66 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
67 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
68 </ol>
69
70 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
71
72 <figure class="caption"><img alt="Saturn V" height="129" src="../../image2/samples/assets/image1.jpg" width="101" />
73 <figcaption>Roll out of Saturn V on launch pad</figcaption>
74 </figure>
75
76 <hr />
77 <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p>
78
79 </textarea>
80
81 <h3>Inline Editor</h3>
82
83 <div id="editor2" contenteditable="true" style="outline: 2px solid #ccc">
84 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
85 <tbody>
86 <tr>
87 <td>This table</td>
88 <td>is the</td>
89 <td>very first</td>
90 <td>element of the document.</td>
91 </tr>
92 <tr>
93 <td>We are still</td>
94 <td>able to acces</td>
95 <td>the space before it.</td>
96 <td style="padding: 25px">
97 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
98 <tbody>
99 <tr>
100 <td>This table is inside of a cell of another table.</td>
101 </tr>
102 <tr>
103 <td>We can type&nbsp;either before or after it though.</td>
104 </tr>
105 </tbody>
106 </table>
107 </td>
108 </tr>
109 </tbody>
110 </table>
111
112 <hr />
113 <hr />
114 <ol style="width: 300px">
115 <li>This numbered list...</li>
116 <li>...is a neighbour of a horizontal line...</li>
117 <li style="padding: 20px;">
118 <ol>
119 <li>Nested list!</li>
120 </ol>
121 </li>
122 </ol>
123
124 <figure class="caption"><img alt="Saturn V" src="../../image2/samples/assets/image1.jpg" width="100" />
125 <figcaption>Roll out of Saturn V on launch pad</figcaption>
126 </figure>
127
128 <ul style="width: 450px">
129 <li>We can type between the lists...</li>
130 <li>...thanks to <strong>Magicline</strong>.</li>
131 </ul>
132
133 <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p>
134
135 <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p>
136
137 <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p>
138
139 <div id="last" style="padding: 10px; text-align: center;">
140 <p>This text is wrapped in a&nbsp;<tt>DIV</tt>&nbsp;element. We can type after this element though.</p>
141 </div>
142 </div>
143
144 <script>
145
146 CKEDITOR.replace( 'editor1', {
147 extraPlugins: 'image2',
148 height: 450,
149 removePlugins: 'image,forms',
150 contentsCss: [ '../../../contents.css', '../../image2/samples/contents.css' ]
151 } );
152
153 CKEDITOR.inline( 'editor2', {
154 extraPlugins: 'image2',
155 height: 450,
156 removePlugins: 'image,forms'
157 } );
158
159 </script>
160
161 <div id="footer">
162 <hr>
163 <p>
164 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
165 </p>
166 <p id="copy">
167 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
168 Knabben. All rights reserved.
169 </p>
170 </div>
171</body>
172</html>
diff --git a/sources/plugins/lineutils/dev/magicfinger.html b/sources/plugins/lineutils/dev/magicfinger.html
new file mode 100644
index 0000000..3172d22
--- /dev/null
+++ b/sources/plugins/lineutils/dev/magicfinger.html
@@ -0,0 +1,285 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Lineutils &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link href="../../../samples/old/sample.css" rel="stylesheet">
12</head>
13<body>
14 <h1 class="samples">
15 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Lineutils
16 </h1>
17
18 <h3>Classic (iframe-based) Editor</h3>
19
20 <textarea id="editor1" cols="10" rows="10">
21 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
22 <tbody>
23 <tr>
24 <td>This table</td>
25 <td>is the</td>
26 <td>very first</td>
27 <td>element of the document.</td>
28 </tr>
29 <tr>
30 <td>We are still</td>
31 <td>able to acces</td>
32 <td>the space before it.</td>
33 <td style="padding: 25px">
34 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
35 <tbody>
36 <tr>
37 <td>This table is inside of a cell of another table.</td>
38 </tr>
39 <tr>
40 <td>We can type&nbsp;either before or after it though.</td>
41 </tr>
42 </tbody>
43 </table>
44 </td>
45 </tr>
46 </tbody>
47 </table>
48
49 <p>Two succesive horizontal lines (<tt>HR</tt> tags). We can access the space in between:</p>
50
51 <hr />
52 <hr />
53 <ol style="width: 300px">
54 <li>This numbered list...</li>
55 <li>...is a neighbour of a horizontal line...</li>
56 <li style="padding: 20px;">
57 <ol>
58 <li>Nested list!</li>
59 </ol>
60 </li>
61 </ol>
62
63 <ul style="width: 450px">
64 <li>We can type between the lists...</li>
65 <li>...thanks to <strong>Magicline</strong>.</li>
66 </ul>
67
68 <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p>
69
70 <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p>
71
72 <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p>
73
74 <div id="last" style="padding: 10px; text-align: center;">
75 <p>This text is wrapped in a&nbsp;<tt>DIV</tt>&nbsp;element. We can type after this element though.</p>
76 </div>
77 </textarea>
78
79 <h3>Inline Editor</h3>
80
81 <div id="editor2" contenteditable="true" style="outline: 2px solid #ccc">
82 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
83 <tbody>
84 <tr>
85 <td>This table</td>
86 <td>is the</td>
87 <td>very first</td>
88 <td>element of the document.</td>
89 </tr>
90 <tr>
91 <td>We are still</td>
92 <td>able to acces</td>
93 <td>the space before it.</td>
94 <td style="padding: 25px">
95 <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; ">
96 <tbody>
97 <tr>
98 <td>This table is inside of a cell of another table.</td>
99 </tr>
100 <tr>
101 <td>We can type&nbsp;either before or after it though.</td>
102 </tr>
103 </tbody>
104 </table>
105 </td>
106 </tr>
107 </tbody>
108 </table>
109
110 <p>Two succesive horizontal lines (<tt>HR</tt> tags). We can access the space in between:</p>
111
112 <hr />
113 <hr />
114 <ol style="width: 300px">
115 <li>This numbered list...</li>
116 <li>...is a neighbour of a horizontal line...</li>
117 <li style="padding: 20px;">
118 <ol>
119 <li>Nested list!</li>
120 </ol>
121 </li>
122 </ol>
123
124 <ul style="width: 450px">
125 <li>We can type between the lists...</li>
126 <li>...thanks to <strong>Magicline</strong>.</li>
127 </ul>
128
129 <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p>
130
131 <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p>
132
133 <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p>
134
135 <div id="last" style="padding: 10px; text-align: center;">
136 <p>This text is wrapped in a&nbsp;<tt>DIV</tt>&nbsp;element. We can type after this element though.</p>
137 </div>
138 </div>
139
140 <h3>Extreme inline</h3>
141
142 <div id="editor3" contenteditable="true" style="left: 123px; outline: 1px solid red; border: 15px solid green; position: relative; top: 30; left: 30px;">
143 <div style="padding: 20px; background: gray; width: 300px" class="1">Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim.</div>
144 <div style="background: violet; padding: 30px;" class="static">
145 Position static
146 <div style="background: green; padding: 30px; border: 14px solid orange">foo</div>
147 </div>
148 <dl class="2">
149 <dt>Key</dt><dd>Value</dd>
150 </dl>
151 <div>Whatever</div>
152 <hr id="hr">
153 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
154 <hr>
155 <hr>
156 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
157 <div style="background: green; padding: 30px; width: 200px">foo</div>
158 </div>
159
160 <h3>Classic (iframe-based) Editor, H-scroll</h3>
161
162 <textarea id="editor4" cols="10" rows="10">
163 <hr />
164 <hr />
165 <ol style="width: 1500px">
166 <li>This numbered list...</li>
167 <li>...is a neighbour of a horizontal line...</li>
168 <li style="padding: 20px;">
169 <ol>
170 <li>Nested list!</li>
171 </ol>
172 </li>
173 </ol>
174
175 <ul style="width: 450px">
176 <li>We can type between the lists...</li>
177 <li>...thanks to <strong>Magicline</strong>.</li>
178 </ul>
179
180 <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p>
181
182 <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p>
183
184 <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p>
185
186 <div id="last" style="padding: 10px; text-align: center;">
187 <p>This text is wrapped in a&nbsp;<tt>DIV</tt>&nbsp;element. We can type after this element though.</p>
188 </div>
189 </textarea>
190
191 <script>
192
193 CKEDITOR.addCss(
194 '.cke_editable * { outline: 1px solid #BCEBFF }'
195 );
196
197 function callback() {
198 var helpers = CKEDITOR.plugins.lineutils;
199 var liner = new helpers.liner( this );
200 var locator = new helpers.locator( this );
201 var finder = new helpers.finder( this, {
202 lookups: {
203 'is block and first child': function( el ) {
204 if ( el.is( CKEDITOR.dtd.$listItem ) )
205 return;
206
207 if ( el.is( CKEDITOR.dtd.$block ) )
208 return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER;
209 }
210 }
211 } ).start( function( relations, x, y ) {
212 locator.locate( relations );
213
214 var locations = locator.locations,
215 uid, type;
216
217 liner.prepare( relations, locations );
218
219 for ( uid in locations ) {
220 for ( type in locations[ uid ] )
221 liner.placeLine( { uid: uid, type: type } );
222 }
223
224 liner.cleanup();
225 } );
226 }
227
228 CKEDITOR.disableAutoInline = true;
229
230 CKEDITOR.replace( 'editor1', {
231 extraPlugins: 'lineutils',
232 height: 450,
233 removePlugins: 'magicline',
234 allowedContent: true,
235 contentsCss: [ '../../../contents.css' ],
236 on: {
237 contentDom: callback
238 }
239 } );
240
241 CKEDITOR.inline( 'editor2', {
242 extraPlugins: 'lineutils',
243 removePlugins: 'magicline',
244 allowedContent: true,
245 contentsCss: [ '../../../contents.css' ],
246 on: {
247 contentDom: callback
248 }
249 } );
250
251 CKEDITOR.inline( 'editor3', {
252 extraPlugins: 'lineutils',
253 removePlugins: 'magicline',
254 allowedContent: true,
255 contentsCss: [ '../../../contents.css' ],
256 on: {
257 contentDom: callback
258 }
259 } );
260
261 CKEDITOR.replace( 'editor4', {
262 extraPlugins: 'lineutils',
263 removePlugins: 'magicline',
264 allowedContent: true,
265 contentsCss: [ '../../../contents.css' ],
266 on: {
267 contentDom: callback
268 }
269 } );
270
271
272 </script>
273
274 <div id="footer">
275 <hr>
276 <p>
277 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
278 </p>
279 <p id="copy">
280 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
281 Knabben. All rights reserved.
282 </p>
283 </div>
284</body>
285</html>
diff --git a/sources/plugins/lineutils/plugin.js b/sources/plugins/lineutils/plugin.js
new file mode 100644
index 0000000..e0473ee
--- /dev/null
+++ b/sources/plugins/lineutils/plugin.js
@@ -0,0 +1,1018 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6 /**
7 * @fileOverview A set of utilities to find and create horizontal spaces in edited content.
8 */
9
10'use strict';
11
12( function() {
13
14 CKEDITOR.plugins.add( 'lineutils' );
15
16 /**
17 * Determines a position relative to an element in DOM (before).
18 *
19 * @readonly
20 * @property {Number} [=0]
21 * @member CKEDITOR
22 */
23 CKEDITOR.LINEUTILS_BEFORE = 1;
24
25 /**
26 * Determines a position relative to an element in DOM (after).
27 *
28 * @readonly
29 * @property {Number} [=2]
30 * @member CKEDITOR
31 */
32 CKEDITOR.LINEUTILS_AFTER = 2;
33
34 /**
35 * Determines a position relative to an element in DOM (inside).
36 *
37 * @readonly
38 * @property {Number} [=4]
39 * @member CKEDITOR
40 */
41 CKEDITOR.LINEUTILS_INSIDE = 4;
42
43 /**
44 * A utility that traverses the DOM tree and discovers elements
45 * (relations) matching user-defined lookups.
46 *
47 * @private
48 * @class CKEDITOR.plugins.lineutils.finder
49 * @constructor Creates a Finder class instance.
50 * @param {CKEDITOR.editor} editor Editor instance that the Finder belongs to.
51 * @param {Object} def Finder's definition.
52 * @since 4.3
53 */
54 function Finder( editor, def ) {
55 CKEDITOR.tools.extend( this, {
56 editor: editor,
57 editable: editor.editable(),
58 doc: editor.document,
59 win: editor.window
60 }, def, true );
61
62 this.inline = this.editable.isInline();
63
64 if ( !this.inline ) {
65 this.frame = this.win.getFrame();
66 }
67
68 this.target = this[ this.inline ? 'editable' : 'doc' ];
69 }
70
71 Finder.prototype = {
72 /**
73 * Initializes searching for elements with every mousemove event fired.
74 * To stop searching use {@link #stop}.
75 *
76 * @param {Function} [callback] Function executed on every iteration.
77 */
78 start: function( callback ) {
79 var that = this,
80 editor = this.editor,
81 doc = this.doc,
82 el, elfp, x, y;
83
84 var moveBuffer = CKEDITOR.tools.eventsBuffer( 50, function() {
85 if ( editor.readOnly || editor.mode != 'wysiwyg' )
86 return;
87
88 that.relations = {};
89
90 // Sometimes it happens that elementFromPoint returns null (especially on IE).
91 // Any further traversal makes no sense if there's no start point. Abort.
92 // Note: In IE8 elementFromPoint may return zombie nodes of undefined nodeType,
93 // so rejecting those as well.
94 if ( !( elfp = doc.$.elementFromPoint( x, y ) ) || !elfp.nodeType ) {
95 return;
96 }
97
98 el = new CKEDITOR.dom.element( elfp );
99
100 that.traverseSearch( el );
101
102 if ( !isNaN( x + y ) ) {
103 that.pixelSearch( el, x, y );
104 }
105
106 callback && callback( that.relations, x, y );
107 } );
108
109 // Searching starting from element from point on mousemove.
110 this.listener = this.editable.attachListener( this.target, 'mousemove', function( evt ) {
111 x = evt.data.$.clientX;
112 y = evt.data.$.clientY;
113
114 moveBuffer.input();
115 } );
116
117 this.editable.attachListener( this.inline ? this.editable : this.frame, 'mouseout', function() {
118 moveBuffer.reset();
119 } );
120 },
121
122 /**
123 * Stops observing mouse events attached by {@link #start}.
124 */
125 stop: function() {
126 if ( this.listener ) {
127 this.listener.removeListener();
128 }
129 },
130
131 /**
132 * Returns a range representing the relation, according to its element
133 * and type.
134 *
135 * @param {Object} location Location containing a unique identifier and type.
136 * @returns {CKEDITOR.dom.range} Range representing the relation.
137 */
138 getRange: ( function() {
139 var where = {};
140
141 where[ CKEDITOR.LINEUTILS_BEFORE ] = CKEDITOR.POSITION_BEFORE_START;
142 where[ CKEDITOR.LINEUTILS_AFTER ] = CKEDITOR.POSITION_AFTER_END;
143 where[ CKEDITOR.LINEUTILS_INSIDE ] = CKEDITOR.POSITION_AFTER_START;
144
145 return function( location ) {
146 var range = this.editor.createRange();
147
148 range.moveToPosition( this.relations[ location.uid ].element, where[ location.type ] );
149
150 return range;
151 };
152 } )(),
153
154 /**
155 * Stores given relation in a {@link #relations} object. Processes the relation
156 * to normalize and avoid duplicates.
157 *
158 * @param {CKEDITOR.dom.element} el Element of the relation.
159 * @param {Number} type Relation, one of `CKEDITOR.LINEUTILS_AFTER`, `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_INSIDE`.
160 */
161 store: ( function() {
162 function merge( el, type, relations ) {
163 var uid = el.getUniqueId();
164
165 if ( uid in relations ) {
166 relations[ uid ].type |= type;
167 } else {
168 relations[ uid ] = { element: el, type: type };
169 }
170 }
171
172 return function( el, type ) {
173 var alt;
174
175 // Normalization to avoid duplicates:
176 // CKEDITOR.LINEUTILS_AFTER becomes CKEDITOR.LINEUTILS_BEFORE of el.getNext().
177 if ( is( type, CKEDITOR.LINEUTILS_AFTER ) && isStatic( alt = el.getNext() ) && alt.isVisible() ) {
178 merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations );
179 type ^= CKEDITOR.LINEUTILS_AFTER;
180 }
181
182 // Normalization to avoid duplicates:
183 // CKEDITOR.LINEUTILS_INSIDE becomes CKEDITOR.LINEUTILS_BEFORE of el.getFirst().
184 if ( is( type, CKEDITOR.LINEUTILS_INSIDE ) && isStatic( alt = el.getFirst() ) && alt.isVisible() ) {
185 merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations );
186 type ^= CKEDITOR.LINEUTILS_INSIDE;
187 }
188
189 merge( el, type, this.relations );
190 };
191 } )(),
192
193 /**
194 * Traverses the DOM tree towards root, checking all ancestors
195 * with lookup rules, avoiding duplicates. Stores positive relations
196 * in the {@link #relations} object.
197 *
198 * @param {CKEDITOR.dom.element} el Element which is the starting point.
199 */
200 traverseSearch: function( el ) {
201 var l, type, uid;
202
203 // Go down DOM towards root (or limit).
204 do {
205 uid = el.$[ 'data-cke-expando' ];
206
207 // This element was already visited and checked.
208 if ( uid && uid in this.relations ) {
209 continue;
210 }
211
212 if ( el.equals( this.editable ) ) {
213 return;
214 }
215
216 if ( isStatic( el ) ) {
217 // Collect all addresses yielded by lookups for that element.
218 for ( l in this.lookups ) {
219
220 if ( ( type = this.lookups[ l ]( el ) ) ) {
221 this.store( el, type );
222 }
223 }
224 }
225 } while ( !isLimit( el ) && ( el = el.getParent() ) );
226 },
227
228 /**
229 * Iterates vertically pixel-by-pixel within a given element starting
230 * from given coordinates, searching for elements in the neighborhood.
231 * Once an element is found it is processed by {@link #traverseSearch}.
232 *
233 * @param {CKEDITOR.dom.element} el Element which is the starting point.
234 * @param {Number} [x] Horizontal mouse coordinate relative to the viewport.
235 * @param {Number} [y] Vertical mouse coordinate relative to the viewport.
236 */
237 pixelSearch: ( function() {
238 var contains = CKEDITOR.env.ie || CKEDITOR.env.webkit ?
239 function( el, found ) {
240 return el.contains( found );
241 } : function( el, found ) {
242 return !!( el.compareDocumentPosition( found ) & 16 );
243 };
244
245 // Iterates pixel-by-pixel from starting coordinates, moving by defined
246 // step and getting elementFromPoint in every iteration. Iteration stops when:
247 // * A valid element is found.
248 // * Condition function returns `false` (i.e. reached boundaries of viewport).
249 // * No element is found (i.e. coordinates out of viewport).
250 // * Element found is ascendant of starting element.
251 //
252 // @param {Object} doc Native DOM document.
253 // @param {Object} el Native DOM element.
254 // @param {Number} xStart Horizontal starting coordinate to use.
255 // @param {Number} yStart Vertical starting coordinate to use.
256 // @param {Number} step Step of the algorithm.
257 // @param {Function} condition A condition relative to current vertical coordinate.
258 function iterate( el, xStart, yStart, step, condition ) {
259 var y = yStart,
260 tryouts = 0,
261 found;
262
263 while ( condition( y ) ) {
264 y += step;
265
266 // If we try and we try, and still nothing's found, let's end
267 // that party.
268 if ( ++tryouts == 25 ) {
269 return;
270 }
271
272 found = this.doc.$.elementFromPoint( xStart, y );
273
274 // Nothing found. This is crazy... but...
275 // It might be that a line, which is in different document,
276 // covers that pixel (elementFromPoint is doc-sensitive).
277 // Better let's have another try.
278 if ( !found ) {
279 continue;
280 }
281
282 // Still in the same element.
283 else if ( found == el ) {
284 tryouts = 0;
285 continue;
286 }
287
288 // Reached the edge of an element and found an ancestor or...
289 // A line, that covers that pixel. Better let's have another try.
290 else if ( !contains( el, found ) ) {
291 continue;
292 }
293
294 tryouts = 0;
295
296 // Found a valid element. Stop iterating.
297 if ( isStatic( ( found = new CKEDITOR.dom.element( found ) ) ) ) {
298 return found;
299 }
300 }
301 }
302
303 return function( el, x, y ) {
304 var paneHeight = this.win.getViewPaneSize().height,
305
306 // Try to find an element iterating *up* from the starting point.
307 neg = iterate.call( this, el.$, x, y, -1, function( y ) {
308 return y > 0;
309 } ),
310
311 // Try to find an element iterating *down* from the starting point.
312 pos = iterate.call( this, el.$, x, y, 1, function( y ) {
313 return y < paneHeight;
314 } );
315
316 if ( neg ) {
317 this.traverseSearch( neg );
318
319 // Iterate towards DOM root until neg is a direct child of el.
320 while ( !neg.getParent().equals( el ) ) {
321 neg = neg.getParent();
322 }
323 }
324
325 if ( pos ) {
326 this.traverseSearch( pos );
327
328 // Iterate towards DOM root until pos is a direct child of el.
329 while ( !pos.getParent().equals( el ) ) {
330 pos = pos.getParent();
331 }
332 }
333
334 // Iterate forwards starting from neg and backwards from
335 // pos to harvest all children of el between those elements.
336 // Stop when neg and pos meet each other or there's none of them.
337 // TODO (?) reduce number of hops forwards/backwards.
338 while ( neg || pos ) {
339 if ( neg ) {
340 neg = neg.getNext( isStatic );
341 }
342
343 if ( !neg || neg.equals( pos ) ) {
344 break;
345 }
346
347 this.traverseSearch( neg );
348
349 if ( pos ) {
350 pos = pos.getPrevious( isStatic );
351 }
352
353 if ( !pos || pos.equals( neg ) ) {
354 break;
355 }
356
357 this.traverseSearch( pos );
358 }
359 };
360 } )(),
361
362 /**
363 * Unlike {@link #traverseSearch}, it collects **all** elements from editable's DOM tree
364 * and runs lookups for every one of them, collecting relations.
365 *
366 * @returns {Object} {@link #relations}.
367 */
368 greedySearch: function() {
369 this.relations = {};
370
371 var all = this.editable.getElementsByTag( '*' ),
372 i = 0,
373 el, type, l;
374
375 while ( ( el = all.getItem( i++ ) ) ) {
376 // Don't consider editable, as it might be inline,
377 // and i.e. checking it's siblings is pointless.
378 if ( el.equals( this.editable ) ) {
379 continue;
380 }
381
382 // On IE8 element.getElementsByTagName returns comments... sic! (#13176)
383 if ( el.type != CKEDITOR.NODE_ELEMENT ) {
384 continue;
385 }
386
387 // Don't visit non-editable internals, for example widget's
388 // guts (above wrapper, below nested). Still check editable limits,
389 // as they are siblings with editable contents.
390 if ( !el.hasAttribute( 'contenteditable' ) && el.isReadOnly() ) {
391 continue;
392 }
393
394 if ( isStatic( el ) && el.isVisible() ) {
395 // Collect all addresses yielded by lookups for that element.
396 for ( l in this.lookups ) {
397 if ( ( type = this.lookups[ l ]( el ) ) ) {
398 this.store( el, type );
399 }
400 }
401 }
402 }
403
404 return this.relations;
405 }
406
407 /**
408 * Relations express elements in DOM that match user-defined {@link #lookups}.
409 * Every relation has its own `type` that determines whether
410 * it refers to the space before, after or inside the `element`.
411 * This object stores relations found by {@link #traverseSearch} or {@link #greedySearch}, structured
412 * in the following way:
413 *
414 * relations: {
415 * // Unique identifier of the element.
416 * Number: {
417 * // Element of this relation.
418 * element: {@link CKEDITOR.dom.element}
419 * // Conjunction of CKEDITOR.LINEUTILS_BEFORE, CKEDITOR.LINEUTILS_AFTER and CKEDITOR.LINEUTILS_INSIDE.
420 * type: Number
421 * },
422 * ...
423 * }
424 *
425 * @property {Object} relations
426 * @readonly
427 */
428
429 /**
430 * A set of user-defined functions used by Finder to check if an element
431 * is a valid relation, belonging to {@link #relations}.
432 * When the criterion is met, lookup returns a logical conjunction of `CKEDITOR.LINEUTILS_BEFORE`,
433 * `CKEDITOR.LINEUTILS_AFTER` or `CKEDITOR.LINEUTILS_INSIDE`.
434 *
435 * Lookups are passed along with Finder's definition.
436 *
437 * lookups: {
438 * 'some lookup': function( el ) {
439 * if ( someCondition )
440 * return CKEDITOR.LINEUTILS_BEFORE;
441 * },
442 * ...
443 * }
444 *
445 * @property {Object} lookups
446 */
447 };
448
449
450 /**
451 * A utility that analyses relations found by
452 * CKEDITOR.plugins.lineutils.finder and locates them
453 * in the viewport as horizontal lines of specific coordinates.
454 *
455 * @private
456 * @class CKEDITOR.plugins.lineutils.locator
457 * @constructor Creates a Locator class instance.
458 * @param {CKEDITOR.editor} editor Editor instance that Locator belongs to.
459 * @since 4.3
460 */
461 function Locator( editor, def ) {
462 CKEDITOR.tools.extend( this, def, {
463 editor: editor
464 }, true );
465 }
466
467 Locator.prototype = {
468 /**
469 * Locates the Y coordinate for all types of every single relation and stores
470 * them in an object.
471 *
472 * @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}.
473 * @returns {Object} {@link #locations}.
474 */
475 locate: ( function() {
476 function locateSibling( rel, type ) {
477 var sib = rel.element[ type === CKEDITOR.LINEUTILS_BEFORE ? 'getPrevious' : 'getNext' ]();
478
479 // Return the middle point between siblings.
480 if ( sib && isStatic( sib ) ) {
481 rel.siblingRect = sib.getClientRect();
482
483 if ( type == CKEDITOR.LINEUTILS_BEFORE ) {
484 return ( rel.siblingRect.bottom + rel.elementRect.top ) / 2;
485 } else {
486 return ( rel.elementRect.bottom + rel.siblingRect.top ) / 2;
487 }
488 }
489
490 // If there's no sibling, use the edge of an element.
491 else {
492 if ( type == CKEDITOR.LINEUTILS_BEFORE ) {
493 return rel.elementRect.top;
494 } else {
495 return rel.elementRect.bottom;
496 }
497 }
498 }
499
500 return function( relations ) {
501 var rel;
502
503 this.locations = {};
504
505 for ( var uid in relations ) {
506 rel = relations[ uid ];
507 rel.elementRect = rel.element.getClientRect();
508
509 if ( is( rel.type, CKEDITOR.LINEUTILS_BEFORE ) ) {
510 this.store( uid, CKEDITOR.LINEUTILS_BEFORE, locateSibling( rel, CKEDITOR.LINEUTILS_BEFORE ) );
511 }
512
513 if ( is( rel.type, CKEDITOR.LINEUTILS_AFTER ) ) {
514 this.store( uid, CKEDITOR.LINEUTILS_AFTER, locateSibling( rel, CKEDITOR.LINEUTILS_AFTER ) );
515 }
516
517 // The middle point of the element.
518 if ( is( rel.type, CKEDITOR.LINEUTILS_INSIDE ) ) {
519 this.store( uid, CKEDITOR.LINEUTILS_INSIDE, ( rel.elementRect.top + rel.elementRect.bottom ) / 2 );
520 }
521 }
522
523 return this.locations;
524 };
525 } )(),
526
527 /**
528 * Calculates distances from every location to given vertical coordinate
529 * and sorts locations according to that distance.
530 *
531 * @param {Number} y The vertical coordinate used for sorting, used as a reference.
532 * @param {Number} [howMany] Determines the number of "closest locations" to be returned.
533 * @returns {Array} Sorted, array representation of {@link #locations}.
534 */
535 sort: ( function() {
536 var locations, sorted,
537 dist, i;
538
539 function distance( y, uid, type ) {
540 return Math.abs( y - locations[ uid ][ type ] );
541 }
542
543 return function( y, howMany ) {
544 locations = this.locations;
545 sorted = [];
546
547 for ( var uid in locations ) {
548 for ( var type in locations[ uid ] ) {
549 dist = distance( y, uid, type );
550
551 // An array is empty.
552 if ( !sorted.length ) {
553 sorted.push( { uid: +uid, type: type, dist: dist } );
554 } else {
555 // Sort the array on fly when it's populated.
556 for ( i = 0; i < sorted.length; i++ ) {
557 if ( dist < sorted[ i ].dist ) {
558 sorted.splice( i, 0, { uid: +uid, type: type, dist: dist } );
559 break;
560 }
561 }
562
563 // Nothing was inserted, so the distance is bigger than
564 // any of already calculated: push to the end.
565 if ( i == sorted.length ) {
566 sorted.push( { uid: +uid, type: type, dist: dist } );
567 }
568 }
569 }
570 }
571
572 if ( typeof howMany != 'undefined' ) {
573 return sorted.slice( 0, howMany );
574 } else {
575 return sorted;
576 }
577 };
578 } )(),
579
580 /**
581 * Stores the location in a collection.
582 *
583 * @param {Number} uid Unique identifier of the relation.
584 * @param {Number} type One of `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_AFTER` and `CKEDITOR.LINEUTILS_INSIDE`.
585 * @param {Number} y Vertical position of the relation.
586 */
587 store: function( uid, type, y ) {
588 if ( !this.locations[ uid ] ) {
589 this.locations[ uid ] = {};
590 }
591
592 this.locations[ uid ][ type ] = y;
593 }
594
595 /**
596 * @readonly
597 * @property {Object} locations
598 */
599 };
600
601 var tipCss = {
602 display: 'block',
603 width: '0px',
604 height: '0px',
605 'border-color': 'transparent',
606 'border-style': 'solid',
607 position: 'absolute',
608 top: '-6px'
609 },
610
611 lineStyle = {
612 height: '0px',
613 'border-top': '1px dashed red',
614 position: 'absolute',
615 'z-index': 9999
616 },
617
618 lineTpl =
619 '<div data-cke-lineutils-line="1" class="cke_reset_all" style="{lineStyle}">' +
620 '<span style="{tipLeftStyle}">&nbsp;</span>' +
621 '<span style="{tipRightStyle}">&nbsp;</span>' +
622 '</div>';
623
624 /**
625 * A utility that draws horizontal lines in DOM according to locations
626 * returned by CKEDITOR.plugins.lineutils.locator.
627 *
628 * @private
629 * @class CKEDITOR.plugins.lineutils.liner
630 * @constructor Creates a Liner class instance.
631 * @param {CKEDITOR.editor} editor Editor instance that Liner belongs to.
632 * @param {Object} def Liner's definition.
633 * @since 4.3
634 */
635 function Liner( editor, def ) {
636 var editable = editor.editable();
637
638 CKEDITOR.tools.extend( this, {
639 editor: editor,
640 editable: editable,
641 inline: editable.isInline(),
642 doc: editor.document,
643 win: editor.window,
644 container: CKEDITOR.document.getBody(),
645 winTop: CKEDITOR.document.getWindow()
646 }, def, true );
647
648 this.hidden = {};
649 this.visible = {};
650
651 if ( !this.inline ) {
652 this.frame = this.win.getFrame();
653 }
654
655 this.queryViewport();
656
657 // Callbacks must be wrapped. Otherwise they're not attached
658 // to global DOM objects (i.e. topmost window) for every editor
659 // because they're treated as duplicates. They belong to the
660 // same prototype shared among Liner instances.
661 var queryViewport = CKEDITOR.tools.bind( this.queryViewport, this ),
662 hideVisible = CKEDITOR.tools.bind( this.hideVisible, this ),
663 removeAll = CKEDITOR.tools.bind( this.removeAll, this );
664
665 editable.attachListener( this.winTop, 'resize', queryViewport );
666 editable.attachListener( this.winTop, 'scroll', queryViewport );
667
668 editable.attachListener( this.winTop, 'resize', hideVisible );
669 editable.attachListener( this.win, 'scroll', hideVisible );
670
671 editable.attachListener( this.inline ? editable : this.frame, 'mouseout', function( evt ) {
672 var x = evt.data.$.clientX,
673 y = evt.data.$.clientY;
674
675 this.queryViewport();
676
677 // Check if mouse is out of the element (iframe/editable).
678 if ( x <= this.rect.left || x >= this.rect.right || y <= this.rect.top || y >= this.rect.bottom ) {
679 this.hideVisible();
680 }
681
682 // Check if mouse is out of the top-window vieport.
683 if ( x <= 0 || x >= this.winTopPane.width || y <= 0 || y >= this.winTopPane.height ) {
684 this.hideVisible();
685 }
686 }, this );
687
688 editable.attachListener( editor, 'resize', queryViewport );
689 editable.attachListener( editor, 'mode', removeAll );
690 editor.on( 'destroy', removeAll );
691
692 this.lineTpl = new CKEDITOR.template( lineTpl ).output( {
693 lineStyle: CKEDITOR.tools.writeCssText(
694 CKEDITOR.tools.extend( {}, lineStyle, this.lineStyle, true )
695 ),
696 tipLeftStyle: CKEDITOR.tools.writeCssText(
697 CKEDITOR.tools.extend( {}, tipCss, {
698 left: '0px',
699 'border-left-color': 'red',
700 'border-width': '6px 0 6px 6px'
701 }, this.tipCss, this.tipLeftStyle, true )
702 ),
703 tipRightStyle: CKEDITOR.tools.writeCssText(
704 CKEDITOR.tools.extend( {}, tipCss, {
705 right: '0px',
706 'border-right-color': 'red',
707 'border-width': '6px 6px 6px 0'
708 }, this.tipCss, this.tipRightStyle, true )
709 )
710 } );
711 }
712
713 Liner.prototype = {
714 /**
715 * Permanently removes all lines (both hidden and visible) from DOM.
716 */
717 removeAll: function() {
718 var l;
719
720 for ( l in this.hidden ) {
721 this.hidden[ l ].remove();
722 delete this.hidden[ l ];
723 }
724
725 for ( l in this.visible ) {
726 this.visible[ l ].remove();
727 delete this.visible[ l ];
728 }
729 },
730
731 /**
732 * Hides a given line.
733 *
734 * @param {CKEDITOR.dom.element} line The line to be hidden.
735 */
736 hideLine: function( line ) {
737 var uid = line.getUniqueId();
738
739 line.hide();
740
741 this.hidden[ uid ] = line;
742 delete this.visible[ uid ];
743 },
744
745 /**
746 * Shows a given line.
747 *
748 * @param {CKEDITOR.dom.element} line The line to be shown.
749 */
750 showLine: function( line ) {
751 var uid = line.getUniqueId();
752
753 line.show();
754
755 this.visible[ uid ] = line;
756 delete this.hidden[ uid ];
757 },
758
759 /**
760 * Hides all visible lines.
761 */
762 hideVisible: function() {
763 for ( var l in this.visible ) {
764 this.hideLine( this.visible[ l ] );
765 }
766 },
767
768 /**
769 * Shows a line at given location.
770 *
771 * @param {Object} location Location object containing the unique identifier of the relation
772 * and its type. Usually returned by {@link CKEDITOR.plugins.lineutils.locator#sort}.
773 * @param {Function} [callback] A callback to be called once the line is shown.
774 */
775 placeLine: function( location, callback ) {
776 var styles, line, l;
777
778 // No style means that line would be out of viewport.
779 if ( !( styles = this.getStyle( location.uid, location.type ) ) ) {
780 return;
781 }
782
783 // Search for any visible line of a different hash first.
784 // It's faster to re-position visible line than to show it.
785 for ( l in this.visible ) {
786 if ( this.visible[ l ].getCustomData( 'hash' ) !== this.hash ) {
787 line = this.visible[ l ];
788 break;
789 }
790 }
791
792 // Search for any hidden line of a different hash.
793 if ( !line ) {
794 for ( l in this.hidden ) {
795 if ( this.hidden[ l ].getCustomData( 'hash' ) !== this.hash ) {
796 this.showLine( ( line = this.hidden[ l ] ) );
797 break;
798 }
799 }
800 }
801
802 // If no line available, add the new one.
803 if ( !line ) {
804 this.showLine( ( line = this.addLine() ) );
805 }
806
807 // Mark the line with current hash.
808 line.setCustomData( 'hash', this.hash );
809
810 // Mark the line as visible.
811 this.visible[ line.getUniqueId() ] = line;
812
813 line.setStyles( styles );
814
815 callback && callback( line );
816 },
817
818 /**
819 * Creates a style set to be used by the line, representing a particular
820 * relation (location).
821 *
822 * @param {Number} uid Unique identifier of the relation.
823 * @param {Number} type Type of the relation.
824 * @returns {Object} An object containing styles.
825 */
826 getStyle: function( uid, type ) {
827 var rel = this.relations[ uid ],
828 loc = this.locations[ uid ][ type ],
829 styles = {},
830 hdiff;
831
832 // Line should be between two elements.
833 if ( rel.siblingRect ) {
834 styles.width = Math.max( rel.siblingRect.width, rel.elementRect.width );
835 }
836 // Line is relative to a single element.
837 else {
838 styles.width = rel.elementRect.width;
839 }
840
841 // Let's calculate the vertical position of the line.
842 if ( this.inline ) {
843 // (#13155)
844 styles.top = loc + this.winTopScroll.y - this.rect.relativeY;
845 } else {
846 styles.top = this.rect.top + this.winTopScroll.y + loc;
847 }
848
849 // Check if line would be vertically out of the viewport.
850 if ( styles.top - this.winTopScroll.y < this.rect.top || styles.top - this.winTopScroll.y > this.rect.bottom ) {
851 return false;
852 }
853
854 // Now let's calculate the horizontal alignment (left and width).
855 if ( this.inline ) {
856 // (#13155)
857 styles.left = rel.elementRect.left - this.rect.relativeX;
858 } else {
859 if ( rel.elementRect.left > 0 )
860 styles.left = this.rect.left + rel.elementRect.left;
861
862 // H-scroll case. Left edge of element may be out of viewport.
863 else {
864 styles.width += rel.elementRect.left;
865 styles.left = this.rect.left;
866 }
867
868 // H-scroll case. Right edge of element may be out of viewport.
869 if ( ( hdiff = styles.left + styles.width - ( this.rect.left + this.winPane.width ) ) > 0 ) {
870 styles.width -= hdiff;
871 }
872 }
873
874 // Finally include horizontal scroll of the global window.
875 styles.left += this.winTopScroll.x;
876
877 // Append 'px' to style values.
878 for ( var style in styles ) {
879 styles[ style ] = CKEDITOR.tools.cssLength( styles[ style ] );
880 }
881
882 return styles;
883 },
884
885 /**
886 * Adds a new line to DOM.
887 *
888 * @returns {CKEDITOR.dom.element} A brand-new line.
889 */
890 addLine: function() {
891 var line = CKEDITOR.dom.element.createFromHtml( this.lineTpl );
892
893 line.appendTo( this.container );
894
895 return line;
896 },
897
898 /**
899 * Assigns a unique hash to the instance that is later used
900 * to tell unwanted lines from new ones. This method **must** be called
901 * before a new set of relations is to be visualized so {@link #cleanup}
902 * eventually hides obsolete lines. This is because lines
903 * are re-used between {@link #placeLine} calls and the number of
904 * necessary ones may vary depending on the number of relations.
905 *
906 * @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}.
907 * @param {Object} locations {@link CKEDITOR.plugins.lineutils.locator#locations}.
908 */
909 prepare: function( relations, locations ) {
910 this.relations = relations;
911 this.locations = locations;
912 this.hash = Math.random();
913 },
914
915 /**
916 * Hides all visible lines that do not belong to current hash
917 * and no longer represent relations (locations).
918 *
919 * See also: {@link #prepare}.
920 */
921 cleanup: function() {
922 var line;
923
924 for ( var l in this.visible ) {
925 line = this.visible[ l ];
926
927 if ( line.getCustomData( 'hash' ) !== this.hash ) {
928 this.hideLine( line );
929 }
930 }
931 },
932
933 /**
934 * Queries dimensions of the viewport, editable, frame etc.
935 * that are used for correct positioning of the line.
936 */
937 queryViewport: function() {
938 this.winPane = this.win.getViewPaneSize();
939 this.winTopScroll = this.winTop.getScrollPosition();
940 this.winTopPane = this.winTop.getViewPaneSize();
941
942 // (#13155)
943 this.rect = this.getClientRect( this.inline ? this.editable : this.frame );
944 },
945
946 /**
947 * Returns `boundingClientRect` of an element, shifted by the position
948 * of `container` when the container is not `static` (#13155).
949 *
950 * See also: {@link CKEDITOR.dom.element#getClientRect}.
951 *
952 * @param {CKEDITOR.dom.element} el A DOM element.
953 * @returns {Object} A shifted rect, extended by `relativeY` and `relativeX` properties.
954 */
955 getClientRect: function( el ) {
956 var rect = el.getClientRect(),
957 relativeContainerDocPosition = this.container.getDocumentPosition(),
958 relativeContainerComputedPosition = this.container.getComputedStyle( 'position' );
959
960 // Static or not, those values are used to offset the position of the line so they cannot be undefined.
961 rect.relativeX = rect.relativeY = 0;
962
963 if ( relativeContainerComputedPosition != 'static' ) {
964 // Remember the offset used to shift the clientRect.
965 rect.relativeY = relativeContainerDocPosition.y;
966 rect.relativeX = relativeContainerDocPosition.x;
967
968 rect.top -= rect.relativeY;
969 rect.bottom -= rect.relativeY;
970 rect.left -= rect.relativeX;
971 rect.right -= rect.relativeX;
972 }
973
974 return rect;
975 }
976 };
977
978 function is( type, flag ) {
979 return type & flag;
980 }
981
982 var floats = { left: 1, right: 1, center: 1 },
983 positions = { absolute: 1, fixed: 1 };
984
985 function isElement( node ) {
986 return node && node.type == CKEDITOR.NODE_ELEMENT;
987 }
988
989 function isFloated( el ) {
990 return !!( floats[ el.getComputedStyle( 'float' ) ] || floats[ el.getAttribute( 'align' ) ] );
991 }
992
993 function isPositioned( el ) {
994 return !!positions[ el.getComputedStyle( 'position' ) ];
995 }
996
997 function isLimit( node ) {
998 return isElement( node ) && node.getAttribute( 'contenteditable' ) == 'true';
999 }
1000
1001 function isStatic( node ) {
1002 return isElement( node ) && !isFloated( node ) && !isPositioned( node );
1003 }
1004
1005 /**
1006 * Global namespace storing definitions and global helpers for the Line Utilities plugin.
1007 *
1008 * @private
1009 * @class
1010 * @singleton
1011 * @since 4.3
1012 */
1013 CKEDITOR.plugins.lineutils = {
1014 finder: Finder,
1015 locator: Locator,
1016 liner: Liner
1017 };
1018} )();
diff --git a/sources/plugins/link/dialogs/anchor.js b/sources/plugins/link/dialogs/anchor.js
new file mode 100644
index 0000000..2b32b71
--- /dev/null
+++ b/sources/plugins/link/dialogs/anchor.js
@@ -0,0 +1,105 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.dialog.add( 'anchor', function( editor ) {
7 // Function called in onShow to load selected element.
8 var loadElements = function( element ) {
9 this._.selectedElement = element;
10
11 var attributeValue = element.data( 'cke-saved-name' );
12 this.setValueOf( 'info', 'txtName', attributeValue || '' );
13 };
14
15 function createFakeAnchor( editor, attributes ) {
16 return editor.createFakeElement( editor.document.createElement( 'a', {
17 attributes: attributes
18 } ), 'cke_anchor', 'anchor' );
19 }
20
21 return {
22 title: editor.lang.link.anchor.title,
23 minWidth: 300,
24 minHeight: 60,
25 onOk: function() {
26 var name = CKEDITOR.tools.trim( this.getValueOf( 'info', 'txtName' ) );
27 var attributes = {
28 id: name,
29 name: name,
30 'data-cke-saved-name': name
31 };
32
33 if ( this._.selectedElement ) {
34 if ( this._.selectedElement.data( 'cke-realelement' ) ) {
35 var newFake = createFakeAnchor( editor, attributes );
36 newFake.replace( this._.selectedElement );
37
38 // Selecting fake element for IE. (#11377)
39 if ( CKEDITOR.env.ie )
40 editor.getSelection().selectElement( newFake );
41 } else {
42 this._.selectedElement.setAttributes( attributes );
43 }
44 } else {
45 var sel = editor.getSelection(),
46 range = sel && sel.getRanges()[ 0 ];
47
48 // Empty anchor
49 if ( range.collapsed ) {
50 var anchor = createFakeAnchor( editor, attributes );
51 range.insertNode( anchor );
52 } else {
53 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
54 attributes[ 'class' ] = 'cke_anchor';
55
56 // Apply style.
57 var style = new CKEDITOR.style( { element: 'a', attributes: attributes } );
58 style.type = CKEDITOR.STYLE_INLINE;
59 editor.applyStyle( style );
60 }
61 }
62 },
63
64 onHide: function() {
65 delete this._.selectedElement;
66 },
67
68 onShow: function() {
69 var sel = editor.getSelection(),
70 fullySelected = sel.getSelectedElement(),
71 fakeSelected = fullySelected && fullySelected.data( 'cke-realelement' ),
72 linkElement = fakeSelected ?
73 CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, fullySelected ) :
74 CKEDITOR.plugins.link.getSelectedLink( editor );
75
76 if ( linkElement ) {
77 loadElements.call( this, linkElement );
78 !fakeSelected && sel.selectElement( linkElement );
79
80 if ( fullySelected )
81 this._.selectedElement = fullySelected;
82 }
83
84 this.getContentElement( 'info', 'txtName' ).focus();
85 },
86 contents: [ {
87 id: 'info',
88 label: editor.lang.link.anchor.title,
89 accessKey: 'I',
90 elements: [ {
91 type: 'text',
92 id: 'txtName',
93 label: editor.lang.link.anchor.name,
94 required: true,
95 validate: function() {
96 if ( !this.getValue() ) {
97 alert( editor.lang.link.anchor.errorName ); // jshint ignore:line
98 return false;
99 }
100 return true;
101 }
102 } ]
103 } ]
104 };
105} );
diff --git a/sources/plugins/link/dialogs/link.js b/sources/plugins/link/dialogs/link.js
new file mode 100644
index 0000000..914471f
--- /dev/null
+++ b/sources/plugins/link/dialogs/link.js
@@ -0,0 +1,979 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8( function() {
9 CKEDITOR.dialog.add( 'link', function( editor ) {
10 var plugin = CKEDITOR.plugins.link,
11 initialLinkText;
12
13 // Handles the event when the "Target" selection box is changed.
14 var targetChanged = function() {
15 var dialog = this.getDialog(),
16 popupFeatures = dialog.getContentElement( 'target', 'popupFeatures' ),
17 targetName = dialog.getContentElement( 'target', 'linkTargetName' ),
18 value = this.getValue();
19
20 if ( !popupFeatures || !targetName )
21 return;
22
23 popupFeatures = popupFeatures.getElement();
24 popupFeatures.hide();
25 targetName.setValue( '' );
26
27 switch ( value ) {
28 case 'frame':
29 targetName.setLabel( editor.lang.link.targetFrameName );
30 targetName.getElement().show();
31 break;
32 case 'popup':
33 popupFeatures.show();
34 targetName.setLabel( editor.lang.link.targetPopupName );
35 targetName.getElement().show();
36 break;
37 default:
38 targetName.setValue( value );
39 targetName.getElement().hide();
40 break;
41 }
42
43 };
44
45 // Handles the event when the "Type" selection box is changed.
46 var linkTypeChanged = function() {
47 var dialog = this.getDialog(),
48 partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ],
49 typeValue = this.getValue(),
50 uploadTab = dialog.definition.getContents( 'upload' ),
51 uploadInitiallyHidden = uploadTab && uploadTab.hidden;
52
53 if ( typeValue == 'url' ) {
54 if ( editor.config.linkShowTargetTab )
55 dialog.showPage( 'target' );
56 if ( !uploadInitiallyHidden )
57 dialog.showPage( 'upload' );
58 } else {
59 dialog.hidePage( 'target' );
60 if ( !uploadInitiallyHidden )
61 dialog.hidePage( 'upload' );
62 }
63
64 for ( var i = 0; i < partIds.length; i++ ) {
65 var element = dialog.getContentElement( 'info', partIds[ i ] );
66 if ( !element )
67 continue;
68
69 element = element.getElement().getParent().getParent();
70 if ( partIds[ i ] == typeValue + 'Options' )
71 element.show();
72 else
73 element.hide();
74 }
75
76 dialog.layout();
77 };
78
79 var setupParams = function( page, data ) {
80 if ( data[ page ] )
81 this.setValue( data[ page ][ this.id ] || '' );
82 };
83
84 var setupPopupParams = function( data ) {
85 return setupParams.call( this, 'target', data );
86 };
87
88 var setupAdvParams = function( data ) {
89 return setupParams.call( this, 'advanced', data );
90 };
91
92 var commitParams = function( page, data ) {
93 if ( !data[ page ] )
94 data[ page ] = {};
95
96 data[ page ][ this.id ] = this.getValue() || '';
97 };
98
99 var commitPopupParams = function( data ) {
100 return commitParams.call( this, 'target', data );
101 };
102
103 var commitAdvParams = function( data ) {
104 return commitParams.call( this, 'advanced', data );
105 };
106
107 var commonLang = editor.lang.common,
108 linkLang = editor.lang.link,
109 anchors;
110
111 return {
112 title: linkLang.title,
113 minWidth: ( CKEDITOR.skinName || editor.config.skin ) == 'moono-lisa' ? 450 : 350,
114 minHeight: 240,
115 contents: [ {
116 id: 'info',
117 label: linkLang.info,
118 title: linkLang.info,
119 elements: [ {
120 type: 'text',
121 id: 'linkDisplayText',
122 label: linkLang.displayText,
123 setup: function() {
124 this.enable();
125
126 this.setValue( editor.getSelection().getSelectedText() );
127
128 // Keep inner text so that it can be compared in commit function. By obtaining value from getData()
129 // we get value stripped from new line chars which is important when comparing the value later on.
130 initialLinkText = this.getValue();
131 },
132 commit: function( data ) {
133 data.linkText = this.isEnabled() ? this.getValue() : '';
134 }
135 },
136 {
137 id: 'linkType',
138 type: 'select',
139 label: linkLang.type,
140 'default': 'url',
141 items: [
142 [ linkLang.toUrl, 'url' ],
143 [ linkLang.toAnchor, 'anchor' ],
144 [ linkLang.toEmail, 'email' ]
145 ],
146 onChange: linkTypeChanged,
147 setup: function( data ) {
148 this.setValue( data.type || 'url' );
149 },
150 commit: function( data ) {
151 data.type = this.getValue();
152 }
153 },
154 {
155 type: 'vbox',
156 id: 'urlOptions',
157 children: [ {
158 type: 'hbox',
159 widths: [ '25%', '75%' ],
160 children: [ {
161 id: 'protocol',
162 type: 'select',
163 label: commonLang.protocol,
164 'default': 'http://',
165 items: [
166 // Force 'ltr' for protocol names in BIDI. (#5433)
167 [ 'http://\u200E', 'http://' ],
168 [ 'https://\u200E', 'https://' ],
169 [ 'ftp://\u200E', 'ftp://' ],
170 [ 'news://\u200E', 'news://' ],
171 [ linkLang.other, '' ]
172 ],
173 setup: function( data ) {
174 if ( data.url )
175 this.setValue( data.url.protocol || '' );
176 },
177 commit: function( data ) {
178 if ( !data.url )
179 data.url = {};
180
181 data.url.protocol = this.getValue();
182 }
183 },
184 {
185 type: 'text',
186 id: 'url',
187 label: commonLang.url,
188 required: true,
189 onLoad: function() {
190 this.allowOnChange = true;
191 },
192 onKeyUp: function() {
193 this.allowOnChange = false;
194 var protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ),
195 url = this.getValue(),
196 urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/i,
197 urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i;
198
199 var protocol = urlOnChangeProtocol.exec( url );
200 if ( protocol ) {
201 this.setValue( url.substr( protocol[ 0 ].length ) );
202 protocolCmb.setValue( protocol[ 0 ].toLowerCase() );
203 } else if ( urlOnChangeTestOther.test( url ) ) {
204 protocolCmb.setValue( '' );
205 }
206
207 this.allowOnChange = true;
208 },
209 onChange: function() {
210 if ( this.allowOnChange ) // Dont't call on dialog load.
211 this.onKeyUp();
212 },
213 validate: function() {
214 var dialog = this.getDialog();
215
216 if ( dialog.getContentElement( 'info', 'linkType' ) && dialog.getValueOf( 'info', 'linkType' ) != 'url' )
217 return true;
218
219 if ( !editor.config.linkJavaScriptLinksAllowed && ( /javascript\:/ ).test( this.getValue() ) ) {
220 alert( commonLang.invalidValue ); // jshint ignore:line
221 return false;
222 }
223
224 if ( this.getDialog().fakeObj ) // Edit Anchor.
225 return true;
226
227 var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noUrl );
228 return func.apply( this );
229 },
230 setup: function( data ) {
231 this.allowOnChange = false;
232 if ( data.url )
233 this.setValue( data.url.url );
234 this.allowOnChange = true;
235
236 },
237 commit: function( data ) {
238 // IE will not trigger the onChange event if the mouse has been used
239 // to carry all the operations #4724
240 this.onChange();
241
242 if ( !data.url )
243 data.url = {};
244
245 data.url.url = this.getValue();
246 this.allowOnChange = false;
247 }
248 } ],
249 setup: function() {
250 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
251 this.getElement().show();
252 }
253 },
254 {
255 type: 'button',
256 id: 'browse',
257 hidden: 'true',
258 filebrowser: 'info:url',
259 label: commonLang.browseServer
260 } ]
261 },
262 {
263 type: 'vbox',
264 id: 'anchorOptions',
265 width: 260,
266 align: 'center',
267 padding: 0,
268 children: [ {
269 type: 'fieldset',
270 id: 'selectAnchorText',
271 label: linkLang.selectAnchor,
272 setup: function() {
273 anchors = plugin.getEditorAnchors( editor );
274
275 this.getElement()[ anchors && anchors.length ? 'show' : 'hide' ]();
276 },
277 children: [ {
278 type: 'hbox',
279 id: 'selectAnchor',
280 children: [ {
281 type: 'select',
282 id: 'anchorName',
283 'default': '',
284 label: linkLang.anchorName,
285 style: 'width: 100%;',
286 items: [
287 [ '' ]
288 ],
289 setup: function( data ) {
290 this.clear();
291 this.add( '' );
292
293 if ( anchors ) {
294 for ( var i = 0; i < anchors.length; i++ ) {
295 if ( anchors[ i ].name )
296 this.add( anchors[ i ].name );
297 }
298 }
299
300 if ( data.anchor )
301 this.setValue( data.anchor.name );
302
303 var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
304 if ( linkType && linkType.getValue() == 'email' )
305 this.focus();
306 },
307 commit: function( data ) {
308 if ( !data.anchor )
309 data.anchor = {};
310
311 data.anchor.name = this.getValue();
312 }
313 },
314 {
315 type: 'select',
316 id: 'anchorId',
317 'default': '',
318 label: linkLang.anchorId,
319 style: 'width: 100%;',
320 items: [
321 [ '' ]
322 ],
323 setup: function( data ) {
324 this.clear();
325 this.add( '' );
326
327 if ( anchors ) {
328 for ( var i = 0; i < anchors.length; i++ ) {
329 if ( anchors[ i ].id )
330 this.add( anchors[ i ].id );
331 }
332 }
333
334 if ( data.anchor )
335 this.setValue( data.anchor.id );
336 },
337 commit: function( data ) {
338 if ( !data.anchor )
339 data.anchor = {};
340
341 data.anchor.id = this.getValue();
342 }
343 } ],
344 setup: function() {
345 this.getElement()[ anchors && anchors.length ? 'show' : 'hide' ]();
346 }
347 } ]
348 },
349 {
350 type: 'html',
351 id: 'noAnchors',
352 style: 'text-align: center;',
353 html: '<div role="note" tabIndex="-1">' + CKEDITOR.tools.htmlEncode( linkLang.noAnchors ) + '</div>',
354 // Focus the first element defined in above html.
355 focus: true,
356 setup: function() {
357 this.getElement()[ anchors && anchors.length ? 'hide' : 'show' ]();
358 }
359 } ],
360 setup: function() {
361 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
362 this.getElement().hide();
363 }
364 },
365 {
366 type: 'vbox',
367 id: 'emailOptions',
368 padding: 1,
369 children: [ {
370 type: 'text',
371 id: 'emailAddress',
372 label: linkLang.emailAddress,
373 required: true,
374 validate: function() {
375 var dialog = this.getDialog();
376
377 if ( !dialog.getContentElement( 'info', 'linkType' ) || dialog.getValueOf( 'info', 'linkType' ) != 'email' )
378 return true;
379
380 var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noEmail );
381 return func.apply( this );
382 },
383 setup: function( data ) {
384 if ( data.email )
385 this.setValue( data.email.address );
386
387 var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
388 if ( linkType && linkType.getValue() == 'email' )
389 this.select();
390 },
391 commit: function( data ) {
392 if ( !data.email )
393 data.email = {};
394
395 data.email.address = this.getValue();
396 }
397 },
398 {
399 type: 'text',
400 id: 'emailSubject',
401 label: linkLang.emailSubject,
402 setup: function( data ) {
403 if ( data.email )
404 this.setValue( data.email.subject );
405 },
406 commit: function( data ) {
407 if ( !data.email )
408 data.email = {};
409
410 data.email.subject = this.getValue();
411 }
412 },
413 {
414 type: 'textarea',
415 id: 'emailBody',
416 label: linkLang.emailBody,
417 rows: 3,
418 'default': '',
419 setup: function( data ) {
420 if ( data.email )
421 this.setValue( data.email.body );
422 },
423 commit: function( data ) {
424 if ( !data.email )
425 data.email = {};
426
427 data.email.body = this.getValue();
428 }
429 } ],
430 setup: function() {
431 if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
432 this.getElement().hide();
433 }
434 } ]
435 },
436 {
437 id: 'target',
438 requiredContent: 'a[target]', // This is not fully correct, because some target option requires JS.
439 label: linkLang.target,
440 title: linkLang.target,
441 elements: [ {
442 type: 'hbox',
443 widths: [ '50%', '50%' ],
444 children: [ {
445 type: 'select',
446 id: 'linkTargetType',
447 label: commonLang.target,
448 'default': 'notSet',
449 style: 'width : 100%;',
450 'items': [
451 [ commonLang.notSet, 'notSet' ],
452 [ linkLang.targetFrame, 'frame' ],
453 [ linkLang.targetPopup, 'popup' ],
454 [ commonLang.targetNew, '_blank' ],
455 [ commonLang.targetTop, '_top' ],
456 [ commonLang.targetSelf, '_self' ],
457 [ commonLang.targetParent, '_parent' ]
458 ],
459 onChange: targetChanged,
460 setup: function( data ) {
461 if ( data.target )
462 this.setValue( data.target.type || 'notSet' );
463 targetChanged.call( this );
464 },
465 commit: function( data ) {
466 if ( !data.target )
467 data.target = {};
468
469 data.target.type = this.getValue();
470 }
471 },
472 {
473 type: 'text',
474 id: 'linkTargetName',
475 label: linkLang.targetFrameName,
476 'default': '',
477 setup: function( data ) {
478 if ( data.target )
479 this.setValue( data.target.name );
480 },
481 commit: function( data ) {
482 if ( !data.target )
483 data.target = {};
484
485 data.target.name = this.getValue().replace( /([^\x00-\x7F]|\s)/gi, '' );
486 }
487 } ]
488 },
489 {
490 type: 'vbox',
491 width: '100%',
492 align: 'center',
493 padding: 2,
494 id: 'popupFeatures',
495 children: [ {
496 type: 'fieldset',
497 label: linkLang.popupFeatures,
498 children: [ {
499 type: 'hbox',
500 children: [ {
501 type: 'checkbox',
502 id: 'resizable',
503 label: linkLang.popupResizable,
504 setup: setupPopupParams,
505 commit: commitPopupParams
506 },
507 {
508 type: 'checkbox',
509 id: 'status',
510 label: linkLang.popupStatusBar,
511 setup: setupPopupParams,
512 commit: commitPopupParams
513
514 } ]
515 },
516 {
517 type: 'hbox',
518 children: [ {
519 type: 'checkbox',
520 id: 'location',
521 label: linkLang.popupLocationBar,
522 setup: setupPopupParams,
523 commit: commitPopupParams
524
525 },
526 {
527 type: 'checkbox',
528 id: 'toolbar',
529 label: linkLang.popupToolbar,
530 setup: setupPopupParams,
531 commit: commitPopupParams
532
533 } ]
534 },
535 {
536 type: 'hbox',
537 children: [ {
538 type: 'checkbox',
539 id: 'menubar',
540 label: linkLang.popupMenuBar,
541 setup: setupPopupParams,
542 commit: commitPopupParams
543
544 },
545 {
546 type: 'checkbox',
547 id: 'fullscreen',
548 label: linkLang.popupFullScreen,
549 setup: setupPopupParams,
550 commit: commitPopupParams
551
552 } ]
553 },
554 {
555 type: 'hbox',
556 children: [ {
557 type: 'checkbox',
558 id: 'scrollbars',
559 label: linkLang.popupScrollBars,
560 setup: setupPopupParams,
561 commit: commitPopupParams
562
563 },
564 {
565 type: 'checkbox',
566 id: 'dependent',
567 label: linkLang.popupDependent,
568 setup: setupPopupParams,
569 commit: commitPopupParams
570
571 } ]
572 },
573 {
574 type: 'hbox',
575 children: [ {
576 type: 'text',
577 widths: [ '50%', '50%' ],
578 labelLayout: 'horizontal',
579 label: commonLang.width,
580 id: 'width',
581 setup: setupPopupParams,
582 commit: commitPopupParams
583
584 },
585 {
586 type: 'text',
587 labelLayout: 'horizontal',
588 widths: [ '50%', '50%' ],
589 label: linkLang.popupLeft,
590 id: 'left',
591 setup: setupPopupParams,
592 commit: commitPopupParams
593
594 } ]
595 },
596 {
597 type: 'hbox',
598 children: [ {
599 type: 'text',
600 labelLayout: 'horizontal',
601 widths: [ '50%', '50%' ],
602 label: commonLang.height,
603 id: 'height',
604 setup: setupPopupParams,
605 commit: commitPopupParams
606
607 },
608 {
609 type: 'text',
610 labelLayout: 'horizontal',
611 label: linkLang.popupTop,
612 widths: [ '50%', '50%' ],
613 id: 'top',
614 setup: setupPopupParams,
615 commit: commitPopupParams
616
617 } ]
618 } ]
619 } ]
620 } ]
621 },
622 {
623 id: 'upload',
624 label: linkLang.upload,
625 title: linkLang.upload,
626 hidden: true,
627 filebrowser: 'uploadButton',
628 elements: [ {
629 type: 'file',
630 id: 'upload',
631 label: commonLang.upload,
632 style: 'height:40px',
633 size: 29
634 },
635 {
636 type: 'fileButton',
637 id: 'uploadButton',
638 label: commonLang.uploadSubmit,
639 filebrowser: 'info:url',
640 'for': [ 'upload', 'upload' ]
641 } ]
642 },
643 {
644 id: 'advanced',
645 label: linkLang.advanced,
646 title: linkLang.advanced,
647 elements: [ {
648 type: 'vbox',
649 padding: 1,
650 children: [ {
651 type: 'hbox',
652 widths: [ '45%', '35%', '20%' ],
653 children: [ {
654 type: 'text',
655 id: 'advId',
656 requiredContent: 'a[id]',
657 label: linkLang.id,
658 setup: setupAdvParams,
659 commit: commitAdvParams
660 },
661 {
662 type: 'select',
663 id: 'advLangDir',
664 requiredContent: 'a[dir]',
665 label: linkLang.langDir,
666 'default': '',
667 style: 'width:110px',
668 items: [
669 [ commonLang.notSet, '' ],
670 [ linkLang.langDirLTR, 'ltr' ],
671 [ linkLang.langDirRTL, 'rtl' ]
672 ],
673 setup: setupAdvParams,
674 commit: commitAdvParams
675 },
676 {
677 type: 'text',
678 id: 'advAccessKey',
679 requiredContent: 'a[accesskey]',
680 width: '80px',
681 label: linkLang.acccessKey,
682 maxLength: 1,
683 setup: setupAdvParams,
684 commit: commitAdvParams
685
686 } ]
687 },
688 {
689 type: 'hbox',
690 widths: [ '45%', '35%', '20%' ],
691 children: [ {
692 type: 'text',
693 label: linkLang.name,
694 id: 'advName',
695 requiredContent: 'a[name]',
696 setup: setupAdvParams,
697 commit: commitAdvParams
698
699 },
700 {
701 type: 'text',
702 label: linkLang.langCode,
703 id: 'advLangCode',
704 requiredContent: 'a[lang]',
705 width: '110px',
706 'default': '',
707 setup: setupAdvParams,
708 commit: commitAdvParams
709
710 },
711 {
712 type: 'text',
713 label: linkLang.tabIndex,
714 id: 'advTabIndex',
715 requiredContent: 'a[tabindex]',
716 width: '80px',
717 maxLength: 5,
718 setup: setupAdvParams,
719 commit: commitAdvParams
720
721 } ]
722 } ]
723 },
724 {
725 type: 'vbox',
726 padding: 1,
727 children: [ {
728 type: 'hbox',
729 widths: [ '45%', '55%' ],
730 children: [ {
731 type: 'text',
732 label: linkLang.advisoryTitle,
733 requiredContent: 'a[title]',
734 'default': '',
735 id: 'advTitle',
736 setup: setupAdvParams,
737 commit: commitAdvParams
738
739 },
740 {
741 type: 'text',
742 label: linkLang.advisoryContentType,
743 requiredContent: 'a[type]',
744 'default': '',
745 id: 'advContentType',
746 setup: setupAdvParams,
747 commit: commitAdvParams
748
749 } ]
750 },
751 {
752 type: 'hbox',
753 widths: [ '45%', '55%' ],
754 children: [ {
755 type: 'text',
756 label: linkLang.cssClasses,
757 requiredContent: 'a(cke-xyz)', // Random text like 'xyz' will check if all are allowed.
758 'default': '',
759 id: 'advCSSClasses',
760 setup: setupAdvParams,
761 commit: commitAdvParams
762
763 },
764 {
765 type: 'text',
766 label: linkLang.charset,
767 requiredContent: 'a[charset]',
768 'default': '',
769 id: 'advCharset',
770 setup: setupAdvParams,
771 commit: commitAdvParams
772
773 } ]
774 },
775 {
776 type: 'hbox',
777 widths: [ '45%', '55%' ],
778 children: [ {
779 type: 'text',
780 label: linkLang.rel,
781 requiredContent: 'a[rel]',
782 'default': '',
783 id: 'advRel',
784 setup: setupAdvParams,
785 commit: commitAdvParams
786 },
787 {
788 type: 'text',
789 label: linkLang.styles,
790 requiredContent: 'a{cke-xyz}', // Random text like 'xyz' will check if all are allowed.
791 'default': '',
792 id: 'advStyles',
793 validate: CKEDITOR.dialog.validate.inlineStyle( editor.lang.common.invalidInlineStyle ),
794 setup: setupAdvParams,
795 commit: commitAdvParams
796 } ]
797 },
798 {
799 type: 'hbox',
800 widths: [ '45%', '55%' ],
801 children: [ {
802 type: 'checkbox',
803 id: 'download',
804 requiredContent: 'a[download]',
805 label: linkLang.download,
806 setup: function( data ) {
807 if ( data.download !== undefined )
808 this.setValue( 'checked', 'checked' );
809 },
810 commit: function( data ) {
811 if ( this.getValue() ) {
812 data.download = this.getValue();
813 }
814 }
815 } ]
816 } ]
817 } ]
818 } ],
819 onShow: function() {
820 var editor = this.getParentEditor(),
821 selection = editor.getSelection(),
822 selectedElement = selection.getSelectedElement(),
823 displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent(),
824 element = null;
825
826 // Fill in all the relevant fields if there's already one link selected.
827 if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) ) {
828 // Don't change selection if some element is already selected.
829 // For example - don't destroy fake selection.
830 if ( !selectedElement ) {
831 selection.selectElement( element );
832 selectedElement = element;
833 }
834 } else {
835 element = null;
836 }
837
838 // Here we'll decide whether or not we want to show Display Text field.
839 if ( plugin.showDisplayTextForElement( selectedElement, editor ) ) {
840 displayTextField.show();
841 } else {
842 displayTextField.hide();
843 }
844
845 var data = plugin.parseLinkAttributes( editor, element );
846
847 // Record down the selected element in the dialog.
848 this._.selectedElement = element;
849
850 this.setupContent( data );
851 },
852 onOk: function() {
853 var data = {};
854
855 // Collect data from fields.
856 this.commitContent( data );
857
858 var selection = editor.getSelection(),
859 attributes = plugin.getLinkAttributes( editor, data ),
860 bm,
861 nestedLinks;
862
863 if ( !this._.selectedElement ) {
864 var range = selection.getRanges()[ 0 ],
865 text;
866
867 // Use link URL as text with a collapsed cursor.
868 if ( range.collapsed ) {
869 // Short mailto link text view (#5736).
870 text = new CKEDITOR.dom.text( data.linkText || ( data.type == 'email' ?
871 data.email.address : attributes.set[ 'data-cke-saved-href' ] ), editor.document );
872 range.insertNode( text );
873 range.selectNodeContents( text );
874 } else if ( initialLinkText !== data.linkText ) {
875 text = new CKEDITOR.dom.text( data.linkText, editor.document );
876
877 // Shrink range to preserve block element.
878 range.shrink( CKEDITOR.SHRINK_TEXT );
879
880 // Use extractHtmlFromRange to remove markup within the selection. Also this method is a little
881 // smarter than range#deleteContents as it plays better e.g. with table cells.
882 editor.editable().extractHtmlFromRange( range );
883
884 range.insertNode( text );
885 }
886
887 // Editable links nested within current range should be removed, so that the link is applied to whole selection.
888 nestedLinks = range._find( 'a' );
889
890 for ( var i = 0; i < nestedLinks.length; i++ ) {
891 nestedLinks[ i ].remove( true );
892 }
893
894 // Apply style.
895 var style = new CKEDITOR.style( {
896 element: 'a',
897 attributes: attributes.set
898 } );
899
900 style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
901 style.applyToRange( range, editor );
902 range.select();
903 } else {
904 // We're only editing an existing link, so just overwrite the attributes.
905 var element = this._.selectedElement,
906 href = element.data( 'cke-saved-href' ),
907 textView = element.getHtml(),
908 newText;
909
910 element.setAttributes( attributes.set );
911 element.removeAttributes( attributes.removed );
912
913 if ( data.linkText && initialLinkText != data.linkText ) {
914 // Display text has been changed.
915 newText = data.linkText;
916 } else if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 ) {
917 // Update text view when user changes protocol (#4612).
918 // Short mailto link text view (#5736).
919 newText = data.type == 'email' ? data.email.address : attributes.set[ 'data-cke-saved-href' ];
920 }
921
922 if ( newText ) {
923 element.setText( newText );
924 // We changed the content, so need to select it again.
925 selection.selectElement( element );
926 }
927
928 delete this._.selectedElement;
929 }
930 },
931 onLoad: function() {
932 if ( !editor.config.linkShowAdvancedTab )
933 this.hidePage( 'advanced' ); //Hide Advanded tab.
934
935 if ( !editor.config.linkShowTargetTab )
936 this.hidePage( 'target' ); //Hide Target tab.
937 },
938 // Inital focus on 'url' field if link is of type URL.
939 onFocus: function() {
940 var linkType = this.getContentElement( 'info', 'linkType' ),
941 urlField;
942
943 if ( linkType && linkType.getValue() == 'url' ) {
944 urlField = this.getContentElement( 'info', 'url' );
945 urlField.select();
946 }
947 }
948 };
949 } );
950} )();
951// jscs:disable maximumLineLength
952/**
953 * The e-mail address anti-spam protection option. The protection will be
954 * applied when creating or modifying e-mail links through the editor interface.
955 *
956 * Two methods of protection can be chosen:
957 *
958 * 1. The e-mail parts (name, domain, and any other query string) are
959 * assembled into a function call pattern. Such function must be
960 * provided by the developer in the pages that will use the contents.
961 * 2. Only the e-mail address is obfuscated into a special string that
962 * has no meaning for humans or spam bots, but which is properly
963 * rendered and accepted by the browser.
964 *
965 * Both approaches require JavaScript to be enabled.
966 *
967 * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
968 * config.emailProtection = '';
969 *
970 * // href="<a href=\"javascript:void(location.href=\'mailto:\'+String.fromCharCode(116,101,115,116,101,114,64,99,107,101,100,105,116,111,114,46,99,111,109)+\'?subject=subject&body=body\')\">e-mail</a>"
971 * config.emailProtection = 'encode';
972 *
973 * // href="javascript:mt('tester','ckeditor.com','subject','body')"
974 * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
975 *
976 * @since 3.1
977 * @cfg {String} [emailProtection='' (empty string = disabled)]
978 * @member CKEDITOR.config
979 */
diff --git a/sources/plugins/link/icons/anchor-rtl.png b/sources/plugins/link/icons/anchor-rtl.png
new file mode 100644
index 0000000..b068855
--- /dev/null
+++ b/sources/plugins/link/icons/anchor-rtl.png
Binary files differ
diff --git a/sources/plugins/link/icons/anchor.png b/sources/plugins/link/icons/anchor.png
new file mode 100644
index 0000000..e50d6cd
--- /dev/null
+++ b/sources/plugins/link/icons/anchor.png
Binary files differ
diff --git a/sources/plugins/link/icons/hidpi/anchor-rtl.png b/sources/plugins/link/icons/hidpi/anchor-rtl.png
new file mode 100644
index 0000000..3533c38
--- /dev/null
+++ b/sources/plugins/link/icons/hidpi/anchor-rtl.png
Binary files differ
diff --git a/sources/plugins/link/icons/hidpi/anchor.png b/sources/plugins/link/icons/hidpi/anchor.png
new file mode 100644
index 0000000..99eeadd
--- /dev/null
+++ b/sources/plugins/link/icons/hidpi/anchor.png
Binary files differ
diff --git a/sources/plugins/link/icons/hidpi/link.png b/sources/plugins/link/icons/hidpi/link.png
new file mode 100644
index 0000000..43ce99e
--- /dev/null
+++ b/sources/plugins/link/icons/hidpi/link.png
Binary files differ
diff --git a/sources/plugins/link/icons/hidpi/unlink.png b/sources/plugins/link/icons/hidpi/unlink.png
new file mode 100644
index 0000000..8ace29d
--- /dev/null
+++ b/sources/plugins/link/icons/hidpi/unlink.png
Binary files differ
diff --git a/sources/plugins/link/icons/link.png b/sources/plugins/link/icons/link.png
new file mode 100644
index 0000000..c2c450f
--- /dev/null
+++ b/sources/plugins/link/icons/link.png
Binary files differ
diff --git a/sources/plugins/link/icons/unlink.png b/sources/plugins/link/icons/unlink.png
new file mode 100644
index 0000000..c2f3f64
--- /dev/null
+++ b/sources/plugins/link/icons/unlink.png
Binary files differ
diff --git a/sources/plugins/link/images/anchor.png b/sources/plugins/link/images/anchor.png
new file mode 100644
index 0000000..d94adb4
--- /dev/null
+++ b/sources/plugins/link/images/anchor.png
Binary files differ
diff --git a/sources/plugins/link/images/hidpi/anchor.png b/sources/plugins/link/images/hidpi/anchor.png
new file mode 100644
index 0000000..186c3e9
--- /dev/null
+++ b/sources/plugins/link/images/hidpi/anchor.png
Binary files differ
diff --git a/sources/plugins/link/lang/af.js b/sources/plugins/link/lang/af.js
new file mode 100644
index 0000000..3032beb
--- /dev/null
+++ b/sources/plugins/link/lang/af.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'af', {
6 acccessKey: 'Toegangsleutel',
7 advanced: 'Gevorderd',
8 advisoryContentType: 'Aanbevole inhoudstipe',
9 advisoryTitle: 'Aanbevole titel',
10 anchor: {
11 toolbar: 'Anker byvoeg/verander',
12 menu: 'Anker-eienskappe',
13 title: 'Anker-eienskappe',
14 name: 'Ankernaam',
15 errorName: 'Voltooi die ankernaam asseblief',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'Op element Id',
19 anchorName: 'Op ankernaam',
20 charset: 'Karakterstel van geskakelde bron',
21 cssClasses: 'CSS klasse',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-posadres',
25 emailBody: 'Berig-inhoud',
26 emailSubject: 'Berig-onderwerp',
27 id: 'Id',
28 info: 'Skakel informasie',
29 langCode: 'Taalkode',
30 langDir: 'Skryfrigting',
31 langDirLTR: 'Links na regs (LTR)',
32 langDirRTL: 'Regs na links (RTL)',
33 menu: 'Wysig skakel',
34 name: 'Naam',
35 noAnchors: '(Geen ankers beskikbaar in dokument)',
36 noEmail: 'Gee die e-posadres',
37 noUrl: 'Gee die skakel se URL',
38 other: '<ander>',
39 popupDependent: 'Afhanklik (Netscape)',
40 popupFeatures: 'Eienskappe van opspringvenster',
41 popupFullScreen: 'Volskerm (IE)',
42 popupLeft: 'Posisie links',
43 popupLocationBar: 'Adresbalk',
44 popupMenuBar: 'Spyskaartbalk',
45 popupResizable: 'Herskaalbaar',
46 popupScrollBars: 'Skuifbalke',
47 popupStatusBar: 'Statusbalk',
48 popupToolbar: 'Werkbalk',
49 popupTop: 'Posisie bo',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Kies \'n anker',
52 styles: 'Styl',
53 tabIndex: 'Tab indeks',
54 target: 'Doel',
55 targetFrame: '<raam>',
56 targetFrameName: 'Naam van doelraam',
57 targetPopup: '<opspringvenster>',
58 targetPopupName: 'Naam van opspringvenster',
59 title: 'Skakel',
60 toAnchor: 'Anker in bladsy',
61 toEmail: 'E-pos',
62 toUrl: 'URL',
63 toolbar: 'Skakel invoeg/wysig',
64 type: 'Skakelsoort',
65 unlink: 'Verwyder skakel',
66 upload: 'Oplaai'
67} );
diff --git a/sources/plugins/link/lang/ar.js b/sources/plugins/link/lang/ar.js
new file mode 100644
index 0000000..e0dd0d9
--- /dev/null
+++ b/sources/plugins/link/lang/ar.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ar', {
6 acccessKey: 'مفاتيح الإختصار',
7 advanced: 'متقدم',
8 advisoryContentType: 'نوع التقرير',
9 advisoryTitle: 'عنوان التقرير',
10 anchor: {
11 toolbar: 'إشارة مرجعية',
12 menu: 'تحرير الإشارة المرجعية',
13 title: 'خصائص الإشارة المرجعية',
14 name: 'اسم الإشارة المرجعية',
15 errorName: 'الرجاء كتابة اسم الإشارة المرجعية',
16 remove: 'إزالة الإشارة المرجعية'
17 },
18 anchorId: 'حسب رقم العنصر',
19 anchorName: 'حسب إسم الإشارة المرجعية',
20 charset: 'ترميز المادة المطلوبة',
21 cssClasses: 'فئات التنسيق',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'البريد الإلكتروني',
25 emailBody: 'محتوى الرسالة',
26 emailSubject: 'موضوع الرسالة',
27 id: 'هوية',
28 info: 'معلومات الرابط',
29 langCode: 'رمز اللغة',
30 langDir: 'إتجاه نص اللغة',
31 langDirLTR: 'اليسار لليمين (LTR)',
32 langDirRTL: 'اليمين لليسار (RTL)',
33 menu: 'تحرير الرابط',
34 name: 'إسم',
35 noAnchors: '(لا توجد علامات مرجعية في هذا المستند)',
36 noEmail: 'الرجاء كتابة الريد الإلكتروني',
37 noUrl: 'الرجاء كتابة رابط الموقع',
38 other: '<أخرى>',
39 popupDependent: 'تابع (Netscape)',
40 popupFeatures: 'خصائص النافذة المنبثقة',
41 popupFullScreen: 'ملئ الشاشة (IE)',
42 popupLeft: 'التمركز لليسار',
43 popupLocationBar: 'شريط العنوان',
44 popupMenuBar: 'القوائم الرئيسية',
45 popupResizable: 'قابلة التشكيل',
46 popupScrollBars: 'أشرطة التمرير',
47 popupStatusBar: 'شريط الحالة',
48 popupToolbar: 'شريط الأدوات',
49 popupTop: 'التمركز للأعلى',
50 rel: 'العلاقة',
51 selectAnchor: 'اختر علامة مرجعية',
52 styles: 'نمط',
53 tabIndex: 'الترتيب',
54 target: 'هدف الرابط',
55 targetFrame: '<إطار>',
56 targetFrameName: 'اسم الإطار المستهدف',
57 targetPopup: '<نافذة منبثقة>',
58 targetPopupName: 'اسم النافذة المنبثقة',
59 title: 'رابط',
60 toAnchor: 'مكان في هذا المستند',
61 toEmail: 'بريد إلكتروني',
62 toUrl: 'الرابط',
63 toolbar: 'رابط',
64 type: 'نوع الربط',
65 unlink: 'إزالة رابط',
66 upload: 'رفع'
67} );
diff --git a/sources/plugins/link/lang/az.js b/sources/plugins/link/lang/az.js
new file mode 100644
index 0000000..33588fe
--- /dev/null
+++ b/sources/plugins/link/lang/az.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'az', {
6 acccessKey: 'Qısayol düyməsi',
7 advanced: 'Geniş seçimləri',
8 advisoryContentType: 'Məsləhətli məzmunun növü',
9 advisoryTitle: 'Məsləhətli başlıq',
10 anchor: {
11 toolbar: 'Xeş',
12 menu: 'Xeşi redaktə et',
13 title: 'Xeşin seçimləri',
14 name: 'Xeşin adı',
15 errorName: 'Xeşin adı yanlışdır',
16 remove: 'Xeşin adı sil'
17 },
18 anchorId: 'ID görə',
19 anchorName: 'Xeşin adına görə',
20 charset: 'Hədəfin kodlaşdırması',
21 cssClasses: 'Üslub klası',
22 download: 'Məcburi yükləmə',
23 displayText: 'Göstərilən mətn',
24 emailAddress: 'E-poçt ünvanı',
25 emailBody: 'Mesajın məzmunu',
26 emailSubject: 'Mesajın başlığı',
27 id: 'ID',
28 info: 'Linkin xüsusiyyətləri',
29 langCode: 'Dilin kodu',
30 langDir: 'Yaziların istiqaməti',
31 langDirLTR: 'Soldan sağa (LTR)',
32 langDirRTL: 'Sağdan sola (RTL)',
33 menu: 'Linki redaktə et',
34 name: 'Ad',
35 noAnchors: '(heç bir xeş tapılmayıb)',
36 noEmail: 'E-poçt ünvanı daxil edin',
37 noUrl: 'Linkin URL-ı daxil edin',
38 other: '<digər>',
39 popupDependent: 'Asılı (Netscape)',
40 popupFeatures: 'Pəncərənin xüsusiyyətləri',
41 popupFullScreen: 'Tam ekran rejimi (IE)',
42 popupLeft: 'Solda',
43 popupLocationBar: 'Ünvan paneli',
44 popupMenuBar: 'Menyu paneli',
45 popupResizable: 'Olçülər dəyişilir',
46 popupScrollBars: 'Sürüşdürmələr göstər',
47 popupStatusBar: 'Bildirişlərin paneli',
48 popupToolbar: 'Alətlərin paneli',
49 popupTop: 'Yuxarıda',
50 rel: 'Münasibət',
51 selectAnchor: 'Xeşi seçin',
52 styles: 'Üslub',
53 tabIndex: 'Tabın nömrəsi',
54 target: 'Hədəf çərçivə',
55 targetFrame: '<freym>',
56 targetFrameName: 'Freymin adı',
57 targetPopup: '<yeni pəncərə>',
58 targetPopupName: 'Pəncərənin adı',
59 title: 'Link',
60 toAnchor: 'Xeş',
61 toEmail: 'E-poçt',
62 toUrl: 'URL',
63 toolbar: 'Link',
64 type: 'Linkin növü',
65 unlink: 'Linki sil',
66 upload: 'Serverə yüklə'
67} );
diff --git a/sources/plugins/link/lang/bg.js b/sources/plugins/link/lang/bg.js
new file mode 100644
index 0000000..ad32915
--- /dev/null
+++ b/sources/plugins/link/lang/bg.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'bg', {
6 acccessKey: 'Ключ за достъп',
7 advanced: 'Разширено',
8 advisoryContentType: 'Препоръчителен тип на съдържанието',
9 advisoryTitle: 'Препоръчително заглавие',
10 anchor: {
11 toolbar: 'Котва',
12 menu: 'Промяна на котва',
13 title: 'Настройки на котва',
14 name: 'Име на котва',
15 errorName: 'Моля въведете име на котвата',
16 remove: 'Премахване на котва'
17 },
18 anchorId: 'По ID на елемент',
19 anchorName: 'По име на котва',
20 charset: 'Тип на свързания ресурс',
21 cssClasses: 'Класове за CSS',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-mail aдрес',
25 emailBody: 'Съдържание',
26 emailSubject: 'Тема',
27 id: 'ID',
28 info: 'Инфо за връзката',
29 langCode: 'Код за езика',
30 langDir: 'Посока на езика',
31 langDirLTR: 'Ляво на Дясно (ЛнД)',
32 langDirRTL: 'Дясно на Ляво (ДнЛ)',
33 menu: 'Промяна на връзка',
34 name: 'Име',
35 noAnchors: '(Няма котви в текущия документ)',
36 noEmail: 'Моля въведете e-mail aдрес',
37 noUrl: 'Моля въведете URL адреса',
38 other: '<друго>',
39 popupDependent: 'Зависимост (Netscape)',
40 popupFeatures: 'Функции на изкачащ прозорец',
41 popupFullScreen: 'Цял екран (IE)',
42 popupLeft: 'Лява позиция',
43 popupLocationBar: 'Лента с локацията',
44 popupMenuBar: 'Лента за меню',
45 popupResizable: 'Оразмеряем',
46 popupScrollBars: 'Скролери',
47 popupStatusBar: 'Статусна лента',
48 popupToolbar: 'Лента с инструменти',
49 popupTop: 'Горна позиция',
50 rel: 'Връзка',
51 selectAnchor: 'Изберете котва',
52 styles: 'Стил',
53 tabIndex: 'Ред на достъп',
54 target: 'Цел',
55 targetFrame: '<frame>',
56 targetFrameName: 'Име на целевият прозорец',
57 targetPopup: '<изкачащ прозорец>',
58 targetPopupName: 'Име на изкачащ прозорец',
59 title: 'Връзка',
60 toAnchor: 'Връзка към котва в текста',
61 toEmail: 'E-mail',
62 toUrl: 'Уеб адрес',
63 toolbar: 'Връзка',
64 type: 'Тип на връзката',
65 unlink: 'Премахни връзката',
66 upload: 'Качване'
67} );
diff --git a/sources/plugins/link/lang/bn.js b/sources/plugins/link/lang/bn.js
new file mode 100644
index 0000000..c071821
--- /dev/null
+++ b/sources/plugins/link/lang/bn.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'bn', {
6 acccessKey: 'প্রবেশ কী',
7 advanced: 'এডভান্সড',
8 advisoryContentType: 'পরামর্শ কন্টেন্টের প্রকার',
9 advisoryTitle: 'পরামর্শ শীর্ষক',
10 anchor: {
11 toolbar: 'নোঙ্গর',
12 menu: 'নোঙর প্রোপার্টি',
13 title: 'নোঙর প্রোপার্টি',
14 name: 'নোঙরের নাম',
15 errorName: 'নোঙরের নাম টাইপ করুন',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'নোঙরের আইডি দিয়ে',
19 anchorName: 'নোঙরের নাম দিয়ে',
20 charset: 'লিংক রিসোর্স ক্যারেক্টর সেট',
21 cssClasses: 'স্টাইল-শীট ক্লাস',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ইমেইল ঠিকানা',
25 emailBody: 'মেসেজের দেহ',
26 emailSubject: 'মেসেজের বিষয়',
27 id: 'আইডি',
28 info: 'লিংক তথ্য',
29 langCode: 'ভাষা লেখার দিক',
30 langDir: 'ভাষা লেখার দিক',
31 langDirLTR: 'বাম থেকে ডান (LTR)',
32 langDirRTL: 'ডান থেকে বাম (RTL)',
33 menu: 'লিংক সম্পাদন',
34 name: 'নাম',
35 noAnchors: '(No anchors available in the document)', // MISSING
36 noEmail: 'অনুগ্রহ করে ইমেইল এড্রেস টাইপ করুন',
37 noUrl: 'অনুগ্রহ করে URL লিংক টাইপ করুন',
38 other: '<other>', // MISSING
39 popupDependent: 'ডিপেন্ডেন্ট (Netscape)',
40 popupFeatures: 'পপআপ উইন্ডো ফীচার সমূহ',
41 popupFullScreen: 'পূর্ণ পর্দা জুড়ে (IE)',
42 popupLeft: 'বামের পজিশন',
43 popupLocationBar: 'লোকেশন বার',
44 popupMenuBar: 'মেন্যু বার',
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'স্ক্রল বার',
47 popupStatusBar: 'স্ট্যাটাস বার',
48 popupToolbar: 'টুল বার',
49 popupTop: 'ডানের পজিশন',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'নোঙর বাছাই',
52 styles: 'স্টাইল',
53 tabIndex: 'ট্যাব ইন্ডেক্স',
54 target: 'টার্গেট',
55 targetFrame: '<ফ্রেম>',
56 targetFrameName: 'টার্গেট ফ্রেমের নাম',
57 targetPopup: '<পপআপ উইন্ডো>',
58 targetPopupName: 'পপআপ উইন্ডোর নাম',
59 title: 'লিংক',
60 toAnchor: 'এই পেজে নোঙর কর',
61 toEmail: 'ইমেইল',
62 toUrl: 'URL',
63 toolbar: 'লিংক যুক্ত কর',
64 type: 'লিংক প্রকার',
65 unlink: 'লিংক সরাও',
66 upload: 'আপলোড'
67} );
diff --git a/sources/plugins/link/lang/bs.js b/sources/plugins/link/lang/bs.js
new file mode 100644
index 0000000..d23ae35
--- /dev/null
+++ b/sources/plugins/link/lang/bs.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'bs', {
6 acccessKey: 'Pristupna tipka',
7 advanced: 'Naprednije',
8 advisoryContentType: 'Advisory vrsta sadržaja',
9 advisoryTitle: 'Advisory title',
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'Po Id-u elementa',
19 anchorName: 'Po nazivu sidra',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Klase CSS stilova',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Adresa',
25 emailBody: 'Poruka',
26 emailSubject: 'Subjekt poruke',
27 id: 'Id',
28 info: 'Link info',
29 langCode: 'Smjer pisanja',
30 langDir: 'Smjer pisanja',
31 langDirLTR: 'S lijeva na desno (LTR)',
32 langDirRTL: 'S desna na lijevo (RTL)',
33 menu: 'Izmjeni link',
34 name: 'Naziv',
35 noAnchors: '(Nema dostupnih sidra na stranici)',
36 noEmail: 'Molimo ukucajte e-mail adresu',
37 noUrl: 'Molimo ukucajte URL link',
38 other: '<other>', // MISSING
39 popupDependent: 'Ovisno (Netscape)',
40 popupFeatures: 'Moguænosti popup prozora',
41 popupFullScreen: 'Cijeli ekran (IE)',
42 popupLeft: 'Lijeva pozicija',
43 popupLocationBar: 'Traka za lokaciju',
44 popupMenuBar: 'Izborna traka',
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Scroll traka',
47 popupStatusBar: 'Statusna traka',
48 popupToolbar: 'Traka sa alatima',
49 popupTop: 'Gornja pozicija',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Izaberi sidro',
52 styles: 'Stil',
53 tabIndex: 'Tab indeks',
54 target: 'Prozor',
55 targetFrame: '<frejm>',
56 targetFrameName: 'Target Frame Name', // MISSING
57 targetPopup: '<popup prozor>',
58 targetPopupName: 'Naziv popup prozora',
59 title: 'Link',
60 toAnchor: 'Sidro na ovoj stranici',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Ubaci/Izmjeni link',
64 type: 'Tip linka',
65 unlink: 'Izbriši link',
66 upload: 'Šalji'
67} );
diff --git a/sources/plugins/link/lang/ca.js b/sources/plugins/link/lang/ca.js
new file mode 100644
index 0000000..44a9ebd
--- /dev/null
+++ b/sources/plugins/link/lang/ca.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ca', {
6 acccessKey: 'Clau d\'accés',
7 advanced: 'Avançat',
8 advisoryContentType: 'Tipus de contingut consultiu',
9 advisoryTitle: 'Títol consultiu',
10 anchor: {
11 toolbar: 'Insereix/Edita àncora',
12 menu: 'Propietats de l\'àncora',
13 title: 'Propietats de l\'àncora',
14 name: 'Nom de l\'àncora',
15 errorName: 'Si us plau, escriviu el nom de l\'ancora',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'Per Id d\'element',
19 anchorName: 'Per nom d\'àncora',
20 charset: 'Conjunt de caràcters font enllaçat',
21 cssClasses: 'Classes del full d\'estil',
22 download: 'Force Download', // MISSING
23 displayText: 'Text a mostrar',
24 emailAddress: 'Adreça de correu electrònic',
25 emailBody: 'Cos del missatge',
26 emailSubject: 'Assumpte del missatge',
27 id: 'Id',
28 info: 'Informació de l\'enllaç',
29 langCode: 'Direcció de l\'idioma',
30 langDir: 'Direcció de l\'idioma',
31 langDirLTR: 'D\'esquerra a dreta (LTR)',
32 langDirRTL: 'De dreta a esquerra (RTL)',
33 menu: 'Edita l\'enllaç',
34 name: 'Nom',
35 noAnchors: '(No hi ha àncores disponibles en aquest document)',
36 noEmail: 'Si us plau, escrigui l\'adreça correu electrònic',
37 noUrl: 'Si us plau, escrigui l\'enllaç URL',
38 other: '<altre>',
39 popupDependent: 'Depenent (Netscape)',
40 popupFeatures: 'Característiques finestra popup',
41 popupFullScreen: 'Pantalla completa (IE)',
42 popupLeft: 'Posició esquerra',
43 popupLocationBar: 'Barra d\'adreça',
44 popupMenuBar: 'Barra de menú',
45 popupResizable: 'Redimensionable',
46 popupScrollBars: 'Barres d\'scroll',
47 popupStatusBar: 'Barra d\'estat',
48 popupToolbar: 'Barra d\'eines',
49 popupTop: 'Posició dalt',
50 rel: 'Relació',
51 selectAnchor: 'Selecciona una àncora',
52 styles: 'Estil',
53 tabIndex: 'Index de Tab',
54 target: 'Destí',
55 targetFrame: '<marc>',
56 targetFrameName: 'Nom del marc de destí',
57 targetPopup: '<finestra emergent>',
58 targetPopupName: 'Nom finestra popup',
59 title: 'Enllaç',
60 toAnchor: 'Àncora en aquesta pàgina',
61 toEmail: 'Correu electrònic',
62 toUrl: 'URL',
63 toolbar: 'Insereix/Edita enllaç',
64 type: 'Tipus d\'enllaç',
65 unlink: 'Elimina l\'enllaç',
66 upload: 'Puja'
67} );
diff --git a/sources/plugins/link/lang/cs.js b/sources/plugins/link/lang/cs.js
new file mode 100644
index 0000000..508c133
--- /dev/null
+++ b/sources/plugins/link/lang/cs.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'cs', {
6 acccessKey: 'Přístupový klíč',
7 advanced: 'Rozšířené',
8 advisoryContentType: 'Pomocný typ obsahu',
9 advisoryTitle: 'Pomocný titulek',
10 anchor: {
11 toolbar: 'Záložka',
12 menu: 'Vlastnosti záložky',
13 title: 'Vlastnosti záložky',
14 name: 'Název záložky',
15 errorName: 'Zadejte prosím název záložky',
16 remove: 'Odstranit záložku'
17 },
18 anchorId: 'Podle Id objektu',
19 anchorName: 'Podle jména kotvy',
20 charset: 'Přiřazená znaková sada',
21 cssClasses: 'Třída stylu',
22 download: 'Force Download', // MISSING
23 displayText: 'Zobrazit text',
24 emailAddress: 'E-mailová adresa',
25 emailBody: 'Tělo zprávy',
26 emailSubject: 'Předmět zprávy',
27 id: 'Id',
28 info: 'Informace o odkazu',
29 langCode: 'Kód jazyka',
30 langDir: 'Směr jazyka',
31 langDirLTR: 'Zleva doprava (LTR)',
32 langDirRTL: 'Zprava doleva (RTL)',
33 menu: 'Změnit odkaz',
34 name: 'Jméno',
35 noAnchors: '(Ve stránce není definována žádná kotva!)',
36 noEmail: 'Zadejte prosím e-mailovou adresu',
37 noUrl: 'Zadejte prosím URL odkazu',
38 other: '<jiný>',
39 popupDependent: 'Závislost (Netscape)',
40 popupFeatures: 'Vlastnosti vyskakovacího okna',
41 popupFullScreen: 'Celá obrazovka (IE)',
42 popupLeft: 'Levý okraj',
43 popupLocationBar: 'Panel umístění',
44 popupMenuBar: 'Panel nabídky',
45 popupResizable: 'Umožňující měnit velikost',
46 popupScrollBars: 'Posuvníky',
47 popupStatusBar: 'Stavový řádek',
48 popupToolbar: 'Panel nástrojů',
49 popupTop: 'Horní okraj',
50 rel: 'Vztah',
51 selectAnchor: 'Vybrat kotvu',
52 styles: 'Styl',
53 tabIndex: 'Pořadí prvku',
54 target: 'Cíl',
55 targetFrame: '<rámec>',
56 targetFrameName: 'Název cílového rámu',
57 targetPopup: '<vyskakovací okno>',
58 targetPopupName: 'Název vyskakovacího okna',
59 title: 'Odkaz',
60 toAnchor: 'Kotva v této stránce',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Odkaz',
64 type: 'Typ odkazu',
65 unlink: 'Odstranit odkaz',
66 upload: 'Odeslat'
67} );
diff --git a/sources/plugins/link/lang/cy.js b/sources/plugins/link/lang/cy.js
new file mode 100644
index 0000000..024b669
--- /dev/null
+++ b/sources/plugins/link/lang/cy.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'cy', {
6 acccessKey: 'Allwedd Mynediad',
7 advanced: 'Uwch',
8 advisoryContentType: 'Math y Cynnwys Cynghorol',
9 advisoryTitle: 'Teitl Cynghorol',
10 anchor: {
11 toolbar: 'Angor',
12 menu: 'Golygu\'r Angor',
13 title: 'Priodweddau\'r Angor',
14 name: 'Enw\'r Angor',
15 errorName: 'Teipiwch enw\'r angor',
16 remove: 'Tynnwch yr Angor'
17 },
18 anchorId: 'Gan Id yr Elfen',
19 anchorName: 'Gan Enw\'r Angor',
20 charset: 'Set Nodau\'r Adnodd Cysylltiedig',
21 cssClasses: 'Dosbarthiadau Dalen Arddull',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Cyfeiriad E-Bost',
25 emailBody: 'Corff y Neges',
26 emailSubject: 'Testun y Neges',
27 id: 'Id',
28 info: 'Gwyb y Ddolen',
29 langCode: 'Cod Iaith',
30 langDir: 'Cyfeiriad Iaith',
31 langDirLTR: 'Chwith i\'r Dde (LTR)',
32 langDirRTL: 'Dde i\'r Chwith (RTL)',
33 menu: 'Golygu Dolen',
34 name: 'Enw',
35 noAnchors: '(Dim angorau ar gael yn y ddogfen)',
36 noEmail: 'Teipiwch gyfeiriad yr e-bost',
37 noUrl: 'Teipiwch URL y ddolen',
38 other: '<eraill>',
39 popupDependent: 'Dibynnol (Netscape)',
40 popupFeatures: 'Nodweddion Ffenestr Bop',
41 popupFullScreen: 'Sgrin Llawn (IE)',
42 popupLeft: 'Safle Chwith',
43 popupLocationBar: 'Bar Safle',
44 popupMenuBar: 'Dewislen',
45 popupResizable: 'Ailfeintiol',
46 popupScrollBars: 'Barrau Sgrolio',
47 popupStatusBar: 'Bar Statws',
48 popupToolbar: 'Bar Offer',
49 popupTop: 'Safle Top',
50 rel: 'Perthynas',
51 selectAnchor: 'Dewiswch Angor',
52 styles: 'Arddull',
53 tabIndex: 'Indecs Tab',
54 target: 'Targed',
55 targetFrame: '<ffrâm>',
56 targetFrameName: 'Enw Ffrâm y Targed',
57 targetPopup: '<ffenestr bop>',
58 targetPopupName: 'Enw Ffenestr Bop',
59 title: 'Dolen',
60 toAnchor: 'Dolen at angor yn y testun',
61 toEmail: 'E-bost',
62 toUrl: 'URL',
63 toolbar: 'Dolen',
64 type: 'Math y Ddolen',
65 unlink: 'Datgysylltu',
66 upload: 'Lanlwytho'
67} );
diff --git a/sources/plugins/link/lang/da.js b/sources/plugins/link/lang/da.js
new file mode 100644
index 0000000..47adf58
--- /dev/null
+++ b/sources/plugins/link/lang/da.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'da', {
6 acccessKey: 'Genvejstast',
7 advanced: 'Avanceret',
8 advisoryContentType: 'Indholdstype',
9 advisoryTitle: 'Titel',
10 anchor: {
11 toolbar: 'Indsæt/redigér bogmærke',
12 menu: 'Egenskaber for bogmærke',
13 title: 'Egenskaber for bogmærke',
14 name: 'Bogmærkenavn',
15 errorName: 'Indtast bogmærkenavn',
16 remove: 'Fjern bogmærke'
17 },
18 anchorId: 'Efter element-Id',
19 anchorName: 'Efter ankernavn',
20 charset: 'Tegnsæt',
21 cssClasses: 'Typografiark',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-mailadresse',
25 emailBody: 'Besked',
26 emailSubject: 'Emne',
27 id: 'Id',
28 info: 'Generelt',
29 langCode: 'Tekstretning',
30 langDir: 'Tekstretning',
31 langDirLTR: 'Fra venstre mod højre (LTR)',
32 langDirRTL: 'Fra højre mod venstre (RTL)',
33 menu: 'Redigér hyperlink',
34 name: 'Navn',
35 noAnchors: '(Ingen bogmærker i dokumentet)',
36 noEmail: 'Indtast e-mailadresse!',
37 noUrl: 'Indtast hyperlink-URL!',
38 other: '<anden>',
39 popupDependent: 'Koblet/dependent (Netscape)',
40 popupFeatures: 'Egenskaber for popup',
41 popupFullScreen: 'Fuld skærm (IE)',
42 popupLeft: 'Position fra venstre',
43 popupLocationBar: 'Adresselinje',
44 popupMenuBar: 'Menulinje',
45 popupResizable: 'Justérbar',
46 popupScrollBars: 'Scrollbar',
47 popupStatusBar: 'Statuslinje',
48 popupToolbar: 'Værktøjslinje',
49 popupTop: 'Position fra toppen',
50 rel: 'Relation',
51 selectAnchor: 'Vælg et anker',
52 styles: 'Typografi',
53 tabIndex: 'Tabulatorindeks',
54 target: 'Mål',
55 targetFrame: '<ramme>',
56 targetFrameName: 'Destinationsvinduets navn',
57 targetPopup: '<popup vindue>',
58 targetPopupName: 'Popupvinduets navn',
59 title: 'Egenskaber for hyperlink',
60 toAnchor: 'Bogmærke på denne side',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Indsæt/redigér hyperlink',
64 type: 'Type',
65 unlink: 'Fjern hyperlink',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/de-ch.js b/sources/plugins/link/lang/de-ch.js
new file mode 100644
index 0000000..eba8c7e
--- /dev/null
+++ b/sources/plugins/link/lang/de-ch.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'de-ch', {
6 acccessKey: 'Zugriffstaste',
7 advanced: 'Erweitert',
8 advisoryContentType: 'Inhaltstyp',
9 advisoryTitle: 'Titel Beschreibung',
10 anchor: {
11 toolbar: 'Anker',
12 menu: 'Anker bearbeiten',
13 title: 'Ankereigenschaften',
14 name: 'Ankername',
15 errorName: 'Bitte geben Sie den Namen des Ankers ein',
16 remove: 'Anker entfernen'
17 },
18 anchorId: 'Nach Elementkennung',
19 anchorName: 'Nach Ankername',
20 charset: 'Verknüpfter Ressourcenzeichensatz',
21 cssClasses: 'Formatvorlagenklasse',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail-Adresse',
25 emailBody: 'Nachrichtentext',
26 emailSubject: 'Betreffzeile',
27 id: 'Kennung',
28 info: 'Linkinfo',
29 langCode: 'Sprachcode',
30 langDir: 'Schreibrichtung',
31 langDirLTR: 'Links nach Rechts (LTR)',
32 langDirRTL: 'Rechts nach Links (RTL)',
33 menu: 'Link bearbeiten',
34 name: 'Name',
35 noAnchors: '(Keine Anker im Dokument vorhanden)',
36 noEmail: 'Bitte geben Sie E-Mail-Adresse an',
37 noUrl: 'Bitte geben Sie die Link-URL an',
38 other: '<andere>',
39 popupDependent: 'Abhängig (Netscape)',
40 popupFeatures: 'Pop-up Fenstereigenschaften',
41 popupFullScreen: 'Vollbild (IE)',
42 popupLeft: 'Linke Position',
43 popupLocationBar: 'Adressleiste',
44 popupMenuBar: 'Menüleiste',
45 popupResizable: 'Grösse änderbar',
46 popupScrollBars: 'Rollbalken',
47 popupStatusBar: 'Statusleiste',
48 popupToolbar: 'Werkzeugleiste',
49 popupTop: 'Obere Position',
50 rel: 'Beziehung',
51 selectAnchor: 'Anker auswählen',
52 styles: 'Style',
53 tabIndex: 'Tab-Index',
54 target: 'Zielseite',
55 targetFrame: '<Frame>',
56 targetFrameName: 'Ziel-Fenster-Name',
57 targetPopup: '<Pop-up Fenster>',
58 targetPopupName: 'Pop-up Fenster-Name',
59 title: 'Link',
60 toAnchor: 'Anker in dieser Seite',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Link einfügen/editieren',
64 type: 'Link-Typ',
65 unlink: 'Link entfernen',
66 upload: 'Hochladen'
67} );
diff --git a/sources/plugins/link/lang/de.js b/sources/plugins/link/lang/de.js
new file mode 100644
index 0000000..e73093f
--- /dev/null
+++ b/sources/plugins/link/lang/de.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'de', {
6 acccessKey: 'Zugriffstaste',
7 advanced: 'Erweitert',
8 advisoryContentType: 'Inhaltstyp',
9 advisoryTitle: 'Titel Beschreibung',
10 anchor: {
11 toolbar: 'Anker',
12 menu: 'Anker bearbeiten',
13 title: 'Ankereigenschaften',
14 name: 'Ankername',
15 errorName: 'Bitte geben Sie den Namen des Ankers ein',
16 remove: 'Anker entfernen'
17 },
18 anchorId: 'Nach Elementkennung',
19 anchorName: 'Nach Ankername',
20 charset: 'Verknüpfter Ressourcenzeichensatz',
21 cssClasses: 'Formatvorlagenklasse',
22 download: 'Herunterladen erzwingen',
23 displayText: 'Anzeigetext',
24 emailAddress: 'E-Mail-Adresse',
25 emailBody: 'Nachrichtentext',
26 emailSubject: 'Betreffzeile',
27 id: 'Kennung',
28 info: 'Linkinfo',
29 langCode: 'Sprachcode',
30 langDir: 'Schreibrichtung',
31 langDirLTR: 'Links nach Rechts (LTR)',
32 langDirRTL: 'Rechts nach Links (RTL)',
33 menu: 'Link bearbeiten',
34 name: 'Name',
35 noAnchors: '(Keine Anker im Dokument vorhanden)',
36 noEmail: 'Bitte geben Sie E-Mail-Adresse an',
37 noUrl: 'Bitte geben Sie die Link-URL an',
38 other: '<andere>',
39 popupDependent: 'Abhängig (Netscape)',
40 popupFeatures: 'Pop-up Fenstereigenschaften',
41 popupFullScreen: 'Vollbild (IE)',
42 popupLeft: 'Linke Position',
43 popupLocationBar: 'Adressleiste',
44 popupMenuBar: 'Menüleiste',
45 popupResizable: 'Größe änderbar',
46 popupScrollBars: 'Rollbalken',
47 popupStatusBar: 'Statusleiste',
48 popupToolbar: 'Werkzeugleiste',
49 popupTop: 'Obere Position',
50 rel: 'Beziehung',
51 selectAnchor: 'Anker auswählen',
52 styles: 'Style',
53 tabIndex: 'Tab-Index',
54 target: 'Zielseite',
55 targetFrame: '<Frame>',
56 targetFrameName: 'Ziel-Fenster-Name',
57 targetPopup: '<Pop-up Fenster>',
58 targetPopupName: 'Pop-up Fenster-Name',
59 title: 'Link',
60 toAnchor: 'Anker in dieser Seite',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Link einfügen/editieren',
64 type: 'Link-Typ',
65 unlink: 'Link entfernen',
66 upload: 'Hochladen'
67} );
diff --git a/sources/plugins/link/lang/el.js b/sources/plugins/link/lang/el.js
new file mode 100644
index 0000000..bf0fbb9
--- /dev/null
+++ b/sources/plugins/link/lang/el.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'el', {
6 acccessKey: 'Συντόμευση',
7 advanced: 'Για Προχωρημένους',
8 advisoryContentType: 'Ενδεικτικός Τύπος Περιεχομένου',
9 advisoryTitle: 'Ενδεικτικός Τίτλος',
10 anchor: {
11 toolbar: 'Εισαγωγή/επεξεργασία Άγκυρας',
12 menu: 'Ιδιότητες άγκυρας',
13 title: 'Ιδιότητες άγκυρας',
14 name: 'Όνομα άγκυρας',
15 errorName: 'Παρακαλούμε εισάγετε όνομα άγκυρας',
16 remove: 'Αφαίρεση Άγκυρας'
17 },
18 anchorId: 'Βάσει του Element Id',
19 anchorName: 'Βάσει του Ονόματος Άγκυρας',
20 charset: 'Κωδικοποίηση Χαρακτήρων Προσαρτημένης Πηγής',
21 cssClasses: 'Κλάσεις Φύλλων Στυλ',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Διεύθυνση E-mail',
25 emailBody: 'Κείμενο Μηνύματος',
26 emailSubject: 'Θέμα Μηνύματος',
27 id: 'Id',
28 info: 'Πληροφορίες Συνδέσμου',
29 langCode: 'Κατεύθυνση Κειμένου',
30 langDir: 'Κατεύθυνση Κειμένου',
31 langDirLTR: 'Αριστερά προς Δεξιά (LTR)',
32 langDirRTL: 'Δεξιά προς Αριστερά (RTL)',
33 menu: 'Επεξεργασία Συνδέσμου',
34 name: 'Όνομα',
35 noAnchors: '(Δεν υπάρχουν άγκυρες στο κείμενο)',
36 noEmail: 'Εισάγετε τη διεύθυνση ηλεκτρονικού ταχυδρομείου',
37 noUrl: 'Εισάγετε την τοποθεσία (URL) του συνδέσμου',
38 other: '<άλλο>',
39 popupDependent: 'Εξαρτημένο (Netscape)',
40 popupFeatures: 'Επιλογές Αναδυόμενου Παραθύρου',
41 popupFullScreen: 'Πλήρης Οθόνη (IE)',
42 popupLeft: 'Θέση Αριστερά',
43 popupLocationBar: 'Γραμμή Τοποθεσίας',
44 popupMenuBar: 'Γραμμή Επιλογών',
45 popupResizable: 'Προσαρμοζόμενο Μέγεθος',
46 popupScrollBars: 'Μπάρες Κύλισης',
47 popupStatusBar: 'Γραμμή Κατάστασης',
48 popupToolbar: 'Εργαλειοθήκη',
49 popupTop: 'Θέση Πάνω',
50 rel: 'Σχέση',
51 selectAnchor: 'Επιλέξτε μια Άγκυρα',
52 styles: 'Μορφή',
53 tabIndex: 'Σειρά Μεταπήδησης',
54 target: 'Παράθυρο Προορισμού',
55 targetFrame: '<πλαίσιο>',
56 targetFrameName: 'Όνομα Πλαισίου Προορισμού',
57 targetPopup: '<αναδυόμενο παράθυρο>',
58 targetPopupName: 'Όνομα Αναδυόμενου Παραθύρου',
59 title: 'Σύνδεσμος',
60 toAnchor: 'Άγκυρα σε αυτήν τη σελίδα',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Σύνδεσμος',
64 type: 'Τύπος Συνδέσμου',
65 unlink: 'Αφαίρεση Συνδέσμου',
66 upload: 'Αποστολή'
67} );
diff --git a/sources/plugins/link/lang/en-au.js b/sources/plugins/link/lang/en-au.js
new file mode 100644
index 0000000..f67a6f7
--- /dev/null
+++ b/sources/plugins/link/lang/en-au.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'en-au', {
6 acccessKey: 'Access Key',
7 advanced: 'Advanced',
8 advisoryContentType: 'Advisory Content Type',
9 advisoryTitle: 'Advisory Title',
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'By Element Id',
19 anchorName: 'By Anchor Name',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet Classes',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Address',
25 emailBody: 'Message Body',
26 emailSubject: 'Message Subject',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Language Code',
30 langDir: 'Language Direction',
31 langDirLTR: 'Left to Right (LTR)',
32 langDirRTL: 'Right to Left (RTL)',
33 menu: 'Edit Link',
34 name: 'Name',
35 noAnchors: '(No anchors available in the document)',
36 noEmail: 'Please type the e-mail address',
37 noUrl: 'Please type the link URL',
38 other: '<other>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'Popup Window Features',
41 popupFullScreen: 'Full Screen (IE)',
42 popupLeft: 'Left Position',
43 popupLocationBar: 'Location Bar',
44 popupMenuBar: 'Menu Bar',
45 popupResizable: 'Resizable',
46 popupScrollBars: 'Scroll Bars',
47 popupStatusBar: 'Status Bar',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Top Position',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Select an Anchor',
52 styles: 'Style',
53 tabIndex: 'Tab Index',
54 target: 'Target',
55 targetFrame: '<frame>',
56 targetFrameName: 'Target Frame Name',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Popup Window Name',
59 title: 'Link',
60 toAnchor: 'Link to anchor in the text',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Link',
64 type: 'Link Type',
65 unlink: 'Unlink',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/en-ca.js b/sources/plugins/link/lang/en-ca.js
new file mode 100644
index 0000000..636ee5c
--- /dev/null
+++ b/sources/plugins/link/lang/en-ca.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'en-ca', {
6 acccessKey: 'Access Key',
7 advanced: 'Advanced',
8 advisoryContentType: 'Advisory Content Type',
9 advisoryTitle: 'Advisory Title',
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'By Element Id',
19 anchorName: 'By Anchor Name',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet Classes',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Address',
25 emailBody: 'Message Body',
26 emailSubject: 'Message Subject',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Language Code',
30 langDir: 'Language Direction',
31 langDirLTR: 'Left to Right (LTR)',
32 langDirRTL: 'Right to Left (RTL)',
33 menu: 'Edit Link',
34 name: 'Name',
35 noAnchors: '(No anchors available in the document)',
36 noEmail: 'Please type the e-mail address',
37 noUrl: 'Please type the link URL',
38 other: '<other>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'Popup Window Features',
41 popupFullScreen: 'Full Screen (IE)',
42 popupLeft: 'Left Position',
43 popupLocationBar: 'Location Bar',
44 popupMenuBar: 'Menu Bar',
45 popupResizable: 'Resizable',
46 popupScrollBars: 'Scroll Bars',
47 popupStatusBar: 'Status Bar',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Top Position',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Select an Anchor',
52 styles: 'Style',
53 tabIndex: 'Tab Index',
54 target: 'Target',
55 targetFrame: '<frame>',
56 targetFrameName: 'Target Frame Name',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Popup Window Name',
59 title: 'Link',
60 toAnchor: 'Link to anchor in the text',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Link',
64 type: 'Link Type',
65 unlink: 'Unlink',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/en-gb.js b/sources/plugins/link/lang/en-gb.js
new file mode 100644
index 0000000..f0f3506
--- /dev/null
+++ b/sources/plugins/link/lang/en-gb.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'en-gb', {
6 acccessKey: 'Access Key',
7 advanced: 'Advanced',
8 advisoryContentType: 'Advisory Content Type',
9 advisoryTitle: 'Advisory Title',
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'By Element Id',
19 anchorName: 'By Anchor Name',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet Classes',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Address',
25 emailBody: 'Message Body',
26 emailSubject: 'Message Subject',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Language Code',
30 langDir: 'Language Direction',
31 langDirLTR: 'Left to Right (LTR)',
32 langDirRTL: 'Right to Left (RTL)',
33 menu: 'Edit Link',
34 name: 'Name',
35 noAnchors: '(No anchors available in the document)',
36 noEmail: 'Please type the e-mail address',
37 noUrl: 'Please type the link URL',
38 other: '<other>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'Popup Window Features',
41 popupFullScreen: 'Full Screen (IE)',
42 popupLeft: 'Left Position',
43 popupLocationBar: 'Location Bar',
44 popupMenuBar: 'Menu Bar',
45 popupResizable: 'Resizable',
46 popupScrollBars: 'Scroll Bars',
47 popupStatusBar: 'Status Bar',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Top Position',
50 rel: 'Relationship',
51 selectAnchor: 'Select an Anchor',
52 styles: 'Style',
53 tabIndex: 'Tab Index',
54 target: 'Target',
55 targetFrame: '<frame>',
56 targetFrameName: 'Target Frame Name',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Popup Window Name',
59 title: 'Link',
60 toAnchor: 'Link to anchor in the text',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Link',
64 type: 'Link Type',
65 unlink: 'Unlink',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/en.js b/sources/plugins/link/lang/en.js
new file mode 100644
index 0000000..8f613de
--- /dev/null
+++ b/sources/plugins/link/lang/en.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'en', {
6 acccessKey: 'Access Key',
7 advanced: 'Advanced',
8 advisoryContentType: 'Advisory Content Type',
9 advisoryTitle: 'Advisory Title',
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'By Element Id',
19 anchorName: 'By Anchor Name',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet Classes',
22 download: 'Force Download',
23 displayText: 'Display Text',
24 emailAddress: 'E-Mail Address',
25 emailBody: 'Message Body',
26 emailSubject: 'Message Subject',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Language Code',
30 langDir: 'Language Direction',
31 langDirLTR: 'Left to Right (LTR)',
32 langDirRTL: 'Right to Left (RTL)',
33 menu: 'Edit Link',
34 name: 'Name',
35 noAnchors: '(No anchors available in the document)',
36 noEmail: 'Please type the e-mail address',
37 noUrl: 'Please type the link URL',
38 other: '<other>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'Popup Window Features',
41 popupFullScreen: 'Full Screen (IE)',
42 popupLeft: 'Left Position',
43 popupLocationBar: 'Location Bar',
44 popupMenuBar: 'Menu Bar',
45 popupResizable: 'Resizable',
46 popupScrollBars: 'Scroll Bars',
47 popupStatusBar: 'Status Bar',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Top Position',
50 rel: 'Relationship',
51 selectAnchor: 'Select an Anchor',
52 styles: 'Style',
53 tabIndex: 'Tab Index',
54 target: 'Target',
55 targetFrame: '<frame>',
56 targetFrameName: 'Target Frame Name',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Popup Window Name',
59 title: 'Link',
60 toAnchor: 'Link to anchor in the text',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Link',
64 type: 'Link Type',
65 unlink: 'Unlink',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/eo.js b/sources/plugins/link/lang/eo.js
new file mode 100644
index 0000000..7991231
--- /dev/null
+++ b/sources/plugins/link/lang/eo.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'eo', {
6 acccessKey: 'Fulmoklavo',
7 advanced: 'Speciala',
8 advisoryContentType: 'Enhavotipo',
9 advisoryTitle: 'Priskriba Titolo',
10 anchor: {
11 toolbar: 'Ankro',
12 menu: 'Enmeti/Ŝanĝi Ankron',
13 title: 'Ankraj Atributoj',
14 name: 'Ankra Nomo',
15 errorName: 'Bv entajpi la ankran nomon',
16 remove: 'Forigi Ankron'
17 },
18 anchorId: 'Per Elementidentigilo',
19 anchorName: 'Per Ankronomo',
20 charset: 'Signaro de la Ligita Rimedo',
21 cssClasses: 'Klasoj de Stilfolioj',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Retpoŝto',
25 emailBody: 'Mesaĝa korpo',
26 emailSubject: 'Mesaĝa Temo',
27 id: 'Id',
28 info: 'Informoj pri la Ligilo',
29 langCode: 'Lingva Kodo',
30 langDir: 'Skribdirekto',
31 langDirLTR: 'De maldekstro dekstren (LTR)',
32 langDirRTL: 'De dekstro maldekstren (RTL)',
33 menu: 'Ŝanĝi Ligilon',
34 name: 'Nomo',
35 noAnchors: '<Ne disponeblas ankroj en la dokumento>',
36 noEmail: 'Bonvolu entajpi la retpoŝtadreson',
37 noUrl: 'Bonvolu entajpi la URL-on',
38 other: '<alia>',
39 popupDependent: 'Dependa (Netscape)',
40 popupFeatures: 'Atributoj de la Ŝprucfenestro',
41 popupFullScreen: 'Tutekrane (IE)',
42 popupLeft: 'Maldekstra Pozicio',
43 popupLocationBar: 'Adresobreto',
44 popupMenuBar: 'Menubreto',
45 popupResizable: 'Dimensiŝanĝebla',
46 popupScrollBars: 'Rulumskaloj',
47 popupStatusBar: 'Statobreto',
48 popupToolbar: 'Ilobreto',
49 popupTop: 'Supra Pozicio',
50 rel: 'Rilato',
51 selectAnchor: 'Elekti Ankron',
52 styles: 'Stilo',
53 tabIndex: 'Taba Indekso',
54 target: 'Celo',
55 targetFrame: '<kadro>',
56 targetFrameName: 'Nomo de CelKadro',
57 targetPopup: '<ŝprucfenestro>',
58 targetPopupName: 'Nomo de Ŝprucfenestro',
59 title: 'Ligilo',
60 toAnchor: 'Ankri en tiu ĉi paĝo',
61 toEmail: 'Retpoŝto',
62 toUrl: 'URL',
63 toolbar: 'Enmeti/Ŝanĝi Ligilon',
64 type: 'Tipo de Ligilo',
65 unlink: 'Forigi Ligilon',
66 upload: 'Alŝuti'
67} );
diff --git a/sources/plugins/link/lang/es.js b/sources/plugins/link/lang/es.js
new file mode 100644
index 0000000..700ad86
--- /dev/null
+++ b/sources/plugins/link/lang/es.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'es', {
6 acccessKey: 'Tecla de Acceso',
7 advanced: 'Avanzado',
8 advisoryContentType: 'Tipo de Contenido',
9 advisoryTitle: 'Título',
10 anchor: {
11 toolbar: 'Referencia',
12 menu: 'Propiedades de Referencia',
13 title: 'Propiedades de Referencia',
14 name: 'Nombre de la Referencia',
15 errorName: 'Por favor, complete el nombre de la Referencia',
16 remove: 'Quitar Referencia'
17 },
18 anchorId: 'Por ID de elemento',
19 anchorName: 'Por Nombre de Referencia',
20 charset: 'Fuente de caracteres vinculado',
21 cssClasses: 'Clases de hojas de estilo',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Dirección de E-Mail',
25 emailBody: 'Cuerpo del Mensaje',
26 emailSubject: 'Título del Mensaje',
27 id: 'Id',
28 info: 'Información de Vínculo',
29 langCode: 'Código idioma',
30 langDir: 'Orientación',
31 langDirLTR: 'Izquierda a Derecha (LTR)',
32 langDirRTL: 'Derecha a Izquierda (RTL)',
33 menu: 'Editar Vínculo',
34 name: 'Nombre',
35 noAnchors: '(No hay referencias disponibles en el documento)',
36 noEmail: 'Por favor escriba la dirección de e-mail',
37 noUrl: 'Por favor escriba el vínculo URL',
38 other: '<otro>',
39 popupDependent: 'Dependiente (Netscape)',
40 popupFeatures: 'Características de Ventana Emergente',
41 popupFullScreen: 'Pantalla Completa (IE)',
42 popupLeft: 'Posición Izquierda',
43 popupLocationBar: 'Barra de ubicación',
44 popupMenuBar: 'Barra de Menú',
45 popupResizable: 'Redimensionable',
46 popupScrollBars: 'Barras de desplazamiento',
47 popupStatusBar: 'Barra de Estado',
48 popupToolbar: 'Barra de Herramientas',
49 popupTop: 'Posición Derecha',
50 rel: 'Relación',
51 selectAnchor: 'Seleccionar una referencia',
52 styles: 'Estilo',
53 tabIndex: 'Indice de tabulación',
54 target: 'Destino',
55 targetFrame: '<marco>',
56 targetFrameName: 'Nombre del Marco Destino',
57 targetPopup: '<ventana emergente>',
58 targetPopupName: 'Nombre de Ventana Emergente',
59 title: 'Vínculo',
60 toAnchor: 'Referencia en esta página',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Insertar/Editar Vínculo',
64 type: 'Tipo de vínculo',
65 unlink: 'Eliminar Vínculo',
66 upload: 'Cargar'
67} );
diff --git a/sources/plugins/link/lang/et.js b/sources/plugins/link/lang/et.js
new file mode 100644
index 0000000..7e31aa6
--- /dev/null
+++ b/sources/plugins/link/lang/et.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'et', {
6 acccessKey: 'Juurdepääsu võti',
7 advanced: 'Täpsemalt',
8 advisoryContentType: 'Juhendava sisu tüüp',
9 advisoryTitle: 'Juhendav tiitel',
10 anchor: {
11 toolbar: 'Ankru sisestamine/muutmine',
12 menu: 'Ankru omadused',
13 title: 'Ankru omadused',
14 name: 'Ankru nimi',
15 errorName: 'Palun sisesta ankru nimi',
16 remove: 'Eemalda ankur'
17 },
18 anchorId: 'Elemendi id järgi',
19 anchorName: 'Ankru nime järgi',
20 charset: 'Lingitud ressursi märgistik',
21 cssClasses: 'Stiilistiku klassid',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-posti aadress',
25 emailBody: 'Sõnumi tekst',
26 emailSubject: 'Sõnumi teema',
27 id: 'ID',
28 info: 'Lingi info',
29 langCode: 'Keele suund',
30 langDir: 'Keele suund',
31 langDirLTR: 'Vasakult paremale (LTR)',
32 langDirRTL: 'Paremalt vasakule (RTL)',
33 menu: 'Muuda linki',
34 name: 'Nimi',
35 noAnchors: '(Selles dokumendis pole ankruid)',
36 noEmail: 'Palun kirjuta e-posti aadress',
37 noUrl: 'Palun kirjuta lingi URL',
38 other: '<muu>',
39 popupDependent: 'Sõltuv (Netscape)',
40 popupFeatures: 'Hüpikakna omadused',
41 popupFullScreen: 'Täisekraan (IE)',
42 popupLeft: 'Vasak asukoht',
43 popupLocationBar: 'Aadressiriba',
44 popupMenuBar: 'Menüüriba',
45 popupResizable: 'Suurust saab muuta',
46 popupScrollBars: 'Kerimisribad',
47 popupStatusBar: 'Olekuriba',
48 popupToolbar: 'Tööriistariba',
49 popupTop: 'Ülemine asukoht',
50 rel: 'Suhe',
51 selectAnchor: 'Vali ankur',
52 styles: 'Laad',
53 tabIndex: 'Tab indeks',
54 target: 'Sihtkoht',
55 targetFrame: '<raam>',
56 targetFrameName: 'Sihtmärk raami nimi',
57 targetPopup: '<hüpikaken>',
58 targetPopupName: 'Hüpikakna nimi',
59 title: 'Link',
60 toAnchor: 'Ankur sellel lehel',
61 toEmail: 'E-post',
62 toUrl: 'URL',
63 toolbar: 'Lingi lisamine/muutmine',
64 type: 'Lingi liik',
65 unlink: 'Lingi eemaldamine',
66 upload: 'Lae üles'
67} );
diff --git a/sources/plugins/link/lang/eu.js b/sources/plugins/link/lang/eu.js
new file mode 100644
index 0000000..7a2727e
--- /dev/null
+++ b/sources/plugins/link/lang/eu.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'eu', {
6 acccessKey: 'Sarbide-tekla',
7 advanced: 'Aurreratua',
8 advisoryContentType: 'Aholkatutako eduki-mota',
9 advisoryTitle: 'Aholkatutako izenburua',
10 anchor: {
11 toolbar: 'Aingura',
12 menu: 'Editatu aingura',
13 title: 'Ainguraren propietateak',
14 name: 'Ainguraren izena',
15 errorName: 'Idatzi ainguraren izena',
16 remove: 'Kendu aingura'
17 },
18 anchorId: 'Elementuaren Id-aren arabera',
19 anchorName: 'Aingura-izenaren arabera',
20 charset: 'Estekatutako baliabide karaktere-jokoa',
21 cssClasses: 'Estilo-orriko klaseak',
22 download: 'Force Download', // MISSING
23 displayText: 'Bistaratu testua',
24 emailAddress: 'E-posta helbidea',
25 emailBody: 'Mezuaren gorputza',
26 emailSubject: 'Mezuaren gaia',
27 id: 'Id',
28 info: 'Estekaren informazioa',
29 langCode: 'Hizkuntzaren kodea',
30 langDir: 'Hizkuntzaren norabidea',
31 langDirLTR: 'Ezkerretik eskuinera (LTR)',
32 langDirRTL: 'Eskuinetik ezkerrera (RTL)',
33 menu: 'Editatu esteka',
34 name: 'Izena',
35 noAnchors: '(Ez dago aingurarik erabilgarri dokumentuan)',
36 noEmail: 'Mesedez idatzi e-posta helbidea',
37 noUrl: 'Mesedez idatzi estekaren URLa',
38 other: '<bestelakoa>',
39 popupDependent: 'Menpekoa (Netscape)',
40 popupFeatures: 'Laster-leihoaren ezaugarriak',
41 popupFullScreen: 'Pantaila osoa (IE)',
42 popupLeft: 'Ezkerreko posizioa',
43 popupLocationBar: 'Kokaleku-barra',
44 popupMenuBar: 'Menu-barra',
45 popupResizable: 'Tamaina aldakorra',
46 popupScrollBars: 'Korritze-barrak',
47 popupStatusBar: 'Egoera-barra',
48 popupToolbar: 'Tresna-barra',
49 popupTop: 'Goiko posizioa',
50 rel: 'Erlazioa',
51 selectAnchor: 'Hautatu aingura',
52 styles: 'Estiloa',
53 tabIndex: 'Tabulazio indizea',
54 target: 'Helburua',
55 targetFrame: '<frame>',
56 targetFrameName: 'Helburuko markoaren izena',
57 targetPopup: '<laster-leihoa>',
58 targetPopupName: 'Laster-leihoaren izena',
59 title: 'Esteka',
60 toAnchor: 'Estekatu testuko aingurara',
61 toEmail: 'E-posta',
62 toUrl: 'URLa',
63 toolbar: 'Esteka',
64 type: 'Esteka-mota',
65 unlink: 'Kendu esteka',
66 upload: 'Kargatu'
67} );
diff --git a/sources/plugins/link/lang/fa.js b/sources/plugins/link/lang/fa.js
new file mode 100644
index 0000000..525d899
--- /dev/null
+++ b/sources/plugins/link/lang/fa.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'fa', {
6 acccessKey: 'کلید دستیابی',
7 advanced: 'پیشرفته',
8 advisoryContentType: 'نوع محتوای کمکی',
9 advisoryTitle: 'عنوان کمکی',
10 anchor: {
11 toolbar: 'گنجاندن/ویرایش لنگر',
12 menu: 'ویژگی​های لنگر',
13 title: 'ویژگی​های لنگر',
14 name: 'نام لنگر',
15 errorName: 'لطفا نام لنگر را بنویسید',
16 remove: 'حذف لنگر'
17 },
18 anchorId: 'با شناسهٴ المان',
19 anchorName: 'با نام لنگر',
20 charset: 'نویسه​گان منبع پیوند شده',
21 cssClasses: 'کلاس​های شیوه​نامه(Stylesheet)',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'نشانی پست الکترونیکی',
25 emailBody: 'متن پیام',
26 emailSubject: 'موضوع پیام',
27 id: 'شناسه',
28 info: 'اطلاعات پیوند',
29 langCode: 'جهت​نمای زبان',
30 langDir: 'جهت​نمای زبان',
31 langDirLTR: 'چپ به راست (LTR)',
32 langDirRTL: 'راست به چپ (RTL)',
33 menu: 'ویرایش پیوند',
34 name: 'نام',
35 noAnchors: '(در این سند لنگری دردسترس نیست)',
36 noEmail: 'لطفا نشانی پست الکترونیکی را بنویسید',
37 noUrl: 'لطفا URL پیوند را بنویسید',
38 other: '<سایر>',
39 popupDependent: 'وابسته (Netscape)',
40 popupFeatures: 'ویژگی​های پنجرهٴ پاپاپ',
41 popupFullScreen: 'تمام صفحه (IE)',
42 popupLeft: 'موقعیت چپ',
43 popupLocationBar: 'نوار موقعیت',
44 popupMenuBar: 'نوار منو',
45 popupResizable: 'قابل تغییر اندازه',
46 popupScrollBars: 'میله​های پیمایش',
47 popupStatusBar: 'نوار وضعیت',
48 popupToolbar: 'نوار ابزار',
49 popupTop: 'موقعیت بالا',
50 rel: 'وابستگی',
51 selectAnchor: 'یک لنگر برگزینید',
52 styles: 'شیوه (style)',
53 tabIndex: 'نمایهٴ دسترسی با برگه',
54 target: 'مقصد',
55 targetFrame: '<فریم>',
56 targetFrameName: 'نام فریم مقصد',
57 targetPopup: '<پنجرهٴ پاپاپ>',
58 targetPopupName: 'نام پنجرهٴ پاپاپ',
59 title: 'پیوند',
60 toAnchor: 'لنگر در همین صفحه',
61 toEmail: 'پست الکترونیکی',
62 toUrl: 'URL',
63 toolbar: 'گنجاندن/ویرایش پیوند',
64 type: 'نوع پیوند',
65 unlink: 'برداشتن پیوند',
66 upload: 'انتقال به سرور'
67} );
diff --git a/sources/plugins/link/lang/fi.js b/sources/plugins/link/lang/fi.js
new file mode 100644
index 0000000..9ab5224
--- /dev/null
+++ b/sources/plugins/link/lang/fi.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'fi', {
6 acccessKey: 'Pikanäppäin',
7 advanced: 'Lisäominaisuudet',
8 advisoryContentType: 'Avustava sisällön tyyppi',
9 advisoryTitle: 'Avustava otsikko',
10 anchor: {
11 toolbar: 'Lisää ankkuri/muokkaa ankkuria',
12 menu: 'Ankkurin ominaisuudet',
13 title: 'Ankkurin ominaisuudet',
14 name: 'Nimi',
15 errorName: 'Ankkurille on kirjoitettava nimi',
16 remove: 'Poista ankkuri'
17 },
18 anchorId: 'Ankkurin ID:n mukaan',
19 anchorName: 'Ankkurin nimen mukaan',
20 charset: 'Linkitetty kirjaimisto',
21 cssClasses: 'Tyyliluokat',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Sähköpostiosoite',
25 emailBody: 'Viesti',
26 emailSubject: 'Aihe',
27 id: 'Tunniste',
28 info: 'Linkin tiedot',
29 langCode: 'Kielen suunta',
30 langDir: 'Kielen suunta',
31 langDirLTR: 'Vasemmalta oikealle (LTR)',
32 langDirRTL: 'Oikealta vasemmalle (RTL)',
33 menu: 'Muokkaa linkkiä',
34 name: 'Nimi',
35 noAnchors: '(Ei ankkureita tässä dokumentissa)',
36 noEmail: 'Kirjoita sähköpostiosoite',
37 noUrl: 'Linkille on kirjoitettava URL',
38 other: '<muu>',
39 popupDependent: 'Riippuva (Netscape)',
40 popupFeatures: 'Popup ikkunan ominaisuudet',
41 popupFullScreen: 'Täysi ikkuna (IE)',
42 popupLeft: 'Vasemmalta (px)',
43 popupLocationBar: 'Osoiterivi',
44 popupMenuBar: 'Valikkorivi',
45 popupResizable: 'Venytettävä',
46 popupScrollBars: 'Vierityspalkit',
47 popupStatusBar: 'Tilarivi',
48 popupToolbar: 'Vakiopainikkeet',
49 popupTop: 'Ylhäältä (px)',
50 rel: 'Suhde',
51 selectAnchor: 'Valitse ankkuri',
52 styles: 'Tyyli',
53 tabIndex: 'Tabulaattori indeksi',
54 target: 'Kohde',
55 targetFrame: '<kehys>',
56 targetFrameName: 'Kohdekehyksen nimi',
57 targetPopup: '<popup ikkuna>',
58 targetPopupName: 'Popup ikkunan nimi',
59 title: 'Linkki',
60 toAnchor: 'Ankkuri tässä sivussa',
61 toEmail: 'Sähköposti',
62 toUrl: 'Osoite',
63 toolbar: 'Lisää linkki/muokkaa linkkiä',
64 type: 'Linkkityyppi',
65 unlink: 'Poista linkki',
66 upload: 'Lisää tiedosto'
67} );
diff --git a/sources/plugins/link/lang/fo.js b/sources/plugins/link/lang/fo.js
new file mode 100644
index 0000000..90ab1ed
--- /dev/null
+++ b/sources/plugins/link/lang/fo.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'fo', {
6 acccessKey: 'Snarvegisknöttur',
7 advanced: 'Fjølbroytt',
8 advisoryContentType: 'Vegleiðandi innihaldsslag',
9 advisoryTitle: 'Vegleiðandi heiti',
10 anchor: {
11 toolbar: 'Ger/broyt marknastein',
12 menu: 'Eginleikar fyri marknastein',
13 title: 'Eginleikar fyri marknastein',
14 name: 'Heiti marknasteinsins',
15 errorName: 'Vinarliga rita marknasteinsins heiti',
16 remove: 'Strika marknastein'
17 },
18 anchorId: 'Eftir element Id',
19 anchorName: 'Eftir navni á marknasteini',
20 charset: 'Atknýtt teknsett',
21 cssClasses: 'Typografi klassar',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Teldupost-adressa',
25 emailBody: 'Breyðtekstur',
26 emailSubject: 'Evni',
27 id: 'Id',
28 info: 'Tilknýtis upplýsingar',
29 langCode: 'Tekstkós',
30 langDir: 'Tekstkós',
31 langDirLTR: 'Frá vinstru til høgru (LTR)',
32 langDirRTL: 'Frá høgru til vinstru (RTL)',
33 menu: 'Broyt tilknýti',
34 name: 'Navn',
35 noAnchors: '(Eingir marknasteinar eru í hesum dokumentið)',
36 noEmail: 'Vinarliga skriva teldupost-adressu',
37 noUrl: 'Vinarliga skriva tilknýti (URL)',
38 other: '<annað>',
39 popupDependent: 'Bundið (Netscape)',
40 popupFeatures: 'Popup vindeygans víðkaðu eginleikar',
41 popupFullScreen: 'Fullur skermur (IE)',
42 popupLeft: 'Frástøða frá vinstru',
43 popupLocationBar: 'Adressulinja',
44 popupMenuBar: 'Skrábjálki',
45 popupResizable: 'Stødd kann broytast',
46 popupScrollBars: 'Rullibjálki',
47 popupStatusBar: 'Støðufrágreiðingarbjálki',
48 popupToolbar: 'Amboðsbjálki',
49 popupTop: 'Frástøða frá íerva',
50 rel: 'Relatión',
51 selectAnchor: 'Vel ein marknastein',
52 styles: 'Typografi',
53 tabIndex: 'Tabulator indeks',
54 target: 'Target',
55 targetFrame: '<ramma>',
56 targetFrameName: 'Vís navn vindeygans',
57 targetPopup: '<popup vindeyga>',
58 targetPopupName: 'Popup vindeygans navn',
59 title: 'Tilknýti',
60 toAnchor: 'Tilknýti til marknastein í tekstinum',
61 toEmail: 'Teldupostur',
62 toUrl: 'URL',
63 toolbar: 'Ger/broyt tilknýti',
64 type: 'Tilknýtisslag',
65 unlink: 'Strika tilknýti',
66 upload: 'Send til ambætaran'
67} );
diff --git a/sources/plugins/link/lang/fr-ca.js b/sources/plugins/link/lang/fr-ca.js
new file mode 100644
index 0000000..ddf2dde
--- /dev/null
+++ b/sources/plugins/link/lang/fr-ca.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'fr-ca', {
6 acccessKey: 'Touche d\'accessibilité',
7 advanced: 'Avancé',
8 advisoryContentType: 'Type de contenu',
9 advisoryTitle: 'Description',
10 anchor: {
11 toolbar: 'Ancre',
12 menu: 'Modifier l\'ancre',
13 title: 'Propriétés de l\'ancre',
14 name: 'Nom de l\'ancre',
15 errorName: 'Veuillez saisir le nom de l\'ancre',
16 remove: 'Supprimer l\'ancre'
17 },
18 anchorId: 'Par ID',
19 anchorName: 'Par nom',
20 charset: 'Encodage de la cible',
21 cssClasses: 'Classes CSS',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Courriel',
25 emailBody: 'Corps du message',
26 emailSubject: 'Objet du message',
27 id: 'ID',
28 info: 'Informations sur le lien',
29 langCode: 'Code de langue',
30 langDir: 'Sens d\'écriture',
31 langDirLTR: 'De gauche à droite (LTR)',
32 langDirRTL: 'De droite à gauche (RTL)',
33 menu: 'Modifier le lien',
34 name: 'Nom',
35 noAnchors: '(Pas d\'ancre disponible dans le document)',
36 noEmail: 'Veuillez saisir le courriel',
37 noUrl: 'Veuillez saisir l\'URL',
38 other: '<autre>',
39 popupDependent: 'Dépendante (Netscape)',
40 popupFeatures: 'Caractéristiques de la fenêtre popup',
41 popupFullScreen: 'Plein écran (IE)',
42 popupLeft: 'Position de la gauche',
43 popupLocationBar: 'Barre d\'adresse',
44 popupMenuBar: 'Barre de menu',
45 popupResizable: 'Redimensionnable',
46 popupScrollBars: 'Barres de défilement',
47 popupStatusBar: 'Barre d\'état',
48 popupToolbar: 'Barre d\'outils',
49 popupTop: 'Position à partir du haut',
50 rel: 'Relation',
51 selectAnchor: 'Sélectionner une ancre',
52 styles: 'Style',
53 tabIndex: 'Ordre de tabulation',
54 target: 'Destination',
55 targetFrame: '<Cadre>',
56 targetFrameName: 'Nom du cadre de destination',
57 targetPopup: '<fenêtre popup>',
58 targetPopupName: 'Nom de la fenêtre popup',
59 title: 'Lien',
60 toAnchor: 'Ancre dans cette page',
61 toEmail: 'Courriel',
62 toUrl: 'URL',
63 toolbar: 'Lien',
64 type: 'Type de lien',
65 unlink: 'Supprimer le lien',
66 upload: 'Téléverser'
67} );
diff --git a/sources/plugins/link/lang/fr.js b/sources/plugins/link/lang/fr.js
new file mode 100644
index 0000000..a4561cb
--- /dev/null
+++ b/sources/plugins/link/lang/fr.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'fr', {
6 acccessKey: 'Touche d\'accessibilité',
7 advanced: 'Avancé',
8 advisoryContentType: 'Type de contenu (indicatif)',
9 advisoryTitle: 'Infobulle',
10 anchor: {
11 toolbar: 'Ancre',
12 menu: 'Modifier l\'ancre',
13 title: 'Propriétés de l\'ancre',
14 name: 'Nom de l\'ancre',
15 errorName: 'Veuillez entrer le nom de l\'ancre.',
16 remove: 'Supprimer l\'ancre'
17 },
18 anchorId: 'Par ID d\'élément',
19 anchorName: 'Par nom d\'ancre',
20 charset: 'Encodage de la ressource liée',
21 cssClasses: 'Classes de style',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Adresse électronique',
25 emailBody: 'Corps du message',
26 emailSubject: 'Sujet du message',
27 id: 'ID',
28 info: 'Informations sur le lien',
29 langCode: 'Code de langue',
30 langDir: 'Sens d\'écriture',
31 langDirLTR: 'Gauche à droite',
32 langDirRTL: 'Droite à gauche (RTL)',
33 menu: 'Modifier le lien',
34 name: 'Nom',
35 noAnchors: '(Aucune ancre disponible dans ce document)',
36 noEmail: 'Veuillez entrer l\'adresse électronique',
37 noUrl: 'Veuillez entrer l\'URL du lien',
38 other: '<autre>',
39 popupDependent: 'Dépendante (Netscape)',
40 popupFeatures: 'Caractéristiques de la fenêtre surgissante',
41 popupFullScreen: 'Plein écran (IE)',
42 popupLeft: 'À gauche',
43 popupLocationBar: 'Barre d\'adresse',
44 popupMenuBar: 'Barre de menu',
45 popupResizable: 'Redimensionnable',
46 popupScrollBars: 'Barres de défilement',
47 popupStatusBar: 'Barre d\'état',
48 popupToolbar: 'Barre d\'outils',
49 popupTop: 'En haut',
50 rel: 'Relation',
51 selectAnchor: 'Sélectionner une ancre',
52 styles: 'Style',
53 tabIndex: 'Indice de tabulation',
54 target: 'Cible',
55 targetFrame: '<cadre>',
56 targetFrameName: 'Nom du cadre affecté',
57 targetPopup: '<fenêtre surgissante>',
58 targetPopupName: 'Nom de la fenêtre surgissante',
59 title: 'Lien',
60 toAnchor: 'Ancre',
61 toEmail: 'Courriel',
62 toUrl: 'URL',
63 toolbar: 'Lien',
64 type: 'Type de lien',
65 unlink: 'Supprimer le lien',
66 upload: 'Téléverser'
67} );
diff --git a/sources/plugins/link/lang/gl.js b/sources/plugins/link/lang/gl.js
new file mode 100644
index 0000000..45ced42
--- /dev/null
+++ b/sources/plugins/link/lang/gl.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'gl', {
6 acccessKey: 'Chave de acceso',
7 advanced: 'Avanzado',
8 advisoryContentType: 'Tipo de contido informativo',
9 advisoryTitle: 'Título',
10 anchor: {
11 toolbar: 'Ancoraxe',
12 menu: 'Editar a ancoraxe',
13 title: 'Propiedades da ancoraxe',
14 name: 'Nome da ancoraxe',
15 errorName: 'Escriba o nome da ancoraxe',
16 remove: 'Retirar a ancoraxe'
17 },
18 anchorId: 'Polo ID do elemento',
19 anchorName: 'Polo nome da ancoraxe',
20 charset: 'Codificación do recurso ligado',
21 cssClasses: 'Clases da folla de estilos',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Enderezo de correo',
25 emailBody: 'Corpo da mensaxe',
26 emailSubject: 'Asunto da mensaxe',
27 id: 'ID',
28 info: 'Información da ligazón',
29 langCode: 'Código do idioma',
30 langDir: 'Dirección de escritura do idioma',
31 langDirLTR: 'Esquerda a dereita (LTR)',
32 langDirRTL: 'Dereita a esquerda (RTL)',
33 menu: 'Editar a ligazón',
34 name: 'Nome',
35 noAnchors: '(Non hai ancoraxes dispoñíbeis no documento)',
36 noEmail: 'Escriba o enderezo de correo',
37 noUrl: 'Escriba a ligazón URL',
38 other: '<outro>',
39 popupDependent: 'Dependente (Netscape)',
40 popupFeatures: 'Características da xanela emerxente',
41 popupFullScreen: 'Pantalla completa (IE)',
42 popupLeft: 'Posición esquerda',
43 popupLocationBar: 'Barra de localización',
44 popupMenuBar: 'Barra do menú',
45 popupResizable: 'Redimensionábel',
46 popupScrollBars: 'Barras de desprazamento',
47 popupStatusBar: 'Barra de estado',
48 popupToolbar: 'Barra de ferramentas',
49 popupTop: 'Posición superior',
50 rel: 'Relación',
51 selectAnchor: 'Seleccionar unha ancoraxe',
52 styles: 'Estilo',
53 tabIndex: 'Índice de tabulación',
54 target: 'Destino',
55 targetFrame: '<marco>',
56 targetFrameName: 'Nome do marco de destino',
57 targetPopup: '<xanela emerxente>',
58 targetPopupName: 'Nome da xanela emerxente',
59 title: 'Ligazón',
60 toAnchor: 'Ligar coa ancoraxe no testo',
61 toEmail: 'Correo',
62 toUrl: 'URL',
63 toolbar: 'Ligazón',
64 type: 'Tipo de ligazón',
65 unlink: 'Eliminar a ligazón',
66 upload: 'Enviar'
67} );
diff --git a/sources/plugins/link/lang/gu.js b/sources/plugins/link/lang/gu.js
new file mode 100644
index 0000000..2bbf577
--- /dev/null
+++ b/sources/plugins/link/lang/gu.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'gu', {
6 acccessKey: 'ઍક્સેસ કી',
7 advanced: 'અડ્વાન્સડ',
8 advisoryContentType: 'મુખ્ય કન્ટેન્ટ પ્રકાર',
9 advisoryTitle: 'મુખ્ય મથાળું',
10 anchor: {
11 toolbar: 'ઍંકર ઇન્સર્ટ/દાખલ કરવી',
12 menu: 'ઍંકરના ગુણ',
13 title: 'ઍંકરના ગુણ',
14 name: 'ઍંકરનું નામ',
15 errorName: 'ઍંકરનું નામ ટાઈપ કરો',
16 remove: 'સ્થિર નકરવું'
17 },
18 anchorId: 'ઍંકર એલિમન્ટ Id થી પસંદ કરો',
19 anchorName: 'ઍંકર નામથી પસંદ કરો',
20 charset: 'લિંક રિસૉર્સ કૅરિક્ટર સેટ',
21 cssClasses: 'સ્ટાઇલ-શીટ ક્લાસ',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ઈ-મેલ સરનામું',
25 emailBody: 'સંદેશ',
26 emailSubject: 'ઈ-મેલ વિષય',
27 id: 'Id',
28 info: 'લિંક ઇન્ફૉ ટૅબ',
29 langCode: 'ભાષા લેખવાની પદ્ધતિ',
30 langDir: 'ભાષા લેખવાની પદ્ધતિ',
31 langDirLTR: 'ડાબે થી જમણે (LTR)',
32 langDirRTL: 'જમણે થી ડાબે (RTL)',
33 menu: ' લિંક એડિટ/માં ફેરફાર કરવો',
34 name: 'નામ',
35 noAnchors: '(ડૉક્યુમન્ટમાં ઍંકરની સંખ્યા)',
36 noEmail: 'ઈ-મેલ સરનામું ટાઇપ કરો',
37 noUrl: 'લિંક URL ટાઇપ કરો',
38 other: '<other> <અન્ય>',
39 popupDependent: 'ડિપેન્ડન્ટ (Netscape)',
40 popupFeatures: 'પૉપ-અપ વિન્ડો ફીચરસૅ',
41 popupFullScreen: 'ફુલ સ્ક્રીન (IE)',
42 popupLeft: 'ડાબી બાજુ',
43 popupLocationBar: 'લોકેશન બાર',
44 popupMenuBar: 'મેન્યૂ બાર',
45 popupResizable: 'રીસાઈઝએબલ',
46 popupScrollBars: 'સ્ક્રોલ બાર',
47 popupStatusBar: 'સ્ટૅટસ બાર',
48 popupToolbar: 'ટૂલ બાર',
49 popupTop: 'જમણી બાજુ',
50 rel: 'સંબંધની સ્થિતિ',
51 selectAnchor: 'ઍંકર પસંદ કરો',
52 styles: 'સ્ટાઇલ',
53 tabIndex: 'ટૅબ ઇન્ડેક્સ',
54 target: 'ટાર્ગેટ/લક્ષ્ય',
55 targetFrame: '<ફ્રેમ>',
56 targetFrameName: 'ટાર્ગેટ ફ્રેમ નું નામ',
57 targetPopup: '<પૉપ-અપ વિન્ડો>',
58 targetPopupName: 'પૉપ-અપ વિન્ડો નું નામ',
59 title: 'લિંક',
60 toAnchor: 'આ પેજનો ઍંકર',
61 toEmail: 'ઈ-મેલ',
62 toUrl: 'URL',
63 toolbar: 'લિંક ઇન્સર્ટ/દાખલ કરવી',
64 type: 'લિંક પ્રકાર',
65 unlink: 'લિંક કાઢવી',
66 upload: 'અપલોડ'
67} );
diff --git a/sources/plugins/link/lang/he.js b/sources/plugins/link/lang/he.js
new file mode 100644
index 0000000..a00f60a
--- /dev/null
+++ b/sources/plugins/link/lang/he.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'he', {
6 acccessKey: 'מקש גישה',
7 advanced: 'אפשרויות מתקדמות',
8 advisoryContentType: 'Content Type מוצע',
9 advisoryTitle: 'כותרת מוצעת',
10 anchor: {
11 toolbar: 'הוספת/עריכת נקודת עיגון',
12 menu: 'מאפייני נקודת עיגון',
13 title: 'מאפייני נקודת עיגון',
14 name: 'שם לנקודת עיגון',
15 errorName: 'יש להקליד שם לנקודת עיגון',
16 remove: 'מחיקת נקודת עיגון'
17 },
18 anchorId: 'עפ"י זיהוי (ID) האלמנט',
19 anchorName: 'עפ"י שם העוגן',
20 charset: 'קידוד המשאב המקושר',
21 cssClasses: 'גיליונות עיצוב קבוצות',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'כתובת הדוא"ל',
25 emailBody: 'גוף ההודעה',
26 emailSubject: 'נושא ההודעה',
27 id: 'זיהוי (ID)',
28 info: 'מידע על הקישור',
29 langCode: 'קוד שפה',
30 langDir: 'כיוון שפה',
31 langDirLTR: 'שמאל לימין (LTR)',
32 langDirRTL: 'ימין לשמאל (RTL)',
33 menu: 'מאפייני קישור',
34 name: 'שם',
35 noAnchors: '(אין עוגנים זמינים בדף)',
36 noEmail: 'יש להקליד את כתובת הדוא"ל',
37 noUrl: 'יש להקליד את כתובת הקישור (URL)',
38 other: '<אחר>',
39 popupDependent: 'תלוי (Netscape)',
40 popupFeatures: 'תכונות החלון הקופץ',
41 popupFullScreen: 'מסך מלא (IE)',
42 popupLeft: 'מיקום צד שמאל',
43 popupLocationBar: 'סרגל כתובת',
44 popupMenuBar: 'סרגל תפריט',
45 popupResizable: 'שינוי גודל',
46 popupScrollBars: 'ניתן לגלילה',
47 popupStatusBar: 'סרגל חיווי',
48 popupToolbar: 'סרגל הכלים',
49 popupTop: 'מיקום צד עליון',
50 rel: 'קשר גומלין',
51 selectAnchor: 'בחירת עוגן',
52 styles: 'סגנון',
53 tabIndex: 'מספר טאב',
54 target: 'מטרה',
55 targetFrame: '<מסגרת>',
56 targetFrameName: 'שם מסגרת היעד',
57 targetPopup: '<חלון קופץ>',
58 targetPopupName: 'שם החלון הקופץ',
59 title: 'קישור',
60 toAnchor: 'עוגן בעמוד זה',
61 toEmail: 'דוא"ל',
62 toUrl: 'כתובת (URL)',
63 toolbar: 'הוספת/עריכת קישור',
64 type: 'סוג קישור',
65 unlink: 'הסרת הקישור',
66 upload: 'העלאה'
67} );
diff --git a/sources/plugins/link/lang/hi.js b/sources/plugins/link/lang/hi.js
new file mode 100644
index 0000000..88b7df9
--- /dev/null
+++ b/sources/plugins/link/lang/hi.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'hi', {
6 acccessKey: 'ऍक्सॅस की',
7 advanced: 'ऍड्वान्स्ड',
8 advisoryContentType: 'परामर्श कन्टॅन्ट प्रकार',
9 advisoryTitle: 'परामर्श शीर्शक',
10 anchor: {
11 toolbar: 'ऐंकर इन्सर्ट/संपादन',
12 menu: 'ऐंकर प्रॉपर्टीज़',
13 title: 'ऐंकर प्रॉपर्टीज़',
14 name: 'ऐंकर का नाम',
15 errorName: 'ऐंकर का नाम टाइप करें',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'ऍलीमॅन्ट Id से',
19 anchorName: 'ऐंकर नाम से',
20 charset: 'लिंक रिसोर्स करॅक्टर सॅट',
21 cssClasses: 'स्टाइल-शीट क्लास',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ई-मेल पता',
25 emailBody: 'संदेश',
26 emailSubject: 'संदेश विषय',
27 id: 'Id',
28 info: 'लिंक ',
29 langCode: 'भाषा लिखने की दिशा',
30 langDir: 'भाषा लिखने की दिशा',
31 langDirLTR: 'बायें से दायें (LTR)',
32 langDirRTL: 'दायें से बायें (RTL)',
33 menu: 'लिंक संपादन',
34 name: 'नाम',
35 noAnchors: '(डॉक्यूमॅन्ट में ऐंकर्स की संख्या)',
36 noEmail: 'ई-मेल पता टाइप करें',
37 noUrl: 'लिंक URL टाइप करें',
38 other: '<अन्य>',
39 popupDependent: 'डिपेन्डॅन्ट (Netscape)',
40 popupFeatures: 'पॉप-अप विन्डो फ़ीचर्स',
41 popupFullScreen: 'फ़ुल स्क्रीन (IE)',
42 popupLeft: 'बायीं तरफ',
43 popupLocationBar: 'लोकेशन बार',
44 popupMenuBar: 'मॅन्यू बार',
45 popupResizable: 'आकार बदलने लायक',
46 popupScrollBars: 'स्क्रॉल बार',
47 popupStatusBar: 'स्टेटस बार',
48 popupToolbar: 'टूल बार',
49 popupTop: 'दायीं तरफ',
50 rel: 'संबंध',
51 selectAnchor: 'ऐंकर चुनें',
52 styles: 'स्टाइल',
53 tabIndex: 'टैब इन्डॅक्स',
54 target: 'टार्गेट',
55 targetFrame: '<फ़्रेम>',
56 targetFrameName: 'टार्गेट फ़्रेम का नाम',
57 targetPopup: '<पॉप-अप विन्डो>',
58 targetPopupName: 'पॉप-अप विन्डो का नाम',
59 title: 'लिंक',
60 toAnchor: 'इस पेज का ऐंकर',
61 toEmail: 'ई-मेल',
62 toUrl: 'URL',
63 toolbar: 'लिंक इन्सर्ट/संपादन',
64 type: 'लिंक प्रकार',
65 unlink: 'लिंक हटायें',
66 upload: 'अपलोड'
67} );
diff --git a/sources/plugins/link/lang/hr.js b/sources/plugins/link/lang/hr.js
new file mode 100644
index 0000000..898b18b
--- /dev/null
+++ b/sources/plugins/link/lang/hr.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'hr', {
6 acccessKey: 'Pristupna tipka',
7 advanced: 'Napredno',
8 advisoryContentType: 'Advisory vrsta sadržaja',
9 advisoryTitle: 'Advisory naslov',
10 anchor: {
11 toolbar: 'Ubaci/promijeni sidro',
12 menu: 'Svojstva sidra',
13 title: 'Svojstva sidra',
14 name: 'Ime sidra',
15 errorName: 'Molimo unesite ime sidra',
16 remove: 'Ukloni sidro'
17 },
18 anchorId: 'Po Id elementa',
19 anchorName: 'Po nazivu sidra',
20 charset: 'Kodna stranica povezanih resursa',
21 cssClasses: 'Stylesheet klase',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail adresa',
25 emailBody: 'Sadržaj poruke',
26 emailSubject: 'Naslov',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Smjer jezika',
30 langDir: 'Smjer jezika',
31 langDirLTR: 'S lijeva na desno (LTR)',
32 langDirRTL: 'S desna na lijevo (RTL)',
33 menu: 'Promijeni link',
34 name: 'Naziv',
35 noAnchors: '(Nema dostupnih sidra)',
36 noEmail: 'Molimo upišite e-mail adresu',
37 noUrl: 'Molimo upišite URL link',
38 other: '<drugi>',
39 popupDependent: 'Ovisno (Netscape)',
40 popupFeatures: 'Mogućnosti popup prozora',
41 popupFullScreen: 'Cijeli ekran (IE)',
42 popupLeft: 'Lijeva pozicija',
43 popupLocationBar: 'Traka za lokaciju',
44 popupMenuBar: 'Izborna traka',
45 popupResizable: 'Promjenjiva veličina',
46 popupScrollBars: 'Scroll traka',
47 popupStatusBar: 'Statusna traka',
48 popupToolbar: 'Traka s alatima',
49 popupTop: 'Gornja pozicija',
50 rel: 'Veza',
51 selectAnchor: 'Odaberi sidro',
52 styles: 'Stil',
53 tabIndex: 'Tab Indeks',
54 target: 'Meta',
55 targetFrame: '<okvir>',
56 targetFrameName: 'Ime ciljnog okvira',
57 targetPopup: '<popup prozor>',
58 targetPopupName: 'Naziv popup prozora',
59 title: 'Link',
60 toAnchor: 'Sidro na ovoj stranici',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Ubaci/promijeni link',
64 type: 'Link vrsta',
65 unlink: 'Ukloni link',
66 upload: 'Pošalji'
67} );
diff --git a/sources/plugins/link/lang/hu.js b/sources/plugins/link/lang/hu.js
new file mode 100644
index 0000000..52c09a8
--- /dev/null
+++ b/sources/plugins/link/lang/hu.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'hu', {
6 acccessKey: 'Billentyűkombináció',
7 advanced: 'További opciók',
8 advisoryContentType: 'Súgó tartalomtípusa',
9 advisoryTitle: 'Súgócimke',
10 anchor: {
11 toolbar: 'Horgony beillesztése/szerkesztése',
12 menu: 'Horgony tulajdonságai',
13 title: 'Horgony tulajdonságai',
14 name: 'Horgony neve',
15 errorName: 'Kérem adja meg a horgony nevét',
16 remove: 'Horgony eltávolítása'
17 },
18 anchorId: 'Azonosító szerint',
19 anchorName: 'Horgony név szerint',
20 charset: 'Hivatkozott tartalom kódlapja',
21 cssClasses: 'Stíluskészlet',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail cím',
25 emailBody: 'Üzenet',
26 emailSubject: 'Üzenet tárgya',
27 id: 'Id',
28 info: 'Alaptulajdonságok',
29 langCode: 'Írás iránya',
30 langDir: 'Írás iránya',
31 langDirLTR: 'Balról jobbra',
32 langDirRTL: 'Jobbról balra',
33 menu: 'Hivatkozás módosítása',
34 name: 'Név',
35 noAnchors: '(Nincs horgony a dokumentumban)',
36 noEmail: 'Adja meg az E-Mail címet',
37 noUrl: 'Adja meg a hivatkozás webcímét',
38 other: '<más>',
39 popupDependent: 'Szülőhöz kapcsolt (csak Netscape)',
40 popupFeatures: 'Felugró ablak jellemzői',
41 popupFullScreen: 'Teljes képernyő (csak IE)',
42 popupLeft: 'Bal pozíció',
43 popupLocationBar: 'Címsor',
44 popupMenuBar: 'Menü sor',
45 popupResizable: 'Átméretezés',
46 popupScrollBars: 'Gördítősáv',
47 popupStatusBar: 'Állapotsor',
48 popupToolbar: 'Eszköztár',
49 popupTop: 'Felső pozíció',
50 rel: 'Kapcsolat típusa',
51 selectAnchor: 'Horgony választása',
52 styles: 'Stílus',
53 tabIndex: 'Tabulátor index',
54 target: 'Tartalom megjelenítése',
55 targetFrame: '<keretben>',
56 targetFrameName: 'Keret neve',
57 targetPopup: '<felugró ablakban>',
58 targetPopupName: 'Felugró ablak neve',
59 title: 'Hivatkozás tulajdonságai',
60 toAnchor: 'Horgony az oldalon',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Hivatkozás beillesztése/módosítása',
64 type: 'Hivatkozás típusa',
65 unlink: 'Hivatkozás törlése',
66 upload: 'Feltöltés'
67} );
diff --git a/sources/plugins/link/lang/id.js b/sources/plugins/link/lang/id.js
new file mode 100644
index 0000000..e255eb5
--- /dev/null
+++ b/sources/plugins/link/lang/id.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'id', {
6 acccessKey: 'Access Key', // MISSING
7 advanced: 'Advanced', // MISSING
8 advisoryContentType: 'Advisory Content Type', // MISSING
9 advisoryTitle: 'Penasehat Judul',
10 anchor: {
11 toolbar: 'Anchor', // MISSING
12 menu: 'Edit Anchor', // MISSING
13 title: 'Anchor Properties', // MISSING
14 name: 'Anchor Name', // MISSING
15 errorName: 'Please type the anchor name', // MISSING
16 remove: 'Remove Anchor' // MISSING
17 },
18 anchorId: 'By Element Id', // MISSING
19 anchorName: 'By Anchor Name', // MISSING
20 charset: 'Linked Resource Charset', // MISSING
21 cssClasses: 'Kelas Stylesheet',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Alamat E-mail',
25 emailBody: 'Message Body', // MISSING
26 emailSubject: 'Judul Pesan',
27 id: 'Id',
28 info: 'Link Info', // MISSING
29 langCode: 'Kode Bahasa',
30 langDir: 'Arah Bahasa',
31 langDirLTR: 'Kiri ke Kanan (LTR)',
32 langDirRTL: 'Kanan ke Kiri (RTL)',
33 menu: 'Sunting Tautan',
34 name: 'Nama',
35 noAnchors: '(No anchors available in the document)', // MISSING
36 noEmail: 'Silahkan ketikkan alamat e-mail',
37 noUrl: 'Silahkan ketik URL tautan',
38 other: '<lainnya>',
39 popupDependent: 'Dependent (Netscape)', // MISSING
40 popupFeatures: 'Popup Window Features', // MISSING
41 popupFullScreen: 'Full Screen (IE)', // MISSING
42 popupLeft: 'Left Position', // MISSING
43 popupLocationBar: 'Location Bar', // MISSING
44 popupMenuBar: 'Menu Bar', // MISSING
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Scroll Bars', // MISSING
47 popupStatusBar: 'Status Bar', // MISSING
48 popupToolbar: 'Toolbar', // MISSING
49 popupTop: 'Top Position', // MISSING
50 rel: 'Hubungan',
51 selectAnchor: 'Select an Anchor', // MISSING
52 styles: 'Gaya',
53 tabIndex: 'Tab Index', // MISSING
54 target: 'Sasaran',
55 targetFrame: '<frame>', // MISSING
56 targetFrameName: 'Target Frame Name', // MISSING
57 targetPopup: '<popup window>', // MISSING
58 targetPopupName: 'Popup Window Name', // MISSING
59 title: 'Tautan',
60 toAnchor: 'Link to anchor in the text', // MISSING
61 toEmail: 'E-mail', // MISSING
62 toUrl: 'URL',
63 toolbar: 'Tautan',
64 type: 'Link Type', // MISSING
65 unlink: 'Unlink', // MISSING
66 upload: 'Unggah'
67} );
diff --git a/sources/plugins/link/lang/is.js b/sources/plugins/link/lang/is.js
new file mode 100644
index 0000000..ccdea0a
--- /dev/null
+++ b/sources/plugins/link/lang/is.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'is', {
6 acccessKey: 'Skammvalshnappur',
7 advanced: 'Tæknilegt',
8 advisoryContentType: 'Tegund innihalds',
9 advisoryTitle: 'Titill',
10 anchor: {
11 toolbar: 'Stofna/breyta kaflamerki',
12 menu: 'Eigindi kaflamerkis',
13 title: 'Eigindi kaflamerkis',
14 name: 'Nafn bókamerkis',
15 errorName: 'Sláðu inn nafn bókamerkis!',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'Eftir auðkenni einingar',
19 anchorName: 'Eftir akkerisnafni',
20 charset: 'Táknróf',
21 cssClasses: 'Stílsniðsflokkur',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Netfang',
25 emailBody: 'Meginmál',
26 emailSubject: 'Efni',
27 id: 'Auðkenni',
28 info: 'Almennt',
29 langCode: 'Lesstefna',
30 langDir: 'Lesstefna',
31 langDirLTR: 'Frá vinstri til hægri (LTR)',
32 langDirRTL: 'Frá hægri til vinstri (RTL)',
33 menu: 'Breyta stiklu',
34 name: 'Nafn',
35 noAnchors: '<Engin bókamerki á skrá>',
36 noEmail: 'Sláðu inn netfang!',
37 noUrl: 'Sláðu inn veffang stiklunnar!',
38 other: '<annar>',
39 popupDependent: 'Háð venslum (Netscape)',
40 popupFeatures: 'Eigindi sprettiglugga',
41 popupFullScreen: 'Heilskjár (IE)',
42 popupLeft: 'Fjarlægð frá vinstri',
43 popupLocationBar: 'Fanglína',
44 popupMenuBar: 'Vallína',
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Skrunstikur',
47 popupStatusBar: 'Stöðustika',
48 popupToolbar: 'Verkfærastika',
49 popupTop: 'Fjarlægð frá efri brún',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Veldu akkeri',
52 styles: 'Stíll',
53 tabIndex: 'Raðnúmer innsláttarreits',
54 target: 'Mark',
55 targetFrame: '<rammi>',
56 targetFrameName: 'Nafn markglugga',
57 targetPopup: '<sprettigluggi>',
58 targetPopupName: 'Nafn sprettiglugga',
59 title: 'Stikla',
60 toAnchor: 'Bókamerki á þessari síðu',
61 toEmail: 'Netfang',
62 toUrl: 'Vefslóð',
63 toolbar: 'Stofna/breyta stiklu',
64 type: 'Stikluflokkur',
65 unlink: 'Fjarlægja stiklu',
66 upload: 'Senda upp'
67} );
diff --git a/sources/plugins/link/lang/it.js b/sources/plugins/link/lang/it.js
new file mode 100644
index 0000000..b6b93bf
--- /dev/null
+++ b/sources/plugins/link/lang/it.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'it', {
6 acccessKey: 'Scorciatoia da tastiera',
7 advanced: 'Avanzate',
8 advisoryContentType: 'Tipo della risorsa collegata',
9 advisoryTitle: 'Titolo',
10 anchor: {
11 toolbar: 'Inserisci/Modifica Ancora',
12 menu: 'Proprietà ancora',
13 title: 'Proprietà ancora',
14 name: 'Nome ancora',
15 errorName: 'Inserici il nome dell\'ancora',
16 remove: 'Rimuovi l\'ancora'
17 },
18 anchorId: 'Per id elemento',
19 anchorName: 'Per Nome',
20 charset: 'Set di caretteri della risorsa collegata',
21 cssClasses: 'Nome classe CSS',
22 download: 'Forza scaricamento',
23 displayText: 'Mostra testo',
24 emailAddress: 'Indirizzo E-Mail',
25 emailBody: 'Corpo del messaggio',
26 emailSubject: 'Oggetto del messaggio',
27 id: 'Id',
28 info: 'Informazioni collegamento',
29 langCode: 'Direzione scrittura',
30 langDir: 'Direzione scrittura',
31 langDirLTR: 'Da Sinistra a Destra (LTR)',
32 langDirRTL: 'Da Destra a Sinistra (RTL)',
33 menu: 'Modifica collegamento',
34 name: 'Nome',
35 noAnchors: '(Nessuna ancora disponibile nel documento)',
36 noEmail: 'Devi inserire un\'indirizzo e-mail',
37 noUrl: 'Devi inserire l\'URL del collegamento',
38 other: '<altro>',
39 popupDependent: 'Dipendente (Netscape)',
40 popupFeatures: 'Caratteristiche finestra popup',
41 popupFullScreen: 'A tutto schermo (IE)',
42 popupLeft: 'Posizione da sinistra',
43 popupLocationBar: 'Barra degli indirizzi',
44 popupMenuBar: 'Barra del menu',
45 popupResizable: 'Ridimensionabile',
46 popupScrollBars: 'Barre di scorrimento',
47 popupStatusBar: 'Barra di stato',
48 popupToolbar: 'Barra degli strumenti',
49 popupTop: 'Posizione dall\'alto',
50 rel: 'Relazioni',
51 selectAnchor: 'Scegli Ancora',
52 styles: 'Stile',
53 tabIndex: 'Ordine di tabulazione',
54 target: 'Destinazione',
55 targetFrame: '<riquadro>',
56 targetFrameName: 'Nome del riquadro di destinazione',
57 targetPopup: '<finestra popup>',
58 targetPopupName: 'Nome finestra popup',
59 title: 'Collegamento',
60 toAnchor: 'Ancora nel testo',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Collegamento',
64 type: 'Tipo di Collegamento',
65 unlink: 'Elimina collegamento',
66 upload: 'Carica'
67} );
diff --git a/sources/plugins/link/lang/ja.js b/sources/plugins/link/lang/ja.js
new file mode 100644
index 0000000..94108b5
--- /dev/null
+++ b/sources/plugins/link/lang/ja.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ja', {
6 acccessKey: 'アクセスキー',
7 advanced: '高度な設定',
8 advisoryContentType: 'Content Type属性',
9 advisoryTitle: 'Title属性',
10 anchor: {
11 toolbar: 'アンカー挿入/編集',
12 menu: 'アンカーの編集',
13 title: 'アンカーのプロパティ',
14 name: 'アンカー名',
15 errorName: 'アンカー名を入力してください。',
16 remove: 'アンカーを削除'
17 },
18 anchorId: 'エレメントID',
19 anchorName: 'アンカー名',
20 charset: 'リンク先のcharset',
21 cssClasses: 'スタイルシートクラス',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail アドレス',
25 emailBody: '本文',
26 emailSubject: '件名',
27 id: 'Id',
28 info: 'ハイパーリンク情報',
29 langCode: '言語コード',
30 langDir: '文字表記の方向',
31 langDirLTR: '左から右 (LTR)',
32 langDirRTL: '右から左 (RTL)',
33 menu: 'リンクを編集',
34 name: 'Name属性',
35 noAnchors: '(このドキュメント内にアンカーはありません)',
36 noEmail: 'メールアドレスを入力してください。',
37 noUrl: 'リンクURLを入力してください。',
38 other: '<その他の>',
39 popupDependent: '開いたウィンドウに連動して閉じる (Netscape)',
40 popupFeatures: 'ポップアップウィンドウ特徴',
41 popupFullScreen: '全画面モード(IE)',
42 popupLeft: '左端からの座標で指定',
43 popupLocationBar: 'ロケーションバー',
44 popupMenuBar: 'メニューバー',
45 popupResizable: 'サイズ可変',
46 popupScrollBars: 'スクロールバー',
47 popupStatusBar: 'ステータスバー',
48 popupToolbar: 'ツールバー',
49 popupTop: '上端からの座標で指定',
50 rel: '関連リンク',
51 selectAnchor: 'アンカーを選択',
52 styles: 'スタイルシート',
53 tabIndex: 'タブインデックス',
54 target: 'ターゲット',
55 targetFrame: '<フレーム>',
56 targetFrameName: 'ターゲットのフレーム名',
57 targetPopup: '<ポップアップウィンドウ>',
58 targetPopupName: 'ポップアップウィンドウ名',
59 title: 'ハイパーリンク',
60 toAnchor: 'ページ内のアンカー',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'リンク挿入/編集',
64 type: 'リンクタイプ',
65 unlink: 'リンクを削除',
66 upload: 'アップロード'
67} );
diff --git a/sources/plugins/link/lang/ka.js b/sources/plugins/link/lang/ka.js
new file mode 100644
index 0000000..439c43d
--- /dev/null
+++ b/sources/plugins/link/lang/ka.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ka', {
6 acccessKey: 'წვდომის ღილაკი',
7 advanced: 'დაწვრილებით',
8 advisoryContentType: 'შიგთავსის ტიპი',
9 advisoryTitle: 'სათაური',
10 anchor: {
11 toolbar: 'ღუზა',
12 menu: 'ღუზის რედაქტირება',
13 title: 'ღუზის პარამეტრები',
14 name: 'ღუზუს სახელი',
15 errorName: 'აკრიფეთ ღუზის სახელი',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'ელემენტის Id-თ',
19 anchorName: 'ღუზის სახელით',
20 charset: 'კოდირება',
21 cssClasses: 'CSS კლასი',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ელფოსტის მისამართები',
25 emailBody: 'წერილის ტექსტი',
26 emailSubject: 'წერილის სათაური',
27 id: 'Id',
28 info: 'ბმულის ინფორმაცია',
29 langCode: 'ენის კოდი',
30 langDir: 'ენის მიმართულება',
31 langDirLTR: 'მარცხნიდან მარჯვნივ (LTR)',
32 langDirRTL: 'მარჯვნიდან მარცხნივ (RTL)',
33 menu: 'ბმულის რედაქტირება',
34 name: 'სახელი',
35 noAnchors: '(ამ დოკუმენტში ღუზა არაა)',
36 noEmail: 'აკრიფეთ ელფოსტის მისამართი',
37 noUrl: 'აკრიფეთ ბმულის URL',
38 other: '<სხვა>',
39 popupDependent: 'დამოკიდებული (Netscape)',
40 popupFeatures: 'Popup ფანჯრის პარამეტრები',
41 popupFullScreen: 'მთელი ეკრანი (IE)',
42 popupLeft: 'მარცხენა პოზიცია',
43 popupLocationBar: 'ნავიგაციის ზოლი',
44 popupMenuBar: 'მენიუს ზოლი',
45 popupResizable: 'ცვალებადი ზომით',
46 popupScrollBars: 'გადახვევის ზოლები',
47 popupStatusBar: 'სტატუსის ზოლი',
48 popupToolbar: 'ხელსაწყოთა ზოლი',
49 popupTop: 'ზედა პოზიცია',
50 rel: 'კავშირი',
51 selectAnchor: 'აირჩიეთ ღუზა',
52 styles: 'CSS სტილი',
53 tabIndex: 'Tab-ის ინდექსი',
54 target: 'გახსნის ადგილი',
55 targetFrame: '<frame>',
56 targetFrameName: 'Frame-ის სახელი',
57 targetPopup: '<popup ფანჯარა>',
58 targetPopupName: 'Popup ფანჯრის სახელი',
59 title: 'ბმული',
60 toAnchor: 'ბმული ტექსტში ღუზაზე',
61 toEmail: 'ელფოსტა',
62 toUrl: 'URL',
63 toolbar: 'ბმული',
64 type: 'ბმულის ტიპი',
65 unlink: 'ბმულის მოხსნა',
66 upload: 'აქაჩვა'
67} );
diff --git a/sources/plugins/link/lang/km.js b/sources/plugins/link/lang/km.js
new file mode 100644
index 0000000..5d0be03
--- /dev/null
+++ b/sources/plugins/link/lang/km.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'km', {
6 acccessKey: 'សោរ​ចូល',
7 advanced: 'កម្រិត​ខ្ពស់',
8 advisoryContentType: 'ប្រភេទអត្ថបទ​ប្រឹក្សា',
9 advisoryTitle: 'ចំណងជើង​ប្រឹក្សា',
10 anchor: {
11 toolbar: 'យុថ្កា',
12 menu: 'កែ​យុថ្កា',
13 title: 'លក្ខណៈ​យុថ្កា',
14 name: 'ឈ្មោះ​យុថ្កា',
15 errorName: 'សូម​បញ្ចូល​ឈ្មោះ​យុថ្កា',
16 remove: 'ដក​យុថ្កា​ចេញ'
17 },
18 anchorId: 'តាម ID ធាតុ',
19 anchorName: 'តាម​ឈ្មោះ​យុថ្កា',
20 charset: 'លេខកូតអក្សររបស់ឈ្នាប់',
21 cssClasses: 'Stylesheet Classes',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'អាសយដ្ឋាន​អ៊ីមែល',
25 emailBody: 'តួ​អត្ថបទ',
26 emailSubject: 'ប្រធានបទ​សារ',
27 id: 'Id',
28 info: 'ព័ត៌មាន​ពី​តំណ',
29 langCode: 'កូដ​ភាសា',
30 langDir: 'ទិសដៅភាសា',
31 langDirLTR: 'ពីឆ្វេងទៅស្តាំ(LTR)',
32 langDirRTL: 'ពីស្តាំទៅឆ្វេង(RTL)',
33 menu: 'កែ​តំណ',
34 name: 'ឈ្មោះ',
35 noAnchors: '(មិន​មាន​យុថ្កា​នៅ​ក្នុង​ឯកសារ​អត្ថថបទ​ទេ)',
36 noEmail: 'សូម​បញ្ចូល​អាសយដ្ឋាន​អ៊ីមែល',
37 noUrl: 'សូម​បញ្ចូល​តំណ URL',
38 other: '<ផ្សេង​ទៀត>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'មុខ​ងារ​ផុស​ផ្ទាំង​វីនដូ​ឡើង',
41 popupFullScreen: 'ពេញ​អេក្រង់ (IE)',
42 popupLeft: 'ទីតាំងខាងឆ្វេង',
43 popupLocationBar: 'របារ​ទីតាំង',
44 popupMenuBar: 'របារ​ម៉ឺនុយ',
45 popupResizable: 'អាច​ប្ដូរ​ទំហំ',
46 popupScrollBars: 'របារ​រំកិល',
47 popupStatusBar: 'របារ​ស្ថានភាព',
48 popupToolbar: 'របារ​ឧបករណ៍',
49 popupTop: 'ទីតាំង​កំពូល',
50 rel: 'សម្ពន្ធ​ភាព',
51 selectAnchor: 'រើស​យក​យុថ្កា​មួយ',
52 styles: 'ស្ទីល',
53 tabIndex: 'លេខ Tab',
54 target: 'គោលដៅ',
55 targetFrame: '<ស៊ុម>',
56 targetFrameName: 'ឈ្មោះ​ស៊ុម​ជា​គោល​ដៅ',
57 targetPopup: '<វីនដូ​ផុស​ឡើង>',
58 targetPopupName: 'ឈ្មោះ​វីនដូត​ផុស​ឡើង',
59 title: 'តំណ',
60 toAnchor: 'ត​ភ្ជាប់​ទៅ​យុថ្កា​ក្នុង​អត្ថបទ',
61 toEmail: 'អ៊ីមែល',
62 toUrl: 'URL',
63 toolbar: 'តំណ',
64 type: 'ប្រភេទ​តំណ',
65 unlink: 'ផ្ដាច់​តំណ',
66 upload: 'ផ្ទុក​ឡើង'
67} );
diff --git a/sources/plugins/link/lang/ko.js b/sources/plugins/link/lang/ko.js
new file mode 100644
index 0000000..86a797d
--- /dev/null
+++ b/sources/plugins/link/lang/ko.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ko', {
6 acccessKey: '액세스 키',
7 advanced: '고급',
8 advisoryContentType: '보조 콘텐츠 유형',
9 advisoryTitle: '보조 제목',
10 anchor: {
11 toolbar: '책갈피',
12 menu: '책갈피 편집',
13 title: '책갈피 속성',
14 name: '책갈피 이름',
15 errorName: '책갈피 이름을 입력하십시오',
16 remove: '책갈피 제거'
17 },
18 anchorId: '책갈피 ID',
19 anchorName: '책갈피 이름',
20 charset: '링크된 자료 문자열 인코딩',
21 cssClasses: '스타일시트 클래스',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: '이메일 주소',
25 emailBody: '메시지 내용',
26 emailSubject: '메시지 제목',
27 id: 'ID',
28 info: '링크 정보',
29 langCode: '언어 코드',
30 langDir: '언어 방향',
31 langDirLTR: '왼쪽에서 오른쪽 (LTR)',
32 langDirRTL: '오른쪽에서 왼쪽 (RTL)',
33 menu: '링크 수정',
34 name: '이름',
35 noAnchors: '(문서에 책갈피가 없습니다.)',
36 noEmail: '이메일 주소를 입력하십시오',
37 noUrl: '링크 주소(URL)를 입력하십시오',
38 other: '<기타>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: '팝업창 속성',
41 popupFullScreen: '전체화면 (IE)',
42 popupLeft: '왼쪽 위치',
43 popupLocationBar: '주소 표시줄',
44 popupMenuBar: '메뉴 바',
45 popupResizable: '크기 조절 가능',
46 popupScrollBars: '스크롤 바',
47 popupStatusBar: '상태 바',
48 popupToolbar: '툴바',
49 popupTop: '위쪽 위치',
50 rel: '관계',
51 selectAnchor: '책갈피 선택',
52 styles: '스타일',
53 tabIndex: '탭 순서',
54 target: '타겟',
55 targetFrame: '<프레임>',
56 targetFrameName: '타겟 프레임 이름',
57 targetPopup: '<팝업 창>',
58 targetPopupName: '팝업 창 이름',
59 title: '링크',
60 toAnchor: '책갈피',
61 toEmail: '이메일',
62 toUrl: '주소(URL)',
63 toolbar: '링크 삽입/변경',
64 type: '링크 종류',
65 unlink: '링크 지우기',
66 upload: '업로드'
67} );
diff --git a/sources/plugins/link/lang/ku.js b/sources/plugins/link/lang/ku.js
new file mode 100644
index 0000000..16faf24
--- /dev/null
+++ b/sources/plugins/link/lang/ku.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ku', {
6 acccessKey: 'کلیلی دەستپێگەیشتن',
7 advanced: 'پێشکەوتوو',
8 advisoryContentType: 'جۆری ناوەڕۆکی ڕاویژکار',
9 advisoryTitle: 'ڕاوێژکاری سەردێڕ',
10 anchor: {
11 toolbar: 'دانان/چاکسازی لەنگەر',
12 menu: 'چاکسازی لەنگەر',
13 title: 'خاسیەتی لەنگەر',
14 name: 'ناوی لەنگەر',
15 errorName: 'تکایه ناوی لەنگەر بنووسه',
16 remove: 'لابردنی لەنگەر'
17 },
18 anchorId: 'بەپێی ناسنامەی توخم',
19 anchorName: 'بەپێی ناوی لەنگەر',
20 charset: 'بەستەری سەرچاوەی نووسە',
21 cssClasses: 'شێوازی چینی پەڕه',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ناونیشانی ئیمەیل',
25 emailBody: 'ناوەڕۆکی نامە',
26 emailSubject: 'بابەتی نامە',
27 id: 'ناسنامە',
28 info: 'زانیاری بەستەر',
29 langCode: 'هێمای زمان',
30 langDir: 'ئاراستەی زمان',
31 langDirLTR: 'چەپ بۆ ڕاست (LTR)',
32 langDirRTL: 'ڕاست بۆ چەپ (RTL)',
33 menu: 'چاکسازی بەستەر',
34 name: 'ناو',
35 noAnchors: '(هیچ جۆرێکی لەنگەر ئامادە نیە لەم پەڕەیه)',
36 noEmail: 'تکایە ناونیشانی ئیمەیل بنووسە',
37 noUrl: 'تکایە ناونیشانی بەستەر بنووسە',
38 other: '<هیتر>',
39 popupDependent: 'پێوەبەستراو (Netscape)',
40 popupFeatures: 'خاسیەتی پەنجەرەی سەرهەڵدەر',
41 popupFullScreen: 'پڕ بەپڕی شاشە (IE)',
42 popupLeft: 'جێگای چەپ',
43 popupLocationBar: 'هێڵی ناونیشانی بەستەر',
44 popupMenuBar: 'هێڵی لیسته',
45 popupResizable: 'توانای گۆڕینی قەباره',
46 popupScrollBars: 'هێڵی هاتووچۆپێکردن',
47 popupStatusBar: 'هێڵی دۆخ',
48 popupToolbar: 'هێڵی تووڵامراز',
49 popupTop: 'جێگای سەرەوە',
50 rel: 'پەیوەندی',
51 selectAnchor: 'هەڵبژاردنی لەنگەرێك',
52 styles: 'شێواز',
53 tabIndex: 'بازدەری تابی ئیندێکس',
54 target: 'ئامانج',
55 targetFrame: '<چووارچێوە>',
56 targetFrameName: 'ناوی ئامانجی چووارچێوە',
57 targetPopup: '<پەنجەرەی سەرهەڵدەر>',
58 targetPopupName: 'ناوی پەنجەرەی سەرهەڵدەر',
59 title: 'بەستەر',
60 toAnchor: 'بەستەر بۆ لەنگەر له دەق',
61 toEmail: 'ئیمەیل',
62 toUrl: 'ناونیشانی بەستەر',
63 toolbar: 'دانان/ڕێکخستنی بەستەر',
64 type: 'جۆری بەستەر',
65 unlink: 'لابردنی بەستەر',
66 upload: 'بارکردن'
67} );
diff --git a/sources/plugins/link/lang/lt.js b/sources/plugins/link/lang/lt.js
new file mode 100644
index 0000000..27aa8b7
--- /dev/null
+++ b/sources/plugins/link/lang/lt.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'lt', {
6 acccessKey: 'Prieigos raktas',
7 advanced: 'Papildomas',
8 advisoryContentType: 'Konsultacinio turinio tipas',
9 advisoryTitle: 'Konsultacinė antraštė',
10 anchor: {
11 toolbar: 'Įterpti/modifikuoti žymę',
12 menu: 'Žymės savybės',
13 title: 'Žymės savybės',
14 name: 'Žymės vardas',
15 errorName: 'Prašome įvesti žymės vardą',
16 remove: 'Pašalinti žymę'
17 },
18 anchorId: 'Pagal žymės Id',
19 anchorName: 'Pagal žymės vardą',
20 charset: 'Susietų išteklių simbolių lentelė',
21 cssClasses: 'Stilių lentelės klasės',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'El.pašto adresas',
25 emailBody: 'Žinutės turinys',
26 emailSubject: 'Žinutės tema',
27 id: 'Id',
28 info: 'Nuorodos informacija',
29 langCode: 'Teksto kryptis',
30 langDir: 'Teksto kryptis',
31 langDirLTR: 'Iš kairės į dešinę (LTR)',
32 langDirRTL: 'Iš dešinės į kairę (RTL)',
33 menu: 'Taisyti nuorodą',
34 name: 'Vardas',
35 noAnchors: '(Šiame dokumente žymių nėra)',
36 noEmail: 'Prašome įvesti el.pašto adresą',
37 noUrl: 'Prašome įvesti nuorodos URL',
38 other: '<kitas>',
39 popupDependent: 'Priklausomas (Netscape)',
40 popupFeatures: 'Išskleidžiamo lango savybės',
41 popupFullScreen: 'Visas ekranas (IE)',
42 popupLeft: 'Kairė pozicija',
43 popupLocationBar: 'Adreso juosta',
44 popupMenuBar: 'Meniu juosta',
45 popupResizable: 'Kintamas dydis',
46 popupScrollBars: 'Slinkties juostos',
47 popupStatusBar: 'Būsenos juosta',
48 popupToolbar: 'Mygtukų juosta',
49 popupTop: 'Viršutinė pozicija',
50 rel: 'Sąsajos',
51 selectAnchor: 'Pasirinkite žymę',
52 styles: 'Stilius',
53 tabIndex: 'Tabuliavimo indeksas',
54 target: 'Paskirties vieta',
55 targetFrame: '<kadras>',
56 targetFrameName: 'Paskirties kadro vardas',
57 targetPopup: '<išskleidžiamas langas>',
58 targetPopupName: 'Paskirties lango vardas',
59 title: 'Nuoroda',
60 toAnchor: 'Žymė šiame puslapyje',
61 toEmail: 'El.paštas',
62 toUrl: 'Nuoroda',
63 toolbar: 'Įterpti/taisyti nuorodą',
64 type: 'Nuorodos tipas',
65 unlink: 'Panaikinti nuorodą',
66 upload: 'Siųsti'
67} );
diff --git a/sources/plugins/link/lang/lv.js b/sources/plugins/link/lang/lv.js
new file mode 100644
index 0000000..ef8a3f2
--- /dev/null
+++ b/sources/plugins/link/lang/lv.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'lv', {
6 acccessKey: 'Pieejas taustiņš',
7 advanced: 'Izvērstais',
8 advisoryContentType: 'Konsultatīvs satura tips',
9 advisoryTitle: 'Konsultatīvs virsraksts',
10 anchor: {
11 toolbar: 'Ievietot/Labot iezīmi',
12 menu: 'Labot iezīmi',
13 title: 'Iezīmes uzstādījumi',
14 name: 'Iezīmes nosaukums',
15 errorName: 'Lūdzu norādiet iezīmes nosaukumu',
16 remove: 'Noņemt iezīmi'
17 },
18 anchorId: 'Pēc elementa ID',
19 anchorName: 'Pēc iezīmes nosaukuma',
20 charset: 'Pievienotā resursa kodējums',
21 cssClasses: 'Stilu saraksta klases',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-pasta adrese',
25 emailBody: 'Ziņas saturs',
26 emailSubject: 'Ziņas tēma',
27 id: 'ID',
28 info: 'Hipersaites informācija',
29 langCode: 'Valodas kods',
30 langDir: 'Valodas lasīšanas virziens',
31 langDirLTR: 'No kreisās uz labo (LTR)',
32 langDirRTL: 'No labās uz kreiso (RTL)',
33 menu: 'Labot hipersaiti',
34 name: 'Nosaukums',
35 noAnchors: '(Šajā dokumentā nav iezīmju)',
36 noEmail: 'Lūdzu norādi e-pasta adresi',
37 noUrl: 'Lūdzu norādi hipersaiti',
38 other: '<cits>',
39 popupDependent: 'Atkarīgs (Netscape)',
40 popupFeatures: 'Uznirstošā loga nosaukums īpašības',
41 popupFullScreen: 'Pilnā ekrānā (IE)',
42 popupLeft: 'Kreisā koordināte',
43 popupLocationBar: 'Atrašanās vietas josla',
44 popupMenuBar: 'Izvēlnes josla',
45 popupResizable: 'Mērogojams',
46 popupScrollBars: 'Ritjoslas',
47 popupStatusBar: 'Statusa josla',
48 popupToolbar: 'Rīku josla',
49 popupTop: 'Augšējā koordināte',
50 rel: 'Relācija',
51 selectAnchor: 'Izvēlēties iezīmi',
52 styles: 'Stils',
53 tabIndex: 'Ciļņu indekss',
54 target: 'Mērķis',
55 targetFrame: '<ietvars>',
56 targetFrameName: 'Mērķa ietvara nosaukums',
57 targetPopup: '<uznirstošā logā>',
58 targetPopupName: 'Uznirstošā loga nosaukums',
59 title: 'Hipersaite',
60 toAnchor: 'Iezīme šajā lapā',
61 toEmail: 'E-pasts',
62 toUrl: 'Adrese',
63 toolbar: 'Ievietot/Labot hipersaiti',
64 type: 'Hipersaites tips',
65 unlink: 'Noņemt hipersaiti',
66 upload: 'Augšupielādēt'
67} );
diff --git a/sources/plugins/link/lang/mk.js b/sources/plugins/link/lang/mk.js
new file mode 100644
index 0000000..5fb9655
--- /dev/null
+++ b/sources/plugins/link/lang/mk.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'mk', {
6 acccessKey: 'Access Key', // MISSING
7 advanced: 'Advanced', // MISSING
8 advisoryContentType: 'Advisory Content Type', // MISSING
9 advisoryTitle: 'Advisory Title', // MISSING
10 anchor: {
11 toolbar: 'Anchor',
12 menu: 'Edit Anchor',
13 title: 'Anchor Properties',
14 name: 'Anchor Name',
15 errorName: 'Please type the anchor name',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'By Element Id', // MISSING
19 anchorName: 'By Anchor Name', // MISSING
20 charset: 'Linked Resource Charset', // MISSING
21 cssClasses: 'Stylesheet Classes', // MISSING
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Address', // MISSING
25 emailBody: 'Message Body', // MISSING
26 emailSubject: 'Message Subject', // MISSING
27 id: 'Id',
28 info: 'Link Info', // MISSING
29 langCode: 'Код на јазик',
30 langDir: 'Насока на јазик',
31 langDirLTR: 'Лево кон десно',
32 langDirRTL: 'Десно кон лево',
33 menu: 'Edit Link', // MISSING
34 name: 'Name',
35 noAnchors: '(No anchors available in the document)', // MISSING
36 noEmail: 'Please type the e-mail address', // MISSING
37 noUrl: 'Please type the link URL', // MISSING
38 other: '<other>', // MISSING
39 popupDependent: 'Dependent (Netscape)', // MISSING
40 popupFeatures: 'Popup Window Features', // MISSING
41 popupFullScreen: 'Full Screen (IE)', // MISSING
42 popupLeft: 'Left Position', // MISSING
43 popupLocationBar: 'Location Bar', // MISSING
44 popupMenuBar: 'Menu Bar', // MISSING
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Scroll Bars', // MISSING
47 popupStatusBar: 'Status Bar', // MISSING
48 popupToolbar: 'Toolbar', // MISSING
49 popupTop: 'Top Position', // MISSING
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Select an Anchor', // MISSING
52 styles: 'Стил',
53 tabIndex: 'Tab Index', // MISSING
54 target: 'Target', // MISSING
55 targetFrame: '<frame>', // MISSING
56 targetFrameName: 'Target Frame Name', // MISSING
57 targetPopup: '<popup window>', // MISSING
58 targetPopupName: 'Popup Window Name', // MISSING
59 title: 'Врска',
60 toAnchor: 'Link to anchor in the text', // MISSING
61 toEmail: 'E-mail', // MISSING
62 toUrl: 'URL',
63 toolbar: 'Врска',
64 type: 'Link Type', // MISSING
65 unlink: 'Unlink', // MISSING
66 upload: 'Прикачи'
67} );
diff --git a/sources/plugins/link/lang/mn.js b/sources/plugins/link/lang/mn.js
new file mode 100644
index 0000000..ed159c7
--- /dev/null
+++ b/sources/plugins/link/lang/mn.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'mn', {
6 acccessKey: 'Холбох түлхүүр',
7 advanced: 'Нэмэлт',
8 advisoryContentType: 'Зөвлөлдөх төрлийн агуулга',
9 advisoryTitle: 'Зөвлөлдөх гарчиг',
10 anchor: {
11 toolbar: 'Зангуу',
12 menu: 'Зангууг болосруулах',
13 title: 'Зангуугийн шинж чанар',
14 name: 'Зангуугийн нэр',
15 errorName: 'Зангуугийн нэрийг оруулна уу',
16 remove: 'Зангууг устгах'
17 },
18 anchorId: 'Элемэнтйн Id нэрээр',
19 anchorName: 'Зангуугийн нэрээр',
20 charset: 'Тэмдэгт оноох нөөцөд холбогдсон',
21 cssClasses: 'Stylesheet классууд',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Э-шуудангийн хаяг',
25 emailBody: 'Зурвасны их бие',
26 emailSubject: 'Зурвасны гарчиг',
27 id: 'Id',
28 info: 'Холбоосын тухай мэдээлэл',
29 langCode: 'Хэлний код',
30 langDir: 'Хэлний чиглэл',
31 langDirLTR: 'Зүүнээс баруун (LTR)',
32 langDirRTL: 'Баруунаас зүүн (RTL)',
33 menu: 'Холбоос засварлах',
34 name: 'Нэр',
35 noAnchors: '(Баримт бичиг зангуугүй байна)',
36 noEmail: 'Э-шуудангий хаягаа шивнэ үү',
37 noUrl: 'Холбоосны URL хаягийг шивнэ үү',
38 other: '<other>', // MISSING
39 popupDependent: 'Хамаатай (Netscape)',
40 popupFeatures: 'Popup цонхны онцлог',
41 popupFullScreen: 'Цонх дүүргэх (Internet Explorer)',
42 popupLeft: 'Зүүн байрлал',
43 popupLocationBar: 'Location хэсэг',
44 popupMenuBar: 'Цэсний самбар',
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Скрол хэсэгүүд',
47 popupStatusBar: 'Статус хэсэг',
48 popupToolbar: 'Багажны самбар',
49 popupTop: 'Дээд байрлал',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Нэг зангууг сонгоно уу',
52 styles: 'Загвар',
53 tabIndex: 'Tab индекс',
54 target: 'Байрлал',
55 targetFrame: '<Агуулах хүрээ>',
56 targetFrameName: 'Очих фремын нэр',
57 targetPopup: '<popup цонх>',
58 targetPopupName: 'Popup цонхны нэр',
59 title: 'Холбоос',
60 toAnchor: 'Энэ бичвэр дэх зангуу руу очих холбоос',
61 toEmail: 'Э-захиа',
62 toUrl: 'цахим хуудасны хаяг (URL)',
63 toolbar: 'Холбоос',
64 type: 'Линкийн төрөл',
65 unlink: 'Холбоос авч хаях',
66 upload: 'Хуулах'
67} );
diff --git a/sources/plugins/link/lang/ms.js b/sources/plugins/link/lang/ms.js
new file mode 100644
index 0000000..9a2e499
--- /dev/null
+++ b/sources/plugins/link/lang/ms.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ms', {
6 acccessKey: 'Kunci Akses',
7 advanced: 'Advanced',
8 advisoryContentType: 'Jenis Kandungan Makluman',
9 advisoryTitle: 'Tajuk Makluman',
10 anchor: {
11 toolbar: 'Masukkan/Sunting Pautan',
12 menu: 'Ciri-ciri Pautan',
13 title: 'Ciri-ciri Pautan',
14 name: 'Nama Pautan',
15 errorName: 'Sila taip nama pautan',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'dengan menggunakan ID elemen',
19 anchorName: 'dengan menggunakan nama pautan',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Kelas-kelas Stylesheet',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Alamat E-Mail',
25 emailBody: 'Isi Kandungan Mesej',
26 emailSubject: 'Subjek Mesej',
27 id: 'Id',
28 info: 'Butiran Sambungan',
29 langCode: 'Arah Tulisan',
30 langDir: 'Arah Tulisan',
31 langDirLTR: 'Kiri ke Kanan (LTR)',
32 langDirRTL: 'Kanan ke Kiri (RTL)',
33 menu: 'Sunting Sambungan',
34 name: 'Nama',
35 noAnchors: '(Tiada pautan terdapat dalam dokumen ini)',
36 noEmail: 'Sila taip alamat e-mail',
37 noUrl: 'Sila taip sambungan URL',
38 other: '<lain>',
39 popupDependent: 'Bergantungan (Netscape)',
40 popupFeatures: 'Ciri Tetingkap Popup',
41 popupFullScreen: 'Skrin Penuh (IE)',
42 popupLeft: 'Posisi Kiri',
43 popupLocationBar: 'Bar Lokasi',
44 popupMenuBar: 'Bar Menu',
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Bar-bar skrol',
47 popupStatusBar: 'Bar Status',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Posisi Atas',
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Sila pilih pautan',
52 styles: 'Stail',
53 tabIndex: 'Indeks Tab ',
54 target: 'Sasaran',
55 targetFrame: '<bingkai>',
56 targetFrameName: 'Nama Bingkai Sasaran',
57 targetPopup: '<tetingkap popup>',
58 targetPopupName: 'Nama Tetingkap Popup',
59 title: 'Sambungan',
60 toAnchor: 'Pautan dalam muka surat ini',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Masukkan/Sunting Sambungan',
64 type: 'Jenis Sambungan',
65 unlink: 'Buang Sambungan',
66 upload: 'Muat Naik'
67} );
diff --git a/sources/plugins/link/lang/nb.js b/sources/plugins/link/lang/nb.js
new file mode 100644
index 0000000..7253b4a
--- /dev/null
+++ b/sources/plugins/link/lang/nb.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'nb', {
6 acccessKey: 'Aksessknapp',
7 advanced: 'Avansert',
8 advisoryContentType: 'Type',
9 advisoryTitle: 'Tittel',
10 anchor: {
11 toolbar: 'Anker',
12 menu: 'Rediger anker',
13 title: 'Egenskaper for anker',
14 name: 'Ankernavn',
15 errorName: 'Vennligst skriv inn ankernavnet',
16 remove: 'Fjern anker'
17 },
18 anchorId: 'Element etter ID',
19 anchorName: 'Anker etter navn',
20 charset: 'Lenket tegnsett',
21 cssClasses: 'Stilarkklasser',
22 download: 'Tving nedlasting',
23 displayText: 'Tekst som skal vises',
24 emailAddress: 'E-postadresse',
25 emailBody: 'Melding',
26 emailSubject: 'Meldingsemne',
27 id: 'Id',
28 info: 'Lenkeinfo',
29 langCode: 'Språkkode',
30 langDir: 'Språkretning',
31 langDirLTR: 'Venstre til høyre (LTR)',
32 langDirRTL: 'Høyre til venstre (RTL)',
33 menu: 'Rediger lenke',
34 name: 'Navn',
35 noAnchors: '(Ingen anker i dokumentet)',
36 noEmail: 'Vennligst skriv inn e-postadressen',
37 noUrl: 'Vennligst skriv inn lenkens URL',
38 other: '<annen>',
39 popupDependent: 'Avhenging (Netscape)',
40 popupFeatures: 'Egenskaper for popup-vindu',
41 popupFullScreen: 'Fullskjerm (IE)',
42 popupLeft: 'Venstre posisjon',
43 popupLocationBar: 'Adresselinje',
44 popupMenuBar: 'Menylinje',
45 popupResizable: 'Skalerbar',
46 popupScrollBars: 'Scrollbar',
47 popupStatusBar: 'Statuslinje',
48 popupToolbar: 'Verktøylinje',
49 popupTop: 'Topp-posisjon',
50 rel: 'Relasjon (rel)',
51 selectAnchor: 'Velg et anker',
52 styles: 'Stil',
53 tabIndex: 'Tabindeks',
54 target: 'Mål',
55 targetFrame: '<ramme>',
56 targetFrameName: 'Målramme',
57 targetPopup: '<popup-vindu>',
58 targetPopupName: 'Navn på popup-vindu',
59 title: 'Lenke',
60 toAnchor: 'Lenke til anker i teksten',
61 toEmail: 'E-post',
62 toUrl: 'URL',
63 toolbar: 'Lenke',
64 type: 'Lenketype',
65 unlink: 'Fjern lenke',
66 upload: 'Last opp'
67} );
diff --git a/sources/plugins/link/lang/nl.js b/sources/plugins/link/lang/nl.js
new file mode 100644
index 0000000..12cb509
--- /dev/null
+++ b/sources/plugins/link/lang/nl.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'nl', {
6 acccessKey: 'Toegangstoets',
7 advanced: 'Geavanceerd',
8 advisoryContentType: 'Aanbevolen content-type',
9 advisoryTitle: 'Adviserende titel',
10 anchor: {
11 toolbar: 'Interne link',
12 menu: 'Eigenschappen interne link',
13 title: 'Eigenschappen interne link',
14 name: 'Naam interne link',
15 errorName: 'Geef de naam van de interne link op',
16 remove: 'Interne link verwijderen'
17 },
18 anchorId: 'Op kenmerk interne link',
19 anchorName: 'Op naam interne link',
20 charset: 'Karakterset van gelinkte bron',
21 cssClasses: 'Stylesheet-klassen',
22 download: 'Download forceren',
23 displayText: 'Weergavetekst',
24 emailAddress: 'E-mailadres',
25 emailBody: 'Inhoud bericht',
26 emailSubject: 'Onderwerp bericht',
27 id: 'Id',
28 info: 'Linkomschrijving',
29 langCode: 'Taalcode',
30 langDir: 'Schrijfrichting',
31 langDirLTR: 'Links naar rechts (LTR)',
32 langDirRTL: 'Rechts naar links (RTL)',
33 menu: 'Link wijzigen',
34 name: 'Naam',
35 noAnchors: '(Geen interne links in document gevonden)',
36 noEmail: 'Geef een e-mailadres',
37 noUrl: 'Geef de link van de URL',
38 other: '<ander>',
39 popupDependent: 'Afhankelijk (Netscape)',
40 popupFeatures: 'Instellingen popupvenster',
41 popupFullScreen: 'Volledig scherm (IE)',
42 popupLeft: 'Positie links',
43 popupLocationBar: 'Locatiemenu',
44 popupMenuBar: 'Menubalk',
45 popupResizable: 'Herschaalbaar',
46 popupScrollBars: 'Schuifbalken',
47 popupStatusBar: 'Statusbalk',
48 popupToolbar: 'Werkbalk',
49 popupTop: 'Positie boven',
50 rel: 'Relatie',
51 selectAnchor: 'Kies een interne link',
52 styles: 'Stijl',
53 tabIndex: 'Tabvolgorde',
54 target: 'Doelvenster',
55 targetFrame: '<frame>',
56 targetFrameName: 'Naam doelframe',
57 targetPopup: '<popupvenster>',
58 targetPopupName: 'Naam popupvenster',
59 title: 'Link',
60 toAnchor: 'Interne link in pagina',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Link invoegen/wijzigen',
64 type: 'Linktype',
65 unlink: 'Link verwijderen',
66 upload: 'Upload'
67} );
diff --git a/sources/plugins/link/lang/no.js b/sources/plugins/link/lang/no.js
new file mode 100644
index 0000000..bdd7fc6
--- /dev/null
+++ b/sources/plugins/link/lang/no.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'no', {
6 acccessKey: 'Aksessknapp',
7 advanced: 'Avansert',
8 advisoryContentType: 'Type',
9 advisoryTitle: 'Tittel',
10 anchor: {
11 toolbar: 'Sett inn/Rediger anker',
12 menu: 'Egenskaper for anker',
13 title: 'Egenskaper for anker',
14 name: 'Ankernavn',
15 errorName: 'Vennligst skriv inn ankernavnet',
16 remove: 'Fjern anker'
17 },
18 anchorId: 'Element etter ID',
19 anchorName: 'Anker etter navn',
20 charset: 'Lenket tegnsett',
21 cssClasses: 'Stilarkklasser',
22 download: 'Force Download', // MISSING
23 displayText: 'Tekst som skal vises',
24 emailAddress: 'E-postadresse',
25 emailBody: 'Melding',
26 emailSubject: 'Meldingsemne',
27 id: 'Id',
28 info: 'Lenkeinfo',
29 langCode: 'Språkkode',
30 langDir: 'Språkretning',
31 langDirLTR: 'Venstre til høyre (VTH)',
32 langDirRTL: 'Høyre til venstre (HTV)',
33 menu: 'Rediger lenke',
34 name: 'Navn',
35 noAnchors: '(Ingen anker i dokumentet)',
36 noEmail: 'Vennligst skriv inn e-postadressen',
37 noUrl: 'Vennligst skriv inn lenkens URL',
38 other: '<annen>',
39 popupDependent: 'Avhenging (Netscape)',
40 popupFeatures: 'Egenskaper for popup-vindu',
41 popupFullScreen: 'Fullskjerm (IE)',
42 popupLeft: 'Venstre posisjon',
43 popupLocationBar: 'Adresselinje',
44 popupMenuBar: 'Menylinje',
45 popupResizable: 'Skalerbar',
46 popupScrollBars: 'Scrollbar',
47 popupStatusBar: 'Statuslinje',
48 popupToolbar: 'Verktøylinje',
49 popupTop: 'Topp-posisjon',
50 rel: 'Relasjon (rel)',
51 selectAnchor: 'Velg et anker',
52 styles: 'Stil',
53 tabIndex: 'Tabindeks',
54 target: 'Mål',
55 targetFrame: '<ramme>',
56 targetFrameName: 'Målramme',
57 targetPopup: '<popup-vindu>',
58 targetPopupName: 'Navn på popup-vindu',
59 title: 'Lenke',
60 toAnchor: 'Lenke til anker i teksten',
61 toEmail: 'E-post',
62 toUrl: 'URL',
63 toolbar: 'Sett inn/Rediger lenke',
64 type: 'Lenketype',
65 unlink: 'Fjern lenke',
66 upload: 'Last opp'
67} );
diff --git a/sources/plugins/link/lang/oc.js b/sources/plugins/link/lang/oc.js
new file mode 100644
index 0000000..f9e51cd
--- /dev/null
+++ b/sources/plugins/link/lang/oc.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'oc', {
6 acccessKey: 'Tòca d\'accessibilitat',
7 advanced: 'Avançat',
8 advisoryContentType: 'Tipe de contengut (indicatiu)',
9 advisoryTitle: 'Infobulla',
10 anchor: {
11 toolbar: 'Ancòra',
12 menu: 'Modificar l\'ancòra',
13 title: 'Proprietats de l\'ancòra',
14 name: 'Nom de l\'ancòra',
15 errorName: 'Entratz lo nom de l\'ancòra',
16 remove: 'Suprimir l\'ancòra'
17 },
18 anchorId: 'Per ID d\'element',
19 anchorName: 'Per nom d\'ancòra',
20 charset: 'Encodatge de la ressorsa ligada',
21 cssClasses: 'Classas d\'estil',
22 download: 'Forçar lo telecargament',
23 displayText: 'Afichar lo tèxte',
24 emailAddress: 'Adreça electronica',
25 emailBody: 'Còs del messatge',
26 emailSubject: 'Subjècte del messatge',
27 id: 'Id',
28 info: 'Informacions sul ligam',
29 langCode: 'Còdi de lenga',
30 langDir: 'Sens d\'escritura',
31 langDirLTR: 'Esquèrra a dreita (LTR)',
32 langDirRTL: 'Dreita a esquèrra (RTL)',
33 menu: 'Modificar lo ligam',
34 name: 'Nom',
35 noAnchors: '(Cap d\'ancòra pas disponibla dins aqueste document)',
36 noEmail: 'Entratz l\'adreça electronica',
37 noUrl: 'Entratz l\'URL del ligam',
38 other: '<autre>',
39 popupDependent: 'Dependenta (Netscape)',
40 popupFeatures: 'Caracteristicas de la fenèstra sorgissenta',
41 popupFullScreen: 'Ecran complet (IE)',
42 popupLeft: 'A esquèrra',
43 popupLocationBar: 'Barra d\'adreça',
44 popupMenuBar: 'Barra de menú',
45 popupResizable: 'Redimensionable',
46 popupScrollBars: 'Barras de desfilament',
47 popupStatusBar: 'Barra d\'estat',
48 popupToolbar: 'Barra d\'aisinas',
49 popupTop: 'Amont',
50 rel: 'Relacion',
51 selectAnchor: 'Seleccionar una ancòra',
52 styles: 'Estil',
53 tabIndex: 'Indici de tabulacion',
54 target: 'Cibla',
55 targetFrame: '<quadre>',
56 targetFrameName: 'Nom del quadre afectat',
57 targetPopup: '<fenèstra sorgissenta>',
58 targetPopupName: 'Nom de la fenèstra sorgissenta',
59 title: 'Ligam',
60 toAnchor: 'Ancòra',
61 toEmail: 'Corrièl',
62 toUrl: 'URL',
63 toolbar: 'Ligam',
64 type: 'Tipe de ligam',
65 unlink: 'Suprimir lo ligam',
66 upload: 'Mandar'
67} );
diff --git a/sources/plugins/link/lang/pl.js b/sources/plugins/link/lang/pl.js
new file mode 100644
index 0000000..41858d3
--- /dev/null
+++ b/sources/plugins/link/lang/pl.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'pl', {
6 acccessKey: 'Klawisz dostępu',
7 advanced: 'Zaawansowane',
8 advisoryContentType: 'Typ MIME obiektu docelowego',
9 advisoryTitle: 'Opis obiektu docelowego',
10 anchor: {
11 toolbar: 'Wstaw/edytuj kotwicę',
12 menu: 'Właściwości kotwicy',
13 title: 'Właściwości kotwicy',
14 name: 'Nazwa kotwicy',
15 errorName: 'Wpisz nazwę kotwicy',
16 remove: 'Usuń kotwicę'
17 },
18 anchorId: 'Wg identyfikatora',
19 anchorName: 'Wg nazwy',
20 charset: 'Kodowanie znaków obiektu docelowego',
21 cssClasses: 'Nazwa klasy CSS',
22 download: 'Wymuś pobieranie',
23 displayText: 'Wyświetlany tekst',
24 emailAddress: 'Adres e-mail',
25 emailBody: 'Treść',
26 emailSubject: 'Temat',
27 id: 'Id',
28 info: 'Informacje ',
29 langCode: 'Kod języka',
30 langDir: 'Kierunek tekstu',
31 langDirLTR: 'Od lewej do prawej (LTR)',
32 langDirRTL: 'Od prawej do lewej (RTL)',
33 menu: 'Edytuj odnośnik',
34 name: 'Nazwa',
35 noAnchors: '(W dokumencie nie zdefiniowano żadnych kotwic)',
36 noEmail: 'Podaj adres e-mail',
37 noUrl: 'Podaj adres URL',
38 other: '<inny>',
39 popupDependent: 'Okno zależne (Netscape)',
40 popupFeatures: 'Właściwości wyskakującego okna',
41 popupFullScreen: 'Pełny ekran (IE)',
42 popupLeft: 'Pozycja w poziomie',
43 popupLocationBar: 'Pasek adresu',
44 popupMenuBar: 'Pasek menu',
45 popupResizable: 'Skalowalny',
46 popupScrollBars: 'Paski przewijania',
47 popupStatusBar: 'Pasek statusu',
48 popupToolbar: 'Pasek narzędzi',
49 popupTop: 'Pozycja w pionie',
50 rel: 'Relacja',
51 selectAnchor: 'Wybierz kotwicę',
52 styles: 'Styl',
53 tabIndex: 'Indeks kolejności',
54 target: 'Obiekt docelowy',
55 targetFrame: '<ramka>',
56 targetFrameName: 'Nazwa ramki docelowej',
57 targetPopup: '<wyskakujące okno>',
58 targetPopupName: 'Nazwa wyskakującego okna',
59 title: 'Odnośnik',
60 toAnchor: 'Odnośnik wewnątrz strony (kotwica)',
61 toEmail: 'Adres e-mail',
62 toUrl: 'Adres URL',
63 toolbar: 'Wstaw/edytuj odnośnik',
64 type: 'Typ odnośnika',
65 unlink: 'Usuń odnośnik',
66 upload: 'Wyślij'
67} );
diff --git a/sources/plugins/link/lang/pt-br.js b/sources/plugins/link/lang/pt-br.js
new file mode 100644
index 0000000..0c43149
--- /dev/null
+++ b/sources/plugins/link/lang/pt-br.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'pt-br', {
6 acccessKey: 'Chave de Acesso',
7 advanced: 'Avançado',
8 advisoryContentType: 'Tipo de Conteúdo',
9 advisoryTitle: 'Título',
10 anchor: {
11 toolbar: 'Inserir/Editar Âncora',
12 menu: 'Formatar Âncora',
13 title: 'Formatar Âncora',
14 name: 'Nome da Âncora',
15 errorName: 'Por favor, digite o nome da âncora',
16 remove: 'Remover Âncora'
17 },
18 anchorId: 'Id da âncora',
19 anchorName: 'Nome da âncora',
20 charset: 'Charset do Link',
21 cssClasses: 'Classe de CSS',
22 download: 'Forçar Download',
23 displayText: 'Exibir Texto',
24 emailAddress: 'Endereço E-Mail',
25 emailBody: 'Corpo da Mensagem',
26 emailSubject: 'Assunto da Mensagem',
27 id: 'Id',
28 info: 'Informações',
29 langCode: 'Direção do idioma',
30 langDir: 'Direção do idioma',
31 langDirLTR: 'Esquerda para Direita (LTR)',
32 langDirRTL: 'Direita para Esquerda (RTL)',
33 menu: 'Editar Link',
34 name: 'Nome',
35 noAnchors: '(Não há âncoras no documento)',
36 noEmail: 'Por favor, digite o endereço de e-mail',
37 noUrl: 'Por favor, digite o endereço do Link',
38 other: '<outro>',
39 popupDependent: 'Dependente (Netscape)',
40 popupFeatures: 'Propriedades da Janela Pop-up',
41 popupFullScreen: 'Modo Tela Cheia (IE)',
42 popupLeft: 'Esquerda',
43 popupLocationBar: 'Barra de Endereços',
44 popupMenuBar: 'Barra de Menus',
45 popupResizable: 'Redimensionável',
46 popupScrollBars: 'Barras de Rolagem',
47 popupStatusBar: 'Barra de Status',
48 popupToolbar: 'Barra de Ferramentas',
49 popupTop: 'Topo',
50 rel: 'Tipo de Relação',
51 selectAnchor: 'Selecione uma âncora',
52 styles: 'Estilos',
53 tabIndex: 'Índice de Tabulação',
54 target: 'Destino',
55 targetFrame: '<frame>',
56 targetFrameName: 'Nome do Frame de Destino',
57 targetPopup: '<janela popup>',
58 targetPopupName: 'Nome da Janela Pop-up',
59 title: 'Editar Link',
60 toAnchor: 'Âncora nesta página',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Inserir/Editar Link',
64 type: 'Tipo de hiperlink',
65 unlink: 'Remover Link',
66 upload: 'Enviar ao Servidor'
67} );
diff --git a/sources/plugins/link/lang/pt.js b/sources/plugins/link/lang/pt.js
new file mode 100644
index 0000000..5f45548
--- /dev/null
+++ b/sources/plugins/link/lang/pt.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'pt', {
6 acccessKey: 'Chave de acesso',
7 advanced: 'Avançado',
8 advisoryContentType: 'Tipo de conteúdo',
9 advisoryTitle: 'Título',
10 anchor: {
11 toolbar: ' Inserir/Editar âncora',
12 menu: 'Propriedades da âncora',
13 title: 'Propriedades da âncora',
14 name: 'Nome da âncora',
15 errorName: 'Por favor, introduza o nome da âncora',
16 remove: 'Remover âncora'
17 },
18 anchorId: 'Por ID do elemento',
19 anchorName: 'Por Nome de Referência',
20 charset: 'Fonte de caracteres vinculado',
21 cssClasses: 'Classes de Estilo',
22 download: 'Force Download', // MISSING
23 displayText: 'Mostrar texto',
24 emailAddress: 'Endereço de email',
25 emailBody: 'Corpo da mensagem',
26 emailSubject: 'Título de mensagem',
27 id: 'ID',
28 info: 'Informação da hiperligação',
29 langCode: 'Código de idioma',
30 langDir: 'Orientação de idioma',
31 langDirLTR: 'Esquerda para a Direita (EPD)',
32 langDirRTL: 'Direita para a Esquerda (DPE)',
33 menu: 'Editar hiperligação',
34 name: 'Nome',
35 noAnchors: '(Não existem âncoras no documento)',
36 noEmail: 'Por favor, escreva o endereço de email',
37 noUrl: 'Por favor, introduza o endereço URL',
38 other: '<outro>',
39 popupDependent: 'Dependente (Netscape)',
40 popupFeatures: 'Características de janela flutuante',
41 popupFullScreen: 'Janela completa (IE)',
42 popupLeft: 'Posição esquerda',
43 popupLocationBar: 'Barra de localização',
44 popupMenuBar: 'Barra de menu',
45 popupResizable: 'Redimensionável',
46 popupScrollBars: 'Barras de deslocamento',
47 popupStatusBar: 'Barra de estado',
48 popupToolbar: 'Barra de ferramentas',
49 popupTop: 'Posição topo',
50 rel: 'Relação',
51 selectAnchor: 'Selecionar âncora',
52 styles: 'Estilo',
53 tabIndex: 'Índice de tabulação',
54 target: 'Alvo',
55 targetFrame: '<frame>',
56 targetFrameName: 'Nome da janela de destino',
57 targetPopup: '<janela de popup>',
58 targetPopupName: 'Nome da janela flutuante',
59 title: 'Hiperligação',
60 toAnchor: 'Ligar a âncora no texto',
61 toEmail: 'Email',
62 toUrl: 'URL',
63 toolbar: 'Hiperligação',
64 type: 'Tipo de hiperligação',
65 unlink: 'Eliminar hiperligação',
66 upload: 'Carregar'
67} );
diff --git a/sources/plugins/link/lang/ro.js b/sources/plugins/link/lang/ro.js
new file mode 100644
index 0000000..a5d79a3
--- /dev/null
+++ b/sources/plugins/link/lang/ro.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ro', {
6 acccessKey: 'Tasta de acces',
7 advanced: 'Avansat',
8 advisoryContentType: 'Tipul consultativ al titlului',
9 advisoryTitle: 'Titlul consultativ',
10 anchor: {
11 toolbar: 'Inserează/Editează ancoră',
12 menu: 'Proprietăţi ancoră',
13 title: 'Proprietăţi ancoră',
14 name: 'Numele ancorei',
15 errorName: 'Vă rugăm scrieţi numele ancorei',
16 remove: 'Elimină ancora'
17 },
18 anchorId: 'după Id-ul elementului',
19 anchorName: 'după numele ancorei',
20 charset: 'Setul de caractere al resursei legate',
21 cssClasses: 'Clasele cu stilul paginii (CSS)',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Adresă de e-mail',
25 emailBody: 'Opțiuni Meniu Contextual',
26 emailSubject: 'Subiectul mesajului',
27 id: 'Id',
28 info: 'Informaţii despre link (Legătură web)',
29 langCode: 'Direcţia cuvintelor',
30 langDir: 'Direcţia cuvintelor',
31 langDirLTR: 'stânga-dreapta (LTR)',
32 langDirRTL: 'dreapta-stânga (RTL)',
33 menu: 'Editează Link',
34 name: 'Nume',
35 noAnchors: '(Nicio ancoră disponibilă în document)',
36 noEmail: 'Vă rugăm să scrieţi adresa de e-mail',
37 noUrl: 'Vă rugăm să scrieţi URL-ul',
38 other: '<alt>',
39 popupDependent: 'Dependent (Netscape)',
40 popupFeatures: 'Proprietăţile ferestrei popup',
41 popupFullScreen: 'Tot ecranul (Full Screen)(IE)',
42 popupLeft: 'Poziţia la stânga',
43 popupLocationBar: 'Bara de locaţie',
44 popupMenuBar: 'Bara de meniu',
45 popupResizable: 'Redimensionabil',
46 popupScrollBars: 'Bare de derulare',
47 popupStatusBar: 'Bara de status',
48 popupToolbar: 'Bara de opţiuni',
49 popupTop: 'Poziţia la dreapta',
50 rel: 'Relație',
51 selectAnchor: 'Selectaţi o ancoră',
52 styles: 'Stil',
53 tabIndex: 'Indexul tabului',
54 target: 'Ţintă (Target)',
55 targetFrame: '<frame>',
56 targetFrameName: 'Numele frameului ţintă',
57 targetPopup: '<fereastra popup>',
58 targetPopupName: 'Numele ferestrei popup',
59 title: 'Link (Legătură web)',
60 toAnchor: 'Ancoră în această pagină',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Inserează/Editează link (legătură web)',
64 type: 'Tipul link-ului (al legăturii web)',
65 unlink: 'Înlătură link (legătură web)',
66 upload: 'Încarcă'
67} );
diff --git a/sources/plugins/link/lang/ru.js b/sources/plugins/link/lang/ru.js
new file mode 100644
index 0000000..7f4b775
--- /dev/null
+++ b/sources/plugins/link/lang/ru.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ru', {
6 acccessKey: 'Клавиша доступа',
7 advanced: 'Дополнительно',
8 advisoryContentType: 'Тип содержимого',
9 advisoryTitle: 'Заголовок',
10 anchor: {
11 toolbar: 'Вставить / редактировать якорь',
12 menu: 'Изменить якорь',
13 title: 'Свойства якоря',
14 name: 'Имя якоря',
15 errorName: 'Пожалуйста, введите имя якоря',
16 remove: 'Удалить якорь'
17 },
18 anchorId: 'По идентификатору',
19 anchorName: 'По имени',
20 charset: 'Кодировка ресурса',
21 cssClasses: 'Классы CSS',
22 download: 'Force Download', // MISSING
23 displayText: 'Отображаемый текст',
24 emailAddress: 'Email адрес',
25 emailBody: 'Текст сообщения',
26 emailSubject: 'Тема сообщения',
27 id: 'Идентификатор',
28 info: 'Информация о ссылке',
29 langCode: 'Код языка',
30 langDir: 'Направление текста',
31 langDirLTR: 'Слева направо (LTR)',
32 langDirRTL: 'Справа налево (RTL)',
33 menu: 'Редактировать ссылку',
34 name: 'Имя',
35 noAnchors: '(В документе нет ни одного якоря)',
36 noEmail: 'Пожалуйста, введите email адрес',
37 noUrl: 'Пожалуйста, введите ссылку',
38 other: '<другой>',
39 popupDependent: 'Зависимое (Netscape)',
40 popupFeatures: 'Параметры всплывающего окна',
41 popupFullScreen: 'Полноэкранное (IE)',
42 popupLeft: 'Отступ слева',
43 popupLocationBar: 'Панель адреса',
44 popupMenuBar: 'Панель меню',
45 popupResizable: 'Изменяемый размер',
46 popupScrollBars: 'Полосы прокрутки',
47 popupStatusBar: 'Строка состояния',
48 popupToolbar: 'Панель инструментов',
49 popupTop: 'Отступ сверху',
50 rel: 'Отношение',
51 selectAnchor: 'Выберите якорь',
52 styles: 'Стиль',
53 tabIndex: 'Последовательность перехода',
54 target: 'Цель',
55 targetFrame: '<фрейм>',
56 targetFrameName: 'Имя целевого фрейма',
57 targetPopup: '<всплывающее окно>',
58 targetPopupName: 'Имя всплывающего окна',
59 title: 'Ссылка',
60 toAnchor: 'Ссылка на якорь в тексте',
61 toEmail: 'Email',
62 toUrl: 'Ссылка',
63 toolbar: 'Вставить/Редактировать ссылку',
64 type: 'Тип ссылки',
65 unlink: 'Убрать ссылку',
66 upload: 'Загрузка'
67} );
diff --git a/sources/plugins/link/lang/si.js b/sources/plugins/link/lang/si.js
new file mode 100644
index 0000000..7ad9935
--- /dev/null
+++ b/sources/plugins/link/lang/si.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'si', {
6 acccessKey: 'ප්‍රවේශ යතුර',
7 advanced: 'දීය',
8 advisoryContentType: 'උපදේශාත්මක අන්තර්ගත ආකාරය',
9 advisoryTitle: 'උපදේශාත්මක නාමය',
10 anchor: {
11 toolbar: 'ආධාරය',
12 menu: 'ආධාරය වෙනස් කිරීම',
13 title: 'ආධාරක ',
14 name: 'ආධාරකයේ නාමය',
15 errorName: 'කරුණාකර ආධාරකයේ නාමය ඇතුල් කරන්න',
16 remove: 'ආධාරකය ඉවත් කිරීම'
17 },
18 anchorId: 'By Element Id', // MISSING
19 anchorName: 'By Anchor Name', // MISSING
20 charset: 'Linked Resource Charset', // MISSING
21 cssClasses: 'විලාසපත්‍ර පන්තිය',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail Address', // MISSING
25 emailBody: 'Message Body', // MISSING
26 emailSubject: 'Message Subject', // MISSING
27 id: 'අංකය',
28 info: 'Link Info', // MISSING
29 langCode: 'භාෂා කේතය',
30 langDir: 'භාෂා දිශාව',
31 langDirLTR: 'වමේසිට දකුණුට',
32 langDirRTL: 'දකුණේ සිට වමට',
33 menu: 'Edit Link', // MISSING
34 name: 'නම',
35 noAnchors: '(No anchors available in the document)', // MISSING
36 noEmail: 'Please type the e-mail address', // MISSING
37 noUrl: 'Please type the link URL', // MISSING
38 other: '<other>', // MISSING
39 popupDependent: 'Dependent (Netscape)', // MISSING
40 popupFeatures: 'Popup Window Features', // MISSING
41 popupFullScreen: 'Full Screen (IE)', // MISSING
42 popupLeft: 'Left Position', // MISSING
43 popupLocationBar: 'Location Bar', // MISSING
44 popupMenuBar: 'Menu Bar', // MISSING
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Scroll Bars', // MISSING
47 popupStatusBar: 'Status Bar', // MISSING
48 popupToolbar: 'Toolbar', // MISSING
49 popupTop: 'Top Position', // MISSING
50 rel: 'Relationship', // MISSING
51 selectAnchor: 'Select an Anchor', // MISSING
52 styles: 'විලාසය',
53 tabIndex: 'Tab Index', // MISSING
54 target: 'අරමුණ',
55 targetFrame: '<frame>', // MISSING
56 targetFrameName: 'Target Frame Name', // MISSING
57 targetPopup: '<popup window>', // MISSING
58 targetPopupName: 'Popup Window Name', // MISSING
59 title: 'සබැඳිය',
60 toAnchor: 'Link to anchor in the text', // MISSING
61 toEmail: 'E-mail', // MISSING
62 toUrl: 'URL',
63 toolbar: 'සබැඳිය',
64 type: 'Link Type', // MISSING
65 unlink: 'Unlink', // MISSING
66 upload: 'උඩුගතකිරීම'
67} );
diff --git a/sources/plugins/link/lang/sk.js b/sources/plugins/link/lang/sk.js
new file mode 100644
index 0000000..87b60bd
--- /dev/null
+++ b/sources/plugins/link/lang/sk.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sk', {
6 acccessKey: 'Prístupový kľúč',
7 advanced: 'Rozšírené',
8 advisoryContentType: 'Pomocný typ obsahu',
9 advisoryTitle: 'Pomocný titulok',
10 anchor: {
11 toolbar: 'Kotva',
12 menu: 'Upraviť kotvu',
13 title: 'Vlastnosti kotvy',
14 name: 'Názov kotvy',
15 errorName: 'Zadajte prosím názov kotvy',
16 remove: 'Odstrániť kotvu'
17 },
18 anchorId: 'Podľa Id objektu',
19 anchorName: 'Podľa mena kotvy',
20 charset: 'Priradená znaková sada',
21 cssClasses: 'Triedy štýlu',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mailová adresa',
25 emailBody: 'Telo správy',
26 emailSubject: 'Predmet správy',
27 id: 'Id',
28 info: 'Informácie o odkaze',
29 langCode: 'Orientácia jazyka',
30 langDir: 'Orientácia jazyka',
31 langDirLTR: 'Zľava doprava (LTR)',
32 langDirRTL: 'Sprava doľava (RTL)',
33 menu: 'Upraviť odkaz',
34 name: 'Názov',
35 noAnchors: '(V dokumente nie sú dostupné žiadne kotvy)',
36 noEmail: 'Zadajte prosím e-mailovú adresu',
37 noUrl: 'Zadajte prosím URL odkazu',
38 other: '<iný>',
39 popupDependent: 'Závislosť (Netscape)',
40 popupFeatures: 'Vlastnosti vyskakovacieho okna',
41 popupFullScreen: 'Celá obrazovka (IE)',
42 popupLeft: 'Ľavý okraj',
43 popupLocationBar: 'Panel umiestnenia (location bar)',
44 popupMenuBar: 'Panel ponuky (menu bar)',
45 popupResizable: 'Meniteľná veľkosť (resizable)',
46 popupScrollBars: 'Posuvníky (scroll bars)',
47 popupStatusBar: 'Stavový riadok (status bar)',
48 popupToolbar: 'Panel nástrojov (toolbar)',
49 popupTop: 'Horný okraj',
50 rel: 'Vzťah (rel)',
51 selectAnchor: 'Vybrať kotvu',
52 styles: 'Štýl',
53 tabIndex: 'Poradie prvku (tab index)',
54 target: 'Cieľ',
55 targetFrame: '<rámec>',
56 targetFrameName: 'Názov rámu cieľa',
57 targetPopup: '<vyskakovacie okno>',
58 targetPopupName: 'Názov vyskakovacieho okna',
59 title: 'Odkaz',
60 toAnchor: 'Odkaz na kotvu v texte',
61 toEmail: 'E-mail',
62 toUrl: 'URL',
63 toolbar: 'Odkaz',
64 type: 'Typ odkazu',
65 unlink: 'Odstrániť odkaz',
66 upload: 'Nahrať'
67} );
diff --git a/sources/plugins/link/lang/sl.js b/sources/plugins/link/lang/sl.js
new file mode 100644
index 0000000..911203f
--- /dev/null
+++ b/sources/plugins/link/lang/sl.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sl', {
6 acccessKey: 'Tipka za dostop',
7 advanced: 'Napredno',
8 advisoryContentType: 'Predlagana vrsta vsebine',
9 advisoryTitle: 'Predlagani naslov',
10 anchor: {
11 toolbar: 'Sidro',
12 menu: 'Uredi sidro',
13 title: 'Lastnosti sidra',
14 name: 'Ime sidra',
15 errorName: 'Prosimo, vnesite ime sidra',
16 remove: 'Odstrani sidro'
17 },
18 anchorId: 'Po ID-ju elementa',
19 anchorName: 'Po imenu sidra',
20 charset: 'Nabor znakov povezanega vira',
21 cssClasses: 'Razredi slogovne predloge',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-poštni naslov',
25 emailBody: 'Telo sporočila',
26 emailSubject: 'Zadeva sporočila',
27 id: 'Id',
28 info: 'Podatki o povezavi',
29 langCode: 'Koda jezika',
30 langDir: 'Smer jezika',
31 langDirLTR: 'Od leve proti desni (LTR)',
32 langDirRTL: 'Od desne proti levi (RTL)',
33 menu: 'Uredi povezavo',
34 name: 'Ime',
35 noAnchors: '(V tem dokumentu ni sider)',
36 noEmail: 'Vnesite e-poštni naslov',
37 noUrl: 'Vnesite URL povezave',
38 other: '<drugo>',
39 popupDependent: 'Podokno (Netscape)',
40 popupFeatures: 'Značilnosti pojavnega okna',
41 popupFullScreen: 'Celozaslonsko (IE)',
42 popupLeft: 'Lega levo',
43 popupLocationBar: 'Naslovna vrstica',
44 popupMenuBar: 'Menijska vrstica',
45 popupResizable: 'Spremenljive velikosti',
46 popupScrollBars: 'Drsniki',
47 popupStatusBar: 'Vrstica stanja',
48 popupToolbar: 'Orodna vrstica',
49 popupTop: 'Lega na vrhu',
50 rel: 'Odnos',
51 selectAnchor: 'Izberite sidro',
52 styles: 'Slog',
53 tabIndex: 'Številka tabulatorja',
54 target: 'Cilj',
55 targetFrame: '<okvir>',
56 targetFrameName: 'Ime ciljnega okvirja',
57 targetPopup: '<pojavno okno>',
58 targetPopupName: 'Ime pojavnega okna',
59 title: 'Povezava',
60 toAnchor: 'Sidro na tej strani',
61 toEmail: 'E-pošta',
62 toUrl: 'URL',
63 toolbar: 'Vstavi/uredi povezavo',
64 type: 'Vrsta povezave',
65 unlink: 'Odstrani povezavo',
66 upload: 'Naloži'
67} );
diff --git a/sources/plugins/link/lang/sq.js b/sources/plugins/link/lang/sq.js
new file mode 100644
index 0000000..83b2fb7
--- /dev/null
+++ b/sources/plugins/link/lang/sq.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sq', {
6 acccessKey: 'Sipas ID-së së Elementit',
7 advanced: 'Të përparuara',
8 advisoryContentType: 'Lloji i Përmbajtjes Këshillimore',
9 advisoryTitle: 'Titull',
10 anchor: {
11 toolbar: 'Spirancë',
12 menu: 'Redakto Spirancën',
13 title: 'Anchor Properties', // MISSING
14 name: 'Emri i Spirancës',
15 errorName: 'Ju lutemi shkruani emrin e spirancës',
16 remove: 'Largo Spirancën'
17 },
18 anchorId: 'Sipas ID-së së Elementit',
19 anchorName: 'Sipas Emrit të Spirancës',
20 charset: 'Seti i Karaktereve të Burimeve të Nëdlidhura',
21 cssClasses: 'Klasa stili CSS',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Posta Elektronike',
25 emailBody: 'Trupi i Porosisë',
26 emailSubject: 'Titulli i Porosisë',
27 id: 'Id',
28 info: 'Informacione të Nyjes',
29 langCode: 'Kod gjuhe',
30 langDir: 'Drejtim teksti',
31 langDirLTR: 'Nga e majta në të djathë (LTR)',
32 langDirRTL: 'Nga e djathta në të majtë (RTL)',
33 menu: 'Redakto Nyjen',
34 name: 'Emër',
35 noAnchors: '(Nuk ka asnjë spirancë në dokument)',
36 noEmail: 'Ju lutemi shkruani postën elektronike',
37 noUrl: 'Ju lutemi shkruani URL-në e nyjes',
38 other: '<tjetër>',
39 popupDependent: 'E Varur (Netscape)',
40 popupFeatures: 'Karakteristikat e Dritares së Dialogut',
41 popupFullScreen: 'Ekran i Plotë (IE)',
42 popupLeft: 'Pozita Majtas',
43 popupLocationBar: 'Shiriti i Lokacionit',
44 popupMenuBar: 'Shiriti i Menysë',
45 popupResizable: 'I ndryshueshëm',
46 popupScrollBars: 'Shiritat zvarritës',
47 popupStatusBar: 'Shiriti i Statutit',
48 popupToolbar: 'Shiriti i Mejteve',
49 popupTop: 'Top Pozita',
50 rel: 'Marrëdhëniet',
51 selectAnchor: 'Përzgjidh një Spirancë',
52 styles: 'Stil',
53 tabIndex: 'Indeksi i fletave',
54 target: 'Objektivi',
55 targetFrame: '<frame>',
56 targetFrameName: 'Emri i Kornizës së Synuar',
57 targetPopup: '<popup window>',
58 targetPopupName: 'Emri i Dritares së Dialogut',
59 title: 'Nyja',
60 toAnchor: 'Lidhu me spirancën në tekst',
61 toEmail: 'Posta Elektronike',
62 toUrl: 'URL',
63 toolbar: 'Nyja',
64 type: 'Lloji i Nyjes',
65 unlink: 'Largo Nyjen',
66 upload: 'Ngarko'
67} );
diff --git a/sources/plugins/link/lang/sr-latn.js b/sources/plugins/link/lang/sr-latn.js
new file mode 100644
index 0000000..8f6f6a7
--- /dev/null
+++ b/sources/plugins/link/lang/sr-latn.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sr-latn', {
6 acccessKey: 'Pristupni taster',
7 advanced: 'Napredni tagovi',
8 advisoryContentType: 'Advisory vrsta sadržaja',
9 advisoryTitle: 'Advisory naslov',
10 anchor: {
11 toolbar: 'Unesi/izmeni sidro',
12 menu: 'Osobine sidra',
13 title: 'Osobine sidra',
14 name: 'Naziv sidra',
15 errorName: 'Unesite naziv sidra',
16 remove: 'Ukloni sidro'
17 },
18 anchorId: 'Po Id-u elementa',
19 anchorName: 'Po nazivu sidra',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet klase',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'E-Mail adresa',
25 emailBody: 'Sadržaj poruke',
26 emailSubject: 'Naslov',
27 id: 'Id',
28 info: 'Link Info',
29 langCode: 'Smer jezika',
30 langDir: 'Smer jezika',
31 langDirLTR: 'S leva na desno (LTR)',
32 langDirRTL: 'S desna na levo (RTL)',
33 menu: 'Izmeni link',
34 name: 'Naziv',
35 noAnchors: '(Nema dostupnih sidra)',
36 noEmail: 'Otkucajte adresu elektronske pote',
37 noUrl: 'Unesite URL linka',
38 other: '<остало>',
39 popupDependent: 'Zavisno (Netscape)',
40 popupFeatures: 'Mogućnosti popup prozora',
41 popupFullScreen: 'Prikaz preko celog ekrana (IE)',
42 popupLeft: 'Od leve ivice ekrana (px)',
43 popupLocationBar: 'Lokacija',
44 popupMenuBar: 'Kontekstni meni',
45 popupResizable: 'Promenljive veličine',
46 popupScrollBars: 'Scroll bar',
47 popupStatusBar: 'Statusna linija',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Od vrha ekrana (px)',
50 rel: 'Odnos',
51 selectAnchor: 'Odaberi sidro',
52 styles: 'Stil',
53 tabIndex: 'Tab indeks',
54 target: 'Meta',
55 targetFrame: '<okvir>',
56 targetFrameName: 'Naziv odredišnog frejma',
57 targetPopup: '<popup prozor>',
58 targetPopupName: 'Naziv popup prozora',
59 title: 'Link',
60 toAnchor: 'Sidro na ovoj stranici',
61 toEmail: 'E-Mail',
62 toUrl: 'URL',
63 toolbar: 'Unesi/izmeni link',
64 type: 'Vrsta linka',
65 unlink: 'Ukloni link',
66 upload: 'Pošalji'
67} );
diff --git a/sources/plugins/link/lang/sr.js b/sources/plugins/link/lang/sr.js
new file mode 100644
index 0000000..18689da
--- /dev/null
+++ b/sources/plugins/link/lang/sr.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sr', {
6 acccessKey: 'Приступни тастер',
7 advanced: 'Напредни тагови',
8 advisoryContentType: 'Advisory врста садржаја',
9 advisoryTitle: 'Advisory наслов',
10 anchor: {
11 toolbar: 'Унеси/измени сидро',
12 menu: 'Особине сидра',
13 title: 'Особине сидра',
14 name: 'Име сидра',
15 errorName: 'Молимо Вас да унесете име сидра',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'Пo Ид-jу елемента',
19 anchorName: 'По називу сидра',
20 charset: 'Linked Resource Charset',
21 cssClasses: 'Stylesheet класе',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Адреса електронске поште',
25 emailBody: 'Садржај поруке',
26 emailSubject: 'Наслов',
27 id: 'Ид',
28 info: 'Линк инфо',
29 langCode: 'Смер језика',
30 langDir: 'Смер језика',
31 langDirLTR: 'С лева на десно (LTR)',
32 langDirRTL: 'С десна на лево (RTL)',
33 menu: 'Промени линк',
34 name: 'Назив',
35 noAnchors: '(Нема доступних сидра)',
36 noEmail: 'Откуцајте адресу електронске поште',
37 noUrl: 'Унесите УРЛ линка',
38 other: '<друго>',
39 popupDependent: 'Зависно (Netscape)',
40 popupFeatures: 'Могућности искачућег прозора',
41 popupFullScreen: 'Приказ преко целог екрана (ИE)',
42 popupLeft: 'Од леве ивице екрана (пиксела)',
43 popupLocationBar: 'Локација',
44 popupMenuBar: 'Контекстни мени',
45 popupResizable: 'Величина се мења',
46 popupScrollBars: 'Скрол бар',
47 popupStatusBar: 'Статусна линија',
48 popupToolbar: 'Toolbar',
49 popupTop: 'Од врха екрана (пиксела)',
50 rel: 'Однос',
51 selectAnchor: 'Одабери сидро',
52 styles: 'Стил',
53 tabIndex: 'Таб индекс',
54 target: 'Meтa',
55 targetFrame: '<оквир>',
56 targetFrameName: 'Назив одредишног фрејма',
57 targetPopup: '<искачући прозор>',
58 targetPopupName: 'Назив искачућег прозора',
59 title: 'Линк',
60 toAnchor: 'Сидро на овој страници',
61 toEmail: 'Eлектронска пошта',
62 toUrl: 'УРЛ',
63 toolbar: 'Унеси/измени линк',
64 type: 'Врста линка',
65 unlink: 'Уклони линк',
66 upload: 'Пошаљи'
67} );
diff --git a/sources/plugins/link/lang/sv.js b/sources/plugins/link/lang/sv.js
new file mode 100644
index 0000000..bc9f4c2
--- /dev/null
+++ b/sources/plugins/link/lang/sv.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'sv', {
6 acccessKey: 'Behörighetsnyckel',
7 advanced: 'Avancerad',
8 advisoryContentType: 'Innehållstyp',
9 advisoryTitle: 'Titel',
10 anchor: {
11 toolbar: 'Infoga/Redigera ankarlänk',
12 menu: 'Egenskaper för ankarlänk',
13 title: 'Egenskaper för ankarlänk',
14 name: 'Ankarnamn',
15 errorName: 'Var god ange ett ankarnamn',
16 remove: 'Radera ankare'
17 },
18 anchorId: 'Efter element-id',
19 anchorName: 'Efter ankarnamn',
20 charset: 'Teckenuppställning',
21 cssClasses: 'Stilmall',
22 download: 'Tvinga nerladdning',
23 displayText: 'Visningstext',
24 emailAddress: 'E-postadress',
25 emailBody: 'Innehåll',
26 emailSubject: 'Ämne',
27 id: 'Id',
28 info: 'Länkinformation',
29 langCode: 'Språkkod',
30 langDir: 'Språkriktning',
31 langDirLTR: 'Vänster till höger (VTH)',
32 langDirRTL: 'Höger till vänster (HTV)',
33 menu: 'Redigera länk',
34 name: 'Namn',
35 noAnchors: '(Inga ankare kunde hittas)',
36 noEmail: 'Var god ange e-postadress',
37 noUrl: 'Var god ange länkens URL',
38 other: '<annan>',
39 popupDependent: 'Beroende (endast Netscape)',
40 popupFeatures: 'Popup-fönstrets egenskaper',
41 popupFullScreen: 'Helskärm (endast IE)',
42 popupLeft: 'Position från vänster',
43 popupLocationBar: 'Adressfält',
44 popupMenuBar: 'Menyfält',
45 popupResizable: 'Skalbart',
46 popupScrollBars: 'Scrolllista',
47 popupStatusBar: 'Statusfält',
48 popupToolbar: 'Verktygsfält',
49 popupTop: 'Position från sidans topp',
50 rel: 'Förhållande',
51 selectAnchor: 'Välj ett ankare',
52 styles: 'Stilmall',
53 tabIndex: 'Tabindex',
54 target: 'Mål',
55 targetFrame: '<ram>',
56 targetFrameName: 'Målets ramnamn',
57 targetPopup: '<popup-fönster>',
58 targetPopupName: 'Popup-fönstrets namn',
59 title: 'Länk',
60 toAnchor: 'Länk till ankare i texten',
61 toEmail: 'E-post',
62 toUrl: 'URL',
63 toolbar: 'Infoga/Redigera länk',
64 type: 'Länktyp',
65 unlink: 'Radera länk',
66 upload: 'Ladda upp'
67} );
diff --git a/sources/plugins/link/lang/th.js b/sources/plugins/link/lang/th.js
new file mode 100644
index 0000000..593838d
--- /dev/null
+++ b/sources/plugins/link/lang/th.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'th', {
6 acccessKey: 'แอคเซส คีย์',
7 advanced: 'ขั้นสูง',
8 advisoryContentType: 'ชนิดของคำเกริ่นนำ',
9 advisoryTitle: 'คำเกริ่นนำ',
10 anchor: {
11 toolbar: 'แทรก/แก้ไข Anchor',
12 menu: 'รายละเอียด Anchor',
13 title: 'รายละเอียด Anchor',
14 name: 'ชื่อ Anchor',
15 errorName: 'กรุณาระบุชื่อของ Anchor',
16 remove: 'Remove Anchor'
17 },
18 anchorId: 'ไอดี',
19 anchorName: 'ชื่อ',
20 charset: 'ลิงค์เชื่อมโยงไปยังชุดตัวอักษร',
21 cssClasses: 'คลาสของไฟล์กำหนดลักษณะการแสดงผล',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'อีเมล์ (E-Mail)',
25 emailBody: 'ข้อความ',
26 emailSubject: 'หัวเรื่อง',
27 id: 'ไอดี',
28 info: 'รายละเอียด',
29 langCode: 'การเขียน-อ่านภาษา',
30 langDir: 'การเขียน-อ่านภาษา',
31 langDirLTR: 'จากซ้ายไปขวา (LTR)',
32 langDirRTL: 'จากขวามาซ้าย (RTL)',
33 menu: 'แก้ไข ลิงค์',
34 name: 'ชื่อ',
35 noAnchors: '(ยังไม่มีจุดเชื่อมโยงภายในหน้าเอกสารนี้)',
36 noEmail: 'กรุณาระบุอีเมล์ (E-mail)',
37 noUrl: 'กรุณาระบุที่อยู่อ้างอิงออนไลน์ (URL)',
38 other: '<อื่น ๆ>',
39 popupDependent: 'แสดงเต็มหน้าจอ (Netscape)',
40 popupFeatures: 'คุณสมบัติของหน้าจอเล็ก (Pop-up)',
41 popupFullScreen: 'แสดงเต็มหน้าจอ (IE5.5++ เท่านั้น)',
42 popupLeft: 'พิกัดซ้าย (Left Position)',
43 popupLocationBar: 'แสดงที่อยู่ของไฟล์',
44 popupMenuBar: 'แสดงแถบเมนู',
45 popupResizable: 'สามารถปรับขนาดได้',
46 popupScrollBars: 'แสดงแถบเลื่อน',
47 popupStatusBar: 'แสดงแถบสถานะ',
48 popupToolbar: 'แสดงแถบเครื่องมือ',
49 popupTop: 'พิกัดบน (Top Position)',
50 rel: 'ความสัมพันธ์',
51 selectAnchor: 'ระบุข้อมูลของจุดเชื่อมโยง (Anchor)',
52 styles: 'ลักษณะการแสดงผล',
53 tabIndex: 'ลำดับของ แท็บ',
54 target: 'การเปิดหน้าลิงค์',
55 targetFrame: '<เปิดในเฟรม>',
56 targetFrameName: 'ชื่อทาร์เก็ตเฟรม',
57 targetPopup: '<เปิดหน้าจอเล็ก (Pop-up)>',
58 targetPopupName: 'ระบุชื่อหน้าจอเล็ก (Pop-up)',
59 title: 'ลิงค์เชื่อมโยงเว็บ อีเมล์ รูปภาพ หรือไฟล์อื่นๆ',
60 toAnchor: 'จุดเชื่อมโยง (Anchor)',
61 toEmail: 'ส่งอีเมล์ (E-Mail)',
62 toUrl: 'ที่อยู่อ้างอิง URL',
63 toolbar: 'แทรก/แก้ไข ลิงค์',
64 type: 'ประเภทของลิงค์',
65 unlink: 'ลบ ลิงค์',
66 upload: 'อัพโหลดไฟล์'
67} );
diff --git a/sources/plugins/link/lang/tr.js b/sources/plugins/link/lang/tr.js
new file mode 100644
index 0000000..424ad7b
--- /dev/null
+++ b/sources/plugins/link/lang/tr.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'tr', {
6 acccessKey: 'Erişim Tuşu',
7 advanced: 'Gelişmiş',
8 advisoryContentType: 'Danışma İçerik Türü',
9 advisoryTitle: 'Danışma Başlığı',
10 anchor: {
11 toolbar: 'Bağlantı Ekle/Düzenle',
12 menu: 'Bağlantı Özellikleri',
13 title: 'Bağlantı Özellikleri',
14 name: 'Bağlantı Adı',
15 errorName: 'Lütfen bağlantı için ad giriniz',
16 remove: 'Bağlantıyı Kaldır'
17 },
18 anchorId: 'Eleman Kimlik Numarası ile',
19 anchorName: 'Bağlantı Adı ile',
20 charset: 'Bağlı Kaynak Karakter Gurubu',
21 cssClasses: 'Biçem Sayfası Sınıfları',
22 download: 'İndirmeye Zorla',
23 displayText: 'Gösterim Metni',
24 emailAddress: 'E-Posta Adresi',
25 emailBody: 'İleti Gövdesi',
26 emailSubject: 'İleti Konusu',
27 id: 'Id',
28 info: 'Link Bilgisi',
29 langCode: 'Dil Yönü',
30 langDir: 'Dil Yönü',
31 langDirLTR: 'Soldan Sağa (LTR)',
32 langDirRTL: 'Sağdan Sola (RTL)',
33 menu: 'Link Düzenle',
34 name: 'Ad',
35 noAnchors: '(Bu belgede hiç çapa yok)',
36 noEmail: 'Lütfen E-posta adresini yazın',
37 noUrl: 'Lütfen Link URL\'sini yazın',
38 other: '<diğer>',
39 popupDependent: 'Bağımlı (Netscape)',
40 popupFeatures: 'Yeni Açılan Pencere Özellikleri',
41 popupFullScreen: 'Tam Ekran (IE)',
42 popupLeft: 'Sola Göre Konum',
43 popupLocationBar: 'Yer Çubuğu',
44 popupMenuBar: 'Menü Çubuğu',
45 popupResizable: 'Resizable',
46 popupScrollBars: 'Kaydırma Çubukları',
47 popupStatusBar: 'Durum Çubuğu',
48 popupToolbar: 'Araç Çubuğu',
49 popupTop: 'Yukarıya Göre Konum',
50 rel: 'İlişki',
51 selectAnchor: 'Bağlantı Seç',
52 styles: 'Biçem',
53 tabIndex: 'Sekme İndeksi',
54 target: 'Hedef',
55 targetFrame: '<çerçeve>',
56 targetFrameName: 'Hedef Çerçeve Adı',
57 targetPopup: '<yeni açılan pencere>',
58 targetPopupName: 'Yeni Açılan Pencere Adı',
59 title: 'Link',
60 toAnchor: 'Bu sayfada çapa',
61 toEmail: 'E-Posta',
62 toUrl: 'URL',
63 toolbar: 'Link Ekle/Düzenle',
64 type: 'Link Türü',
65 unlink: 'Köprü Kaldır',
66 upload: 'Karşıya Yükle'
67} );
diff --git a/sources/plugins/link/lang/tt.js b/sources/plugins/link/lang/tt.js
new file mode 100644
index 0000000..25bd354
--- /dev/null
+++ b/sources/plugins/link/lang/tt.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'tt', {
6 acccessKey: 'Access Key', // MISSING
7 advanced: 'Киңәйтелгән көйләүләр',
8 advisoryContentType: 'Advisory Content Type', // MISSING
9 advisoryTitle: 'Киңәш исем',
10 anchor: {
11 toolbar: 'Якорь',
12 menu: 'Якорьне үзгәртү',
13 title: 'Якорь үзлекләре',
14 name: 'Якорь исеме',
15 errorName: 'Якорьнең исемен языгыз',
16 remove: 'Якорьне бетерү'
17 },
18 anchorId: 'Элемент идентификаторы буенча',
19 anchorName: 'Якорь исеме буенча',
20 charset: 'Linked Resource Charset', // MISSING
21 cssClasses: 'Стильләр класслары',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Электрон почта адресы',
25 emailBody: 'Хат эчтәлеге',
26 emailSubject: 'Хат темасы',
27 id: 'Идентификатор',
28 info: 'Сылталама тасвирламасы',
29 langCode: 'Тел коды',
30 langDir: 'Язылыш юнəлеше',
31 langDirLTR: 'Сулдан уңга язылыш (LTR)',
32 langDirRTL: 'Уңнан сулга язылыш (RTL)',
33 menu: 'Сылталамаyны үзгәртү',
34 name: 'Исем',
35 noAnchors: '(Әлеге документта якорьләр табылмады)',
36 noEmail: 'Электрон почта адресын языгыз',
37 noUrl: 'Сылталаманы языгыз',
38 other: '<бүтән>',
39 popupDependent: 'Бәйле (Netscape)',
40 popupFeatures: 'Popup Window Features', // MISSING
41 popupFullScreen: 'Тулы экран (IE)',
42 popupLeft: 'Left Position', // MISSING
43 popupLocationBar: 'Location Bar', // MISSING
44 popupMenuBar: 'Menu Bar', // MISSING
45 popupResizable: 'Resizable', // MISSING
46 popupScrollBars: 'Scroll Bars', // MISSING
47 popupStatusBar: 'Status Bar', // MISSING
48 popupToolbar: 'Toolbar', // MISSING
49 popupTop: 'Top Position', // MISSING
50 rel: 'Бәйләнеш',
51 selectAnchor: 'Якорьне сайлау',
52 styles: 'Стиль',
53 tabIndex: 'Tab Index', // MISSING
54 target: 'Максат',
55 targetFrame: '<frame>',
56 targetFrameName: 'Target Frame Name', // MISSING
57 targetPopup: '<popup window>',
58 targetPopupName: 'Попап тәрәзәсе исеме',
59 title: 'Сылталама',
60 toAnchor: 'Якорьне текст белән бәйләү',
61 toEmail: 'Электрон почта',
62 toUrl: 'Сылталама',
63 toolbar: 'Сылталама',
64 type: 'Сылталама төре',
65 unlink: 'Сылталаманы бетерү',
66 upload: 'Йөкләү'
67} );
diff --git a/sources/plugins/link/lang/ug.js b/sources/plugins/link/lang/ug.js
new file mode 100644
index 0000000..3cf75b4
--- /dev/null
+++ b/sources/plugins/link/lang/ug.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'ug', {
6 acccessKey: 'زىيارەت كۇنۇپكا',
7 advanced: 'ئالىي',
8 advisoryContentType: 'مەزمۇن تىپى',
9 advisoryTitle: 'ماۋزۇ',
10 anchor: {
11 toolbar: 'لەڭگەرلىك نۇقتا ئۇلانمىسى قىستۇر/تەھرىرلە',
12 menu: 'لەڭگەرلىك نۇقتا ئۇلانما خاسلىقى',
13 title: 'لەڭگەرلىك نۇقتا ئۇلانما خاسلىقى',
14 name: 'لەڭگەرلىك نۇقتا ئاتى',
15 errorName: 'لەڭگەرلىك نۇقتا ئاتىنى كىرگۈزۈڭ',
16 remove: 'لەڭگەرلىك نۇقتا ئۆچۈر'
17 },
18 anchorId: 'لەڭگەرلىك نۇقتا ID سى بويىچە',
19 anchorName: 'لەڭگەرلىك نۇقتا ئاتى بويىچە',
20 charset: 'ھەرپ كودلىنىشى',
21 cssClasses: 'ئۇسلۇب خىلى ئاتى',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'ئادرېس',
25 emailBody: 'مەزمۇن',
26 emailSubject: 'ماۋزۇ',
27 id: 'ID',
28 info: 'ئۇلانما ئۇچۇرى',
29 langCode: 'تىل كودى',
30 langDir: 'تىل يۆنىلىشى',
31 langDirLTR: 'سولدىن ئوڭغا (LTR)',
32 langDirRTL: 'ئوڭدىن سولغا (RTL)',
33 menu: 'ئۇلانما تەھرىر',
34 name: 'ئات',
35 noAnchors: '(بۇ پۈتۈكتە ئىشلەتكىلى بولىدىغان لەڭگەرلىك نۇقتا يوق)',
36 noEmail: 'ئېلخەت ئادرېسىنى كىرگۈزۈڭ',
37 noUrl: 'ئۇلانما ئادرېسىنى كىرگۈزۈڭ',
38 other: '‹باشقا›',
39 popupDependent: 'تەۋە (NS)',
40 popupFeatures: 'قاڭقىش كۆزنەك خاسلىقى',
41 popupFullScreen: 'پۈتۈن ئېكران (IE)',
42 popupLeft: 'سول',
43 popupLocationBar: 'ئادرېس بالداق',
44 popupMenuBar: 'تىزىملىك بالداق',
45 popupResizable: 'چوڭلۇقى ئۆزگەرتىشچان',
46 popupScrollBars: 'دومىلىما سۈرگۈچ',
47 popupStatusBar: 'ھالەت بالداق',
48 popupToolbar: 'قورال بالداق',
49 popupTop: 'ئوڭ',
50 rel: 'باغلىنىش',
51 selectAnchor: 'بىر لەڭگەرلىك نۇقتا تاللاڭ',
52 styles: 'قۇر ئىچىدىكى ئۇسلۇبى',
53 tabIndex: 'Tab تەرتىپى',
54 target: 'نىشان',
55 targetFrame: '‹كاندۇك›',
56 targetFrameName: 'نىشان كاندۇك ئاتى',
57 targetPopup: '‹قاڭقىش كۆزنەك›',
58 targetPopupName: 'قاڭقىش كۆزنەك ئاتى',
59 title: 'ئۇلانما',
60 toAnchor: 'بەت ئىچىدىكى لەڭگەرلىك نۇقتا ئۇلانمىسى',
61 toEmail: 'ئېلخەت',
62 toUrl: 'ئادرېس',
63 toolbar: 'ئۇلانما قىستۇر/تەھرىرلە',
64 type: 'ئۇلانما تىپى',
65 unlink: 'ئۇلانما بىكار قىل',
66 upload: 'يۈكلە'
67} );
diff --git a/sources/plugins/link/lang/uk.js b/sources/plugins/link/lang/uk.js
new file mode 100644
index 0000000..8322d86
--- /dev/null
+++ b/sources/plugins/link/lang/uk.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'uk', {
6 acccessKey: 'Гаряча клавіша',
7 advanced: 'Додаткове',
8 advisoryContentType: 'Тип вмісту',
9 advisoryTitle: 'Заголовок',
10 anchor: {
11 toolbar: 'Вставити/Редагувати якір',
12 menu: 'Властивості якоря',
13 title: 'Властивості якоря',
14 name: 'Ім\'я якоря',
15 errorName: 'Будь ласка, вкажіть ім\'я якоря',
16 remove: 'Прибрати якір'
17 },
18 anchorId: 'За ідентифікатором елементу',
19 anchorName: 'За ім\'ям елементу',
20 charset: 'Кодування',
21 cssClasses: 'Клас CSS',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Адреса ел. пошти',
25 emailBody: 'Тіло повідомлення',
26 emailSubject: 'Тема листа',
27 id: 'Ідентифікатор',
28 info: 'Інформація посилання',
29 langCode: 'Код мови',
30 langDir: 'Напрямок мови',
31 langDirLTR: 'Зліва направо (LTR)',
32 langDirRTL: 'Справа наліво (RTL)',
33 menu: 'Вставити посилання',
34 name: 'Ім\'я',
35 noAnchors: '(В цьому документі немає якорів)',
36 noEmail: 'Будь ласка, вкажіть адрес ел. пошти',
37 noUrl: 'Будь ласка, вкажіть URL посилання',
38 other: '<інший>',
39 popupDependent: 'Залежний (Netscape)',
40 popupFeatures: 'Властивості випливаючого вікна',
41 popupFullScreen: 'Повний екран (IE)',
42 popupLeft: 'Позиція зліва',
43 popupLocationBar: 'Панель локації',
44 popupMenuBar: 'Панель меню',
45 popupResizable: 'Масштабоване',
46 popupScrollBars: 'Стрічки прокрутки',
47 popupStatusBar: 'Рядок статусу',
48 popupToolbar: 'Панель інструментів',
49 popupTop: 'Позиція зверху',
50 rel: 'Зв\'язок',
51 selectAnchor: 'Оберіть якір',
52 styles: 'Стиль CSS',
53 tabIndex: 'Послідовність переходу',
54 target: 'Ціль',
55 targetFrame: '<фрейм>',
56 targetFrameName: 'Ім\'я цільового фрейму',
57 targetPopup: '<випливаюче вікно>',
58 targetPopupName: 'Ім\'я випливаючого вікна',
59 title: 'Посилання',
60 toAnchor: 'Якір на цю сторінку',
61 toEmail: 'Ел. пошта',
62 toUrl: 'URL',
63 toolbar: 'Вставити/Редагувати посилання',
64 type: 'Тип посилання',
65 unlink: 'Видалити посилання',
66 upload: 'Надіслати'
67} );
diff --git a/sources/plugins/link/lang/vi.js b/sources/plugins/link/lang/vi.js
new file mode 100644
index 0000000..d78012d
--- /dev/null
+++ b/sources/plugins/link/lang/vi.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'vi', {
6 acccessKey: 'Phím hỗ trợ truy cập',
7 advanced: 'Mở rộng',
8 advisoryContentType: 'Nội dung hướng dẫn',
9 advisoryTitle: 'Nhan đề hướng dẫn',
10 anchor: {
11 toolbar: 'Chèn/Sửa điểm neo',
12 menu: 'Thuộc tính điểm neo',
13 title: 'Thuộc tính điểm neo',
14 name: 'Tên của điểm neo',
15 errorName: 'Hãy nhập vào tên của điểm neo',
16 remove: 'Xóa neo'
17 },
18 anchorId: 'Theo định danh thành phần',
19 anchorName: 'Theo tên điểm neo',
20 charset: 'Bảng mã của tài nguyên được liên kết đến',
21 cssClasses: 'Lớp Stylesheet',
22 download: 'Force Download', // MISSING
23 displayText: 'Display Text', // MISSING
24 emailAddress: 'Thư điện tử',
25 emailBody: 'Nội dung thông điệp',
26 emailSubject: 'Tiêu đề thông điệp',
27 id: 'Định danh',
28 info: 'Thông tin liên kết',
29 langCode: 'Mã ngôn ngữ',
30 langDir: 'Hướng ngôn ngữ',
31 langDirLTR: 'Trái sang phải (LTR)',
32 langDirRTL: 'Phải sang trái (RTL)',
33 menu: 'Sửa liên kết',
34 name: 'Tên',
35 noAnchors: '(Không có điểm neo nào trong tài liệu)',
36 noEmail: 'Hãy đưa vào địa chỉ thư điện tử',
37 noUrl: 'Hãy đưa vào đường dẫn liên kết (URL)',
38 other: '<khác>',
39 popupDependent: 'Phụ thuộc (Netscape)',
40 popupFeatures: 'Đặc điểm của cửa sổ Popup',
41 popupFullScreen: 'Toàn màn hình (IE)',
42 popupLeft: 'Vị trí bên trái',
43 popupLocationBar: 'Thanh vị trí',
44 popupMenuBar: 'Thanh Menu',
45 popupResizable: 'Có thể thay đổi kích cỡ',
46 popupScrollBars: 'Thanh cuộn',
47 popupStatusBar: 'Thanh trạng thái',
48 popupToolbar: 'Thanh công cụ',
49 popupTop: 'Vị trí phía trên',
50 rel: 'Quan hệ',
51 selectAnchor: 'Chọn một điểm neo',
52 styles: 'Kiểu (style)',
53 tabIndex: 'Chỉ số của Tab',
54 target: 'Đích',
55 targetFrame: '<khung>',
56 targetFrameName: 'Tên khung đích',
57 targetPopup: '<cửa sổ popup>',
58 targetPopupName: 'Tên cửa sổ Popup',
59 title: 'Liên kết',
60 toAnchor: 'Neo trong trang này',
61 toEmail: 'Thư điện tử',
62 toUrl: 'URL',
63 toolbar: 'Chèn/Sửa liên kết',
64 type: 'Kiểu liên kết',
65 unlink: 'Xoá liên kết',
66 upload: 'Tải lên'
67} );
diff --git a/sources/plugins/link/lang/zh-cn.js b/sources/plugins/link/lang/zh-cn.js
new file mode 100644
index 0000000..6da9e96
--- /dev/null
+++ b/sources/plugins/link/lang/zh-cn.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'zh-cn', {
6 acccessKey: '访问键',
7 advanced: '高级',
8 advisoryContentType: '内容类型',
9 advisoryTitle: '标题',
10 anchor: {
11 toolbar: '插入/编辑锚点链接',
12 menu: '锚点链接属性',
13 title: '锚点链接属性',
14 name: '锚点名称',
15 errorName: '请输入锚点名称',
16 remove: '删除锚点'
17 },
18 anchorId: '按锚点 ID',
19 anchorName: '按锚点名称',
20 charset: '字符编码',
21 cssClasses: '样式类名称',
22 download: '强制下载',
23 displayText: '显示文本',
24 emailAddress: '地址',
25 emailBody: '内容',
26 emailSubject: '主题',
27 id: 'ID',
28 info: '超链接信息',
29 langCode: '语言代码',
30 langDir: '语言方向',
31 langDirLTR: '从左到右 (LTR)',
32 langDirRTL: '从右到左 (RTL)',
33 menu: '编辑超链接',
34 name: '名称',
35 noAnchors: '(此文档没有可用的锚点)',
36 noEmail: '请输入电子邮件地址',
37 noUrl: '请输入超链接地址',
38 other: '<其他>',
39 popupDependent: '依附 (NS)',
40 popupFeatures: '弹出窗口属性',
41 popupFullScreen: '全屏 (IE)',
42 popupLeft: '左',
43 popupLocationBar: '地址栏',
44 popupMenuBar: '菜单栏',
45 popupResizable: '可缩放',
46 popupScrollBars: '滚动条',
47 popupStatusBar: '状态栏',
48 popupToolbar: '工具栏',
49 popupTop: '右',
50 rel: '关联',
51 selectAnchor: '选择一个锚点',
52 styles: '行内样式',
53 tabIndex: 'Tab 键次序',
54 target: '目标',
55 targetFrame: '<框架>',
56 targetFrameName: '目标框架名称',
57 targetPopup: '<弹出窗口>',
58 targetPopupName: '弹出窗口名称',
59 title: '超链接',
60 toAnchor: '页内锚点链接',
61 toEmail: '电子邮件',
62 toUrl: '地址',
63 toolbar: '插入/编辑超链接',
64 type: '超链接类型',
65 unlink: '取消超链接',
66 upload: '上传'
67} );
diff --git a/sources/plugins/link/lang/zh.js b/sources/plugins/link/lang/zh.js
new file mode 100644
index 0000000..5ba3d1c
--- /dev/null
+++ b/sources/plugins/link/lang/zh.js
@@ -0,0 +1,67 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'link', 'zh', {
6 acccessKey: '便捷鍵',
7 advanced: '進階',
8 advisoryContentType: '建議內容類型',
9 advisoryTitle: '標題',
10 anchor: {
11 toolbar: '錨點',
12 menu: '編輯錨點',
13 title: '錨點內容',
14 name: '錨點名稱',
15 errorName: '請輸入錨點名稱',
16 remove: '移除錨點'
17 },
18 anchorId: '依元件編號',
19 anchorName: '依錨點名稱',
20 charset: '連結資源的字元集',
21 cssClasses: '樣式表類別',
22 download: 'Force Download', // MISSING
23 displayText: '顯示文字',
24 emailAddress: '電子郵件地址',
25 emailBody: '郵件本文',
26 emailSubject: '郵件主旨',
27 id: 'ID',
28 info: '連結資訊',
29 langCode: '語言碼',
30 langDir: '語言方向',
31 langDirLTR: '由左至右 (LTR)',
32 langDirRTL: '由右至左 (RTL)',
33 menu: '編輯連結',
34 name: '名稱',
35 noAnchors: '(本文件中無可用之錨點)',
36 noEmail: '請輸入電子郵件',
37 noUrl: '請輸入連結 URL',
38 other: '<其他>',
39 popupDependent: '獨立 (Netscape)',
40 popupFeatures: '快顯視窗功能',
41 popupFullScreen: '全螢幕 (IE)',
42 popupLeft: '左側位置',
43 popupLocationBar: '位置列',
44 popupMenuBar: '功能表列',
45 popupResizable: '可調大小',
46 popupScrollBars: '捲軸',
47 popupStatusBar: '狀態列',
48 popupToolbar: '工具列',
49 popupTop: '頂端位置',
50 rel: '關係',
51 selectAnchor: '選取一個錨點',
52 styles: '樣式',
53 tabIndex: '定位順序',
54 target: '目標',
55 targetFrame: '<框架>',
56 targetFrameName: '目標框架名稱',
57 targetPopup: '<快顯視窗>',
58 targetPopupName: '快顯視窗名稱',
59 title: '連結',
60 toAnchor: '文字中的錨點連結',
61 toEmail: '電子郵件',
62 toUrl: '網址',
63 toolbar: '連結',
64 type: '連結類型',
65 unlink: '取消連結',
66 upload: '上傳'
67} );
diff --git a/sources/plugins/link/plugin.js b/sources/plugins/link/plugin.js
new file mode 100644
index 0000000..94d582b
--- /dev/null
+++ b/sources/plugins/link/plugin.js
@@ -0,0 +1,828 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6'use strict';
7
8( function() {
9 CKEDITOR.plugins.add( 'link', {
10 requires: 'dialog,fakeobjects',
11 // jscs:disable maximumLineLength
12 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
13 // jscs:enable maximumLineLength
14 icons: 'anchor,anchor-rtl,link,unlink', // %REMOVE_LINE_CORE%
15 hidpi: true, // %REMOVE_LINE_CORE%
16 onLoad: function() {
17 // Add the CSS styles for anchor placeholders.
18 var iconPath = CKEDITOR.getUrl( this.path + 'images' + ( CKEDITOR.env.hidpi ? '/hidpi' : '' ) + '/anchor.png' ),
19 baseStyle = 'background:url(' + iconPath + ') no-repeat %1 center;border:1px dotted #00f;background-size:16px;';
20
21 var template = '.%2 a.cke_anchor,' +
22 '.%2 a.cke_anchor_empty' +
23 ',.cke_editable.%2 a[name]' +
24 ',.cke_editable.%2 a[data-cke-saved-name]' +
25 '{' +
26 baseStyle +
27 'padding-%1:18px;' +
28 // Show the arrow cursor for the anchor image (FF at least).
29 'cursor:auto;' +
30 '}' +
31 '.%2 img.cke_anchor' +
32 '{' +
33 baseStyle +
34 'width:16px;' +
35 'min-height:15px;' +
36 // The default line-height on IE.
37 'height:1.15em;' +
38 // Opera works better with "middle" (even if not perfect)
39 'vertical-align:text-bottom;' +
40 '}';
41
42 // Styles with contents direction awareness.
43 function cssWithDir( dir ) {
44 return template.replace( /%1/g, dir == 'rtl' ? 'right' : 'left' ).replace( /%2/g, 'cke_contents_' + dir );
45 }
46
47 CKEDITOR.addCss( cssWithDir( 'ltr' ) + cssWithDir( 'rtl' ) );
48 },
49
50 init: function( editor ) {
51 var allowed = 'a[!href]',
52 required = 'a[href]';
53
54 if ( CKEDITOR.dialog.isTabEnabled( editor, 'link', 'advanced' ) )
55 allowed = allowed.replace( ']', ',accesskey,charset,dir,id,lang,name,rel,tabindex,title,type,download]{*}(*)' );
56 if ( CKEDITOR.dialog.isTabEnabled( editor, 'link', 'target' ) )
57 allowed = allowed.replace( ']', ',target,onclick]' );
58
59 // Add the link and unlink buttons.
60 editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link', {
61 allowedContent: allowed,
62 requiredContent: required
63 } ) );
64 editor.addCommand( 'anchor', new CKEDITOR.dialogCommand( 'anchor', {
65 allowedContent: 'a[!name,id]',
66 requiredContent: 'a[name]'
67 } ) );
68 editor.addCommand( 'unlink', new CKEDITOR.unlinkCommand() );
69 editor.addCommand( 'removeAnchor', new CKEDITOR.removeAnchorCommand() );
70
71 editor.setKeystroke( CKEDITOR.CTRL + 76 /*L*/, 'link' );
72
73 if ( editor.ui.addButton ) {
74 editor.ui.addButton( 'Link', {
75 label: editor.lang.link.toolbar,
76 command: 'link',
77 toolbar: 'links,10'
78 } );
79 editor.ui.addButton( 'Unlink', {
80 label: editor.lang.link.unlink,
81 command: 'unlink',
82 toolbar: 'links,20'
83 } );
84 editor.ui.addButton( 'Anchor', {
85 label: editor.lang.link.anchor.toolbar,
86 command: 'anchor',
87 toolbar: 'links,30'
88 } );
89 }
90
91 CKEDITOR.dialog.add( 'link', this.path + 'dialogs/link.js' );
92 CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );
93
94 editor.on( 'doubleclick', function( evt ) {
95 var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element;
96
97 if ( !element.isReadOnly() ) {
98 if ( element.is( 'a' ) ) {
99 evt.data.dialog = ( element.getAttribute( 'name' ) && ( !element.getAttribute( 'href' ) || !element.getChildCount() ) ) ? 'anchor' : 'link';
100
101 // Pass the link to be selected along with event data.
102 evt.data.link = element;
103 } else if ( CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element ) ) {
104 evt.data.dialog = 'anchor';
105 }
106 }
107 }, null, null, 0 );
108
109 // If event was cancelled, link passed in event data will not be selected.
110 editor.on( 'doubleclick', function( evt ) {
111 // Make sure both links and anchors are selected (#11822).
112 if ( evt.data.dialog in { link: 1, anchor: 1 } && evt.data.link )
113 editor.getSelection().selectElement( evt.data.link );
114 }, null, null, 20 );
115
116 // If the "menu" plugin is loaded, register the menu items.
117 if ( editor.addMenuItems ) {
118 editor.addMenuItems( {
119 anchor: {
120 label: editor.lang.link.anchor.menu,
121 command: 'anchor',
122 group: 'anchor',
123 order: 1
124 },
125
126 removeAnchor: {
127 label: editor.lang.link.anchor.remove,
128 command: 'removeAnchor',
129 group: 'anchor',
130 order: 5
131 },
132
133 link: {
134 label: editor.lang.link.menu,
135 command: 'link',
136 group: 'link',
137 order: 1
138 },
139
140 unlink: {
141 label: editor.lang.link.unlink,
142 command: 'unlink',
143 group: 'link',
144 order: 5
145 }
146 } );
147 }
148
149 // If the "contextmenu" plugin is loaded, register the listeners.
150 if ( editor.contextMenu ) {
151 editor.contextMenu.addListener( function( element ) {
152 if ( !element || element.isReadOnly() )
153 return null;
154
155 var anchor = CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element );
156
157 if ( !anchor && !( anchor = CKEDITOR.plugins.link.getSelectedLink( editor ) ) )
158 return null;
159
160 var menu = {};
161
162 if ( anchor.getAttribute( 'href' ) && anchor.getChildCount() )
163 menu = { link: CKEDITOR.TRISTATE_OFF, unlink: CKEDITOR.TRISTATE_OFF };
164
165 if ( anchor && anchor.hasAttribute( 'name' ) )
166 menu.anchor = menu.removeAnchor = CKEDITOR.TRISTATE_OFF;
167
168 return menu;
169 } );
170 }
171
172 this.compiledProtectionFunction = getCompiledProtectionFunction( editor );
173 },
174
175 afterInit: function( editor ) {
176 // Empty anchors upcasting to fake objects.
177 editor.dataProcessor.dataFilter.addRules( {
178 elements: {
179 a: function( element ) {
180 if ( !element.attributes.name )
181 return null;
182
183 if ( !element.children.length )
184 return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' );
185
186 return null;
187 }
188 }
189 } );
190
191 var pathFilters = editor._.elementsPath && editor._.elementsPath.filters;
192 if ( pathFilters ) {
193 pathFilters.push( function( element, name ) {
194 if ( name == 'a' ) {
195 if ( CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element ) || ( element.getAttribute( 'name' ) && ( !element.getAttribute( 'href' ) || !element.getChildCount() ) ) )
196 return 'anchor';
197 }
198 } );
199 }
200 }
201 } );
202
203 // Loads the parameters in a selected link to the link dialog fields.
204 var javascriptProtocolRegex = /^javascript:/,
205 emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
206 emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/i,
207 emailBodyRegex = /body=([^;?:@&=$,\/]*)/i,
208 anchorRegex = /^#(.*)$/,
209 urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
210 selectableTargets = /^(_(?:self|top|parent|blank))$/,
211 encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,
212 functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/,
213 popupRegex = /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/,
214 popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi;
215
216 var advAttrNames = {
217 id: 'advId',
218 dir: 'advLangDir',
219 accessKey: 'advAccessKey',
220 // 'data-cke-saved-name': 'advName',
221 name: 'advName',
222 lang: 'advLangCode',
223 tabindex: 'advTabIndex',
224 title: 'advTitle',
225 type: 'advContentType',
226 'class': 'advCSSClasses',
227 charset: 'advCharset',
228 style: 'advStyles',
229 rel: 'advRel'
230 };
231
232 function unescapeSingleQuote( str ) {
233 return str.replace( /\\'/g, '\'' );
234 }
235
236 function escapeSingleQuote( str ) {
237 return str.replace( /'/g, '\\$&' );
238 }
239
240 function protectEmailAddressAsEncodedString( address ) {
241 var charCode,
242 length = address.length,
243 encodedChars = [];
244
245 for ( var i = 0; i < length; i++ ) {
246 charCode = address.charCodeAt( i );
247 encodedChars.push( charCode );
248 }
249
250 return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')';
251 }
252
253 function protectEmailLinkAsFunction( editor, email ) {
254 var plugin = editor.plugins.link,
255 name = plugin.compiledProtectionFunction.name,
256 params = plugin.compiledProtectionFunction.params,
257 paramName, paramValue, retval;
258
259 retval = [ name, '(' ];
260 for ( var i = 0; i < params.length; i++ ) {
261 paramName = params[ i ].toLowerCase();
262 paramValue = email[ paramName ];
263
264 i > 0 && retval.push( ',' );
265 retval.push( '\'', paramValue ? escapeSingleQuote( encodeURIComponent( email[ paramName ] ) ) : '', '\'' );
266 }
267 retval.push( ')' );
268 return retval.join( '' );
269 }
270
271 function getCompiledProtectionFunction( editor ) {
272 var emailProtection = editor.config.emailProtection || '',
273 compiledProtectionFunction;
274
275 // Compile the protection function pattern.
276 if ( emailProtection && emailProtection != 'encode' ) {
277 compiledProtectionFunction = {};
278
279 emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params ) {
280 compiledProtectionFunction.name = funcName;
281 compiledProtectionFunction.params = [];
282 params.replace( /[^,\s]+/g, function( param ) {
283 compiledProtectionFunction.params.push( param );
284 } );
285 } );
286 }
287
288 return compiledProtectionFunction;
289 }
290
291 /**
292 * Set of Link plugin helpers.
293 *
294 * @class
295 * @singleton
296 */
297 CKEDITOR.plugins.link = {
298 /**
299 * Get the surrounding link element of the current selection.
300 *
301 * CKEDITOR.plugins.link.getSelectedLink( editor );
302 *
303 * // The following selections will all return the link element.
304 *
305 * <a href="#">li^nk</a>
306 * <a href="#">[link]</a>
307 * text[<a href="#">link]</a>
308 * <a href="#">li[nk</a>]
309 * [<b><a href="#">li]nk</a></b>]
310 * [<a href="#"><b>li]nk</b></a>
311 *
312 * @since 3.2.1
313 * @param {CKEDITOR.editor} editor
314 */
315 getSelectedLink: function( editor ) {
316 var selection = editor.getSelection();
317 var selectedElement = selection.getSelectedElement();
318 if ( selectedElement && selectedElement.is( 'a' ) )
319 return selectedElement;
320
321 var range = selection.getRanges()[ 0 ];
322
323 if ( range ) {
324 range.shrink( CKEDITOR.SHRINK_TEXT );
325 return editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 );
326 }
327 return null;
328 },
329
330 /**
331 * Collects anchors available in the editor (i.e. used by the Link plugin).
332 * Note that the scope of search is different for inline (the "global" document) and
333 * classic (`iframe`-based) editors (the "inner" document).
334 *
335 * @since 4.3.3
336 * @param {CKEDITOR.editor} editor
337 * @returns {CKEDITOR.dom.element[]} An array of anchor elements.
338 */
339 getEditorAnchors: function( editor ) {
340 var editable = editor.editable(),
341
342 // The scope of search for anchors is the entire document for inline editors
343 // and editor's editable for classic editor/divarea (#11359).
344 scope = ( editable.isInline() && !editor.plugins.divarea ) ? editor.document : editable,
345
346 links = scope.getElementsByTag( 'a' ),
347 imgs = scope.getElementsByTag( 'img' ),
348 anchors = [],
349 i = 0,
350 item;
351
352 // Retrieve all anchors within the scope.
353 while ( ( item = links.getItem( i++ ) ) ) {
354 if ( item.data( 'cke-saved-name' ) || item.hasAttribute( 'name' ) ) {
355 anchors.push( {
356 name: item.data( 'cke-saved-name' ) || item.getAttribute( 'name' ),
357 id: item.getAttribute( 'id' )
358 } );
359 }
360 }
361 // Retrieve all "fake anchors" within the scope.
362 i = 0;
363
364 while ( ( item = imgs.getItem( i++ ) ) ) {
365 if ( ( item = this.tryRestoreFakeAnchor( editor, item ) ) ) {
366 anchors.push( {
367 name: item.getAttribute( 'name' ),
368 id: item.getAttribute( 'id' )
369 } );
370 }
371 }
372
373 return anchors;
374 },
375
376 /**
377 * Opera and WebKit do not make it possible to select empty anchors. Fake
378 * elements must be used for them.
379 *
380 * @readonly
381 * @deprecated 4.3.3 It is set to `true` in every browser.
382 * @property {Boolean}
383 */
384 fakeAnchor: true,
385
386 /**
387 * For browsers that do not support CSS3 `a[name]:empty()`. Note that IE9 is included because of #7783.
388 *
389 * @readonly
390 * @deprecated 4.3.3 It is set to `false` in every browser.
391 * @property {Boolean} synAnchorSelector
392 */
393
394 /**
395 * For browsers that have editing issues with an empty anchor.
396 *
397 * @readonly
398 * @deprecated 4.3.3 It is set to `false` in every browser.
399 * @property {Boolean} emptyAnchorFix
400 */
401
402 /**
403 * Returns an element representing a real anchor restored from a fake anchor.
404 *
405 * @param {CKEDITOR.editor} editor
406 * @param {CKEDITOR.dom.element} element
407 * @returns {CKEDITOR.dom.element} Restored anchor element or nothing if the
408 * passed element was not a fake anchor.
409 */
410 tryRestoreFakeAnchor: function( editor, element ) {
411 if ( element && element.data( 'cke-real-element-type' ) && element.data( 'cke-real-element-type' ) == 'anchor' ) {
412 var link = editor.restoreRealElement( element );
413 if ( link.data( 'cke-saved-name' ) )
414 return link;
415 }
416 },
417
418 /**
419 * Parses attributes of the link element and returns an object representing
420 * the current state (data) of the link. This data format is a plain object accepted
421 * e.g. by the Link dialog window and {@link #getLinkAttributes}.
422 *
423 * **Note:** Data model format produced by the parser must be compatible with the Link
424 * plugin dialog because it is passed directly to {@link CKEDITOR.dialog#setupContent}.
425 *
426 * @since 4.4
427 * @param {CKEDITOR.editor} editor
428 * @param {CKEDITOR.dom.element} element
429 * @returns {Object} An object of link data.
430 */
431 parseLinkAttributes: function( editor, element ) {
432 var href = ( element && ( element.data( 'cke-saved-href' ) || element.getAttribute( 'href' ) ) ) || '',
433 compiledProtectionFunction = editor.plugins.link.compiledProtectionFunction,
434 emailProtection = editor.config.emailProtection,
435 javascriptMatch, emailMatch, anchorMatch, urlMatch,
436 retval = {};
437
438 if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) ) {
439 if ( emailProtection == 'encode' ) {
440 href = href.replace( encodedEmailLinkRegex, function( match, protectedAddress, rest ) {
441 // Without it 'undefined' is appended to e-mails without subject and body (#9192).
442 rest = rest || '';
443
444 return 'mailto:' +
445 String.fromCharCode.apply( String, protectedAddress.split( ',' ) ) +
446 unescapeSingleQuote( rest );
447 } );
448 }
449 // Protected email link as function call.
450 else if ( emailProtection ) {
451 href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs ) {
452 if ( funcName == compiledProtectionFunction.name ) {
453 retval.type = 'email';
454 var email = retval.email = {};
455
456 var paramRegex = /[^,\s]+/g,
457 paramQuoteRegex = /(^')|('$)/g,
458 paramsMatch = funcArgs.match( paramRegex ),
459 paramsMatchLength = paramsMatch.length,
460 paramName, paramVal;
461
462 for ( var i = 0; i < paramsMatchLength; i++ ) {
463 paramVal = decodeURIComponent( unescapeSingleQuote( paramsMatch[ i ].replace( paramQuoteRegex, '' ) ) );
464 paramName = compiledProtectionFunction.params[ i ].toLowerCase();
465 email[ paramName ] = paramVal;
466 }
467 email.address = [ email.name, email.domain ].join( '@' );
468 }
469 } );
470 }
471 }
472
473 if ( !retval.type ) {
474 if ( ( anchorMatch = href.match( anchorRegex ) ) ) {
475 retval.type = 'anchor';
476 retval.anchor = {};
477 retval.anchor.name = retval.anchor.id = anchorMatch[ 1 ];
478 }
479 // Protected email link as encoded string.
480 else if ( ( emailMatch = href.match( emailRegex ) ) ) {
481 var subjectMatch = href.match( emailSubjectRegex ),
482 bodyMatch = href.match( emailBodyRegex );
483
484 retval.type = 'email';
485 var email = ( retval.email = {} );
486 email.address = emailMatch[ 1 ];
487 subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) );
488 bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) );
489 }
490 // urlRegex matches empty strings, so need to check for href as well.
491 else if ( href && ( urlMatch = href.match( urlRegex ) ) ) {
492 retval.type = 'url';
493 retval.url = {};
494 retval.url.protocol = urlMatch[ 1 ];
495 retval.url.url = urlMatch[ 2 ];
496 }
497 }
498
499 // Load target and popup settings.
500 if ( element ) {
501 var target = element.getAttribute( 'target' );
502
503 // IE BUG: target attribute is an empty string instead of null in IE if it's not set.
504 if ( !target ) {
505 var onclick = element.data( 'cke-pa-onclick' ) || element.getAttribute( 'onclick' ),
506 onclickMatch = onclick && onclick.match( popupRegex );
507
508 if ( onclickMatch ) {
509 retval.target = {
510 type: 'popup',
511 name: onclickMatch[ 1 ]
512 };
513
514 var featureMatch;
515 while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[ 2 ] ) ) ) {
516 // Some values should remain numbers (#7300)
517 if ( ( featureMatch[ 2 ] == 'yes' || featureMatch[ 2 ] == '1' ) && !( featureMatch[ 1 ] in { height: 1, width: 1, top: 1, left: 1 } ) )
518 retval.target[ featureMatch[ 1 ] ] = true;
519 else if ( isFinite( featureMatch[ 2 ] ) )
520 retval.target[ featureMatch[ 1 ] ] = featureMatch[ 2 ];
521 }
522 }
523 } else {
524 retval.target = {
525 type: target.match( selectableTargets ) ? target : 'frame',
526 name: target
527 };
528 }
529
530 var download = element.getAttribute( 'download' );
531 if ( download !== null ) {
532 retval.download = true;
533 }
534
535 var advanced = {};
536
537 for ( var a in advAttrNames ) {
538 var val = element.getAttribute( a );
539
540 if ( val )
541 advanced[ advAttrNames[ a ] ] = val;
542 }
543
544 var advName = element.data( 'cke-saved-name' ) || advanced.advName;
545
546 if ( advName )
547 advanced.advName = advName;
548
549 if ( !CKEDITOR.tools.isEmpty( advanced ) )
550 retval.advanced = advanced;
551 }
552
553 return retval;
554 },
555
556 /**
557 * Converts link data produced by {@link #parseLinkAttributes} into an object which consists
558 * of attributes to be set (with their values) and an array of attributes to be removed.
559 * This method can be used to compose or to update any link element with the given data.
560 *
561 * @since 4.4
562 * @param {CKEDITOR.editor} editor
563 * @param {Object} data Data in {@link #parseLinkAttributes} format.
564 * @returns {Object} An object consisting of two keys, i.e.:
565 *
566 * {
567 * // Attributes to be set.
568 * set: {
569 * href: 'http://foo.bar',
570 * target: 'bang'
571 * },
572 * // Attributes to be removed.
573 * removed: [
574 * 'id', 'style'
575 * ]
576 * }
577 *
578 */
579 getLinkAttributes: function( editor, data ) {
580 var emailProtection = editor.config.emailProtection || '',
581 set = {};
582
583 // Compose the URL.
584 switch ( data.type ) {
585 case 'url':
586 var protocol = ( data.url && data.url.protocol !== undefined ) ? data.url.protocol : 'http://',
587 url = ( data.url && CKEDITOR.tools.trim( data.url.url ) ) || '';
588
589 set[ 'data-cke-saved-href' ] = ( url.indexOf( '/' ) === 0 ) ? url : protocol + url;
590
591 break;
592 case 'anchor':
593 var name = ( data.anchor && data.anchor.name ),
594 id = ( data.anchor && data.anchor.id );
595
596 set[ 'data-cke-saved-href' ] = '#' + ( name || id || '' );
597
598 break;
599 case 'email':
600 var email = data.email,
601 address = email.address,
602 linkHref;
603
604 switch ( emailProtection ) {
605 case '':
606 case 'encode':
607 var subject = encodeURIComponent( email.subject || '' ),
608 body = encodeURIComponent( email.body || '' ),
609 argList = [];
610
611 // Build the e-mail parameters first.
612 subject && argList.push( 'subject=' + subject );
613 body && argList.push( 'body=' + body );
614 argList = argList.length ? '?' + argList.join( '&' ) : '';
615
616 if ( emailProtection == 'encode' ) {
617 linkHref = [
618 'javascript:void(location.href=\'mailto:\'+', // jshint ignore:line
619 protectEmailAddressAsEncodedString( address )
620 ];
621 // parameters are optional.
622 argList && linkHref.push( '+\'', escapeSingleQuote( argList ), '\'' );
623
624 linkHref.push( ')' );
625 } else {
626 linkHref = [ 'mailto:', address, argList ];
627 }
628
629 break;
630 default:
631 // Separating name and domain.
632 var nameAndDomain = address.split( '@', 2 );
633 email.name = nameAndDomain[ 0 ];
634 email.domain = nameAndDomain[ 1 ];
635
636 linkHref = [ 'javascript:', protectEmailLinkAsFunction( editor, email ) ]; // jshint ignore:line
637 }
638
639 set[ 'data-cke-saved-href' ] = linkHref.join( '' );
640 break;
641 }
642
643 // Popups and target.
644 if ( data.target ) {
645 if ( data.target.type == 'popup' ) {
646 var onclickList = [
647 'window.open(this.href, \'', data.target.name || '', '\', \''
648 ],
649 featureList = [
650 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen', 'scrollbars', 'dependent'
651 ],
652 featureLength = featureList.length,
653 addFeature = function( featureName ) {
654 if ( data.target[ featureName ] )
655 featureList.push( featureName + '=' + data.target[ featureName ] );
656 };
657
658 for ( var i = 0; i < featureLength; i++ )
659 featureList[ i ] = featureList[ i ] + ( data.target[ featureList[ i ] ] ? '=yes' : '=no' );
660
661 addFeature( 'width' );
662 addFeature( 'left' );
663 addFeature( 'height' );
664 addFeature( 'top' );
665
666 onclickList.push( featureList.join( ',' ), '\'); return false;' );
667 set[ 'data-cke-pa-onclick' ] = onclickList.join( '' );
668 }
669 else if ( data.target.type != 'notSet' && data.target.name ) {
670 set.target = data.target.name;
671 }
672 }
673
674 // Force download attribute.
675 if ( data.download ) {
676 set.download = '';
677 }
678
679 // Advanced attributes.
680 if ( data.advanced ) {
681 for ( var a in advAttrNames ) {
682 var val = data.advanced[ advAttrNames[ a ] ];
683
684 if ( val )
685 set[ a ] = val;
686 }
687
688 if ( set.name )
689 set[ 'data-cke-saved-name' ] = set.name;
690 }
691
692 // Browser need the "href" fro copy/paste link to work. (#6641)
693 if ( set[ 'data-cke-saved-href' ] )
694 set.href = set[ 'data-cke-saved-href' ];
695
696 var removed = {
697 target: 1,
698 onclick: 1,
699 'data-cke-pa-onclick': 1,
700 'data-cke-saved-name': 1,
701 'download': 1
702 };
703
704 if ( data.advanced )
705 CKEDITOR.tools.extend( removed, advAttrNames );
706
707 // Remove all attributes which are not currently set.
708 for ( var s in set )
709 delete removed[ s ];
710
711 return {
712 set: set,
713 removed: CKEDITOR.tools.objectKeys( removed )
714 };
715 },
716
717
718 /**
719 * Determines whether an element should have a "Display Text" field in the Link dialog.
720 *
721 * @since 4.5.11
722 * @param {CKEDITOR.dom.element/null} element Selected element, `null` if none selected or if a ranged selection
723 * is made.
724 * @param {CKEDITOR.editor} editor The editor instance for which the check is performed.
725 * @returns {Boolean}
726 */
727 showDisplayTextForElement: function( element, editor ) {
728 var undesiredElements = {
729 img: 1,
730 table: 1,
731 tbody: 1,
732 thead: 1,
733 tfoot: 1,
734 input: 1,
735 select: 1,
736 textarea: 1
737 };
738
739 // Widget duck typing, we don't want to show display text for widgets.
740 if ( editor.widgets && editor.widgets.focused ) {
741 return false;
742 }
743
744 return !element || !element.getName || !element.is( undesiredElements );
745 }
746 };
747
748 // TODO Much probably there's no need to expose these as public objects.
749
750 CKEDITOR.unlinkCommand = function() {};
751 CKEDITOR.unlinkCommand.prototype = {
752 exec: function( editor ) {
753 var style = new CKEDITOR.style( { element: 'a', type: CKEDITOR.STYLE_INLINE, alwaysRemoveElement: 1 } );
754 editor.removeStyle( style );
755 },
756
757 refresh: function( editor, path ) {
758 // Despite our initial hope, document.queryCommandEnabled() does not work
759 // for this in Firefox. So we must detect the state by element paths.
760
761 var element = path.lastElement && path.lastElement.getAscendant( 'a', true );
762
763 if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) && element.getChildCount() )
764 this.setState( CKEDITOR.TRISTATE_OFF );
765 else
766 this.setState( CKEDITOR.TRISTATE_DISABLED );
767 },
768
769 contextSensitive: 1,
770 startDisabled: 1,
771 requiredContent: 'a[href]'
772 };
773
774 CKEDITOR.removeAnchorCommand = function() {};
775 CKEDITOR.removeAnchorCommand.prototype = {
776 exec: function( editor ) {
777 var sel = editor.getSelection(),
778 bms = sel.createBookmarks(),
779 anchor;
780 if ( sel && ( anchor = sel.getSelectedElement() ) && ( !anchor.getChildCount() ? CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, anchor ) : anchor.is( 'a' ) ) )
781 anchor.remove( 1 );
782 else {
783 if ( ( anchor = CKEDITOR.plugins.link.getSelectedLink( editor ) ) ) {
784 if ( anchor.hasAttribute( 'href' ) ) {
785 anchor.removeAttributes( { name: 1, 'data-cke-saved-name': 1 } );
786 anchor.removeClass( 'cke_anchor' );
787 } else {
788 anchor.remove( 1 );
789 }
790 }
791 }
792 sel.selectBookmarks( bms );
793 },
794 requiredContent: 'a[name]'
795 };
796
797 CKEDITOR.tools.extend( CKEDITOR.config, {
798 /**
799 * Whether to show the Advanced tab in the Link dialog window.
800 *
801 * @cfg {Boolean} [linkShowAdvancedTab=true]
802 * @member CKEDITOR.config
803 */
804 linkShowAdvancedTab: true,
805
806 /**
807 * Whether to show the Target tab in the Link dialog window.
808 *
809 * @cfg {Boolean} [linkShowTargetTab=true]
810 * @member CKEDITOR.config
811 */
812 linkShowTargetTab: true
813
814 /**
815 * Whether JavaScript code is allowed as a `href` attribute in an anchor tag.
816 * With this option enabled it is possible to create links like:
817 *
818 * <a href="javascript:alert('Hello world!')">hello world</a>
819 *
820 * By default JavaScript links are not allowed and will not pass
821 * the Link dialog window validation.
822 *
823 * @since 4.4.1
824 * @cfg {Boolean} [linkJavaScriptLinksAllowed=false]
825 * @member CKEDITOR.config
826 */
827 } );
828} )();
diff --git a/sources/plugins/list/icons/bulletedlist-rtl.png b/sources/plugins/list/icons/bulletedlist-rtl.png
new file mode 100644
index 0000000..2fed6b5
--- /dev/null
+++ b/sources/plugins/list/icons/bulletedlist-rtl.png
Binary files differ
diff --git a/sources/plugins/list/icons/bulletedlist.png b/sources/plugins/list/icons/bulletedlist.png
new file mode 100644
index 0000000..8d33138
--- /dev/null
+++ b/sources/plugins/list/icons/bulletedlist.png
Binary files differ
diff --git a/sources/plugins/list/icons/hidpi/bulletedlist-rtl.png b/sources/plugins/list/icons/hidpi/bulletedlist-rtl.png
new file mode 100644
index 0000000..7e08fb3
--- /dev/null
+++ b/sources/plugins/list/icons/hidpi/bulletedlist-rtl.png
Binary files differ
diff --git a/sources/plugins/list/icons/hidpi/bulletedlist.png b/sources/plugins/list/icons/hidpi/bulletedlist.png
new file mode 100644
index 0000000..796923f
--- /dev/null
+++ b/sources/plugins/list/icons/hidpi/bulletedlist.png
Binary files differ
diff --git a/sources/plugins/list/icons/hidpi/numberedlist-rtl.png b/sources/plugins/list/icons/hidpi/numberedlist-rtl.png
new file mode 100644
index 0000000..2ece272
--- /dev/null
+++ b/sources/plugins/list/icons/hidpi/numberedlist-rtl.png
Binary files differ
diff --git a/sources/plugins/list/icons/hidpi/numberedlist.png b/sources/plugins/list/icons/hidpi/numberedlist.png
new file mode 100644
index 0000000..20fe003
--- /dev/null
+++ b/sources/plugins/list/icons/hidpi/numberedlist.png
Binary files differ
diff --git a/sources/plugins/list/icons/numberedlist-rtl.png b/sources/plugins/list/icons/numberedlist-rtl.png
new file mode 100644
index 0000000..3c62d8d
--- /dev/null
+++ b/sources/plugins/list/icons/numberedlist-rtl.png
Binary files differ
diff --git a/sources/plugins/list/icons/numberedlist.png b/sources/plugins/list/icons/numberedlist.png
new file mode 100644
index 0000000..d47e0d5
--- /dev/null
+++ b/sources/plugins/list/icons/numberedlist.png
Binary files differ
diff --git a/sources/plugins/list/lang/af.js b/sources/plugins/list/lang/af.js
new file mode 100644
index 0000000..6b92ff6
--- /dev/null
+++ b/sources/plugins/list/lang/af.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'af', {
6 bulletedlist: 'Ongenommerde lys',
7 numberedlist: 'Genommerde lys'
8} );
diff --git a/sources/plugins/list/lang/ar.js b/sources/plugins/list/lang/ar.js
new file mode 100644
index 0000000..a7a7de7
--- /dev/null
+++ b/sources/plugins/list/lang/ar.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ar', {
6 bulletedlist: 'ادخال/حذف تعداد نقطي',
7 numberedlist: 'ادخال/حذف تعداد رقمي'
8} );
diff --git a/sources/plugins/list/lang/az.js b/sources/plugins/list/lang/az.js
new file mode 100644
index 0000000..5d4e513
--- /dev/null
+++ b/sources/plugins/list/lang/az.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'az', {
6 bulletedlist: 'Markerlənmiş siyahını başlat/sil',
7 numberedlist: 'Nömrələnmiş siyahını başlat/sil'
8} );
diff --git a/sources/plugins/list/lang/bg.js b/sources/plugins/list/lang/bg.js
new file mode 100644
index 0000000..6ac7ab6
--- /dev/null
+++ b/sources/plugins/list/lang/bg.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'bg', {
6 bulletedlist: 'Вмъкване/Премахване на точков списък',
7 numberedlist: 'Вмъкване/Премахване на номериран списък'
8} );
diff --git a/sources/plugins/list/lang/bn.js b/sources/plugins/list/lang/bn.js
new file mode 100644
index 0000000..cf6a85a
--- /dev/null
+++ b/sources/plugins/list/lang/bn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'bn', {
6 bulletedlist: 'বুলেটেড তালিকা প্রবেশ/অপসারন করি',
7 numberedlist: 'সাংখ্যিক লিস্টের লেবেল'
8} );
diff --git a/sources/plugins/list/lang/bs.js b/sources/plugins/list/lang/bs.js
new file mode 100644
index 0000000..76877b5
--- /dev/null
+++ b/sources/plugins/list/lang/bs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'bs', {
6 bulletedlist: 'Lista',
7 numberedlist: 'Numerisana lista'
8} );
diff --git a/sources/plugins/list/lang/ca.js b/sources/plugins/list/lang/ca.js
new file mode 100644
index 0000000..408cf53
--- /dev/null
+++ b/sources/plugins/list/lang/ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ca', {
6 bulletedlist: 'Llista de pics',
7 numberedlist: 'Llista numerada'
8} );
diff --git a/sources/plugins/list/lang/cs.js b/sources/plugins/list/lang/cs.js
new file mode 100644
index 0000000..e04b94d
--- /dev/null
+++ b/sources/plugins/list/lang/cs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'cs', {
6 bulletedlist: 'Odrážky',
7 numberedlist: 'Číslování'
8} );
diff --git a/sources/plugins/list/lang/cy.js b/sources/plugins/list/lang/cy.js
new file mode 100644
index 0000000..c786d4b
--- /dev/null
+++ b/sources/plugins/list/lang/cy.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'cy', {
6 bulletedlist: 'Mewnosod/Tynnu Rhestr Bwled',
7 numberedlist: 'Mewnosod/Tynnu Rhestr Rhifol'
8} );
diff --git a/sources/plugins/list/lang/da.js b/sources/plugins/list/lang/da.js
new file mode 100644
index 0000000..5c90ec9
--- /dev/null
+++ b/sources/plugins/list/lang/da.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'da', {
6 bulletedlist: 'Punktopstilling',
7 numberedlist: 'Talopstilling'
8} );
diff --git a/sources/plugins/list/lang/de-ch.js b/sources/plugins/list/lang/de-ch.js
new file mode 100644
index 0000000..7d72503
--- /dev/null
+++ b/sources/plugins/list/lang/de-ch.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'de-ch', {
6 bulletedlist: 'Liste',
7 numberedlist: 'Nummerierte Liste einfügen/entfernen'
8} );
diff --git a/sources/plugins/list/lang/de.js b/sources/plugins/list/lang/de.js
new file mode 100644
index 0000000..ef4b5f2
--- /dev/null
+++ b/sources/plugins/list/lang/de.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'de', {
6 bulletedlist: 'Liste',
7 numberedlist: 'Nummerierte Liste einfügen/entfernen'
8} );
diff --git a/sources/plugins/list/lang/el.js b/sources/plugins/list/lang/el.js
new file mode 100644
index 0000000..feeebac
--- /dev/null
+++ b/sources/plugins/list/lang/el.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'el', {
6 bulletedlist: 'Εισαγωγή/Απομάκρυνση Λίστας Κουκκίδων',
7 numberedlist: 'Εισαγωγή/Απομάκρυνση Αριθμημένης Λίστας'
8} );
diff --git a/sources/plugins/list/lang/en-au.js b/sources/plugins/list/lang/en-au.js
new file mode 100644
index 0000000..d3bbc2b
--- /dev/null
+++ b/sources/plugins/list/lang/en-au.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'en-au', {
6 bulletedlist: 'Insert/Remove Bulleted List',
7 numberedlist: 'Insert/Remove Numbered List'
8} );
diff --git a/sources/plugins/list/lang/en-ca.js b/sources/plugins/list/lang/en-ca.js
new file mode 100644
index 0000000..80be02f
--- /dev/null
+++ b/sources/plugins/list/lang/en-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'en-ca', {
6 bulletedlist: 'Insert/Remove Bulleted List',
7 numberedlist: 'Insert/Remove Numbered List'
8} );
diff --git a/sources/plugins/list/lang/en-gb.js b/sources/plugins/list/lang/en-gb.js
new file mode 100644
index 0000000..07db96c
--- /dev/null
+++ b/sources/plugins/list/lang/en-gb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'en-gb', {
6 bulletedlist: 'Insert/Remove Bulleted List',
7 numberedlist: 'Insert/Remove Numbered List'
8} );
diff --git a/sources/plugins/list/lang/en.js b/sources/plugins/list/lang/en.js
new file mode 100644
index 0000000..0bdc852
--- /dev/null
+++ b/sources/plugins/list/lang/en.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'en', {
6 bulletedlist: 'Insert/Remove Bulleted List',
7 numberedlist: 'Insert/Remove Numbered List'
8} );
diff --git a/sources/plugins/list/lang/eo.js b/sources/plugins/list/lang/eo.js
new file mode 100644
index 0000000..9242615
--- /dev/null
+++ b/sources/plugins/list/lang/eo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'eo', {
6 bulletedlist: 'Bula Listo',
7 numberedlist: 'Numera Listo'
8} );
diff --git a/sources/plugins/list/lang/es.js b/sources/plugins/list/lang/es.js
new file mode 100644
index 0000000..37f1904
--- /dev/null
+++ b/sources/plugins/list/lang/es.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'es', {
6 bulletedlist: 'Viñetas',
7 numberedlist: 'Numeración'
8} );
diff --git a/sources/plugins/list/lang/et.js b/sources/plugins/list/lang/et.js
new file mode 100644
index 0000000..498c8a5
--- /dev/null
+++ b/sources/plugins/list/lang/et.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'et', {
6 bulletedlist: 'Punktloend',
7 numberedlist: 'Numberloend'
8} );
diff --git a/sources/plugins/list/lang/eu.js b/sources/plugins/list/lang/eu.js
new file mode 100644
index 0000000..254793d
--- /dev/null
+++ b/sources/plugins/list/lang/eu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'eu', {
6 bulletedlist: 'Buletdun Zerrenda',
7 numberedlist: 'Zenbakidun Zerrenda'
8} );
diff --git a/sources/plugins/list/lang/fa.js b/sources/plugins/list/lang/fa.js
new file mode 100644
index 0000000..af3f9dd
--- /dev/null
+++ b/sources/plugins/list/lang/fa.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'fa', {
6 bulletedlist: 'فهرست نقطه​ای',
7 numberedlist: 'فهرست شماره​دار'
8} );
diff --git a/sources/plugins/list/lang/fi.js b/sources/plugins/list/lang/fi.js
new file mode 100644
index 0000000..3874597
--- /dev/null
+++ b/sources/plugins/list/lang/fi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'fi', {
6 bulletedlist: 'Luettelomerkit',
7 numberedlist: 'Numerointi'
8} );
diff --git a/sources/plugins/list/lang/fo.js b/sources/plugins/list/lang/fo.js
new file mode 100644
index 0000000..416c667
--- /dev/null
+++ b/sources/plugins/list/lang/fo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'fo', {
6 bulletedlist: 'Punktmerktur listi',
7 numberedlist: 'Talmerktur listi'
8} );
diff --git a/sources/plugins/list/lang/fr-ca.js b/sources/plugins/list/lang/fr-ca.js
new file mode 100644
index 0000000..e9eb2b7
--- /dev/null
+++ b/sources/plugins/list/lang/fr-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'fr-ca', {
6 bulletedlist: 'Liste à puces',
7 numberedlist: 'Liste numérotée'
8} );
diff --git a/sources/plugins/list/lang/fr.js b/sources/plugins/list/lang/fr.js
new file mode 100644
index 0000000..cb49ec7
--- /dev/null
+++ b/sources/plugins/list/lang/fr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'fr', {
6 bulletedlist: 'Insérer/Supprimer une liste à puces',
7 numberedlist: 'Insérer/Supprimer une liste numérotée'
8} );
diff --git a/sources/plugins/list/lang/gl.js b/sources/plugins/list/lang/gl.js
new file mode 100644
index 0000000..d020a69
--- /dev/null
+++ b/sources/plugins/list/lang/gl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'gl', {
6 bulletedlist: 'Inserir/retirar lista viñeteada',
7 numberedlist: 'Inserir/retirar lista numerada'
8} );
diff --git a/sources/plugins/list/lang/gu.js b/sources/plugins/list/lang/gu.js
new file mode 100644
index 0000000..24a728f
--- /dev/null
+++ b/sources/plugins/list/lang/gu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'gu', {
6 bulletedlist: 'બુલેટ સૂચિ',
7 numberedlist: 'સંખ્યાંકન સૂચિ'
8} );
diff --git a/sources/plugins/list/lang/he.js b/sources/plugins/list/lang/he.js
new file mode 100644
index 0000000..118ddae
--- /dev/null
+++ b/sources/plugins/list/lang/he.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'he', {
6 bulletedlist: 'רשימת נקודות',
7 numberedlist: 'רשימה ממוספרת'
8} );
diff --git a/sources/plugins/list/lang/hi.js b/sources/plugins/list/lang/hi.js
new file mode 100644
index 0000000..a6bbca5
--- /dev/null
+++ b/sources/plugins/list/lang/hi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'hi', {
6 bulletedlist: 'बुलॅट सूची',
7 numberedlist: 'अंकीय सूची'
8} );
diff --git a/sources/plugins/list/lang/hr.js b/sources/plugins/list/lang/hr.js
new file mode 100644
index 0000000..ceb0a4c
--- /dev/null
+++ b/sources/plugins/list/lang/hr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'hr', {
6 bulletedlist: 'Obična lista',
7 numberedlist: 'Brojčana lista'
8} );
diff --git a/sources/plugins/list/lang/hu.js b/sources/plugins/list/lang/hu.js
new file mode 100644
index 0000000..cf2fe96
--- /dev/null
+++ b/sources/plugins/list/lang/hu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'hu', {
6 bulletedlist: 'Felsorolás',
7 numberedlist: 'Számozás'
8} );
diff --git a/sources/plugins/list/lang/id.js b/sources/plugins/list/lang/id.js
new file mode 100644
index 0000000..0b360dc
--- /dev/null
+++ b/sources/plugins/list/lang/id.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'id', {
6 bulletedlist: 'Sisip/Hapus Daftar Bullet',
7 numberedlist: 'Sisip/Hapus Daftar Bernomor'
8} );
diff --git a/sources/plugins/list/lang/is.js b/sources/plugins/list/lang/is.js
new file mode 100644
index 0000000..a23e87e
--- /dev/null
+++ b/sources/plugins/list/lang/is.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'is', {
6 bulletedlist: 'Punktalisti',
7 numberedlist: 'Númeraður listi'
8} );
diff --git a/sources/plugins/list/lang/it.js b/sources/plugins/list/lang/it.js
new file mode 100644
index 0000000..611f6fb
--- /dev/null
+++ b/sources/plugins/list/lang/it.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'it', {
6 bulletedlist: 'Inserisci/Rimuovi Elenco Puntato',
7 numberedlist: 'Inserisci/Rimuovi Elenco Numerato'
8} );
diff --git a/sources/plugins/list/lang/ja.js b/sources/plugins/list/lang/ja.js
new file mode 100644
index 0000000..c2df282
--- /dev/null
+++ b/sources/plugins/list/lang/ja.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ja', {
6 bulletedlist: '番号無しリスト',
7 numberedlist: '番号付きリスト'
8} );
diff --git a/sources/plugins/list/lang/ka.js b/sources/plugins/list/lang/ka.js
new file mode 100644
index 0000000..2053130
--- /dev/null
+++ b/sources/plugins/list/lang/ka.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ka', {
6 bulletedlist: 'ღილიანი სია',
7 numberedlist: 'გადანომრილი სია'
8} );
diff --git a/sources/plugins/list/lang/km.js b/sources/plugins/list/lang/km.js
new file mode 100644
index 0000000..71c0c7b
--- /dev/null
+++ b/sources/plugins/list/lang/km.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'km', {
6 bulletedlist: 'បញ្ចូល / លុប​បញ្ជី​ជា​ចំណុច​មូល',
7 numberedlist: 'បញ្ចូល / លុប​បញ្ជី​ជា​លេខ'
8} );
diff --git a/sources/plugins/list/lang/ko.js b/sources/plugins/list/lang/ko.js
new file mode 100644
index 0000000..48b4fd0
--- /dev/null
+++ b/sources/plugins/list/lang/ko.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ko', {
6 bulletedlist: '순서 없는 목록',
7 numberedlist: '순서 있는 목록'
8} );
diff --git a/sources/plugins/list/lang/ku.js b/sources/plugins/list/lang/ku.js
new file mode 100644
index 0000000..c5d0d9c
--- /dev/null
+++ b/sources/plugins/list/lang/ku.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ku', {
6 bulletedlist: 'دانان/لابردنی خاڵی لیست',
7 numberedlist: 'دانان/لابردنی ژمارەی لیست'
8} );
diff --git a/sources/plugins/list/lang/lt.js b/sources/plugins/list/lang/lt.js
new file mode 100644
index 0000000..0eac62e
--- /dev/null
+++ b/sources/plugins/list/lang/lt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'lt', {
6 bulletedlist: 'Suženklintas sąrašas',
7 numberedlist: 'Numeruotas sąrašas'
8} );
diff --git a/sources/plugins/list/lang/lv.js b/sources/plugins/list/lang/lv.js
new file mode 100644
index 0000000..6738856
--- /dev/null
+++ b/sources/plugins/list/lang/lv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'lv', {
6 bulletedlist: 'Pievienot/Noņemt vienkāršu sarakstu',
7 numberedlist: 'Numurēts saraksts'
8} );
diff --git a/sources/plugins/list/lang/mk.js b/sources/plugins/list/lang/mk.js
new file mode 100644
index 0000000..4054ea2
--- /dev/null
+++ b/sources/plugins/list/lang/mk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'mk', {
6 bulletedlist: 'Insert/Remove Bulleted List', // MISSING
7 numberedlist: 'Insert/Remove Numbered List' // MISSING
8} );
diff --git a/sources/plugins/list/lang/mn.js b/sources/plugins/list/lang/mn.js
new file mode 100644
index 0000000..ef9d4e0
--- /dev/null
+++ b/sources/plugins/list/lang/mn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'mn', {
6 bulletedlist: 'Цэгтэй жагсаалт',
7 numberedlist: 'Дугаарлагдсан жагсаалт'
8} );
diff --git a/sources/plugins/list/lang/ms.js b/sources/plugins/list/lang/ms.js
new file mode 100644
index 0000000..6d51a33
--- /dev/null
+++ b/sources/plugins/list/lang/ms.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ms', {
6 bulletedlist: 'Senarai tidak bernombor',
7 numberedlist: 'Senarai bernombor'
8} );
diff --git a/sources/plugins/list/lang/nb.js b/sources/plugins/list/lang/nb.js
new file mode 100644
index 0000000..0e817c8
--- /dev/null
+++ b/sources/plugins/list/lang/nb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'nb', {
6 bulletedlist: 'Legg til / fjern punktliste',
7 numberedlist: 'Legg til / fjern nummerert liste'
8} );
diff --git a/sources/plugins/list/lang/nl.js b/sources/plugins/list/lang/nl.js
new file mode 100644
index 0000000..65f71e9
--- /dev/null
+++ b/sources/plugins/list/lang/nl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'nl', {
6 bulletedlist: 'Opsomming invoegen',
7 numberedlist: 'Genummerde lijst invoegen'
8} );
diff --git a/sources/plugins/list/lang/no.js b/sources/plugins/list/lang/no.js
new file mode 100644
index 0000000..dc129c5
--- /dev/null
+++ b/sources/plugins/list/lang/no.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'no', {
6 bulletedlist: 'Legg til/Fjern punktmerket liste',
7 numberedlist: 'Legg til/Fjern nummerert liste'
8} );
diff --git a/sources/plugins/list/lang/oc.js b/sources/plugins/list/lang/oc.js
new file mode 100644
index 0000000..4705e9a
--- /dev/null
+++ b/sources/plugins/list/lang/oc.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'oc', {
6 bulletedlist: 'Inserir/Suprimir una lista amb de piuses',
7 numberedlist: 'Inserir/Suprimir una lista numerotada'
8} );
diff --git a/sources/plugins/list/lang/pl.js b/sources/plugins/list/lang/pl.js
new file mode 100644
index 0000000..0a0e552
--- /dev/null
+++ b/sources/plugins/list/lang/pl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'pl', {
6 bulletedlist: 'Lista wypunktowana',
7 numberedlist: 'Lista numerowana'
8} );
diff --git a/sources/plugins/list/lang/pt-br.js b/sources/plugins/list/lang/pt-br.js
new file mode 100644
index 0000000..b0edd8e
--- /dev/null
+++ b/sources/plugins/list/lang/pt-br.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'pt-br', {
6 bulletedlist: 'Lista sem números',
7 numberedlist: 'Lista numerada'
8} );
diff --git a/sources/plugins/list/lang/pt.js b/sources/plugins/list/lang/pt.js
new file mode 100644
index 0000000..52d4348
--- /dev/null
+++ b/sources/plugins/list/lang/pt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'pt', {
6 bulletedlist: 'Marcas',
7 numberedlist: 'Numeração'
8} );
diff --git a/sources/plugins/list/lang/ro.js b/sources/plugins/list/lang/ro.js
new file mode 100644
index 0000000..c229901
--- /dev/null
+++ b/sources/plugins/list/lang/ro.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ro', {
6 bulletedlist: 'Inserează / Elimină Listă cu puncte',
7 numberedlist: 'Inserează / Elimină Listă numerotată'
8} );
diff --git a/sources/plugins/list/lang/ru.js b/sources/plugins/list/lang/ru.js
new file mode 100644
index 0000000..862fa78
--- /dev/null
+++ b/sources/plugins/list/lang/ru.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ru', {
6 bulletedlist: 'Вставить / удалить маркированный список',
7 numberedlist: 'Вставить / удалить нумерованный список'
8} );
diff --git a/sources/plugins/list/lang/si.js b/sources/plugins/list/lang/si.js
new file mode 100644
index 0000000..de2fc4d
--- /dev/null
+++ b/sources/plugins/list/lang/si.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'si', {
6 bulletedlist: 'ඇතුලත් / ඉවත් කිරීම ලඉස්තුව',
7 numberedlist: 'ඇතුලත් / ඉවත් කිරීම අන්න්කිත ලඉස්තුව'
8} );
diff --git a/sources/plugins/list/lang/sk.js b/sources/plugins/list/lang/sk.js
new file mode 100644
index 0000000..11ca0ee
--- /dev/null
+++ b/sources/plugins/list/lang/sk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sk', {
6 bulletedlist: 'Vložiť/odstrániť zoznam s odrážkami',
7 numberedlist: 'Vložiť/odstrániť číslovaný zoznam'
8} );
diff --git a/sources/plugins/list/lang/sl.js b/sources/plugins/list/lang/sl.js
new file mode 100644
index 0000000..368f9f6
--- /dev/null
+++ b/sources/plugins/list/lang/sl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sl', {
6 bulletedlist: 'Vstavi/odstrani neoštevilčen seznam',
7 numberedlist: 'Vstavi/odstrani oštevilčen seznam'
8} );
diff --git a/sources/plugins/list/lang/sq.js b/sources/plugins/list/lang/sq.js
new file mode 100644
index 0000000..121b41e
--- /dev/null
+++ b/sources/plugins/list/lang/sq.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sq', {
6 bulletedlist: 'Vendos/Largo Listën me Pika',
7 numberedlist: 'Vendos/Largo Listën me Numra'
8} );
diff --git a/sources/plugins/list/lang/sr-latn.js b/sources/plugins/list/lang/sr-latn.js
new file mode 100644
index 0000000..134aa69
--- /dev/null
+++ b/sources/plugins/list/lang/sr-latn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sr-latn', {
6 bulletedlist: 'Nenabrojiva lista',
7 numberedlist: 'Nabrojiva lista'
8} );
diff --git a/sources/plugins/list/lang/sr.js b/sources/plugins/list/lang/sr.js
new file mode 100644
index 0000000..c54ca8a
--- /dev/null
+++ b/sources/plugins/list/lang/sr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sr', {
6 bulletedlist: 'Ненабројива листа',
7 numberedlist: 'Набројиву листу'
8} );
diff --git a/sources/plugins/list/lang/sv.js b/sources/plugins/list/lang/sv.js
new file mode 100644
index 0000000..3a12793
--- /dev/null
+++ b/sources/plugins/list/lang/sv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'sv', {
6 bulletedlist: 'Infoga/ta bort punktlista',
7 numberedlist: 'Infoga/ta bort numrerad lista'
8} );
diff --git a/sources/plugins/list/lang/th.js b/sources/plugins/list/lang/th.js
new file mode 100644
index 0000000..8a47731
--- /dev/null
+++ b/sources/plugins/list/lang/th.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'th', {
6 bulletedlist: 'ลำดับรายการแบบสัญลักษณ์',
7 numberedlist: 'ลำดับรายการแบบตัวเลข'
8} );
diff --git a/sources/plugins/list/lang/tr.js b/sources/plugins/list/lang/tr.js
new file mode 100644
index 0000000..976e479
--- /dev/null
+++ b/sources/plugins/list/lang/tr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'tr', {
6 bulletedlist: 'Simgeli Liste',
7 numberedlist: 'Numaralı Liste'
8} );
diff --git a/sources/plugins/list/lang/tt.js b/sources/plugins/list/lang/tt.js
new file mode 100644
index 0000000..eb103ab
--- /dev/null
+++ b/sources/plugins/list/lang/tt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'tt', {
6 bulletedlist: 'Маркерлы тезмә өстәү/бетерү',
7 numberedlist: ' Номерланган тезмә өстәү/бетерү'
8} );
diff --git a/sources/plugins/list/lang/ug.js b/sources/plugins/list/lang/ug.js
new file mode 100644
index 0000000..442b92e
--- /dev/null
+++ b/sources/plugins/list/lang/ug.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'ug', {
6 bulletedlist: 'تۈر بەلگە تىزىمى',
7 numberedlist: 'تەرتىپ نومۇر تىزىمى'
8} );
diff --git a/sources/plugins/list/lang/uk.js b/sources/plugins/list/lang/uk.js
new file mode 100644
index 0000000..65a3e1d
--- /dev/null
+++ b/sources/plugins/list/lang/uk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'uk', {
6 bulletedlist: 'Маркірований список',
7 numberedlist: 'Нумерований список'
8} );
diff --git a/sources/plugins/list/lang/vi.js b/sources/plugins/list/lang/vi.js
new file mode 100644
index 0000000..e9e3acc
--- /dev/null
+++ b/sources/plugins/list/lang/vi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'vi', {
6 bulletedlist: 'Chèn/Xoá Danh sách không thứ tự',
7 numberedlist: 'Chèn/Xoá Danh sách có thứ tự'
8} );
diff --git a/sources/plugins/list/lang/zh-cn.js b/sources/plugins/list/lang/zh-cn.js
new file mode 100644
index 0000000..5e0408b
--- /dev/null
+++ b/sources/plugins/list/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'zh-cn', {
6 bulletedlist: '项目列表',
7 numberedlist: '编号列表'
8} );
diff --git a/sources/plugins/list/lang/zh.js b/sources/plugins/list/lang/zh.js
new file mode 100644
index 0000000..3d207d6
--- /dev/null
+++ b/sources/plugins/list/lang/zh.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'list', 'zh', {
6 bulletedlist: '插入/移除項目符號清單',
7 numberedlist: '插入/移除編號清單清單'
8} );
diff --git a/sources/plugins/list/plugin.js b/sources/plugins/list/plugin.js
new file mode 100644
index 0000000..7280cc2
--- /dev/null
+++ b/sources/plugins/list/plugin.js
@@ -0,0 +1,1111 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview Insert and remove numbered and bulleted lists.
8 */
9
10( function() {
11 var listNodeNames = { ol: 1, ul: 1 };
12
13 var whitespaces = CKEDITOR.dom.walker.whitespaces(),
14 bookmarks = CKEDITOR.dom.walker.bookmark(),
15 nonEmpty = function( node ) {
16 return !( whitespaces( node ) || bookmarks( node ) );
17 },
18 blockBogus = CKEDITOR.dom.walker.bogus();
19
20 function cleanUpDirection( element ) {
21 var dir, parent, parentDir;
22 if ( ( dir = element.getDirection() ) ) {
23 parent = element.getParent();
24 while ( parent && !( parentDir = parent.getDirection() ) )
25 parent = parent.getParent();
26
27 if ( dir == parentDir )
28 element.removeAttribute( 'dir' );
29 }
30 }
31
32 // Inherit inline styles from another element.
33 function inheritInlineStyles( parent, el ) {
34 var style = parent.getAttribute( 'style' );
35
36 // Put parent styles before child styles.
37 style && el.setAttribute( 'style', style.replace( /([^;])$/, '$1;' ) + ( el.getAttribute( 'style' ) || '' ) );
38 }
39
40 CKEDITOR.plugins.list = {
41 /**
42 * Convert a DOM list tree into a data structure that is easier to
43 * manipulate. This operation should be non-intrusive in the sense that it
44 * does not change the DOM tree, with the exception that it may add some
45 * markers to the list item nodes when database is specified.
46 *
47 * @member CKEDITOR.plugins.list
48 * @todo params
49 */
50 listToArray: function( listNode, database, baseArray, baseIndentLevel, grandparentNode ) {
51 if ( !listNodeNames[ listNode.getName() ] )
52 return [];
53
54 if ( !baseIndentLevel )
55 baseIndentLevel = 0;
56 if ( !baseArray )
57 baseArray = [];
58
59 // Iterate over all list items to and look for inner lists.
60 for ( var i = 0, count = listNode.getChildCount(); i < count; i++ ) {
61 var listItem = listNode.getChild( i );
62
63 // Fixing malformed nested lists by moving it into a previous list item. (#6236)
64 if ( listItem.type == CKEDITOR.NODE_ELEMENT && listItem.getName() in CKEDITOR.dtd.$list )
65 CKEDITOR.plugins.list.listToArray( listItem, database, baseArray, baseIndentLevel + 1 );
66
67 // It may be a text node or some funny stuff.
68 if ( listItem.$.nodeName.toLowerCase() != 'li' )
69 continue;
70
71 var itemObj = { 'parent': listNode, indent: baseIndentLevel, element: listItem, contents: [] };
72 if ( !grandparentNode ) {
73 itemObj.grandparent = listNode.getParent();
74 if ( itemObj.grandparent && itemObj.grandparent.$.nodeName.toLowerCase() == 'li' )
75 itemObj.grandparent = itemObj.grandparent.getParent();
76 } else {
77 itemObj.grandparent = grandparentNode;
78 }
79
80 if ( database )
81 CKEDITOR.dom.element.setMarker( database, listItem, 'listarray_index', baseArray.length );
82 baseArray.push( itemObj );
83
84 for ( var j = 0, itemChildCount = listItem.getChildCount(), child; j < itemChildCount; j++ ) {
85 child = listItem.getChild( j );
86 if ( child.type == CKEDITOR.NODE_ELEMENT && listNodeNames[ child.getName() ] )
87 // Note the recursion here, it pushes inner list items with
88 // +1 indentation in the correct order.
89 CKEDITOR.plugins.list.listToArray( child, database, baseArray, baseIndentLevel + 1, itemObj.grandparent );
90 else
91 itemObj.contents.push( child );
92 }
93 }
94 return baseArray;
95 },
96
97 /**
98 * Convert our internal representation of a list back to a DOM forest.
99 *
100 * @member CKEDITOR.plugins.list
101 * @todo params
102 */
103 arrayToList: function( listArray, database, baseIndex, paragraphMode, dir ) {
104 if ( !baseIndex )
105 baseIndex = 0;
106 if ( !listArray || listArray.length < baseIndex + 1 )
107 return null;
108
109 var i,
110 doc = listArray[ baseIndex ].parent.getDocument(),
111 retval = new CKEDITOR.dom.documentFragment( doc ),
112 rootNode = null,
113 currentIndex = baseIndex,
114 indentLevel = Math.max( listArray[ baseIndex ].indent, 0 ),
115 currentListItem = null,
116 orgDir, block,
117 paragraphName = ( paragraphMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
118
119 while ( 1 ) {
120 var item = listArray[ currentIndex ],
121 itemGrandParent = item.grandparent;
122
123 orgDir = item.element.getDirection( 1 );
124
125 if ( item.indent == indentLevel ) {
126 if ( !rootNode || listArray[ currentIndex ].parent.getName() != rootNode.getName() ) {
127 rootNode = listArray[ currentIndex ].parent.clone( false, 1 );
128 dir && rootNode.setAttribute( 'dir', dir );
129 retval.append( rootNode );
130 }
131 currentListItem = rootNode.append( item.element.clone( 0, 1 ) );
132
133 if ( orgDir != rootNode.getDirection( 1 ) )
134 currentListItem.setAttribute( 'dir', orgDir );
135
136 for ( i = 0; i < item.contents.length; i++ )
137 currentListItem.append( item.contents[ i ].clone( 1, 1 ) );
138 currentIndex++;
139 } else if ( item.indent == Math.max( indentLevel, 0 ) + 1 ) {
140 // Maintain original direction (#6861).
141 var currDir = listArray[ currentIndex - 1 ].element.getDirection( 1 ),
142 listData = CKEDITOR.plugins.list.arrayToList( listArray, null, currentIndex, paragraphMode, currDir != orgDir ? orgDir : null );
143
144 // If the next block is an <li> with another list tree as the first
145 // child, we'll need to append a filler (<br>/NBSP) or the list item
146 // wouldn't be editable. (#6724)
147 if ( !currentListItem.getChildCount() && CKEDITOR.env.needsNbspFiller && doc.$.documentMode <= 7 )
148 currentListItem.append( doc.createText( '\xa0' ) );
149 currentListItem.append( listData.listNode );
150 currentIndex = listData.nextIndex;
151 } else if ( item.indent == -1 && !baseIndex && itemGrandParent ) {
152 if ( listNodeNames[ itemGrandParent.getName() ] ) {
153 currentListItem = item.element.clone( false, true );
154 if ( orgDir != itemGrandParent.getDirection( 1 ) )
155 currentListItem.setAttribute( 'dir', orgDir );
156 } else {
157 currentListItem = new CKEDITOR.dom.documentFragment( doc );
158 }
159
160 // Migrate all children to the new container,
161 // apply the proper text direction.
162 var dirLoose = itemGrandParent.getDirection( 1 ) != orgDir,
163 li = item.element,
164 className = li.getAttribute( 'class' ),
165 style = li.getAttribute( 'style' );
166
167 var needsBlock = currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && ( paragraphMode != CKEDITOR.ENTER_BR || dirLoose || style || className );
168
169 var child,
170 count = item.contents.length,
171 cachedBookmark;
172
173 for ( i = 0; i < count; i++ ) {
174 child = item.contents[ i ];
175
176 // Append bookmark if we can, or cache it and append it when we'll know
177 // what to do with it. Generally - we want to keep it next to its original neighbour.
178 // Exception: if bookmark is the only child it hasn't got any neighbour, so handle it normally
179 // (wrap with block if needed).
180 if ( bookmarks( child ) && count > 1 ) {
181 // If we don't need block, it's simple - append bookmark directly to the current list item.
182 if ( !needsBlock )
183 currentListItem.append( child.clone( 1, 1 ) );
184 else
185 cachedBookmark = child.clone( 1, 1 );
186 }
187 // Block content goes directly to the current list item, without wrapping.
188 else if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() ) {
189 // Apply direction on content blocks.
190 if ( dirLoose && !child.getDirection() )
191 child.setAttribute( 'dir', orgDir );
192
193 inheritInlineStyles( li, child );
194
195 className && child.addClass( className );
196
197 // Close the block which we started for inline content.
198 block = null;
199 // Append bookmark directly before current child.
200 if ( cachedBookmark ) {
201 currentListItem.append( cachedBookmark );
202 cachedBookmark = null;
203 }
204 // Append this block element to the list item.
205 currentListItem.append( child.clone( 1, 1 ) );
206 }
207 // Some inline content was found - wrap it with block and append that
208 // block to the current list item or append it to the block previously created.
209 else if ( needsBlock ) {
210 // Establish new block to hold text direction and styles.
211 if ( !block ) {
212 block = doc.createElement( paragraphName );
213 currentListItem.append( block );
214 dirLoose && block.setAttribute( 'dir', orgDir );
215 }
216
217 // Copy over styles to new block;
218 style && block.setAttribute( 'style', style );
219 className && block.setAttribute( 'class', className );
220
221 // Append bookmark directly before current child.
222 if ( cachedBookmark ) {
223 block.append( cachedBookmark );
224 cachedBookmark = null;
225 }
226 block.append( child.clone( 1, 1 ) );
227 }
228 // E.g. BR mode - inline content appended directly to the list item.
229 else {
230 currentListItem.append( child.clone( 1, 1 ) );
231 }
232 }
233
234 // No content after bookmark - append it to the block if we had one
235 // or directly to the current list item if we finished directly in the current list item.
236 if ( cachedBookmark ) {
237 ( block || currentListItem ).append( cachedBookmark );
238 cachedBookmark = null;
239 }
240
241 if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && currentIndex != listArray.length - 1 ) {
242 var last;
243
244 // Remove bogus <br> if this browser uses them.
245 if ( CKEDITOR.env.needsBrFiller ) {
246 last = currentListItem.getLast();
247 if ( last && last.type == CKEDITOR.NODE_ELEMENT && last.is( 'br' ) )
248 last.remove();
249 }
250
251 // If the last element is not a block, append <br> to separate merged list items.
252 last = currentListItem.getLast( nonEmpty );
253 if ( !( last && last.type == CKEDITOR.NODE_ELEMENT && last.is( CKEDITOR.dtd.$block ) ) )
254 currentListItem.append( doc.createElement( 'br' ) );
255 }
256
257 var currentListItemName = currentListItem.$.nodeName.toLowerCase();
258 if ( currentListItemName == 'div' || currentListItemName == 'p' ) {
259 currentListItem.appendBogus();
260 }
261 retval.append( currentListItem );
262 rootNode = null;
263 currentIndex++;
264 } else {
265 return null;
266 }
267
268 block = null;
269
270 if ( listArray.length <= currentIndex || Math.max( listArray[ currentIndex ].indent, 0 ) < indentLevel )
271 break;
272 }
273
274 if ( database ) {
275 var currentNode = retval.getFirst();
276
277 while ( currentNode ) {
278 if ( currentNode.type == CKEDITOR.NODE_ELEMENT ) {
279 // Clear marker attributes for the new list tree made of cloned nodes, if any.
280 CKEDITOR.dom.element.clearMarkers( database, currentNode );
281
282 // Clear redundant direction attribute specified on list items.
283 if ( currentNode.getName() in CKEDITOR.dtd.$listItem )
284 cleanUpDirection( currentNode );
285 }
286
287 currentNode = currentNode.getNextSourceNode();
288 }
289 }
290
291 return { listNode: retval, nextIndex: currentIndex };
292 }
293 };
294
295 function changeListType( editor, groupObj, database, listsCreated ) {
296 // This case is easy...
297 // 1. Convert the whole list into a one-dimensional array.
298 // 2. Change the list type by modifying the array.
299 // 3. Recreate the whole list by converting the array to a list.
300 // 4. Replace the original list with the recreated list.
301 var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
302 selectedListItems = [];
303
304 for ( var i = 0; i < groupObj.contents.length; i++ ) {
305 var itemNode = groupObj.contents[ i ];
306 itemNode = itemNode.getAscendant( 'li', true );
307 if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
308 continue;
309 selectedListItems.push( itemNode );
310 CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
311 }
312
313 var root = groupObj.root,
314 doc = root.getDocument(),
315 listNode, newListNode;
316
317 for ( i = 0; i < selectedListItems.length; i++ ) {
318 var listIndex = selectedListItems[ i ].getCustomData( 'listarray_index' );
319 listNode = listArray[ listIndex ].parent;
320
321 // Switch to new list node for this particular item.
322 if ( !listNode.is( this.type ) ) {
323 newListNode = doc.createElement( this.type );
324 // Copy all attributes, except from 'start' and 'type'.
325 listNode.copyAttributes( newListNode, { start: 1, type: 1 } );
326 // The list-style-type property should be ignored.
327 newListNode.removeStyle( 'list-style-type' );
328 listArray[ listIndex ].parent = newListNode;
329 }
330 }
331
332 var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
333 var child,
334 length = newList.listNode.getChildCount();
335 for ( i = 0; i < length && ( child = newList.listNode.getChild( i ) ); i++ ) {
336 if ( child.getName() == this.type )
337 listsCreated.push( child );
338 }
339 newList.listNode.replace( groupObj.root );
340
341 editor.fire( 'contentDomInvalidated' );
342 }
343
344 function createList( editor, groupObj, listsCreated ) {
345 var contents = groupObj.contents,
346 doc = groupObj.root.getDocument(),
347 listContents = [];
348
349 // It is possible to have the contents returned by DomRangeIterator to be the same as the root.
350 // e.g. when we're running into table cells.
351 // In such a case, enclose the childNodes of contents[0] into a <div>.
352 if ( contents.length == 1 && contents[ 0 ].equals( groupObj.root ) ) {
353 var divBlock = doc.createElement( 'div' );
354 contents[ 0 ].moveChildren && contents[ 0 ].moveChildren( divBlock );
355 contents[ 0 ].append( divBlock );
356 contents[ 0 ] = divBlock;
357 }
358
359 // Calculate the common parent node of all content blocks.
360 var commonParent = groupObj.contents[ 0 ].getParent();
361 for ( var i = 0; i < contents.length; i++ )
362 commonParent = commonParent.getCommonAncestor( contents[ i ].getParent() );
363
364 var useComputedState = editor.config.useComputedState,
365 listDir, explicitDirection;
366
367 useComputedState = useComputedState === undefined || useComputedState;
368
369 // We want to insert things that are in the same tree level only, so calculate the contents again
370 // by expanding the selected blocks to the same tree level.
371 for ( i = 0; i < contents.length; i++ ) {
372 var contentNode = contents[ i ],
373 parentNode;
374 while ( ( parentNode = contentNode.getParent() ) ) {
375 if ( parentNode.equals( commonParent ) ) {
376 listContents.push( contentNode );
377
378 // Determine the lists's direction.
379 if ( !explicitDirection && contentNode.getDirection() )
380 explicitDirection = 1;
381
382 var itemDir = contentNode.getDirection( useComputedState );
383
384 if ( listDir !== null ) {
385 // If at least one LI have a different direction than current listDir, we can't have listDir.
386 if ( listDir && listDir != itemDir )
387 listDir = null;
388 else
389 listDir = itemDir;
390 }
391
392 break;
393 }
394 contentNode = parentNode;
395 }
396 }
397
398 if ( listContents.length < 1 )
399 return;
400
401 // Insert the list to the DOM tree.
402 var insertAnchor = listContents[ listContents.length - 1 ].getNext(),
403 listNode = doc.createElement( this.type );
404
405 listsCreated.push( listNode );
406
407 var contentBlock, listItem;
408
409 while ( listContents.length ) {
410 contentBlock = listContents.shift();
411 listItem = doc.createElement( 'li' );
412
413 // If current block should be preserved, append it to list item instead of
414 // transforming it to <li> element.
415 if ( shouldPreserveBlock( contentBlock ) )
416 contentBlock.appendTo( listItem );
417 else {
418 contentBlock.copyAttributes( listItem );
419 // Remove direction attribute after it was merged into list root. (#7657)
420 if ( listDir && contentBlock.getDirection() ) {
421 listItem.removeStyle( 'direction' );
422 listItem.removeAttribute( 'dir' );
423 }
424 contentBlock.moveChildren( listItem );
425 contentBlock.remove();
426 }
427
428 listItem.appendTo( listNode );
429 }
430
431 // Apply list root dir only if it has been explicitly declared.
432 if ( listDir && explicitDirection )
433 listNode.setAttribute( 'dir', listDir );
434
435 if ( insertAnchor )
436 listNode.insertBefore( insertAnchor );
437 else
438 listNode.appendTo( commonParent );
439 }
440
441 function removeList( editor, groupObj, database ) {
442 // This is very much like the change list type operation.
443 // Except that we're changing the selected items' indent to -1 in the list array.
444 var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
445 selectedListItems = [];
446
447 for ( var i = 0; i < groupObj.contents.length; i++ ) {
448 var itemNode = groupObj.contents[ i ];
449 itemNode = itemNode.getAscendant( 'li', true );
450 if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
451 continue;
452 selectedListItems.push( itemNode );
453 CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
454 }
455
456 var lastListIndex = null;
457 for ( i = 0; i < selectedListItems.length; i++ ) {
458 var listIndex = selectedListItems[ i ].getCustomData( 'listarray_index' );
459 listArray[ listIndex ].indent = -1;
460 lastListIndex = listIndex;
461 }
462
463 // After cutting parts of the list out with indent=-1, we still have to maintain the array list
464 // model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the
465 // list cannot be converted back to a real DOM list.
466 for ( i = lastListIndex + 1; i < listArray.length; i++ ) {
467 if ( listArray[ i ].indent > listArray[ i - 1 ].indent + 1 ) {
468 var indentOffset = listArray[ i - 1 ].indent + 1 - listArray[ i ].indent;
469 var oldIndent = listArray[ i ].indent;
470 while ( listArray[ i ] && listArray[ i ].indent >= oldIndent ) {
471 listArray[ i ].indent += indentOffset;
472 i++;
473 }
474 i--;
475 }
476 }
477
478 var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, groupObj.root.getAttribute( 'dir' ) );
479
480 // Compensate <br> before/after the list node if the surrounds are non-blocks.(#3836)
481 var docFragment = newList.listNode,
482 boundaryNode, siblingNode;
483
484 function compensateBrs( isStart ) {
485 if (
486 ( boundaryNode = docFragment[ isStart ? 'getFirst' : 'getLast' ]() ) &&
487 !( boundaryNode.is && boundaryNode.isBlockBoundary() ) &&
488 ( siblingNode = groupObj.root[ isStart ? 'getPrevious' : 'getNext' ]( CKEDITOR.dom.walker.invisible( true ) ) ) &&
489 !( siblingNode.is && siblingNode.isBlockBoundary( { br: 1 } ) )
490 ) {
491 editor.document.createElement( 'br' )[ isStart ? 'insertBefore' : 'insertAfter' ]( boundaryNode );
492 }
493 }
494 compensateBrs( true );
495 compensateBrs();
496
497 docFragment.replace( groupObj.root );
498
499 editor.fire( 'contentDomInvalidated' );
500 }
501
502 var headerTagRegex = /^h[1-6]$/;
503
504 // Checks wheather this block should be element preserved (not transformed to <li>) when creating list.
505 function shouldPreserveBlock( block ) {
506 return (
507 // #5335
508 block.is( 'pre' ) ||
509 // #5271 - this is a header.
510 headerTagRegex.test( block.getName() ) ||
511 // 11083 - this is a non-editable element.
512 block.getAttribute( 'contenteditable' ) == 'false'
513 );
514 }
515
516 function listCommand( name, type ) {
517 this.name = name;
518 this.type = type;
519 this.context = type;
520 this.allowedContent = type + ' li';
521 this.requiredContent = type;
522 }
523
524 var elementType = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_ELEMENT );
525
526 // Merge child nodes with direction preserved. (#7448)
527 function mergeChildren( from, into, refNode, forward ) {
528 var child, itemDir;
529 while ( ( child = from[ forward ? 'getLast' : 'getFirst' ]( elementType ) ) ) {
530 if ( ( itemDir = child.getDirection( 1 ) ) !== into.getDirection( 1 ) )
531 child.setAttribute( 'dir', itemDir );
532
533 child.remove();
534
535 refNode ? child[ forward ? 'insertBefore' : 'insertAfter' ]( refNode ) : into.append( child, forward );
536 }
537 }
538
539 listCommand.prototype = {
540 exec: function( editor ) {
541 // Run state check first of all.
542 this.refresh( editor, editor.elementPath() );
543
544 var config = editor.config,
545 selection = editor.getSelection(),
546 ranges = selection && selection.getRanges();
547
548 // Midas lists rule #1 says we can create a list even in an empty document.
549 // But DOM iterator wouldn't run if the document is really empty.
550 // So create a paragraph if the document is empty and we're going to create a list.
551 if ( this.state == CKEDITOR.TRISTATE_OFF ) {
552 var editable = editor.editable();
553 if ( !editable.getFirst( nonEmpty ) ) {
554 config.enterMode == CKEDITOR.ENTER_BR ? editable.appendBogus() : ranges[ 0 ].fixBlock( 1, config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
555
556 selection.selectRanges( ranges );
557 }
558 // Maybe a single range there enclosing the whole list,
559 // turn on the list state manually(#4129).
560 else {
561 var range = ranges.length == 1 && ranges[ 0 ],
562 enclosedNode = range && range.getEnclosedNode();
563 if ( enclosedNode && enclosedNode.is && this.type == enclosedNode.getName() )
564 this.setState( CKEDITOR.TRISTATE_ON );
565 }
566 }
567
568 var bookmarks = selection.createBookmarks( true );
569
570 // Group the blocks up because there are many cases where multiple lists have to be created,
571 // or multiple lists have to be cancelled.
572 var listGroups = [],
573 database = {},
574 rangeIterator = ranges.createIterator(),
575 index = 0;
576
577 while ( ( range = rangeIterator.getNextRange() ) && ++index ) {
578 var boundaryNodes = range.getBoundaryNodes(),
579 startNode = boundaryNodes.startNode,
580 endNode = boundaryNodes.endNode;
581
582 if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.getName() == 'td' )
583 range.setStartAt( boundaryNodes.startNode, CKEDITOR.POSITION_AFTER_START );
584
585 if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.getName() == 'td' )
586 range.setEndAt( boundaryNodes.endNode, CKEDITOR.POSITION_BEFORE_END );
587
588 var iterator = range.createIterator(),
589 block;
590
591 iterator.forceBrBreak = ( this.state == CKEDITOR.TRISTATE_OFF );
592
593 while ( ( block = iterator.getNextParagraph() ) ) {
594 // Avoid duplicate blocks get processed across ranges.
595 if ( block.getCustomData( 'list_block' ) )
596 continue;
597 else
598 CKEDITOR.dom.element.setMarker( database, block, 'list_block', 1 );
599
600 var path = editor.elementPath( block ),
601 pathElements = path.elements,
602 pathElementsCount = pathElements.length,
603 processedFlag = 0,
604 blockLimit = path.blockLimit,
605 element;
606
607 // First, try to group by a list ancestor.
608 for ( var i = pathElementsCount - 1; i >= 0 && ( element = pathElements[ i ] ); i-- ) {
609 // Don't leak outside block limit (#3940).
610 if ( listNodeNames[ element.getName() ] && blockLimit.contains( element ) ) {
611 // If we've encountered a list inside a block limit
612 // The last group object of the block limit element should
613 // no longer be valid. Since paragraphs after the list
614 // should belong to a different group of paragraphs before
615 // the list. (Bug #1309)
616 blockLimit.removeCustomData( 'list_group_object_' + index );
617
618 var groupObj = element.getCustomData( 'list_group_object' );
619 if ( groupObj )
620 groupObj.contents.push( block );
621 else {
622 groupObj = { root: element, contents: [ block ] };
623 listGroups.push( groupObj );
624 CKEDITOR.dom.element.setMarker( database, element, 'list_group_object', groupObj );
625 }
626 processedFlag = 1;
627 break;
628 }
629 }
630
631 if ( processedFlag )
632 continue;
633
634 // No list ancestor? Group by block limit, but don't mix contents from different ranges.
635 var root = blockLimit;
636 if ( root.getCustomData( 'list_group_object_' + index ) )
637 root.getCustomData( 'list_group_object_' + index ).contents.push( block );
638 else {
639 groupObj = { root: root, contents: [ block ] };
640 CKEDITOR.dom.element.setMarker( database, root, 'list_group_object_' + index, groupObj );
641 listGroups.push( groupObj );
642 }
643 }
644 }
645
646 // Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element.
647 // We either have to build lists or remove lists, for removing a list does not makes sense when we are looking
648 // at the group that's not rooted at lists. So we have three cases to handle.
649 var listsCreated = [];
650 while ( listGroups.length > 0 ) {
651 groupObj = listGroups.shift();
652 if ( this.state == CKEDITOR.TRISTATE_OFF ) {
653 if ( listNodeNames[ groupObj.root.getName() ] )
654 changeListType.call( this, editor, groupObj, database, listsCreated );
655 else
656 createList.call( this, editor, groupObj, listsCreated );
657 } else if ( this.state == CKEDITOR.TRISTATE_ON && listNodeNames[ groupObj.root.getName() ] ) {
658 removeList.call( this, editor, groupObj, database );
659 }
660 }
661
662 // For all new lists created, merge into adjacent, same type lists.
663 for ( i = 0; i < listsCreated.length; i++ )
664 mergeListSiblings( listsCreated[ i ] );
665
666 // Clean up, restore selection and update toolbar button states.
667 CKEDITOR.dom.element.clearAllMarkers( database );
668 selection.selectBookmarks( bookmarks );
669 editor.focus();
670 },
671
672 refresh: function( editor, path ) {
673 var list = path.contains( listNodeNames, 1 ),
674 limit = path.blockLimit || path.root;
675
676 // 1. Only a single type of list activate.
677 // 2. Do not show list outside of block limit.
678 if ( list && limit.contains( list ) )
679 this.setState( list.is( this.type ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
680 else
681 this.setState( CKEDITOR.TRISTATE_OFF );
682 }
683 };
684
685 // Merge list adjacent, of same type lists.
686 function mergeListSiblings( listNode ) {
687
688 function mergeSibling( rtl ) {
689 var sibling = listNode[ rtl ? 'getPrevious' : 'getNext' ]( nonEmpty );
690 if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT && sibling.is( listNode.getName() ) ) {
691 // Move children order by merge direction.(#3820)
692 mergeChildren( listNode, sibling, null, !rtl );
693
694 listNode.remove();
695 listNode = sibling;
696 }
697 }
698
699 mergeSibling();
700 mergeSibling( 1 );
701 }
702
703 // Check if node is block element that recieves text.
704 function isTextBlock( node ) {
705 return node.type == CKEDITOR.NODE_ELEMENT && ( node.getName() in CKEDITOR.dtd.$block || node.getName() in CKEDITOR.dtd.$listItem ) && CKEDITOR.dtd[ node.getName() ][ '#' ];
706 }
707
708 // Join visually two block lines.
709 function joinNextLineToCursor( editor, cursor, nextCursor ) {
710 editor.fire( 'saveSnapshot' );
711
712 // Merge with previous block's content.
713 nextCursor.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
714 var frag = nextCursor.extractContents();
715
716 cursor.trim( false, true );
717 var bm = cursor.createBookmark();
718
719 // Kill original bogus;
720 var currentPath = new CKEDITOR.dom.elementPath( cursor.startContainer ),
721 pathBlock = currentPath.block,
722 currentBlock = currentPath.lastElement.getAscendant( 'li', 1 ) || pathBlock,
723 nextPath = new CKEDITOR.dom.elementPath( nextCursor.startContainer ),
724 nextLi = nextPath.contains( CKEDITOR.dtd.$listItem ),
725 nextList = nextPath.contains( CKEDITOR.dtd.$list ),
726 last;
727
728 // Remove bogus node the current block/pseudo block.
729 if ( pathBlock ) {
730 var bogus = pathBlock.getBogus();
731 bogus && bogus.remove();
732 }
733 else if ( nextList ) {
734 last = nextList.getPrevious( nonEmpty );
735 if ( last && blockBogus( last ) )
736 last.remove();
737 }
738
739 // Kill the tail br in extracted.
740 last = frag.getLast();
741 if ( last && last.type == CKEDITOR.NODE_ELEMENT && last.is( 'br' ) )
742 last.remove();
743
744 // Insert fragment at the range position.
745 var nextNode = cursor.startContainer.getChild( cursor.startOffset );
746 if ( nextNode )
747 frag.insertBefore( nextNode );
748 else
749 cursor.startContainer.append( frag );
750
751 // Move the sub list nested in the next list item.
752 if ( nextLi ) {
753 var sublist = getSubList( nextLi );
754 if ( sublist ) {
755 // If next line is in the sub list of the current list item.
756 if ( currentBlock.contains( nextLi ) ) {
757 mergeChildren( sublist, nextLi.getParent(), nextLi );
758 sublist.remove();
759 }
760 // Migrate the sub list to current list item.
761 else {
762 currentBlock.append( sublist );
763 }
764 }
765 }
766
767 var nextBlock, parent;
768 // Remove any remaining zombies path blocks at the end after line merged.
769 while ( nextCursor.checkStartOfBlock() && nextCursor.checkEndOfBlock() ) {
770 nextPath = nextCursor.startPath();
771 nextBlock = nextPath.block;
772
773 // Abort when nothing to be removed (#10890).
774 if ( !nextBlock )
775 break;
776
777 // Check if also to remove empty list.
778 if ( nextBlock.is( 'li' ) ) {
779 parent = nextBlock.getParent();
780 if ( nextBlock.equals( parent.getLast( nonEmpty ) ) && nextBlock.equals( parent.getFirst( nonEmpty ) ) )
781 nextBlock = parent;
782 }
783
784 nextCursor.moveToPosition( nextBlock, CKEDITOR.POSITION_BEFORE_START );
785 nextBlock.remove();
786 }
787
788 // Check if need to further merge with the list resides after the merged block. (#9080)
789 var walkerRng = nextCursor.clone(), editable = editor.editable();
790 walkerRng.setEndAt( editable, CKEDITOR.POSITION_BEFORE_END );
791 var walker = new CKEDITOR.dom.walker( walkerRng );
792 walker.evaluator = function( node ) {
793 return nonEmpty( node ) && !blockBogus( node );
794 };
795 var next = walker.next();
796 if ( next && next.type == CKEDITOR.NODE_ELEMENT && next.getName() in CKEDITOR.dtd.$list )
797 mergeListSiblings( next );
798
799 cursor.moveToBookmark( bm );
800
801 // Make fresh selection.
802 cursor.select();
803
804 editor.fire( 'saveSnapshot' );
805 }
806
807 function getSubList( li ) {
808 var last = li.getLast( nonEmpty );
809 return last && last.type == CKEDITOR.NODE_ELEMENT && last.getName() in listNodeNames ? last : null;
810 }
811
812 CKEDITOR.plugins.add( 'list', {
813 // jscs:disable maximumLineLength
814 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
815 // jscs:enable maximumLineLength
816 icons: 'bulletedlist,bulletedlist-rtl,numberedlist,numberedlist-rtl', // %REMOVE_LINE_CORE%
817 hidpi: true, // %REMOVE_LINE_CORE%
818 requires: 'indentlist',
819 init: function( editor ) {
820 if ( editor.blockless )
821 return;
822
823 // Register commands.
824 editor.addCommand( 'numberedlist', new listCommand( 'numberedlist', 'ol' ) );
825 editor.addCommand( 'bulletedlist', new listCommand( 'bulletedlist', 'ul' ) );
826
827 // Register the toolbar button.
828 if ( editor.ui.addButton ) {
829 editor.ui.addButton( 'NumberedList', {
830 label: editor.lang.list.numberedlist,
831 command: 'numberedlist',
832 directional: true,
833 toolbar: 'list,10'
834 } );
835 editor.ui.addButton( 'BulletedList', {
836 label: editor.lang.list.bulletedlist,
837 command: 'bulletedlist',
838 directional: true,
839 toolbar: 'list,20'
840 } );
841 }
842
843 // Handled backspace/del key to join list items. (#8248,#9080)
844 editor.on( 'key', function( evt ) {
845 // Use getKey directly in order to ignore modifiers.
846 // Justification: http://dev.ckeditor.com/ticket/11861#comment:13
847 var key = evt.data.domEvent.getKey(), li;
848
849 // DEl/BACKSPACE
850 if ( editor.mode == 'wysiwyg' && key in { 8: 1, 46: 1 } ) {
851 var sel = editor.getSelection(),
852 range = sel.getRanges()[ 0 ],
853 path = range && range.startPath();
854
855 if ( !range || !range.collapsed )
856 return;
857
858 var isBackspace = key == 8;
859 var editable = editor.editable();
860 var walker = new CKEDITOR.dom.walker( range.clone() );
861 walker.evaluator = function( node ) {
862 return nonEmpty( node ) && !blockBogus( node );
863 };
864 // Backspace/Del behavior at the start/end of table is handled in core.
865 walker.guard = function( node, isOut ) {
866 return !( isOut && node.type == CKEDITOR.NODE_ELEMENT && node.is( 'table' ) );
867 };
868
869 var cursor = range.clone();
870
871 if ( isBackspace ) {
872 var previous, joinWith;
873
874 // Join a sub list's first line, with the previous visual line in parent.
875 if (
876 ( previous = path.contains( listNodeNames ) ) &&
877 range.checkBoundaryOfElement( previous, CKEDITOR.START ) &&
878 ( previous = previous.getParent() ) && previous.is( 'li' ) &&
879 ( previous = getSubList( previous ) )
880 ) {
881 joinWith = previous;
882 previous = previous.getPrevious( nonEmpty );
883 // Place cursor before the nested list.
884 cursor.moveToPosition(
885 previous && blockBogus( previous ) ? previous : joinWith,
886 CKEDITOR.POSITION_BEFORE_START );
887 }
888 // Join any line following a list, with the last visual line of the list.
889 else {
890 walker.range.setStartAt( editable, CKEDITOR.POSITION_AFTER_START );
891 walker.range.setEnd( range.startContainer, range.startOffset );
892
893 previous = walker.previous();
894
895 if (
896 previous && previous.type == CKEDITOR.NODE_ELEMENT &&
897 ( previous.getName() in listNodeNames ||
898 previous.is( 'li' ) )
899 ) {
900 if ( !previous.is( 'li' ) ) {
901 walker.range.selectNodeContents( previous );
902 walker.reset();
903 walker.evaluator = isTextBlock;
904 previous = walker.previous();
905 }
906
907 joinWith = previous;
908 // Place cursor at the end of previous block.
909 cursor.moveToElementEditEnd( joinWith );
910
911 // And then just before end of closest block element (#12729).
912 cursor.moveToPosition( cursor.endPath().block, CKEDITOR.POSITION_BEFORE_END );
913 }
914 }
915
916 if ( joinWith ) {
917 joinNextLineToCursor( editor, cursor, range );
918 evt.cancel();
919 }
920 else {
921 var list = path.contains( listNodeNames );
922 // Backspace pressed at the start of list outdents the first list item. (#9129)
923 if ( list && range.checkBoundaryOfElement( list, CKEDITOR.START ) ) {
924 li = list.getFirst( nonEmpty );
925
926 if ( range.checkBoundaryOfElement( li, CKEDITOR.START ) ) {
927 previous = list.getPrevious( nonEmpty );
928
929 // Only if the list item contains a sub list, do nothing but
930 // simply move cursor backward one character.
931 if ( getSubList( li ) ) {
932 if ( previous ) {
933 range.moveToElementEditEnd( previous );
934 range.select();
935 }
936
937 evt.cancel();
938 }
939 else {
940 editor.execCommand( 'outdent' );
941 evt.cancel();
942 }
943 }
944 }
945 }
946
947 } else {
948 var next, nextLine;
949
950 li = path.contains( 'li' );
951
952 if ( li ) {
953 walker.range.setEndAt( editable, CKEDITOR.POSITION_BEFORE_END );
954
955 var last = li.getLast( nonEmpty );
956 var block = last && isTextBlock( last ) ? last : li;
957
958 // Indicate cursor at the visual end of an list item.
959 var isAtEnd = 0;
960
961 next = walker.next();
962
963 // When list item contains a sub list.
964 if (
965 next && next.type == CKEDITOR.NODE_ELEMENT &&
966 next.getName() in listNodeNames &&
967 next.equals( last )
968 ) {
969 isAtEnd = 1;
970
971 // Move to the first item in sub list.
972 next = walker.next();
973 }
974 // Right at the end of list item.
975 else if ( range.checkBoundaryOfElement( block, CKEDITOR.END ) ) {
976 isAtEnd = 2;
977 }
978
979 if ( isAtEnd && next ) {
980 // Put cursor range there.
981 nextLine = range.clone();
982 nextLine.moveToElementEditStart( next );
983
984 // #13409
985 // For the following case and similar
986 //
987 // <ul>
988 // <li>
989 // <p><a href="#one"><em>x^</em></a></p>
990 // <ul>
991 // <li><span>y</span></li>
992 // </ul>
993 // </li>
994 // </ul>
995 if ( isAtEnd == 1 ) {
996 // Move the cursor to <em> if attached to "x" text node.
997 cursor.optimize();
998
999 // Abort if the range is attached directly in <li>, like
1000 //
1001 // <ul>
1002 // <li>
1003 // x^
1004 // <ul>
1005 // <li><span>y</span></li>
1006 // </ul>
1007 // </li>
1008 // </ul>
1009 if ( !cursor.startContainer.equals( li ) ) {
1010 var node = cursor.startContainer,
1011 farthestInlineAscendant;
1012
1013 // Find <a>, which is farthest from <em> but still inline element.
1014 while ( node.is( CKEDITOR.dtd.$inline ) ) {
1015 farthestInlineAscendant = node;
1016 node = node.getParent();
1017 }
1018
1019 // Move the range so it does not contain inline elements.
1020 // It prevents <span> from being included in <em>.
1021 //
1022 // <ul>
1023 // <li>
1024 // <p><a href="#one"><em>x</em></a>^</p>
1025 // <ul>
1026 // <li><span>y</span></li>
1027 // </ul>
1028 // </li>
1029 // </ul>
1030 //
1031 // so instead of
1032 //
1033 // <ul>
1034 // <li>
1035 // <p><a href="#one"><em>x^<span>y</span></em></a></p>
1036 // </li>
1037 // </ul>
1038 //
1039 // pressing DELETE produces
1040 //
1041 // <ul>
1042 // <li>
1043 // <p><a href="#one"><em>x</em></a>^<span>y</span></p>
1044 // </li>
1045 // </ul>
1046 if ( farthestInlineAscendant ) {
1047 cursor.moveToPosition( farthestInlineAscendant, CKEDITOR.POSITION_AFTER_END );
1048 }
1049 }
1050 }
1051
1052 // Moving `cursor` and `next line` only when at the end literally (#12729).
1053 if ( isAtEnd == 2 ) {
1054 cursor.moveToPosition( cursor.endPath().block, CKEDITOR.POSITION_BEFORE_END );
1055
1056 // Next line might be text node not wrapped in block element.
1057 if ( nextLine.endPath().block ) {
1058 nextLine.moveToPosition( nextLine.endPath().block, CKEDITOR.POSITION_AFTER_START );
1059 }
1060 }
1061
1062 joinNextLineToCursor( editor, cursor, nextLine );
1063 evt.cancel();
1064 }
1065 } else {
1066 // Handle Del key pressed before the list.
1067 walker.range.setEndAt( editable, CKEDITOR.POSITION_BEFORE_END );
1068 next = walker.next();
1069
1070 if ( next && next.type == CKEDITOR.NODE_ELEMENT && next.is( listNodeNames ) ) {
1071 // The start <li>
1072 next = next.getFirst( nonEmpty );
1073
1074 // Simply remove the current empty block, move cursor to the
1075 // subsequent list.
1076 if ( path.block && range.checkStartOfBlock() && range.checkEndOfBlock() ) {
1077 path.block.remove();
1078 range.moveToElementEditStart( next );
1079 range.select();
1080 evt.cancel();
1081 }
1082 // Preventing the default (merge behavior), but simply move
1083 // the cursor one character forward if subsequent list item
1084 // contains sub list.
1085 else if ( getSubList( next ) ) {
1086 range.moveToElementEditStart( next );
1087 range.select();
1088 evt.cancel();
1089 }
1090 // Merge the first list item with the current line.
1091 else {
1092 nextLine = range.clone();
1093 nextLine.moveToElementEditStart( next );
1094 joinNextLineToCursor( editor, cursor, nextLine );
1095 evt.cancel();
1096 }
1097 }
1098 }
1099
1100 }
1101
1102 // The backspace/del could potentially put cursor at a bad position,
1103 // being it handled or not, check immediately the selection to have it fixed.
1104 setTimeout( function() {
1105 editor.selectionChange( 1 );
1106 } );
1107 }
1108 } );
1109 }
1110 } );
1111} )();
diff --git a/sources/plugins/listblock/plugin.js b/sources/plugins/listblock/plugin.js
new file mode 100644
index 0000000..21e6b08
--- /dev/null
+++ b/sources/plugins/listblock/plugin.js
@@ -0,0 +1,241 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'listblock', {
7 requires: 'panel',
8
9 onLoad: function() {
10 var list = CKEDITOR.addTemplate( 'panel-list', '<ul role="presentation" class="cke_panel_list">{items}</ul>' ),
11 listItem = CKEDITOR.addTemplate( 'panel-list-item', '<li id="{id}" class="cke_panel_listItem" role=presentation>' +
12 '<a id="{id}_option" _cke_focus=1 hidefocus=true' +
13 ' title="{title}"' +
14 ' href="javascript:void(\'{val}\')" ' +
15 ' {onclick}="CKEDITOR.tools.callFunction({clickFn},\'{val}\'); return false;"' + // #188
16 ' role="option">' +
17 '{text}' +
18 '</a>' +
19 '</li>' ),
20 listGroup = CKEDITOR.addTemplate( 'panel-list-group', '<h1 id="{id}" class="cke_panel_grouptitle" role="presentation" >{label}</h1>' ),
21 reSingleQuote = /\'/g,
22 escapeSingleQuotes = function( str ) {
23 return str.replace( reSingleQuote, '\\\'' );
24 };
25
26 CKEDITOR.ui.panel.prototype.addListBlock = function( name, definition ) {
27 return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), definition ) );
28 };
29
30 CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass( {
31 base: CKEDITOR.ui.panel.block,
32
33 $: function( blockHolder, blockDefinition ) {
34 blockDefinition = blockDefinition || {};
35
36 var attribs = blockDefinition.attributes || ( blockDefinition.attributes = {} );
37 ( this.multiSelect = !!blockDefinition.multiSelect ) && ( attribs[ 'aria-multiselectable' ] = true );
38 // Provide default role of 'listbox'.
39 !attribs.role && ( attribs.role = 'listbox' );
40
41 // Call the base contructor.
42 this.base.apply( this, arguments );
43
44 // Set the proper a11y attributes.
45 this.element.setAttribute( 'role', attribs.role );
46
47 var keys = this.keys;
48 keys[ 40 ] = 'next'; // ARROW-DOWN
49 keys[ 9 ] = 'next'; // TAB
50 keys[ 38 ] = 'prev'; // ARROW-UP
51 keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
52 keys[ 32 ] = CKEDITOR.env.ie ? 'mouseup' : 'click'; // SPACE
53 CKEDITOR.env.ie && ( keys[ 13 ] = 'mouseup' ); // Manage ENTER, since onclick is blocked in IE (#8041).
54
55 this._.pendingHtml = [];
56 this._.pendingList = [];
57 this._.items = {};
58 this._.groups = {};
59 },
60
61 _: {
62 close: function() {
63 if ( this._.started ) {
64 var output = list.output( { items: this._.pendingList.join( '' ) } );
65 this._.pendingList = [];
66 this._.pendingHtml.push( output );
67 delete this._.started;
68 }
69 },
70
71 getClick: function() {
72 if ( !this._.click ) {
73 this._.click = CKEDITOR.tools.addFunction( function( value ) {
74 var marked = this.toggle( value );
75 if ( this.onClick )
76 this.onClick( value, marked );
77 }, this );
78 }
79 return this._.click;
80 }
81 },
82
83 proto: {
84 add: function( value, html, title ) {
85 var id = CKEDITOR.tools.getNextId();
86
87 if ( !this._.started ) {
88 this._.started = 1;
89 this._.size = this._.size || 0;
90 }
91
92 this._.items[ value ] = id;
93
94 var data = {
95 id: id,
96 val: escapeSingleQuotes( CKEDITOR.tools.htmlEncodeAttr( value ) ),
97 onclick: CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick',
98 clickFn: this._.getClick(),
99 title: CKEDITOR.tools.htmlEncodeAttr( title || value ),
100 text: html || value
101 };
102
103 this._.pendingList.push( listItem.output( data ) );
104 },
105
106 startGroup: function( title ) {
107 this._.close();
108
109 var id = CKEDITOR.tools.getNextId();
110
111 this._.groups[ title ] = id;
112
113 this._.pendingHtml.push( listGroup.output( { id: id, label: title } ) );
114 },
115
116 commit: function() {
117 this._.close();
118 this.element.appendHtml( this._.pendingHtml.join( '' ) );
119 delete this._.size;
120
121 this._.pendingHtml = [];
122 },
123
124 toggle: function( value ) {
125 var isMarked = this.isMarked( value );
126
127 if ( isMarked )
128 this.unmark( value );
129 else
130 this.mark( value );
131
132 return !isMarked;
133 },
134
135 hideGroup: function( groupTitle ) {
136 var group = this.element.getDocument().getById( this._.groups[ groupTitle ] ),
137 list = group && group.getNext();
138
139 if ( group ) {
140 group.setStyle( 'display', 'none' );
141
142 if ( list && list.getName() == 'ul' )
143 list.setStyle( 'display', 'none' );
144 }
145 },
146
147 hideItem: function( value ) {
148 this.element.getDocument().getById( this._.items[ value ] ).setStyle( 'display', 'none' );
149 },
150
151 showAll: function() {
152 var items = this._.items,
153 groups = this._.groups,
154 doc = this.element.getDocument();
155
156 for ( var value in items ) {
157 doc.getById( items[ value ] ).setStyle( 'display', '' );
158 }
159
160 for ( var title in groups ) {
161 var group = doc.getById( groups[ title ] ),
162 list = group.getNext();
163
164 group.setStyle( 'display', '' );
165
166 if ( list && list.getName() == 'ul' )
167 list.setStyle( 'display', '' );
168 }
169 },
170
171 mark: function( value ) {
172 if ( !this.multiSelect )
173 this.unmarkAll();
174
175 var itemId = this._.items[ value ],
176 item = this.element.getDocument().getById( itemId );
177 item.addClass( 'cke_selected' );
178
179 this.element.getDocument().getById( itemId + '_option' ).setAttribute( 'aria-selected', true );
180 this.onMark && this.onMark( item );
181 },
182
183 unmark: function( value ) {
184 var doc = this.element.getDocument(),
185 itemId = this._.items[ value ],
186 item = doc.getById( itemId );
187
188 item.removeClass( 'cke_selected' );
189 doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
190
191 this.onUnmark && this.onUnmark( item );
192 },
193
194 unmarkAll: function() {
195 var items = this._.items,
196 doc = this.element.getDocument();
197
198 for ( var value in items ) {
199 var itemId = items[ value ];
200
201 doc.getById( itemId ).removeClass( 'cke_selected' );
202 doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
203 }
204
205 this.onUnmark && this.onUnmark();
206 },
207
208 isMarked: function( value ) {
209 return this.element.getDocument().getById( this._.items[ value ] ).hasClass( 'cke_selected' );
210 },
211
212 focus: function( value ) {
213 this._.focusIndex = -1;
214
215 var links = this.element.getElementsByTag( 'a' ),
216 link,
217 selected,
218 i = -1;
219
220 if ( value ) {
221 selected = this.element.getDocument().getById( this._.items[ value ] ).getFirst();
222
223 while ( ( link = links.getItem( ++i ) ) ) {
224 if ( link.equals( selected ) ) {
225 this._.focusIndex = i;
226 break;
227 }
228 }
229 }
230 else {
231 this.element.focus();
232 }
233
234 selected && setTimeout( function() {
235 selected.focus();
236 }, 0 );
237 }
238 }
239 } );
240 }
241} );
diff --git a/sources/plugins/liststyle/dialogs/liststyle.js b/sources/plugins/liststyle/dialogs/liststyle.js
new file mode 100644
index 0000000..4f8f39b
--- /dev/null
+++ b/sources/plugins/liststyle/dialogs/liststyle.js
@@ -0,0 +1,189 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 function getListElement( editor, listTag ) {
8 var range;
9 try {
10 range = editor.getSelection().getRanges()[ 0 ];
11 } catch ( e ) {
12 return null;
13 }
14
15 range.shrink( CKEDITOR.SHRINK_TEXT );
16 return editor.elementPath( range.getCommonAncestor() ).contains( listTag, 1 );
17 }
18
19 var listItem = function( node ) {
20 return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );
21 };
22
23 var mapListStyle = {
24 'a': 'lower-alpha',
25 'A': 'upper-alpha',
26 'i': 'lower-roman',
27 'I': 'upper-roman',
28 '1': 'decimal',
29 'disc': 'disc',
30 'circle': 'circle',
31 'square': 'square'
32 };
33
34 function listStyle( editor, startupPage ) {
35 var lang = editor.lang.liststyle;
36 if ( startupPage == 'bulletedListStyle' ) {
37 return {
38 title: lang.bulletedTitle,
39 minWidth: 300,
40 minHeight: 50,
41 contents: [ {
42 id: 'info',
43 accessKey: 'I',
44 elements: [ {
45 type: 'select',
46 label: lang.type,
47 id: 'type',
48 align: 'center',
49 style: 'width:150px',
50 items: [
51 [ lang.notset, '' ],
52 [ lang.circle, 'circle' ],
53 [ lang.disc, 'disc' ],
54 [ lang.square, 'square' ]
55 ],
56 setup: function( element ) {
57 var value = element.getStyle( 'list-style-type' ) || mapListStyle[ element.getAttribute( 'type' ) ] || element.getAttribute( 'type' ) || '';
58
59 this.setValue( value );
60 },
61 commit: function( element ) {
62 var value = this.getValue();
63 if ( value )
64 element.setStyle( 'list-style-type', value );
65 else
66 element.removeStyle( 'list-style-type' );
67 }
68 } ]
69 } ],
70 onShow: function() {
71 var editor = this.getParentEditor(),
72 element = getListElement( editor, 'ul' );
73
74 element && this.setupContent( element );
75 },
76 onOk: function() {
77 var editor = this.getParentEditor(),
78 element = getListElement( editor, 'ul' );
79
80 element && this.commitContent( element );
81 }
82 };
83 } else if ( startupPage == 'numberedListStyle' ) {
84
85 var listStyleOptions = [
86 [ lang.notset, '' ],
87 [ lang.lowerRoman, 'lower-roman' ],
88 [ lang.upperRoman, 'upper-roman' ],
89 [ lang.lowerAlpha, 'lower-alpha' ],
90 [ lang.upperAlpha, 'upper-alpha' ],
91 [ lang.decimal, 'decimal' ]
92 ];
93
94 if ( !CKEDITOR.env.ie || CKEDITOR.env.version > 7 ) {
95 listStyleOptions.concat( [
96 [ lang.armenian, 'armenian' ],
97 [ lang.decimalLeadingZero, 'decimal-leading-zero' ],
98 [ lang.georgian, 'georgian' ],
99 [ lang.lowerGreek, 'lower-greek' ]
100 ] );
101 }
102
103 return {
104 title: lang.numberedTitle,
105 minWidth: 300,
106 minHeight: 50,
107 contents: [ {
108 id: 'info',
109 accessKey: 'I',
110 elements: [ {
111 type: 'hbox',
112 widths: [ '25%', '75%' ],
113 children: [ {
114 label: lang.start,
115 type: 'text',
116 id: 'start',
117 validate: CKEDITOR.dialog.validate.integer( lang.validateStartNumber ),
118 setup: function( element ) {
119 // List item start number dominates.
120 var value = element.getFirst( listItem ).getAttribute( 'value' ) || element.getAttribute( 'start' ) || 1;
121 value && this.setValue( value );
122 },
123 commit: function( element ) {
124 var firstItem = element.getFirst( listItem );
125 var oldStart = firstItem.getAttribute( 'value' ) || element.getAttribute( 'start' ) || 1;
126
127 // Force start number on list root.
128 element.getFirst( listItem ).removeAttribute( 'value' );
129 var val = parseInt( this.getValue(), 10 );
130 if ( isNaN( val ) )
131 element.removeAttribute( 'start' );
132 else
133 element.setAttribute( 'start', val );
134
135 // Update consequent list item numbering.
136 var nextItem = firstItem,
137 conseq = oldStart,
138 startNumber = isNaN( val ) ? 1 : val;
139 while ( ( nextItem = nextItem.getNext( listItem ) ) && conseq++ ) {
140 if ( nextItem.getAttribute( 'value' ) == conseq )
141 nextItem.setAttribute( 'value', startNumber + conseq - oldStart );
142 }
143 }
144 },
145 {
146 type: 'select',
147 label: lang.type,
148 id: 'type',
149 style: 'width: 100%;',
150 items: listStyleOptions,
151 setup: function( element ) {
152 var value = element.getStyle( 'list-style-type' ) || mapListStyle[ element.getAttribute( 'type' ) ] || element.getAttribute( 'type' ) || '';
153
154 this.setValue( value );
155 },
156 commit: function( element ) {
157 var value = this.getValue();
158 if ( value )
159 element.setStyle( 'list-style-type', value );
160 else
161 element.removeStyle( 'list-style-type' );
162 }
163 } ]
164 } ]
165 } ],
166 onShow: function() {
167 var editor = this.getParentEditor(),
168 element = getListElement( editor, 'ol' );
169
170 element && this.setupContent( element );
171 },
172 onOk: function() {
173 var editor = this.getParentEditor(),
174 element = getListElement( editor, 'ol' );
175
176 element && this.commitContent( element );
177 }
178 };
179 }
180 }
181
182 CKEDITOR.dialog.add( 'numberedListStyle', function( editor ) {
183 return listStyle( editor, 'numberedListStyle' );
184 } );
185
186 CKEDITOR.dialog.add( 'bulletedListStyle', function( editor ) {
187 return listStyle( editor, 'bulletedListStyle' );
188 } );
189} )();
diff --git a/sources/plugins/liststyle/lang/af.js b/sources/plugins/liststyle/lang/af.js
new file mode 100644
index 0000000..71ba760
--- /dev/null
+++ b/sources/plugins/liststyle/lang/af.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'af', {
6 armenian: 'Armeense nommering',
7 bulletedTitle: 'Eienskappe van ongenommerde lys',
8 circle: 'Sirkel',
9 decimal: 'Desimale syfers (1, 2, 3, ens.)',
10 decimalLeadingZero: 'Desimale syfers met voorloopnul (01, 02, 03, ens.)',
11 disc: 'Skyf',
12 georgian: 'Georgiese nommering (an, ban, gan, ens.)',
13 lowerAlpha: 'Kleinletters (a, b, c, d, e, ens.)',
14 lowerGreek: 'Griekse kleinletters (alpha, beta, gamma, ens.)',
15 lowerRoman: 'Romeinse kleinletters (i, ii, iii, iv, v, ens.)',
16 none: 'Geen',
17 notset: '<nie ingestel nie>',
18 numberedTitle: 'Eienskappe van genommerde lys',
19 square: 'Vierkant',
20 start: 'Begin',
21 type: 'Tipe',
22 upperAlpha: 'Hoofletters (A, B, C, D, E, ens.)',
23 upperRoman: 'Romeinse hoofletters (I, II, III, IV, V, ens.)',
24 validateStartNumber: 'Beginnommer van lys moet \'n heelgetal wees.'
25} );
diff --git a/sources/plugins/liststyle/lang/ar.js b/sources/plugins/liststyle/lang/ar.js
new file mode 100644
index 0000000..7d961df
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ar.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ar', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/az.js b/sources/plugins/liststyle/lang/az.js
new file mode 100644
index 0000000..73fc927
--- /dev/null
+++ b/sources/plugins/liststyle/lang/az.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'az', {
6 armenian: 'Erməni nömrələmə',
7 bulletedTitle: 'Markerlənmiş siyahının xüsusiyyətləri',
8 circle: 'Dəirəcik',
9 decimal: 'Rəqəm (1, 2, 3 və s.)',
10 decimalLeadingZero: 'Aparıcı sıfır olan rəqəm (01, 02, 03 və s.)',
11 disc: 'Disk',
12 georgian: 'Gürcü nömrələmə (an, ban, gan, və s.)',
13 lowerAlpha: 'Kiçik hərflər (a, b, c, d, e və s.)',
14 lowerGreek: 'Kiçik Yunan hərfləri (alfa, beta, qamma və s.)',
15 lowerRoman: 'Rum rəqəmləri (i, ii, iii, iv, v və s.)',
16 none: 'Yoxdur',
17 notset: '<seçilməmiş>',
18 numberedTitle: 'Nömrəli siyahının xüsusiyyətləri',
19 square: 'Dördbucaq',
20 start: 'Başlanğıc',
21 type: 'Növ',
22 upperAlpha: 'Böyük hərflər (a, b, c, d, e və s.)',
23 upperRoman: 'Böyük Rum rəqəmləri (I, II, III, IV, V və s.)',
24 validateStartNumber: 'Siyahının başlanğıc nömrəsi tam və müsbət rəqəm olmalıdır.'
25} );
diff --git a/sources/plugins/liststyle/lang/bg.js b/sources/plugins/liststyle/lang/bg.js
new file mode 100644
index 0000000..a119fd4
--- /dev/null
+++ b/sources/plugins/liststyle/lang/bg.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'bg', {
6 armenian: 'Арменско номериране',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Кръг',
9 decimal: 'Числа (1, 2, 3 и др.)',
10 decimalLeadingZero: 'Числа с водеща нула (01, 02, 03 и т.н.)',
11 disc: 'Диск',
12 georgian: 'Грузинско номериране (an, ban, gan, и т.н.)',
13 lowerAlpha: 'Малки букви (а, б, в, г, д и т.н.)',
14 lowerGreek: 'Малки гръцки букви (алфа, бета, гама и т.н.)',
15 lowerRoman: 'Малки римски числа (i, ii, iii, iv, v и т.н.)',
16 none: 'Няма',
17 notset: '<не е указано>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Квадрат',
20 start: 'Старт',
21 type: 'Тип',
22 upperAlpha: 'Големи букви (А, Б, В, Г, Д и т.н.)',
23 upperRoman: 'Големи римски числа (I, II, III, IV, V и т.н.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/bn.js b/sources/plugins/liststyle/lang/bn.js
new file mode 100644
index 0000000..f1b7bf3
--- /dev/null
+++ b/sources/plugins/liststyle/lang/bn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'bn', {
6 armenian: 'আর্মেনিয়ান সংখ্যাক্রমে বিন্যাস',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/bs.js b/sources/plugins/liststyle/lang/bs.js
new file mode 100644
index 0000000..163d1fb
--- /dev/null
+++ b/sources/plugins/liststyle/lang/bs.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'bs', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/ca.js b/sources/plugins/liststyle/lang/ca.js
new file mode 100644
index 0000000..8006ff8
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ca', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/cs.js b/sources/plugins/liststyle/lang/cs.js
new file mode 100644
index 0000000..c1e9a07
--- /dev/null
+++ b/sources/plugins/liststyle/lang/cs.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'cs', {
6 armenian: 'Arménské',
7 bulletedTitle: 'Vlastnosti odrážek',
8 circle: 'Kroužky',
9 decimal: 'Arabská čísla (1, 2, 3, atd.)',
10 decimalLeadingZero: 'Arabská čísla uvozená nulou (01, 02, 03, atd.)',
11 disc: 'Kolečka',
12 georgian: 'Gruzínské (an, ban, gan, atd.)',
13 lowerAlpha: 'Malá latinka (a, b, c, d, e, atd.)',
14 lowerGreek: 'Malé řecké (alpha, beta, gamma, atd.)',
15 lowerRoman: 'Malé římské (i, ii, iii, iv, v, atd.)',
16 none: 'Nic',
17 notset: '<nenastaveno>',
18 numberedTitle: 'Vlastnosti číslování',
19 square: 'Čtverce',
20 start: 'Počátek',
21 type: 'Typ',
22 upperAlpha: 'Velká latinka (A, B, C, D, E, atd.)',
23 upperRoman: 'Velké římské (I, II, III, IV, V, atd.)',
24 validateStartNumber: 'Číslování musí začínat celým číslem.'
25} );
diff --git a/sources/plugins/liststyle/lang/cy.js b/sources/plugins/liststyle/lang/cy.js
new file mode 100644
index 0000000..97902b5
--- /dev/null
+++ b/sources/plugins/liststyle/lang/cy.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'cy', {
6 armenian: 'Rhifo Armeneg',
7 bulletedTitle: 'Priodweddau Rhestr Fwled',
8 circle: 'Cylch',
9 decimal: 'Degol (1, 2, 3, ayyb.)',
10 decimalLeadingZero: 'Degol â sero arweiniol (01, 02, 03, ayyb.)',
11 disc: 'Disg',
12 georgian: 'Rhifau Sioraidd (an, ban, gan, ayyb.)',
13 lowerAlpha: 'Alffa Is (a, b, c, d, e, ayyb.)',
14 lowerGreek: 'Groeg Is (alpha, beta, gamma, ayyb.)',
15 lowerRoman: 'Rhufeinig Is (i, ii, iii, iv, v, ayyb.)',
16 none: 'Dim',
17 notset: '<heb osod>',
18 numberedTitle: 'Priodweddau Rhestr Rifol',
19 square: 'Sgwâr',
20 start: 'Dechrau',
21 type: 'Math',
22 upperAlpha: 'Alffa Uwch (A, B, C, D, E, ayyb.)',
23 upperRoman: 'Rhufeinig Uwch (I, II, III, IV, V, ayyb.)',
24 validateStartNumber: 'Rhaid bod y rhif cychwynnol yn gyfanrif.'
25} );
diff --git a/sources/plugins/liststyle/lang/da.js b/sources/plugins/liststyle/lang/da.js
new file mode 100644
index 0000000..27c47b5
--- /dev/null
+++ b/sources/plugins/liststyle/lang/da.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'da', {
6 armenian: 'Armensk nummering',
7 bulletedTitle: 'Værdier for cirkelpunktopstilling',
8 circle: 'Cirkel',
9 decimal: 'Decimal (1, 2, 3, osv.)',
10 decimalLeadingZero: 'Decimaler med 0 først (01, 02, 03, etc.)',
11 disc: 'Værdier for diskpunktopstilling',
12 georgian: 'Georgiansk nummering (an, ban, gan, etc.)',
13 lowerAlpha: 'Små alfabet (a, b, c, d, e, etc.)',
14 lowerGreek: 'Små græsk (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Små romerske (i, ii, iii, iv, v, etc.)',
16 none: 'Ingen',
17 notset: '<ikke defineret>',
18 numberedTitle: 'Egenskaber for nummereret liste',
19 square: 'Firkant',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Store alfabet (A, B, C, D, E, etc.)',
23 upperRoman: 'Store romerske (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Den nummererede liste skal starte med et rundt nummer'
25} );
diff --git a/sources/plugins/liststyle/lang/de-ch.js b/sources/plugins/liststyle/lang/de-ch.js
new file mode 100644
index 0000000..47d8634
--- /dev/null
+++ b/sources/plugins/liststyle/lang/de-ch.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'de-ch', {
6 armenian: 'Armenische Nummerierung',
7 bulletedTitle: 'Aufzählungslisteneigenschaften',
8 circle: 'Ring',
9 decimal: 'Dezimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Dezimal mit führender Null (01, 02, 03, usw.)',
11 disc: 'Kreis',
12 georgian: 'Georgische Nummerierung (an, ban, gan, usw.)',
13 lowerAlpha: 'Klein Alpha (a, b, c, d, e, usw.)',
14 lowerGreek: 'Klein griechisch (alpha, beta, gamma, usw.)',
15 lowerRoman: 'Klein römisch (i, ii, iii, iv, v, usw.)',
16 none: 'Keine',
17 notset: '<nicht festgelegt>',
18 numberedTitle: 'Nummerierte Listeneigenschaften',
19 square: 'Quadrat',
20 start: 'Start',
21 type: 'Typ',
22 upperAlpha: 'Gross alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Gross römisch (I, II, III, IV, V, usw.)',
24 validateStartNumber: 'Listenstartnummer muss eine ganze Zahl sein.'
25} );
diff --git a/sources/plugins/liststyle/lang/de.js b/sources/plugins/liststyle/lang/de.js
new file mode 100644
index 0000000..cdbf0b3
--- /dev/null
+++ b/sources/plugins/liststyle/lang/de.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'de', {
6 armenian: 'Armenische Nummerierung',
7 bulletedTitle: 'Aufzählungslisteneigenschaften',
8 circle: 'Ring',
9 decimal: 'Dezimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Dezimal mit führender Null (01, 02, 03, usw.)',
11 disc: 'Kreis',
12 georgian: 'Georgische Nummerierung (an, ban, gan, usw.)',
13 lowerAlpha: 'Klein Alpha (a, b, c, d, e, usw.)',
14 lowerGreek: 'Klein griechisch (alpha, beta, gamma, usw.)',
15 lowerRoman: 'Klein römisch (i, ii, iii, iv, v, usw.)',
16 none: 'Keine',
17 notset: '<nicht festgelegt>',
18 numberedTitle: 'Nummerierte Listeneigenschaften',
19 square: 'Quadrat',
20 start: 'Start',
21 type: 'Typ',
22 upperAlpha: 'Groß alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Groß römisch (I, II, III, IV, V, usw.)',
24 validateStartNumber: 'Listenstartnummer muss eine ganze Zahl sein.'
25} );
diff --git a/sources/plugins/liststyle/lang/el.js b/sources/plugins/liststyle/lang/el.js
new file mode 100644
index 0000000..2bd7ce2
--- /dev/null
+++ b/sources/plugins/liststyle/lang/el.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'el', {
6 armenian: 'Αρμενική αρίθμηση',
7 bulletedTitle: 'Ιδιότητες Λίστας Σημείων',
8 circle: 'Κύκλος',
9 decimal: 'Δεκαδική (1, 2, 3, κτλ)',
10 decimalLeadingZero: 'Δεκαδική με αρχικό μηδεν (01, 02, 03, κτλ)',
11 disc: 'Δίσκος',
12 georgian: 'Γεωργιανή αρίθμηση (ა, ბ, გ, κτλ)',
13 lowerAlpha: 'Μικρά Λατινικά (a, b, c, d, e, κτλ.)',
14 lowerGreek: 'Μικρά Ελληνικά (α, β, γ, κτλ)',
15 lowerRoman: 'Μικρά Ρωμαϊκά (i, ii, iii, iv, v, κτλ)',
16 none: 'Καμία',
17 notset: '<δεν έχει οριστεί>',
18 numberedTitle: 'Ιδιότητες Αριθμημένης Λίστας ',
19 square: 'Τετράγωνο',
20 start: 'Εκκίνηση',
21 type: 'Τύπος',
22 upperAlpha: 'Κεφαλαία Λατινικά (A, B, C, D, E, κτλ)',
23 upperRoman: 'Κεφαλαία Ρωμαϊκά (I, II, III, IV, V, κτλ)',
24 validateStartNumber: 'Ο αριθμός εκκίνησης της αρίθμησης πρέπει να είναι ακέραιος αριθμός.'
25} );
diff --git a/sources/plugins/liststyle/lang/en-au.js b/sources/plugins/liststyle/lang/en-au.js
new file mode 100644
index 0000000..af38b3e
--- /dev/null
+++ b/sources/plugins/liststyle/lang/en-au.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'en-au', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/en-ca.js b/sources/plugins/liststyle/lang/en-ca.js
new file mode 100644
index 0000000..ce76d82
--- /dev/null
+++ b/sources/plugins/liststyle/lang/en-ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'en-ca', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/en-gb.js b/sources/plugins/liststyle/lang/en-gb.js
new file mode 100644
index 0000000..7f67124
--- /dev/null
+++ b/sources/plugins/liststyle/lang/en-gb.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'en-gb', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/en.js b/sources/plugins/liststyle/lang/en.js
new file mode 100644
index 0000000..c41b7d7
--- /dev/null
+++ b/sources/plugins/liststyle/lang/en.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'en', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/eo.js b/sources/plugins/liststyle/lang/eo.js
new file mode 100644
index 0000000..b601e76
--- /dev/null
+++ b/sources/plugins/liststyle/lang/eo.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'eo', {
6 armenian: 'Armena nombrado',
7 bulletedTitle: 'Atributoj de Bula Listo',
8 circle: 'Cirklo',
9 decimal: 'Dekumaj Nombroj (1, 2, 3, ktp.)',
10 decimalLeadingZero: 'Dekumaj Nombroj malantaŭ nulo (01, 02, 03, ktp.)',
11 disc: 'Disko',
12 georgian: 'Gruza nombrado (an, ban, gan, ktp.)',
13 lowerAlpha: 'Minusklaj Literoj (a, b, c, d, e, ktp.)',
14 lowerGreek: 'Grekaj Minusklaj Literoj (alpha, beta, gamma, ktp.)',
15 lowerRoman: 'Minusklaj Romanaj Nombroj (i, ii, iii, iv, v, ktp.)',
16 none: 'Neniu',
17 notset: '<Defaŭlta>',
18 numberedTitle: 'Atributoj de Numera Listo',
19 square: 'kvadrato',
20 start: 'Komenco',
21 type: 'Tipo',
22 upperAlpha: 'Majusklaj Literoj (A, B, C, D, E, ktp.)',
23 upperRoman: 'Majusklaj Romanaj Nombroj (I, II, III, IV, V, ktp.)',
24 validateStartNumber: 'La unua listero devas esti entjera nombro.'
25} );
diff --git a/sources/plugins/liststyle/lang/es.js b/sources/plugins/liststyle/lang/es.js
new file mode 100644
index 0000000..75d2920
--- /dev/null
+++ b/sources/plugins/liststyle/lang/es.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'es', {
6 armenian: 'Numeración armenia',
7 bulletedTitle: 'Propiedades de viñetas',
8 circle: 'Círculo',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal con cero inicial (01, 02, 03, etc.)',
11 disc: 'Disco',
12 georgian: 'Numeración georgiana (an, ban, gan, etc.)',
13 lowerAlpha: 'Alfabeto en minúsculas (a, b, c, d, e, etc.)',
14 lowerGreek: 'Letras griegas (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Números romanos en minúsculas (i, ii, iii, iv, v, etc.)',
16 none: 'Ninguno',
17 notset: '<sin establecer>',
18 numberedTitle: 'Propiedades de lista numerada',
19 square: 'Cuadrado',
20 start: 'Inicio',
21 type: 'Tipo',
22 upperAlpha: 'Alfabeto en mayúsculas (A, B, C, D, E, etc.)',
23 upperRoman: 'Números romanos en mayúsculas (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'El Inicio debe ser un número entero.'
25} );
diff --git a/sources/plugins/liststyle/lang/et.js b/sources/plugins/liststyle/lang/et.js
new file mode 100644
index 0000000..d2dfd5e
--- /dev/null
+++ b/sources/plugins/liststyle/lang/et.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'et', {
6 armenian: 'Armeenia numbrid',
7 bulletedTitle: 'Punktloendi omadused',
8 circle: 'Ring',
9 decimal: 'Numbrid (1, 2, 3, jne)',
10 decimalLeadingZero: 'Numbrid algusnulliga (01, 02, 03, jne)',
11 disc: 'Täpp',
12 georgian: 'Gruusia numbrid (an, ban, gan, jne)',
13 lowerAlpha: 'Väiketähed (a, b, c, d, e, jne)',
14 lowerGreek: 'Kreeka väiketähed (alpha, beta, gamma, jne)',
15 lowerRoman: 'Väiksed rooma numbrid (i, ii, iii, iv, v, jne)',
16 none: 'Puudub',
17 notset: '<pole määratud>',
18 numberedTitle: 'Numberloendi omadused',
19 square: 'Ruut',
20 start: 'Algus',
21 type: 'Liik',
22 upperAlpha: 'Suurtähed (A, B, C, D, E, jne)',
23 upperRoman: 'Suured rooma numbrid (I, II, III, IV, V, jne)',
24 validateStartNumber: 'Loendi algusnumber peab olema täisarv.'
25} );
diff --git a/sources/plugins/liststyle/lang/eu.js b/sources/plugins/liststyle/lang/eu.js
new file mode 100644
index 0000000..ef616e5
--- /dev/null
+++ b/sources/plugins/liststyle/lang/eu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'eu', {
6 armenian: 'Zenbakitze armeniarra',
7 bulletedTitle: 'Buletadun zerrendaren propietateak',
8 circle: 'Zirkulua',
9 decimal: 'Hamartarra (1, 2, 3...)',
10 decimalLeadingZero: 'Aurretik zeroa duen hamartarra (01, 02, 03...)',
11 disc: 'Diskoa',
12 georgian: 'Zenbakitze georgiarra (an, ban, gan...)',
13 lowerAlpha: 'Alfabetoa minuskulaz (a, b, c, d, e...)',
14 lowerGreek: 'Greziera minuskulaz (alpha, beta, gamma...)',
15 lowerRoman: 'Erromatarra minuskulaz (i, ii, iii, iv, v...)',
16 none: 'Bat ere ez',
17 notset: '<ezarri gabea>',
18 numberedTitle: 'Zenbakidun zerrendaren propietateak',
19 square: 'Karratua',
20 start: 'Hasi',
21 type: 'Mota',
22 upperAlpha: 'Alfabetoa maiuskulaz (A, B, C, D, E...)',
23 upperRoman: 'Erromatarra maiuskulaz (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Zerrendaren hasierako zenbakiak zenbaki osoa izan behar du.'
25} );
diff --git a/sources/plugins/liststyle/lang/fa.js b/sources/plugins/liststyle/lang/fa.js
new file mode 100644
index 0000000..7a4517c
--- /dev/null
+++ b/sources/plugins/liststyle/lang/fa.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'fa', {
6 armenian: 'شماره‌گذاری ارمنی',
7 bulletedTitle: 'خصوصیات فهرست نقطه‌ای',
8 circle: 'دایره',
9 decimal: 'ده‌دهی (۱، ۲، ۳، ...)',
10 decimalLeadingZero: 'دهدهی همراه با صفر (۰۱، ۰۲، ۰۳، ...)',
11 disc: 'صفحه گرد',
12 georgian: 'شمارهگذاری گریگورین (an, ban, gan, etc.)',
13 lowerAlpha: 'پانویس الفبایی (a, b, c, d, e, etc.)',
14 lowerGreek: 'پانویس یونانی (alpha, beta, gamma, etc.)',
15 lowerRoman: 'پانویس رومی (i, ii, iii, iv, v, etc.)',
16 none: 'هیچ',
17 notset: '<تنظیم نشده>',
18 numberedTitle: 'ویژگیهای فهرست شمارهدار',
19 square: 'چهارگوش',
20 start: 'شروع',
21 type: 'نوع',
22 upperAlpha: 'بالانویس الفبایی (A, B, C, D, E, etc.)',
23 upperRoman: 'بالانویس رومی (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'فهرست شماره شروع باید یک عدد صحیح باشد.'
25} );
diff --git a/sources/plugins/liststyle/lang/fi.js b/sources/plugins/liststyle/lang/fi.js
new file mode 100644
index 0000000..b0cf1b3
--- /dev/null
+++ b/sources/plugins/liststyle/lang/fi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'fi', {
6 armenian: 'Armeenialainen numerointi',
7 bulletedTitle: 'Numeroimattoman listan ominaisuudet',
8 circle: 'Ympyrä',
9 decimal: 'Desimaalit (1, 2, 3, jne.)',
10 decimalLeadingZero: 'Desimaalit, alussa nolla (01, 02, 03, jne.)',
11 disc: 'Levy',
12 georgian: 'Georgialainen numerointi (an, ban, gan, etc.)',
13 lowerAlpha: 'Pienet aakkoset (a, b, c, d, e, jne.)',
14 lowerGreek: 'Pienet kreikkalaiset (alpha, beta, gamma, jne.)',
15 lowerRoman: 'Pienet roomalaiset (i, ii, iii, iv, v, jne.)',
16 none: 'Ei mikään',
17 notset: '<ei asetettu>',
18 numberedTitle: 'Numeroidun listan ominaisuudet',
19 square: 'Neliö',
20 start: 'Alku',
21 type: 'Tyyppi',
22 upperAlpha: 'Isot aakkoset (A, B, C, D, E, jne.)',
23 upperRoman: 'Isot roomalaiset (I, II, III, IV, V, jne.)',
24 validateStartNumber: 'Listan ensimmäisen numeron tulee olla kokonaisluku.'
25} );
diff --git a/sources/plugins/liststyle/lang/fo.js b/sources/plugins/liststyle/lang/fo.js
new file mode 100644
index 0000000..922a85c
--- /dev/null
+++ b/sources/plugins/liststyle/lang/fo.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'fo', {
6 armenian: 'Armensk talskipan',
7 bulletedTitle: 'Eginleikar fyri lista við prikkum',
8 circle: 'Sirkul',
9 decimal: 'Vanlig tøl (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Tøl við null frammanfyri (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgisk talskipan (an, ban, gan, osv.)',
13 lowerAlpha: 'Lítlir bókstavir (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grikskt við lítlum (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lítil rómaratøl (i, ii, iii, iv, v, etc.)',
16 none: 'Einki',
17 notset: '<ikki sett>',
18 numberedTitle: 'Eginleikar fyri lista við tølum',
19 square: 'Fýrkantur',
20 start: 'Byrjan',
21 type: 'Slag',
22 upperAlpha: 'Stórir bókstavir (A, B, C, D, E, etc.)',
23 upperRoman: 'Stór rómaratøl (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Byrjunartalið fyri lista má vera eitt heiltal.'
25} );
diff --git a/sources/plugins/liststyle/lang/fr-ca.js b/sources/plugins/liststyle/lang/fr-ca.js
new file mode 100644
index 0000000..06c2af9
--- /dev/null
+++ b/sources/plugins/liststyle/lang/fr-ca.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'fr-ca', {
6 armenian: 'Numération arménienne',
7 bulletedTitle: 'Propriété de liste à puce',
8 circle: 'Cercle',
9 decimal: 'Décimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Décimal avec zéro (01, 02, 03, etc.)',
11 disc: 'Disque',
12 georgian: 'Numération géorgienne (an, ban, gan, etc.)',
13 lowerAlpha: 'Alphabétique minuscule (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grecque minuscule (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Romain minuscule (i, ii, iii, iv, v, etc.)',
16 none: 'Aucun',
17 notset: '<non défini>',
18 numberedTitle: 'Propriété de la liste numérotée',
19 square: 'Carré',
20 start: 'Début',
21 type: 'Type',
22 upperAlpha: 'Alphabétique majuscule (A, B, C, D, E, etc.)',
23 upperRoman: 'Romain Majuscule (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Le numéro de début de liste doit être un entier.'
25} );
diff --git a/sources/plugins/liststyle/lang/fr.js b/sources/plugins/liststyle/lang/fr.js
new file mode 100644
index 0000000..ccb6944
--- /dev/null
+++ b/sources/plugins/liststyle/lang/fr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'fr', {
6 armenian: 'Numération arménienne',
7 bulletedTitle: 'Propriétés de la liste à puces',
8 circle: 'Cercle',
9 decimal: 'Décimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Décimal précédé par un 0 (01, 02, 03, etc.)',
11 disc: 'Disque',
12 georgian: 'Numération géorgienne (an, ban, gan, etc.)',
13 lowerAlpha: 'Lettres minuscules (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grec minuscule (alpha, bêta, gamma, etc.)',
15 lowerRoman: 'Chiffres romains minuscules (i, ii, iii, iv, v, etc.)',
16 none: 'Aucun',
17 notset: '<indéfini>',
18 numberedTitle: 'Propriétés de la liste numérotée',
19 square: 'Carré',
20 start: 'Début',
21 type: 'Type',
22 upperAlpha: 'Lettres majuscules (A, B, C, D, E, etc.)',
23 upperRoman: 'Chiffres romains majuscules (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Le premier élément de la liste doit être un nombre entier.'
25} );
diff --git a/sources/plugins/liststyle/lang/gl.js b/sources/plugins/liststyle/lang/gl.js
new file mode 100644
index 0000000..eeb622d
--- /dev/null
+++ b/sources/plugins/liststyle/lang/gl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'gl', {
6 armenian: 'Numeración armenia',
7 bulletedTitle: 'Propiedades da lista viñeteada',
8 circle: 'Circulo',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal con cero á esquerda (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Numeración xeorxiana (an, ban, gan, etc.)',
13 lowerAlpha: 'Alfabeto en minúsculas (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grego en minúsculas (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Números romanos en minúsculas (i, ii, iii, iv, v, etc.)',
16 none: 'Ningún',
17 notset: '<sen estabelecer>',
18 numberedTitle: 'Propiedades da lista numerada',
19 square: 'Cadrado',
20 start: 'Inicio',
21 type: 'Tipo',
22 upperAlpha: 'Alfabeto en maiúsculas (A, B, C, D, E, etc.)',
23 upperRoman: 'Números romanos en maiúsculas (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'O número de inicio da lista debe ser un número enteiro.'
25} );
diff --git a/sources/plugins/liststyle/lang/gu.js b/sources/plugins/liststyle/lang/gu.js
new file mode 100644
index 0000000..434f218
--- /dev/null
+++ b/sources/plugins/liststyle/lang/gu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'gu', {
6 armenian: 'અરમેનિયન આંકડા પદ્ધતિ',
7 bulletedTitle: 'બુલેટેડ લીસ્ટના ગુણ',
8 circle: 'વર્તુળ',
9 decimal: 'આંકડા (1, 2, 3, etc.)',
10 decimalLeadingZero: 'સુન્ય આગળ આંકડા (01, 02, 03, etc.)',
11 disc: 'ડિસ્ક',
12 georgian: 'ગેઓર્ગિયન આંકડા પદ્ધતિ (an, ban, gan, etc.)',
13 lowerAlpha: 'આલ્ફા નાના (a, b, c, d, e, etc.)',
14 lowerGreek: 'ગ્રીક નાના (alpha, beta, gamma, etc.)',
15 lowerRoman: 'રોમન નાના (i, ii, iii, iv, v, etc.)',
16 none: 'કસુ ',
17 notset: '<સેટ નથી>',
18 numberedTitle: 'આંકડાના લીસ્ટના ગુણ',
19 square: 'ચોરસ',
20 start: 'શરુ કરવું',
21 type: 'પ્રકાર',
22 upperAlpha: 'આલ્ફા મોટા (A, B, C, D, E, etc.)',
23 upperRoman: 'રોમન મોટા (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'લીસ્ટના સરુઆતનો આંકડો પુરો હોવો જોઈએ.'
25} );
diff --git a/sources/plugins/liststyle/lang/he.js b/sources/plugins/liststyle/lang/he.js
new file mode 100644
index 0000000..93b6106
--- /dev/null
+++ b/sources/plugins/liststyle/lang/he.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'he', {
6 armenian: 'ספרות ארמניות',
7 bulletedTitle: 'תכונות רשימת תבליטים',
8 circle: 'עיגול ריק',
9 decimal: 'ספרות (1, 2, 3 וכו\')',
10 decimalLeadingZero: 'ספרות עם 0 בהתחלה (01, 02, 03 וכו\')',
11 disc: 'עיגול מלא',
12 georgian: 'ספרות גיאורגיות (an, ban, gan וכו\')',
13 lowerAlpha: 'אותיות אנגליות קטנות (a, b, c, d, e וכו\')',
14 lowerGreek: 'אותיות יווניות קטנות (alpha, beta, gamma וכו\')',
15 lowerRoman: 'ספירה רומית באותיות קטנות (i, ii, iii, iv, v וכו\')',
16 none: 'ללא',
17 notset: '<לא נקבע>',
18 numberedTitle: 'תכונות רשימה ממוספרת',
19 square: 'ריבוע',
20 start: 'תחילת מספור',
21 type: 'סוג',
22 upperAlpha: 'אותיות אנגליות גדולות (A, B, C, D, E וכו\')',
23 upperRoman: 'ספירה רומיות באותיות גדולות (I, II, III, IV, V וכו\')',
24 validateStartNumber: 'שדה תחילת המספור חייב להכיל מספר שלם.'
25} );
diff --git a/sources/plugins/liststyle/lang/hi.js b/sources/plugins/liststyle/lang/hi.js
new file mode 100644
index 0000000..0f1ae03
--- /dev/null
+++ b/sources/plugins/liststyle/lang/hi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'hi', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/hr.js b/sources/plugins/liststyle/lang/hr.js
new file mode 100644
index 0000000..8da2ff3
--- /dev/null
+++ b/sources/plugins/liststyle/lang/hr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'hr', {
6 armenian: 'Armenijska numeracija',
7 bulletedTitle: 'Svojstva liste',
8 circle: 'Krug',
9 decimal: 'Decimalna numeracija (1, 2, 3, itd.)',
10 decimalLeadingZero: 'Decimalna s vodećom nulom (01, 02, 03, itd)',
11 disc: 'Disk',
12 georgian: 'Gruzijska numeracija(an, ban, gan, etc.)',
13 lowerAlpha: 'Znakovi mala slova (a, b, c, d, e, itd.)',
14 lowerGreek: 'Grčka numeracija mala slova (alfa, beta, gama, itd).',
15 lowerRoman: 'Romanska numeracija mala slova (i, ii, iii, iv, v, itd.)',
16 none: 'Bez',
17 notset: '<nije određen>',
18 numberedTitle: 'Svojstva brojčane liste',
19 square: 'Kvadrat',
20 start: 'Početak',
21 type: 'Vrsta',
22 upperAlpha: 'Znakovi velika slova (A, B, C, D, E, itd.)',
23 upperRoman: 'Romanska numeracija velika slova (I, II, III, IV, V, itd.)',
24 validateStartNumber: 'Početak brojčane liste mora biti cijeli broj.'
25} );
diff --git a/sources/plugins/liststyle/lang/hu.js b/sources/plugins/liststyle/lang/hu.js
new file mode 100644
index 0000000..4e3d922
--- /dev/null
+++ b/sources/plugins/liststyle/lang/hu.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'hu', {
6 armenian: 'Örmény számozás',
7 bulletedTitle: 'Pontozott lista tulajdonságai',
8 circle: 'Kör',
9 decimal: 'Arab számozás (1, 2, 3, stb.)',
10 decimalLeadingZero: 'Számozás bevezető nullákkal (01, 02, 03, stb.)',
11 disc: 'Korong',
12 georgian: 'Grúz számozás (an, ban, gan, stb.)',
13 lowerAlpha: 'Kisbetűs (a, b, c, d, e, stb.)',
14 lowerGreek: 'Görög (alpha, beta, gamma, stb.)',
15 lowerRoman: 'Római kisbetűs (i, ii, iii, iv, v, stb.)',
16 none: 'Nincs',
17 notset: '<Nincs beállítva>',
18 numberedTitle: 'Sorszámozott lista tulajdonságai',
19 square: 'Négyzet',
20 start: 'Kezdőszám',
21 type: 'Típus',
22 upperAlpha: 'Nagybetűs (A, B, C, D, E, stb.)',
23 upperRoman: 'Római nagybetűs (I, II, III, IV, V, stb.)',
24 validateStartNumber: 'A kezdőszám nem lehet tört érték.'
25} );
diff --git a/sources/plugins/liststyle/lang/id.js b/sources/plugins/liststyle/lang/id.js
new file mode 100644
index 0000000..36ec1ec
--- /dev/null
+++ b/sources/plugins/liststyle/lang/id.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'id', {
6 armenian: 'Armenian numbering', // MISSING
7 bulletedTitle: 'Bulleted List Properties', // MISSING
8 circle: 'Lingkaran',
9 decimal: 'Desimal (1, 2, 3, dst.)',
10 decimalLeadingZero: 'Desimal diawali angka nol (01, 02, 03, dst.)',
11 disc: 'Cakram',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)', // MISSING
13 lowerAlpha: 'Huruf Kecil (a, b, c, d, e, dst.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)', // MISSING
15 lowerRoman: 'Angka Romawi (i, ii, iii, iv, v, dst.)',
16 none: 'Tidak ada',
17 notset: '<tidak diatur>',
18 numberedTitle: 'Numbered List Properties', // MISSING
19 square: 'Persegi',
20 start: 'Mulai',
21 type: 'Tipe',
22 upperAlpha: 'Huruf Besar (A, B, C, D, E, dst.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)', // MISSING
24 validateStartNumber: 'List start number must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/liststyle/lang/is.js b/sources/plugins/liststyle/lang/is.js
new file mode 100644
index 0000000..a05c5bc
--- /dev/null
+++ b/sources/plugins/liststyle/lang/is.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'is', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/it.js b/sources/plugins/liststyle/lang/it.js
new file mode 100644
index 0000000..6ef919d
--- /dev/null
+++ b/sources/plugins/liststyle/lang/it.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'it', {
6 armenian: 'Numerazione Armena',
7 bulletedTitle: 'Proprietà liste puntate',
8 circle: 'Cerchio',
9 decimal: 'Decimale (1, 2, 3, ecc.)',
10 decimalLeadingZero: 'Decimale preceduto da 0 (01, 02, 03, ecc.)',
11 disc: 'Disco',
12 georgian: 'Numerazione Georgiana (an, ban, gan, ecc.)',
13 lowerAlpha: 'Alfabetico minuscolo (a, b, c, d, e, ecc.)',
14 lowerGreek: 'Greco minuscolo (alpha, beta, gamma, ecc.)',
15 lowerRoman: 'Numerazione Romana minuscola (i, ii, iii, iv, v, ecc.)',
16 none: 'Nessuno',
17 notset: '<non impostato>',
18 numberedTitle: 'Proprietà liste numerate',
19 square: 'Quadrato',
20 start: 'Inizio',
21 type: 'Tipo',
22 upperAlpha: 'Alfabetico maiuscolo (A, B, C, D, E, ecc.)',
23 upperRoman: 'Numerazione Romana maiuscola (I, II, III, IV, V, ecc.)',
24 validateStartNumber: 'Il numero di inizio di una lista numerata deve essere un numero intero.'
25} );
diff --git a/sources/plugins/liststyle/lang/ja.js b/sources/plugins/liststyle/lang/ja.js
new file mode 100644
index 0000000..e55dafc
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ja.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ja', {
6 armenian: 'アルメニア数字',
7 bulletedTitle: '箇条書きのプロパティ',
8 circle: '白丸',
9 decimal: '数字 (1, 2, 3, etc.)',
10 decimalLeadingZero: '0付きの数字 (01, 02, 03, etc.)',
11 disc: '黒丸',
12 georgian: 'グルジア数字 (an, ban, gan, etc.)',
13 lowerAlpha: '小文字アルファベット (a, b, c, d, e, etc.)',
14 lowerGreek: '小文字ギリシャ文字 (alpha, beta, gamma, etc.)',
15 lowerRoman: '小文字ローマ数字 (i, ii, iii, iv, v, etc.)',
16 none: 'なし',
17 notset: '<なし>',
18 numberedTitle: '番号付きリストのプロパティ',
19 square: '四角',
20 start: '開始',
21 type: '種類',
22 upperAlpha: '大文字アルファベット (A, B, C, D, E, etc.)',
23 upperRoman: '大文字ローマ数字 (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'リストの開始番号は数値で入力してください。'
25} );
diff --git a/sources/plugins/liststyle/lang/ka.js b/sources/plugins/liststyle/lang/ka.js
new file mode 100644
index 0000000..0ede82d
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ka.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ka', {
6 armenian: 'სომხური გადანომრვა',
7 bulletedTitle: 'ღილებიანი სიის პარამეტრები',
8 circle: 'წრეწირი',
9 decimal: 'რიცხვებით (1, 2, 3, ..)',
10 decimalLeadingZero: 'ნულით დაწყებული რიცხვებით (01, 02, 03, ..)',
11 disc: 'წრე',
12 georgian: 'ქართული გადანომრვა (ან, ბან, გან, ..)',
13 lowerAlpha: 'პატარა ლათინური ასოებით (a, b, c, d, e, ..)',
14 lowerGreek: 'პატარა ბერძნული ასოებით (ალფა, ბეტა, გამა, ..)',
15 lowerRoman: 'რომაული გადანომრვცა პატარა ციფრებით (i, ii, iii, iv, v, ..)',
16 none: 'არაფერი',
17 notset: '<არაფერი>',
18 numberedTitle: 'გადანომრილი სიის პარამეტრები',
19 square: 'კვადრატი',
20 start: 'საწყისი',
21 type: 'ტიპი',
22 upperAlpha: 'დიდი ლათინური ასოებით (A, B, C, D, E, ..)',
23 upperRoman: 'რომაული გადანომრვა დიდი ციფრებით (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'სიის საწყისი მთელი რიცხვი უნდა იყოს.'
25} );
diff --git a/sources/plugins/liststyle/lang/km.js b/sources/plugins/liststyle/lang/km.js
new file mode 100644
index 0000000..51d7365
--- /dev/null
+++ b/sources/plugins/liststyle/lang/km.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'km', {
6 armenian: 'លេខ​អារមេនី',
7 bulletedTitle: 'លក្ខណៈ​សម្បត្តិ​បញ្ជី​ជា​ចំណុច',
8 circle: 'រង្វង់​មូល',
9 decimal: 'លេខ​ទសភាគ (1, 2, 3, ...)',
10 decimalLeadingZero: 'ទសភាគ​ចាប់​ផ្ដើម​ពី​សូន្យ (01, 02, 03, ...)',
11 disc: 'ថាស',
12 georgian: 'លេខ​ចចជា (an, ban, gan, ...)',
13 lowerAlpha: 'ព្យញ្ជនៈ​តូច (a, b, c, d, e, ...)',
14 lowerGreek: 'លេខ​ក្រិក​តូច (alpha, beta, gamma, ...)',
15 lowerRoman: 'លេខ​រ៉ូម៉ាំង​តូច (i, ii, iii, iv, v, ...)',
16 none: 'គ្មាន',
17 notset: '<not set>',
18 numberedTitle: 'លក្ខណៈ​សម្បត្តិ​បញ្ជី​ជា​លេខ',
19 square: 'ការេ',
20 start: 'ចាប់​ផ្ដើម',
21 type: 'ប្រភេទ',
22 upperAlpha: 'អក្សរ​ធំ (A, B, C, D, E, ...)',
23 upperRoman: 'លេខ​រ៉ូម៉ាំង​ធំ (I, II, III, IV, V, ...)',
24 validateStartNumber: 'លេខ​ចាប់​ផ្ដើម​បញ្ជី ត្រូវ​តែ​ជា​តួ​លេខ​ពិត​ប្រាកដ។'
25} );
diff --git a/sources/plugins/liststyle/lang/ko.js b/sources/plugins/liststyle/lang/ko.js
new file mode 100644
index 0000000..8b88e2d
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ko.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ko', {
6 armenian: '아르메니아 숫자',
7 bulletedTitle: '순서 없는 목록 속성',
8 circle: '원',
9 decimal: '수 (1, 2, 3, 등)',
10 decimalLeadingZero: '0이 붙은 수 (01, 02, 03, 등)',
11 disc: '내림차순',
12 georgian: '그루지야 숫자 (an, ban, gan, 등)',
13 lowerAlpha: '영소문자 (a, b, c, d, e, 등)',
14 lowerGreek: '그리스 소문자 (alpha, beta, gamma, 등)',
15 lowerRoman: '로마 소문자 (i, ii, iii, iv, v, 등)',
16 none: '없음',
17 notset: '<설정 없음>',
18 numberedTitle: '순서 있는 목록 속성',
19 square: '사각',
20 start: '시작',
21 type: '유형',
22 upperAlpha: '영대문자 (A, B, C, D, E, 등)',
23 upperRoman: '로마 대문자 (I, II, III, IV, V, 등)',
24 validateStartNumber: '목록 시작 숫자는 정수여야 합니다.'
25} );
diff --git a/sources/plugins/liststyle/lang/ku.js b/sources/plugins/liststyle/lang/ku.js
new file mode 100644
index 0000000..a3a7b47
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ku.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ku', {
6 armenian: 'ئاراستەی ژمارەی ئەرمەنی',
7 bulletedTitle: 'خاسیەتی لیستی خاڵی',
8 circle: 'بازنه',
9 decimal: 'ژمارە (1, 2, 3, وە هیتر.)',
10 decimalLeadingZero: 'ژمارە سفڕی لەپێشەوه (01, 02, 03, وە هیتر.)',
11 disc: 'پەپکە',
12 georgian: 'ئاراستەی ژمارەی جۆڕجی (an, ban, gan, وە هیتر.)',
13 lowerAlpha: 'ئەلفابێی بچووك (a, b, c, d, e, وە هیتر.)',
14 lowerGreek: 'یۆنانی بچووك (alpha, beta, gamma, وە هیتر.)',
15 lowerRoman: 'ژمارەی ڕۆمی بچووك (i, ii, iii, iv, v, وە هیتر.)',
16 none: 'هیچ',
17 notset: '<دانەندراوه>',
18 numberedTitle: 'خاسیەتی لیستی ژمارەیی',
19 square: 'چووراگۆشە',
20 start: 'دەستپێکردن',
21 type: 'جۆر',
22 upperAlpha: 'ئەلفابێی گەوره (A, B, C, D, E, وە هیتر.)',
23 upperRoman: 'ژمارەی ڕۆمی گەوره (I, II, III, IV, V, وە هیتر.)',
24 validateStartNumber: 'دەستپێکەری لیستی ژمارەیی دەبێت تەنها ژمارە بێت.'
25} );
diff --git a/sources/plugins/liststyle/lang/lt.js b/sources/plugins/liststyle/lang/lt.js
new file mode 100644
index 0000000..6b7c949
--- /dev/null
+++ b/sources/plugins/liststyle/lang/lt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'lt', {
6 armenian: 'Armėniški skaitmenys',
7 bulletedTitle: 'Ženklelinio sąrašo nustatymai',
8 circle: 'Apskritimas',
9 decimal: 'Dešimtainis (1, 2, 3, t.t)',
10 decimalLeadingZero: 'Dešimtainis su nuliu priekyje (01, 02, 03, t.t)',
11 disc: 'Diskas',
12 georgian: 'Gruziniški skaitmenys (an, ban, gan, t.t)',
13 lowerAlpha: 'Mažosios Alpha (a, b, c, d, e, t.t)',
14 lowerGreek: 'Mažosios Graikų (alpha, beta, gamma, t.t)',
15 lowerRoman: 'Mažosios Romėnų (i, ii, iii, iv, v, t.t)',
16 none: 'Niekas',
17 notset: '<nenurodytas>',
18 numberedTitle: 'Skaitmeninio sąrašo nustatymai',
19 square: 'Kvadratas',
20 start: 'Pradžia',
21 type: 'Rūšis',
22 upperAlpha: 'Didžiosios Alpha (A, B, C, D, E, t.t)',
23 upperRoman: 'Didžiosios Romėnų (I, II, III, IV, V, t.t)',
24 validateStartNumber: 'Sąrašo pradžios skaitmuo turi būti sveikas skaičius.'
25} );
diff --git a/sources/plugins/liststyle/lang/lv.js b/sources/plugins/liststyle/lang/lv.js
new file mode 100644
index 0000000..17b6da7
--- /dev/null
+++ b/sources/plugins/liststyle/lang/lv.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'lv', {
6 armenian: 'Armēņu skaitļi',
7 bulletedTitle: 'Vienkārša saraksta uzstādījumi',
8 circle: 'Aplis',
9 decimal: 'Decimālie (1, 2, 3, utt)',
10 decimalLeadingZero: 'Decimālie ar nulli (01, 02, 03, utt)',
11 disc: 'Disks',
12 georgian: 'Gruzīņu skaitļi (an, ban, gan, utt)',
13 lowerAlpha: 'Mazie alfabēta (a, b, c, d, e, utt)',
14 lowerGreek: 'Mazie grieķu (alfa, beta, gamma, utt)',
15 lowerRoman: 'Mazie romāņu (i, ii, iii, iv, v, utt)',
16 none: 'Nekas',
17 notset: '<nav norādīts>',
18 numberedTitle: 'Numurēta saraksta uzstādījumi',
19 square: 'Kvadrāts',
20 start: 'Sākt',
21 type: 'Tips',
22 upperAlpha: 'Lielie alfabēta (A, B, C, D, E, utt)',
23 upperRoman: 'Lielie romāņu (I, II, III, IV, V, utt)',
24 validateStartNumber: 'Saraksta sākuma numuram jābūt veselam skaitlim'
25} );
diff --git a/sources/plugins/liststyle/lang/mk.js b/sources/plugins/liststyle/lang/mk.js
new file mode 100644
index 0000000..dbb640b
--- /dev/null
+++ b/sources/plugins/liststyle/lang/mk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'mk', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/mn.js b/sources/plugins/liststyle/lang/mn.js
new file mode 100644
index 0000000..54e884c
--- /dev/null
+++ b/sources/plugins/liststyle/lang/mn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'mn', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Төрөл',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/ms.js b/sources/plugins/liststyle/lang/ms.js
new file mode 100644
index 0000000..297c02c
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ms.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ms', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/nb.js b/sources/plugins/liststyle/lang/nb.js
new file mode 100644
index 0000000..0fe7859
--- /dev/null
+++ b/sources/plugins/liststyle/lang/nb.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'nb', {
6 armenian: 'Armensk nummerering',
7 bulletedTitle: 'Egenskaper for punktliste',
8 circle: 'Sirkel',
9 decimal: 'Tall (1, 2, 3, osv.)',
10 decimalLeadingZero: 'Tall, med førstesiffer null (01, 02, 03, osv.)',
11 disc: 'Disk',
12 georgian: 'Georgisk nummerering (an, ban, gan, osv.)',
13 lowerAlpha: 'Alfabetisk, små (a, b, c, d, e, osv.)',
14 lowerGreek: 'Gresk, små (alpha, beta, gamma, osv.)',
15 lowerRoman: 'Romertall, små (i, ii, iii, iv, v, osv.)',
16 none: 'Ingen',
17 notset: '<ikke satt>',
18 numberedTitle: 'Egenskaper for nummerert liste',
19 square: 'Firkant',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Alfabetisk, store (A, B, C, D, E, osv.)',
23 upperRoman: 'Romertall, store (I, II, III, IV, V, osv.)',
24 validateStartNumber: 'Starten på listen må være et heltall.'
25} );
diff --git a/sources/plugins/liststyle/lang/nl.js b/sources/plugins/liststyle/lang/nl.js
new file mode 100644
index 0000000..88ea3f8
--- /dev/null
+++ b/sources/plugins/liststyle/lang/nl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'nl', {
6 armenian: 'Armeense nummering',
7 bulletedTitle: 'Eigenschappen lijst met opsommingstekens',
8 circle: 'Cirkel',
9 decimal: 'Cijfers (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Cijfers beginnen met nul (01, 02, 03, etc.)',
11 disc: 'Schijf',
12 georgian: 'Georgische nummering (an, ban, gan, etc.)',
13 lowerAlpha: 'Kleine letters (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grieks kleine letters (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Romeins kleine letters (i, ii, iii, iv, v, etc.)',
16 none: 'Geen',
17 notset: '<niet gezet>',
18 numberedTitle: 'Eigenschappen genummerde lijst',
19 square: 'Vierkant',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Hoofdletters (A, B, C, D, E, etc.)',
23 upperRoman: 'Romeinse hoofdletters (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Startnummer van de lijst moet een heel nummer zijn.'
25} );
diff --git a/sources/plugins/liststyle/lang/no.js b/sources/plugins/liststyle/lang/no.js
new file mode 100644
index 0000000..26927e6
--- /dev/null
+++ b/sources/plugins/liststyle/lang/no.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'no', {
6 armenian: 'Armensk nummerering',
7 bulletedTitle: 'Egenskaper for punktmerket liste',
8 circle: 'Sirkel',
9 decimal: 'Tall (1, 2, 3, osv.)',
10 decimalLeadingZero: 'Tall, med førstesiffer null (01, 02, 03, osv.)',
11 disc: 'Disk',
12 georgian: 'Georgisk nummerering (an, ban, gan, osv.)',
13 lowerAlpha: 'Alfabetisk, små (a, b, c, d, e, osv.)',
14 lowerGreek: 'Gresk, små (alpha, beta, gamma, osv.)',
15 lowerRoman: 'Romertall, små (i, ii, iii, iv, v, osv.)',
16 none: 'Ingen',
17 notset: '<ikke satt>',
18 numberedTitle: 'Egenskaper for nummerert liste',
19 square: 'Firkant',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Alfabetisk, store (A, B, C, D, E, osv.)',
23 upperRoman: 'Romertall, store (I, II, III, IV, V, osv.)',
24 validateStartNumber: 'Starten på listen må være et heltall.'
25} );
diff --git a/sources/plugins/liststyle/lang/oc.js b/sources/plugins/liststyle/lang/oc.js
new file mode 100644
index 0000000..eb64753
--- /dev/null
+++ b/sources/plugins/liststyle/lang/oc.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'oc', {
6 armenian: 'Numerotacion armènia',
7 bulletedTitle: 'Proprietats de la lista de piuses',
8 circle: 'Cercle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal precedit per un 0 (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Numeracion georgiana (an, ban, gan, etc.)',
13 lowerAlpha: 'Letras minusculas (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grèc minuscula (alfa, bèta, gamma, etc.)',
15 lowerRoman: 'Chifras romanas minusculas (i, ii, iii, iv, v, etc.)',
16 none: 'Pas cap',
17 notset: '<indefinit>',
18 numberedTitle: 'Proprietats de la lista numerotada',
19 square: 'Carrat',
20 start: 'Començament',
21 type: 'Tipe',
22 upperAlpha: 'Letras majusculas (A, B, C, D, E, etc.)',
23 upperRoman: 'Chifras romanas majusculas (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Lo primièr element de la lista deu èsser un nombre entièr.'
25} );
diff --git a/sources/plugins/liststyle/lang/pl.js b/sources/plugins/liststyle/lang/pl.js
new file mode 100644
index 0000000..37d2cd7
--- /dev/null
+++ b/sources/plugins/liststyle/lang/pl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'pl', {
6 armenian: 'Numerowanie armeńskie',
7 bulletedTitle: 'Właściwości list wypunktowanych',
8 circle: 'Koło',
9 decimal: 'Liczby (1, 2, 3 itd.)',
10 decimalLeadingZero: 'Liczby z początkowym zerem (01, 02, 03 itd.)',
11 disc: 'Okrąg',
12 georgian: 'Numerowanie gruzińskie (an, ban, gan itd.)',
13 lowerAlpha: 'Małe litery (a, b, c, d, e itd.)',
14 lowerGreek: 'Małe litery greckie (alpha, beta, gamma itd.)',
15 lowerRoman: 'Małe cyfry rzymskie (i, ii, iii, iv, v itd.)',
16 none: 'Brak',
17 notset: '<nie ustawiono>',
18 numberedTitle: 'Właściwości list numerowanych',
19 square: 'Kwadrat',
20 start: 'Początek',
21 type: 'Typ punktora',
22 upperAlpha: 'Duże litery (A, B, C, D, E itd.)',
23 upperRoman: 'Duże cyfry rzymskie (I, II, III, IV, V itd.)',
24 validateStartNumber: 'Listę musi rozpoczynać liczba całkowita.'
25} );
diff --git a/sources/plugins/liststyle/lang/pt-br.js b/sources/plugins/liststyle/lang/pt-br.js
new file mode 100644
index 0000000..c5f0296
--- /dev/null
+++ b/sources/plugins/liststyle/lang/pt-br.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'pt-br', {
6 armenian: 'Numeração Armêna',
7 bulletedTitle: 'Propriedades da Lista sem Numeros',
8 circle: 'Círculo',
9 decimal: 'Numeração Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Numeração Decimal com zeros (01, 02, 03, etc.)',
11 disc: 'Disco',
12 georgian: 'Numeração da Geórgia (an, ban, gan, etc.)',
13 lowerAlpha: 'Numeração Alfabética minúscula (a, b, c, d, e, etc.)',
14 lowerGreek: 'Numeração Grega minúscula (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Numeração Romana minúscula (i, ii, iii, iv, v, etc.)',
16 none: 'Nenhum',
17 notset: '<não definido>',
18 numberedTitle: 'Propriedades da Lista Numerada',
19 square: 'Quadrado',
20 start: 'Início',
21 type: 'Tipo',
22 upperAlpha: 'Numeração Alfabética Maiúscula (A, B, C, D, E, etc.)',
23 upperRoman: 'Numeração Romana maiúscula (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'O número inicial da lista deve ser um número inteiro.'
25} );
diff --git a/sources/plugins/liststyle/lang/pt.js b/sources/plugins/liststyle/lang/pt.js
new file mode 100644
index 0000000..7dc1f25
--- /dev/null
+++ b/sources/plugins/liststyle/lang/pt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'pt', {
6 armenian: 'Numeração armênia',
7 bulletedTitle: 'Propriedades da lista não numerada',
8 circle: 'Círculo',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Zero decimal à esquerda (01, 02, 03, etc.)',
11 disc: 'Disco',
12 georgian: 'Numeração georgiana (an, ban, gan, etc.)',
13 lowerAlpha: 'Minúsculas (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grego em minúsculas (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Romano em minúsculas (i, ii, iii, iv, v, etc.)',
16 none: 'Nenhum',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Quadrado',
20 start: 'Iniciar',
21 type: 'Tipo',
22 upperAlpha: 'Maiúsculas (A, B, C, D, E, etc.)',
23 upperRoman: 'Romanos em maiúscula (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'A lista tem iniciar por um número inteiro'
25} );
diff --git a/sources/plugins/liststyle/lang/ro.js b/sources/plugins/liststyle/lang/ro.js
new file mode 100644
index 0000000..5a8c327
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ro.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ro', {
6 armenian: 'Numerotare armeniană',
7 bulletedTitle: 'Proprietățile listei cu simboluri',
8 circle: 'Cerc',
9 decimal: 'Decimale (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimale cu zero în față (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Numerotare georgiană (an, ban, gan, etc.)',
13 lowerAlpha: 'Litere mici (a, b, c, d, e, etc.)',
14 lowerGreek: 'Litere grecești mici (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Cifre romane mici (i, ii, iii, iv, v, etc.)',
16 none: 'Nimic',
17 notset: '<nesetat>',
18 numberedTitle: 'Proprietățile listei numerotate',
19 square: 'Pătrat',
20 start: 'Start',
21 type: 'Tip',
22 upperAlpha: 'Litere mari (A, B, C, D, E, etc.)',
23 upperRoman: 'Cifre romane mari (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Începutul listei trebuie să fie un număr întreg.'
25} );
diff --git a/sources/plugins/liststyle/lang/ru.js b/sources/plugins/liststyle/lang/ru.js
new file mode 100644
index 0000000..5bfa8c6
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ru.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ru', {
6 armenian: 'Армянская нумерация',
7 bulletedTitle: 'Свойства маркированного списка',
8 circle: 'Круг',
9 decimal: 'Десятичные (1, 2, 3, и т.д.)',
10 decimalLeadingZero: 'Десятичные с ведущим нулём (01, 02, 03, и т.д.)',
11 disc: 'Окружность',
12 georgian: 'Грузинская нумерация (ани, бани, гани, и т.д.)',
13 lowerAlpha: 'Строчные латинские (a, b, c, d, e, и т.д.)',
14 lowerGreek: 'Строчные греческие (альфа, бета, гамма, и т.д.)',
15 lowerRoman: 'Строчные римские (i, ii, iii, iv, v, и т.д.)',
16 none: 'Нет',
17 notset: '<не указано>',
18 numberedTitle: 'Свойства нумерованного списка',
19 square: 'Квадрат',
20 start: 'Начиная с',
21 type: 'Тип',
22 upperAlpha: 'Заглавные латинские (A, B, C, D, E, и т.д.)',
23 upperRoman: 'Заглавные римские (I, II, III, IV, V, и т.д.)',
24 validateStartNumber: 'Первый номер списка должен быть задан обычным целым числом.'
25} );
diff --git a/sources/plugins/liststyle/lang/si.js b/sources/plugins/liststyle/lang/si.js
new file mode 100644
index 0000000..b401a13
--- /dev/null
+++ b/sources/plugins/liststyle/lang/si.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'si', {
6 armenian: 'Armenian numbering', // MISSING
7 bulletedTitle: 'Bulleted List Properties', // MISSING
8 circle: 'Circle', // MISSING
9 decimal: 'Decimal (1, 2, 3, etc.)', // MISSING
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)', // MISSING
11 disc: 'Disc', // MISSING
12 georgian: 'Georgian numbering (an, ban, gan, etc.)', // MISSING
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)', // MISSING
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)', // MISSING
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)', // MISSING
16 none: 'කිසිවක්ම නොවේ',
17 notset: '<යොදා >',
18 numberedTitle: 'Numbered List Properties', // MISSING
19 square: 'Square', // MISSING
20 start: 'Start', // MISSING
21 type: 'වර්ගය',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)', // MISSING
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)', // MISSING
24 validateStartNumber: 'List start number must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/liststyle/lang/sk.js b/sources/plugins/liststyle/lang/sk.js
new file mode 100644
index 0000000..2529c18
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sk', {
6 armenian: 'Arménske číslovanie',
7 bulletedTitle: 'Vlastnosti odrážkového zoznamu',
8 circle: 'Kruh',
9 decimal: 'Číselné (1, 2, 3, atď.)',
10 decimalLeadingZero: 'Číselné s nulou (01, 02, 03, atď.)',
11 disc: 'Disk',
12 georgian: 'Gruzínske číslovanie (an, ban, gan, atď.)',
13 lowerAlpha: 'Malé latinské (a, b, c, d, e, atď.)',
14 lowerGreek: 'Malé grécke (alfa, beta, gama, atď.)',
15 lowerRoman: 'Malé rímske (i, ii, iii, iv, v, atď.)',
16 none: 'Nič',
17 notset: '<nenastavené>',
18 numberedTitle: 'Vlastnosti číselného zoznamu',
19 square: 'Štvorec',
20 start: 'Začiatok',
21 type: 'Typ',
22 upperAlpha: 'Veľké latinské (A, B, C, D, E, atď.)',
23 upperRoman: 'Veľké rímske (I, II, III, IV, V, atď.)',
24 validateStartNumber: 'Začiatočné číslo číselného zoznamu musí byť celé číslo.'
25} );
diff --git a/sources/plugins/liststyle/lang/sl.js b/sources/plugins/liststyle/lang/sl.js
new file mode 100644
index 0000000..bd6c27f
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sl.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sl', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/sq.js b/sources/plugins/liststyle/lang/sq.js
new file mode 100644
index 0000000..6ee94a5
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sq.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sq', {
6 armenian: 'Numërim armenian',
7 bulletedTitle: 'Karakteristikat e Listës me Pulla',
8 circle: 'Rreth',
9 decimal: 'Decimal (1, 2, 3, etj.)',
10 decimalLeadingZero: 'Decimal me zerro udhëheqëse (01, 02, 03, etj.)',
11 disc: 'Disk',
12 georgian: 'Numërim gjeorgjian (an, ban, gan, etj.)',
13 lowerAlpha: 'Të vogla alfa (a, b, c, d, e, etj.)',
14 lowerGreek: 'Të vogla greke (alpha, beta, gamma, etj.)',
15 lowerRoman: 'Të vogla romake (i, ii, iii, iv, v, etj.)',
16 none: 'Asnjë',
17 notset: '<e pazgjedhur>',
18 numberedTitle: 'Karakteristikat e Listës me Numra',
19 square: 'Katror',
20 start: 'Fillimi',
21 type: 'LLoji',
22 upperAlpha: 'Të mëdha alfa (A, B, C, D, E, etj.)',
23 upperRoman: 'Të mëdha romake (I, II, III, IV, V, etj.)',
24 validateStartNumber: 'Numri i fillimit të listës duhet të është numër i plotë.'
25} );
diff --git a/sources/plugins/liststyle/lang/sr-latn.js b/sources/plugins/liststyle/lang/sr-latn.js
new file mode 100644
index 0000000..75d1cfa
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sr-latn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sr-latn', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/sr.js b/sources/plugins/liststyle/lang/sr.js
new file mode 100644
index 0000000..f89a441
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sr', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/sv.js b/sources/plugins/liststyle/lang/sv.js
new file mode 100644
index 0000000..49bbf48
--- /dev/null
+++ b/sources/plugins/liststyle/lang/sv.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'sv', {
6 armenian: 'Armenisk numrering',
7 bulletedTitle: 'Egenskaper för punktlista',
8 circle: 'Cirkel',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal nolla (01, 02, 03, etc.)',
11 disc: 'Disk',
12 georgian: 'Georgisk numrering (an, ban, gan, etc.)',
13 lowerAlpha: 'Alpha gemener (a, b, c, d, e, etc.)',
14 lowerGreek: 'Grekiska gemener (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Romerska gemener (i, ii, iii, iv, v, etc.)',
16 none: 'Ingen',
17 notset: '<ej angiven>',
18 numberedTitle: 'Egenskaper för punktlista',
19 square: 'Fyrkant',
20 start: 'Start',
21 type: 'Typ',
22 upperAlpha: 'Alpha versaler (A, B, C, D, E, etc.)',
23 upperRoman: 'Romerska versaler (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'Listans startnummer måste vara ett heltal.'
25} );
diff --git a/sources/plugins/liststyle/lang/th.js b/sources/plugins/liststyle/lang/th.js
new file mode 100644
index 0000000..d1425e8
--- /dev/null
+++ b/sources/plugins/liststyle/lang/th.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'th', {
6 armenian: 'Armenian numbering',
7 bulletedTitle: 'Bulleted List Properties',
8 circle: 'Circle',
9 decimal: 'Decimal (1, 2, 3, etc.)',
10 decimalLeadingZero: 'Decimal leading zero (01, 02, 03, etc.)',
11 disc: 'Disc',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)',
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)',
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)',
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)',
16 none: 'None',
17 notset: '<not set>',
18 numberedTitle: 'Numbered List Properties',
19 square: 'Square',
20 start: 'Start',
21 type: 'Type',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)',
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)',
24 validateStartNumber: 'List start number must be a whole number.'
25} );
diff --git a/sources/plugins/liststyle/lang/tr.js b/sources/plugins/liststyle/lang/tr.js
new file mode 100644
index 0000000..f08131e
--- /dev/null
+++ b/sources/plugins/liststyle/lang/tr.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'tr', {
6 armenian: 'Ermenice sayılandırma',
7 bulletedTitle: 'Simgeli Liste Özellikleri',
8 circle: 'Daire',
9 decimal: 'Ondalık (1, 2, 3, vs.)',
10 decimalLeadingZero: 'Başı sıfırlı ondalık (01, 02, 03, vs.)',
11 disc: 'Disk',
12 georgian: 'Gürcüce numaralandırma (an, ban, gan, vs.)',
13 lowerAlpha: 'Küçük Alpha (a, b, c, d, e, vs.)',
14 lowerGreek: 'Küçük Greek (alpha, beta, gamma, vs.)',
15 lowerRoman: 'Küçük Roman (i, ii, iii, iv, v, vs.)',
16 none: 'Yok',
17 notset: '<ayarlanmamış>',
18 numberedTitle: 'Sayılandırılmış Liste Özellikleri',
19 square: 'Kare',
20 start: 'Başla',
21 type: 'Tipi',
22 upperAlpha: 'Büyük Alpha (A, B, C, D, E, vs.)',
23 upperRoman: 'Büyük Roman (I, II, III, IV, V, vs.)',
24 validateStartNumber: 'Liste başlangıcı tam sayı olmalıdır.'
25} );
diff --git a/sources/plugins/liststyle/lang/tt.js b/sources/plugins/liststyle/lang/tt.js
new file mode 100644
index 0000000..13991f4
--- /dev/null
+++ b/sources/plugins/liststyle/lang/tt.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'tt', {
6 armenian: 'Әрмән номерлавы',
7 bulletedTitle: 'Маркерлы тезмә үзлекләре',
8 circle: 'Түгәрәк',
9 decimal: 'Унарлы (1, 2, 3, ...)',
10 decimalLeadingZero: 'Ноль белән башланган унарлы (01, 02, 03, ...)',
11 disc: 'Диск',
12 georgian: 'Georgian numbering (an, ban, gan, etc.)', // MISSING
13 lowerAlpha: 'Lower Alpha (a, b, c, d, e, etc.)', // MISSING
14 lowerGreek: 'Lower Greek (alpha, beta, gamma, etc.)', // MISSING
15 lowerRoman: 'Lower Roman (i, ii, iii, iv, v, etc.)', // MISSING
16 none: 'Һичбер',
17 notset: '<билгеләнмәгән>',
18 numberedTitle: 'Номерлы тезмә үзлекләре',
19 square: 'Шакмак',
20 start: 'Башлау',
21 type: 'Төр',
22 upperAlpha: 'Upper Alpha (A, B, C, D, E, etc.)', // MISSING
23 upperRoman: 'Upper Roman (I, II, III, IV, V, etc.)', // MISSING
24 validateStartNumber: 'List start number must be a whole number.' // MISSING
25} );
diff --git a/sources/plugins/liststyle/lang/ug.js b/sources/plugins/liststyle/lang/ug.js
new file mode 100644
index 0000000..2d4336e
--- /dev/null
+++ b/sources/plugins/liststyle/lang/ug.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'ug', {
6 armenian: 'قەدىمكى ئەرمىنىيە تەرتىپ نومۇرى شەكلى',
7 bulletedTitle: 'تۈر بەلگە تىزىم خاسلىقى',
8 circle: 'بوش چەمبەر',
9 decimal: 'سان (1, 2, 3 قاتارلىق)',
10 decimalLeadingZero: 'نۆلدىن باشلانغان سان بەلگە (01, 02, 03 قاتارلىق)',
11 disc: 'تولدۇرۇلغان چەمبەر',
12 georgian: 'قەدىمكى جورجىيە تەرتىپ نومۇرى شەكلى (an, ban, gan قاتارلىق)',
13 lowerAlpha: 'ئىنگلىزچە كىچىك ھەرپ (a, b, c, d, e قاتارلىق)',
14 lowerGreek: 'گرېكچە كىچىك ھەرپ (alpha, beta, gamma قاتارلىق)',
15 lowerRoman: 'كىچىك ھەرپلىك رىم رەقىمى (i, ii, iii, iv, v قاتارلىق)',
16 none: 'بەلگە يوق',
17 notset: '‹تەڭشەلمىگەن›',
18 numberedTitle: 'تەرتىپ نومۇر تىزىم خاسلىقى',
19 square: 'تولدۇرۇلغان تۆت چاسا',
20 start: 'باشلىنىش نومۇرى',
21 type: 'بەلگە تىپى',
22 upperAlpha: 'ئىنگلىزچە چوڭ ھەرپ (A, B, C, D, E قاتارلىق)',
23 upperRoman: 'چوڭ ھەرپلىك رىم رەقىمى (I, II, III, IV, V قاتارلىق)',
24 validateStartNumber: 'تىزىم باشلىنىش تەرتىپ نومۇرى چوقۇم پۈتۈن سان پىچىمىدا بولۇشى لازىم'
25} );
diff --git a/sources/plugins/liststyle/lang/uk.js b/sources/plugins/liststyle/lang/uk.js
new file mode 100644
index 0000000..7ef2343
--- /dev/null
+++ b/sources/plugins/liststyle/lang/uk.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'uk', {
6 armenian: 'Вірменська нумерація',
7 bulletedTitle: 'Опції маркованого списку',
8 circle: 'Кільце',
9 decimal: 'Десяткові (1, 2, 3 і т.д.)',
10 decimalLeadingZero: 'Десяткові з нулем (01, 02, 03 і т.д.)',
11 disc: 'Кружечок',
12 georgian: 'Грузинська нумерація (an, ban, gan і т.д.)',
13 lowerAlpha: 'Малі лат. букви (a, b, c, d, e і т.д.)',
14 lowerGreek: 'Малі гр. букви (альфа, бета, гамма і т.д.)',
15 lowerRoman: 'Малі римські (i, ii, iii, iv, v і т.д.)',
16 none: 'Нема',
17 notset: '<не вказано>',
18 numberedTitle: 'Опції нумерованого списку',
19 square: 'Квадратик',
20 start: 'Почати з...',
21 type: 'Тип',
22 upperAlpha: 'Великі лат. букви (A, B, C, D, E і т.д.)',
23 upperRoman: 'Великі римські (I, II, III, IV, V і т.д.)',
24 validateStartNumber: 'Початковий номер списку повинен бути цілим числом.'
25} );
diff --git a/sources/plugins/liststyle/lang/vi.js b/sources/plugins/liststyle/lang/vi.js
new file mode 100644
index 0000000..c5ecc44
--- /dev/null
+++ b/sources/plugins/liststyle/lang/vi.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'vi', {
6 armenian: 'Số theo kiểu Armenian',
7 bulletedTitle: 'Thuộc tính danh sách không thứ tự',
8 circle: 'Khuyên tròn',
9 decimal: 'Kiểu số (1, 2, 3 ...)',
10 decimalLeadingZero: 'Kiểu số (01, 02, 03...)',
11 disc: 'Hình đĩa',
12 georgian: 'Số theo kiểu Georgian (an, ban, gan...)',
13 lowerAlpha: 'Kiểu abc thường (a, b, c, d, e...)',
14 lowerGreek: 'Kiểu Hy Lạp (alpha, beta, gamma...)',
15 lowerRoman: 'Số La Mã kiểu thường (i, ii, iii, iv, v...)',
16 none: 'Không gì cả',
17 notset: '<không thiết lập>',
18 numberedTitle: 'Thuộc tính danh sách có thứ tự',
19 square: 'Hình vuông',
20 start: 'Bắt đầu',
21 type: 'Kiểu loại',
22 upperAlpha: 'Kiểu ABC HOA (A, B, C, D, E...)',
23 upperRoman: 'Số La Mã kiểu HOA (I, II, III, IV, V...)',
24 validateStartNumber: 'Số bắt đầu danh sách phải là một số nguyên.'
25} );
diff --git a/sources/plugins/liststyle/lang/zh-cn.js b/sources/plugins/liststyle/lang/zh-cn.js
new file mode 100644
index 0000000..9d274c2
--- /dev/null
+++ b/sources/plugins/liststyle/lang/zh-cn.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'zh-cn', {
6 armenian: '传统的亚美尼亚编号方式',
7 bulletedTitle: '项目列表属性',
8 circle: '空心圆',
9 decimal: '数字 (1, 2, 3, 等)',
10 decimalLeadingZero: '0开头的数字标记(01, 02, 03, 等)',
11 disc: '实心圆',
12 georgian: '传统的乔治亚编号方式(an, ban, gan, 等)',
13 lowerAlpha: '小写英文字母(a, b, c, d, e, 等)',
14 lowerGreek: '小写希腊字母(alpha, beta, gamma, 等)',
15 lowerRoman: '小写罗马数字(i, ii, iii, iv, v, 等)',
16 none: '无标记',
17 notset: '<没有设置>',
18 numberedTitle: '编号列表属性',
19 square: '实心方块',
20 start: '开始序号',
21 type: '标记类型',
22 upperAlpha: '大写英文字母(A, B, C, D, E, 等)',
23 upperRoman: '大写罗马数字(I, II, III, IV, V, 等)',
24 validateStartNumber: '列表开始序号必须为整数格式'
25} );
diff --git a/sources/plugins/liststyle/lang/zh.js b/sources/plugins/liststyle/lang/zh.js
new file mode 100644
index 0000000..e832518
--- /dev/null
+++ b/sources/plugins/liststyle/lang/zh.js
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'liststyle', 'zh', {
6 armenian: '亞美尼亞數字',
7 bulletedTitle: '項目符號清單屬性',
8 circle: '圓圈',
9 decimal: '小數點 (1, 2, 3, etc.)',
10 decimalLeadingZero: '前綴 0 十位數字 (01, 02, 03, 等)',
11 disc: '圓點',
12 georgian: '喬治王時代數字 (an, ban, gan, 等)',
13 lowerAlpha: '小寫字母 (a, b, c, d, e 等)',
14 lowerGreek: '小寫希臘字母 (alpha, beta, gamma, 等)',
15 lowerRoman: '小寫羅馬數字 (i, ii, iii, iv, v 等)',
16 none: '無',
17 notset: '<未設定>',
18 numberedTitle: '編號清單屬性',
19 square: '方塊',
20 start: '開始',
21 type: '類型',
22 upperAlpha: '大寫字母 (A, B, C, D, E 等)',
23 upperRoman: '大寫羅馬數字 (I, II, III, IV, V 等)',
24 validateStartNumber: '清單起始號碼須為一完整數字。'
25} );
diff --git a/sources/plugins/liststyle/plugin.js b/sources/plugins/liststyle/plugin.js
new file mode 100644
index 0000000..2d94142
--- /dev/null
+++ b/sources/plugins/liststyle/plugin.js
@@ -0,0 +1,75 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 CKEDITOR.plugins.liststyle = {
8 requires: 'dialog,contextmenu',
9 // jscs:disable maximumLineLength
10 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
11 // jscs:enable maximumLineLength
12 init: function( editor ) {
13 if ( editor.blockless )
14 return;
15
16 var def, cmd;
17
18 def = new CKEDITOR.dialogCommand( 'numberedListStyle', {
19 requiredContent: 'ol',
20 allowedContent: 'ol{list-style-type}[start]; li{list-style-type}[value]',
21 contentTransformations: [
22 [ 'ol: listTypeToStyle' ]
23 ]
24 } );
25 cmd = editor.addCommand( 'numberedListStyle', def );
26 editor.addFeature( cmd );
27 CKEDITOR.dialog.add( 'numberedListStyle', this.path + 'dialogs/liststyle.js' );
28
29 def = new CKEDITOR.dialogCommand( 'bulletedListStyle', {
30 requiredContent: 'ul',
31 allowedContent: 'ul{list-style-type}',
32 contentTransformations: [
33 [ 'ul: listTypeToStyle' ]
34 ]
35 } );
36 cmd = editor.addCommand( 'bulletedListStyle', def );
37 editor.addFeature( cmd );
38 CKEDITOR.dialog.add( 'bulletedListStyle', this.path + 'dialogs/liststyle.js' );
39
40 //Register map group;
41 editor.addMenuGroup( 'list', 108 );
42
43 editor.addMenuItems( {
44 numberedlist: {
45 label: editor.lang.liststyle.numberedTitle,
46 group: 'list',
47 command: 'numberedListStyle'
48 },
49 bulletedlist: {
50 label: editor.lang.liststyle.bulletedTitle,
51 group: 'list',
52 command: 'bulletedListStyle'
53 }
54 } );
55
56 editor.contextMenu.addListener( function( element ) {
57 if ( !element || element.isReadOnly() )
58 return null;
59
60 while ( element ) {
61 var name = element.getName();
62 if ( name == 'ol' )
63 return { numberedlist: CKEDITOR.TRISTATE_OFF };
64 else if ( name == 'ul' )
65 return { bulletedlist: CKEDITOR.TRISTATE_OFF };
66
67 element = element.getParent();
68 }
69 return null;
70 } );
71 }
72 };
73
74 CKEDITOR.plugins.add( 'liststyle', CKEDITOR.plugins.liststyle );
75} )();
diff --git a/sources/plugins/magicline/dev/magicline.html b/sources/plugins/magicline/dev/magicline.html
new file mode 100644
index 0000000..077b670
--- /dev/null
+++ b/sources/plugins/magicline/dev/magicline.html
@@ -0,0 +1,594 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Magicline muddy trenches &ndash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link href="../../../samples/old/sample.css" rel="stylesheet">
12 <style>
13 body {
14 margin: 0 0 130px;
15 }
16 #dev {
17 border-top: 1px solid #555;
18 position: fixed;
19 bottom: 0px;
20 left: 0px;
21 right: 0px;
22 height: 110px;
23 background: #B5E5EE;
24 font-size: 15px;
25 }
26 #dev .hl {
27 color: red;
28 }
29 #tr_upper, #tr_lower {
30 padding: 3px 6px;
31 }
32 #tr_upper {
33 background: rgba(255,0,0,.3);
34 }
35 #tr_lower {
36 background: rgba(0,255,0,.3);
37 }
38
39 #dev p {
40 margin: 0;
41 padding: 0;
42 }
43
44 #timeData,
45 #triggerData,
46 #mouseData,
47 #hiddenData {
48 position: absolute;
49 }
50 #timeData {
51 right: 10px;
52 top: 10px;
53 }
54 #hiddenData {
55 right: 10px;
56 top: 40px;
57 }
58 #mouseData {
59 left: 10px;
60 top: 10px;
61 }
62 #dev h2 {
63 top: 10px;
64 left: 10px;
65 }
66 #triggerData {
67 bottom: 10px;
68 left: 10px;
69 }
70 </style>
71</head>
72<body>
73 <h1 class="samples">
74 CKEditor Sample &mdash; magicline muddy trenches
75 </h1>
76
77 <h2>Various cases</h2>
78 <textarea cols="80" id="editor1" name="editor1" rows="10">
79 <div style="padding: 20px; background: gray; width: 300px" class="1">Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim.</div>
80 <div style="background: violet; padding: 30px" class="static">Position static</div>
81 <dl class="2">
82 <dt>Key</dt><dd>Value</dd>
83 </dl>
84 <div>Whatever</div>
85 <hr id="hr">
86 <div style="
87 display: block;
88 cursor: pointer;
89 background: green;
90 height: 50px; width: 50px;" >aasd
91 </div>
92 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
93 <hr>
94 <hr>
95 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
96 <table border="1" class="first">
97 <tbody><tr>
98 <td>
99 Table Cell 1
100 </td>
101 </tr>
102 <tr>
103 <td>
104 Table Cell 2<br>
105 Table Cell 2<br>
106 </td>
107 </tr>
108 </tbody>
109 </table>
110 <div style="border: 1px solid red; padding: 50px">
111 Parent
112 <div style="border: 10px solid green; padding: 10px">Child</div>
113 </div>
114 I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body.
115 I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body. I'm in a body.
116 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
117 <table border="1" style="margin: 15px 0 100px" class="outer">
118 <tbody>
119 <tr>
120 <td>Table Cell 1</td>
121 <td>Table Cell 1</td>
122 </tr>
123 <tr>
124 <td>
125 <table border="10" class="inner">
126 <tbody>
127 <tr>
128 <td>Table Cell 1</td>
129 </tr>
130 <tr>
131 <td>Table Cell 2<br> Table Cell 2<br></td>
132 </tr>
133 </tbody>
134 </table>
135 </td>
136 </tr>
137 </tbody>
138 </table>
139 <table border="1" style="margin: 15px" class="third">
140 <tbody><tr>
141 <td>
142 Table Cell 1
143 </td>
144 <td>
145 Table Cell 1
146 </td>
147 <td>
148 Table Cell 1
149 </td>
150 <td>
151 Table Cell 1
152 </td>
153 </tr>
154 <tr>
155 <td>
156 Table Cell 2
157 </td>
158 </tr>
159 </tbody>
160 </table>
161 <table border="1" style="margin: 15px" class="fourth">
162 <tbody><tr>
163 <td>
164 Table Cell 1
165 </td>
166 <td>
167 Table Cell 1
168 </td>
169 <td>
170 Table Cell 1
171 </td>
172 <td>
173 Table Cell 1
174 </td>
175 </tr>
176 <tr>
177 <td>
178 Table Cell 2
179 </td>
180 </tr>
181 </tbody>
182 </table>
183 <ul style="" class="fifth">
184 <li name="ul_first">List item</li>
185 <li name="ul_second">
186 <ol style="">
187 <li name="ol_first">Nested item</li>
188 <li>Nested item</li>
189 <li>Nested item</li>
190 </ol>
191 </li>
192 <li>List item</li>
193 </ul>
194 <table border="1" class="table#123">
195 <tbody>
196 <tr>
197 <td>Table Cell 1</td>
198 </tr>
199 <tr>
200 <td>Table Cell 2<br> Table Cell 2<br></td>
201 </tr>
202 </tbody>
203 </table>
204 <table border="1" align="right" class="aligned">
205 <tbody>
206 <tr>
207 <td>Table Cell 1</td>
208 </tr>
209 <tr>
210 <td>Table Cell 2<br> Table Cell 2<br></td>
211 </tr>
212 </tbody>
213 </table>
214 <table border="1" style="float: right" class="floated">
215 <tbody>
216 <tr>
217 <td>Table Cell 1</td>
218 </tr>
219 <tr>
220 <td>Table Cell 2<br> Table Cell 2<br></td>
221 </tr>
222 </tbody>
223 </table>
224 <table border="1" align=""class="table#124">
225 <tbody>
226 <tr>
227 <td>Table Cell 1</td>
228 </tr>
229 <tr>
230 <td>Table Cell 2<br> Table Cell 2<br></td>
231 </tr>
232 </tbody>
233 </table>
234 <table border="1"class="table#125">
235 <tbody>
236 <tr>
237 <td>Table Cell 1</td>
238 </tr>
239 <tr>
240 <td>Table Cell 2<br> Table Cell 2<br></td>
241 </tr>
242 </tbody>
243 </table>
244 <p> enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas male</p>
245 <table border="1"class="table#126">
246 <tbody>
247 <tr>
248 <td>Table Cell 1</td>
249 </tr>
250 <tr>
251 <td>Table Cell 2<br> Table Cell 2<br></td>
252 </tr>
253 </tbody>
254 </table>
255 <div style="background: orange; margin: 20px">Upper div</div>
256 <table style="background: blue; margin: 20px"><tr><td>Lower table</td></tr></table>
257 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
258 <div><strong>I'm a div. Let me stay here.</strong></div><dl>
259 <dt>Key</dt>
260 <dd>pendisse a pellentesque dui, non felis</dd>
261 <dt>Key</dt>
262 <dd>pendisse a pellentesque dui, non felis</dd>
263 </dl>
264 <div class="11" style="padding: 20px; background: pink; width: 400px">
265 Parent
266 <div class="12" style="padding: 20px; background: orange">
267 <!-- comment -->
268 <!-- another comment -->
269 <div class="13" style="padding: 20px; background: green">
270 Child#2
271 </div>
272 </div>
273 </div>
274 </textarea>
275
276 <h2>Odd case: first (last) element at the very beginning, short editable</h2>
277 <textarea cols="80" id="editor2" name="editor1a" rows="10">
278 <table border="1" style="width: 300px">
279 <tbody>
280 <tr>
281 <td>
282 Test</td>
283 </tr>
284 </tbody>
285 </table>
286 </textarea>
287
288 <h2>Large document, put everywhere</h2>
289 <textarea id="editor3">
290 <p><div class="navbar" align="center" style="color: rgb(0, 0, 0);font-family: sans-serif;font-size: medium;"><a accesskey="p" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">previous</a>   <a accesskey="n" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/idl-definitions.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">next</a>   <a accesskey="c" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/Overview.html#contents" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">contents</a>   <a accesskey="i" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/def-index.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">index</a><hr title="Navigation area separator"></div><div class="noprint" style="color: rgb(0, 0, 0);font-family: sans-serif;font-size: medium;text-align: right;"><p style="font-family: monospace;font-size: small;">13 November, 2000</p></div><div class="div1" style="color: rgb(0, 0, 0);font-family: sans-serif;font-size: medium;"><a id="Range" name="Range"></a><h1 id="Range-h1" class="div1" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 27px;font-weight: normal; background-color: violet">2. Document Object Model Range</h1><dl style="background: green"><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><i>Editors</i></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Peter Sharpe, SoftQuad Software Inc.</dd><dd style="margin-top: 0px;margin-bottom: 0px;">Vidur Apparao, Netscape Communications Corp.</dd><dd style="margin-top: 0px;margin-bottom: 0px;">Lauren Wood, SoftQuad Software Inc.</dd></dl><div class="noprint"><h2 id="table-of-contents" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">Table of contents</h2><ul class="toc" style="list-style-type: none;list-style-position: initial;list-style-image: initial;"><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-introduction" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.1. Introduction</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Definitions" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial; background: red">2.2. Definitions and Notation</a><ul class="toc" style="list-style-type: none;list-style-position: initial;list-style-image: initial;"><li class="tocline4" style="font-style: italic;"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.2.1. Position</a></li><li class="tocline4" style="font-style: italic;"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Containment" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.2.2. Selection and Partial Selection</a></li><li class="tocline4" style="font-style: italic;"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Notation" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.2.3. Notation</a></li></ul></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Creating" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.3. Creating a Range</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Changing" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.4. Changing a Range's Position</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.5. Comparing Range Boundary-Points</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Deleting-Content" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.6. Deleting Content with a Range</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Extracting" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.7. Extracting Content</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Cloning" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.8. Cloning Content</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Inserting" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.9. Inserting Content</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Surrounding" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.10. Surrounding Content</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Misc" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.11. Miscellaneous Members</a></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.12. Range modification under document mutation</a><ul class="toc" style="list-style-type: none;list-style-position: initial;list-style-image: initial;"><li class="tocline4" style="font-style: italic;"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Insertions" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.12.1. Insertions</a></li><li class="tocline4" style="font-style: italic;"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Deletions" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.12.2. Deletions</a></li></ul></li><li class="tocline3"><a class="tocxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Interface" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">2.13. Formal Description of the Range Interface</a><ul class="toc" style="list-style-type: none;list-style-position: initial;list-style-image: initial;"><li class="tocline4" style="font-style: italic;"><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">Range</a>, <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-DocumentRange-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">DocumentRange</a>, <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">RangeException</a>, <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeExceptionCode" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">RangeExceptionCode</a></li></ul></li></ul></div><div class="div2"><a id="Level-2-Range-introduction" name="Level-2-Range-introduction"></a><h2 id="Level-2-Range-introduction-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.1. Introduction</h2><p>A Range identifies a range of content in a Document, DocumentFragment or Attr. It is contiguous in the sense that it can be characterized as selecting all of the content between a pair of boundary-points.</p><p><b>Note:</b> In a text editor or a word processor, a user can make a selection by pressing down the mouse at one point in a document, moving the mouse to another point, and releasing the mouse. The resulting selection is contiguous and consists of the content between the two points.</p><p>The term 'selecting' does not mean that every Range corresponds to a selection made by a GUI user;however, such a selection can be returned to a DOM user as a Range.</p><p><b>Note:</b> In bidirectional writing (Arabic, Hebrew), a range may correspond to a logical selection that is not necessarily contiguous when displayed. A visually contiguous selection, also used in some cases, may not correspond to a single logical selection, and may therefore have to be represented by more than one range.</p><p>The Range interface provides methods for accessing and manipulating the document tree at a higher level than similar methods in the Node interface. The expectation is that each of the methods provided by the Range interface for the insertion, deletion and copying of content can be directly mapped to a series of Node editing operations enabled by DOM Core. In this sense, the Range operations can be viewed as convenience methods that also enable the implementation to optimize common editing patterns.</p><p>This chapter describes the Range interface, including methods for creating and moving a Range and methods for manipulating content with Ranges.</p><p>The interfaces found within this section are not mandatory. A DOM application may use the <code>hasFeature(feature, version)</code> method of the <code>DOMImplementation</code> interface with parameter values "Range" and "2.0" (respectively) to determine whether or not this module is supported by the implementation. In order to fully support this module, an implementation must also support the "Core" feature defined defined in the DOM Level 2 Core specification [<a class="noxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/references.html#DOMCore" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">DOM Level 2 Core</a>]. Please refer to additional information about <a href="http://www.w3.org/TR/DOM-Level-2-Core/introduction.html#ID-Conformance" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>conformance</em></a> in the DOM Level 2 Core specification [<a class="noxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/references.html#DOMCore" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">DOM Level 2 Core</a>].</p></div><div class="div2" style="background: blue;"><a id="Level-2-Range-Definitions" name="Level-2-Range-Definitions"></a><h2 id="Level-2-Range-Definitions-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal; background: red">2.2. Definitions and Notation</h2><div style="background: yellow" class="div3"><a id="Level-2-Range-Position" name="Level-2-Range-Position"></a><h3 id="Level-2-Range-Position-h3" class="div3" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 19px;font-weight: normal;">2.2.1. Position</h3><p>This chapter refers to two different representations of a document: the text or source form that includes the document markup and the tree representation similar to the one described in the introduction section of the DOM Level 2 Core [<a class="noxref" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/references.html#DOMCore" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">DOM Level 2 Core</a>].</p><p>A Range consists of two <i>boundary-points</i> corresponding to the start and the end of the Range. <a id="td-boundarypoint" name="td-boundarypoint"></a>A boundary-point's position in a Document or DocumentFragment tree can be characterized by a node and an offset. <a id="td-container" name="td-container"></a>The node is called the <i>container</i> of the boundary-point and of its position. <a id="td-ancestor-container" name="td-ancestor-container"></a>The container and its ancestors are the <i>ancestor container</i>s of the boundary-point and of its position.<a id="td-offset" name="td-offset"></a>The offset within the node is called the <i>offset</i> of the boundary-point and its position. If the container is an Attr, Document, DocumentFragment, Element or EntityReference node, the offset is between its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-child" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>child</em></a> nodes. If the container is a CharacterData, Comment or ProcessingInstruction node, the offset is between the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit units</em></a> of the UTF-16 encoded string contained by it.</p><p>The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-points</em></a> of a Range must have a common <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> which is either a Document, DocumentFragment or Attr node. That is, the content of a Range must be entirely within the subtree rooted by a single Document, DocumentFragment or Attr Node. <a id="td-root-container" name="td-root-container"></a>This common <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> is known as the <i>root container</i> of the Range. <a id="td-context-tree" name="td-context-tree"></a>The tree rooted by the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-root-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>root container</em></a> is known as the Range's <i>context tree</i>.</p><p>The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of a Range must be an Element, Comment, ProcessingInstruction, EntityReference, CDATASection, Document, DocumentFragment, Attr, or Text node. None of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a>s of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of a Range can be a DocumentType, Entity or Notation node.</p><p>In terms of the text representation of a document, the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-points</em></a> of a Range can only be on token boundaries. That is, the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of the text range cannot be in the middle of a start- or end-tag of an element or within the name of an entity or character reference. A Range locates a contiguous portion of the content of the structure model.</p><p>The relationship between locations in a text representation of the document and in the Node tree interface of the DOM is illustrated in the following diagram:<br></p><div align="center"><hr width="90%" size="2"><img src="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/images/RangeExample.gif" alt="Range Example"><hr width="90%" size="2"><b>Range Example</b><hr width="90%" size="2"></div><p>In this diagram, four different Ranges are illustrated. The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-points</em></a> of each Range are labelled with <i>s#</i> (the start of the Range) and <i>e#</i> (the end of the Range), where # is the number of the Range. For Range 2, the start is in the BODY element and is immediately after the H1 element and immediately before the P element, so its position is between the H1 and P children of BODY. The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> whose <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> is not a CharacterData node is 0 if it is before the first child, 1 if between the first and second child, and so on. So, for the start of the Range 2, the<a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> is BODY and the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> is 1. The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> whose <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> is a CharacterData node is obtained similarly but using <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit unit</em></a> positions instead. For example, the<a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> labelled s1 of the Range 1 has a Text node (the one containing "Title") as its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> and an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of 2 since it is between the second and third <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit unit</em></a>.</p><p>Notice that the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s of Ranges 3 and 4 correspond to the same location in the text representation. An important feature of the Range is that a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of a Range can unambiguously represent every position within the document tree.</p><p>The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>s and <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a>s of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s can be obtained through the following read-only Range attributes:</p><div class="eg"><pre style="margin-left: 2em;"> readonly attribute Node startContainer;readonly attribute long startOffset;readonly attribute Node endContainer;readonly attribute long endOffset;</pre></div><p><a id="td-collapsed" name="td-collapsed"></a>If the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s of a Range have the same <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>s and <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a>s, the Range is said to be a <i>collapsed</i> Range. (This is often referred to as an insertion point in a user agent.)</p></div><div class="div3"><a id="Level-2-Range-Containment" name="Level-2-Range-Containment"></a><h3 id="Level-2-Range-Containment-h3" class="div3" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 19px;font-weight: normal;">2.2.2. Selection and Partial Selection</h3><p><a id="td-selected" name="td-selected"></a>A node or <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit unit</em></a> unit is said to be <i>selected</i> by a Range if it is between the two <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s of the Range, that is, if the position immediately before the node or 16-bit unit is before the end of the Range and the position immediately after the node or 16-bit unit is after the start of the range. For example, in terms of a text representation of the document, an element would be <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>selected</em></a>by a Range if its corresponding start-tag was located after the start of the Range and its end-tag was located before the end of the Range. In the examples in the above diagram, the Range 2<a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>selects</em></a> the P node and the Range 3 <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>selects</em></a> the text node containing the text "Blah xyz."</p><p><a id="td-partially-selected" name="td-partially-selected"></a>A node is said to be <i>partially selected</i> by a Range if it is an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of exactly one <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of the Range. For example, consider Range 1 in the above diagram. The element H1 is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> by that Range since the start of the Range is within one of its children.</p></div><div class="div3"><a id="Level-2-Range-Notation" name="Level-2-Range-Notation"></a><h3 id="Level-2-Range-Notation-h3" class="div3" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 19px;font-weight: normal;">2.2.3. Notation</h3><p>Many of the examples in this chapter are illustrated using a text representation of a document. The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s of a Range are indicated by displaying the characters (be they markup or data characters) between the two <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s in bold, as in</p><div class="eg"><pre style="margin-left: 2em;"> <FOO>A<b>BC<BAR>DE</b>F</BAR></FOO></pre></div><p>When both <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s are at the same position, they are indicated with a bold caret ('<b>^</b>'), as in</p><div class="eg"><pre style="margin-left: 2em;"> <FOO>A<b>^</b>BC<BAR>DEF</BAR></FOO></pre></div></div></div><div class="div2"><a id="Level-2-Range-Creating" name="Level-2-Range-Creating"></a><h2 id="Level-2-Range-Creating-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.3. Creating a Range</h2><p>A Range is created by calling the <code>createRange()</code> method on the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-DocumentRange-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>DocumentRange</code></a> interface. This interface can be obtained from the object implementing the <code>Document</code> interface using binding-specific casting methods.</p><div class="eg"><pre style="margin-left: 2em;"> interface DocumentRange{Range createRange();}</pre></div><p>The initial state of the Range returned from this method is such that both of its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a>s are positioned at the beginning of the corresponding Document, before any content. In other words, the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of each <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> is the Document node and the offset within that node is 0.</p><p>Like some objects created using methods in the Document interface (such as Nodes and DocumentFragments), Ranges created via a particular document instance can select only content associated with that Document, or with DocumentFragments and Attrs for which that Document is the <code>ownerDocument</code>. Such Ranges, then, can not be used with other Document instances.</p></div><div class="div2"><a id="Level-2-Range-Changing" name="Level-2-Range-Changing"></a><h2 id="Level-2-Range-Changing-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.4. Changing a Range's Position</h2><p>A Range's position can be specified by setting the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> and <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of each boundary-point with the <code>setStart</code> and <code>setEnd</code> methods.</p><div class="eg"><pre style="margin-left: 2em;"> void setStart(in Node parent, in long offset) raises(RangeException);void setEnd(in Node parent, in long offset) raises(RangeException);</pre></div><p>If one boundary-point of a Range is set to have a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-root-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>root container</em></a> other than the current one for the Range, the Range is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> to the new position. This enforces the restriction that both boundary-points of a Range must have the same <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-root-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>root container</em></a>.</p><p>The start position of a Range is guaranteed to never be after the end position. To enforce this restriction, if the start is set to be at a position after the end, the Range is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> to that position. Similarly, if the end is set to be at a position before the start, the Range is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> to that position.</p><p>It is also possible to set a Range's position relative to nodes in the tree:</p><div class="eg"><pre style="margin-left: 2em;"> void setStartBefore(in Node node);raises(RangeException);void setStartAfter(in Node node);raises(RangeException);void setEndBefore(in Node node);raises(RangeException);void setEndAfter(in Node node);raises(RangeException);</pre></div><p>The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-parent" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>parent</em></a> of the node becomes the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> and the Range is subject to the same restrictions as given above in the description of <code>setStart()</code>and <code>setEnd()</code>.</p><p>A Range can be <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> to either boundary-point:</p><div class="eg"><pre style="margin-left: 2em;"> void collapse(in boolean toStart);</pre></div><p>Passing <code>TRUE</code> as the parameter <code>toStart</code> will <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapse</em></a> the Range to its start, <code>FALSE</code> to its end.</p><p>Testing whether a Range is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> can be done by examining the <code>collapsed</code> attribute:</p><div class="eg"><pre style="margin-left: 2em;"> readonly attribute boolean collapsed;</pre></div><p>The following methods can be used to make a Range select the contents of a node or the node itself.</p><div class="eg"><pre style="margin-left: 2em;"> void selectNode(in Node n);void selectNodeContents(in Node n);</pre></div><p>The following examples demonstrate the operation of the methods <code>selectNode</code> and <code>selectNodeContents</code>:</p><div class="eg"><pre style="margin-left: 2em;">Before: <b>^</b><BAR><FOO>A<MOO>B</MOO>C</FOO></BAR>After Range.selectNodeContents(FOO): <BAR><FOO><b>A<MOO>B</MOO>C</b></FOO></BAR>(In this case, FOO is the parent of both boundary-points)After Range.selectNode(FOO):<BAR><b><FOO>A<MOO>B</MOO>C</FOO></b></BAR></pre></div></div><div class="div2"><a id="Level-2-Range-Comparing" name="Level-2-Range-Comparing"></a><h2 id="Level-2-Range-Comparing-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.5. Comparing Range Boundary-Points</h2><p>It is possible to compare two Ranges by comparing their boundary-points:</p><div class="eg"><pre style="margin-left: 2em;"> short compareBoundaryPoints(in CompareHow how, in Range sourceRange) raises(RangeException);</pre></div><p>where <code>CompareHow</code> is one of four values: <code>START_TO_START</code>, <code>START_TO_END</code>, <code>END_TO_END</code> and <code>END_TO_START</code>. The return value is -1, 0 or 1 depending on whether the corresponding boundary-point of the Range is before, equal to, or after the corresponding boundary-point of <code>sourceRange</code>. An exception is thrown if the two Ranges have different <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-root-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>root container</em></a>s.</p><p>The result of comparing two boundary-points (or positions) is specified below. An informal but not always correct specification is that an boundary-point is before, equal to, or after another if it corresponds to a location in a text representation before, equal to, or after the other's corresponding location.</p><p><a id="td-comparison" name="td-comparison"></a>Let A and B be two boundary-points or positions. Then one of the following holds: A is <i>before</i> B, A is <i>equal to</i> B, or A is <i>after</i> B. Which one holds is specified in the following by examining four cases:</p><p>In the first case the boundary-points have the same <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>. A is <i>before</i> B if its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> is less than the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of B, A is <i>equal to</i> B if its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> is equal to the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of B, and A is <i>after</i> B if its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> is greater than the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of B.</p><p>In the second case a child node C of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of A is an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of B. In this case, A is <i>before</i> B if the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of A is less than or equal to the index of the child node C and A is <i>after</i>B otherwise.</p><p>In the third case a child node C of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of B is an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of A. In this case, A is <i>before</i> B if the index of the child node C is less than the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of B and A is <i>after</i> B otherwise.</p><p>In the fourth case, none of three other cases hold: the containers of A and B are <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-sibling" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>siblings</em></a> or <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-descendant" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>descendants</em></a> of sibling nodes. In this case, A is <i>before</i> B if the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of A is before the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of B in a pre-order traversal of the Ranges' <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a> and A is <i>after</i> B otherwise.</p><p>Note that because the same location in a text representation of the document can correspond to two different positions in the DOM tree, it is possible for two boundary-points to not compare equal even though they would be equal in the text representation. For this reason, the informal definition above can sometimes be incorrect.</p></div><div class="div2"><a id="Level-2-Range-Deleting-Content" name="Level-2-Range-Deleting-Content"></a><h2 id="Level-2-Range-Deleting-Content-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.6. Deleting Content with a Range</h2><p>One can delete the contents selected by a Range with:</p><div class="eg"><pre style="margin-left: 2em;"> void deleteContents();</pre></div><p><code>deleteContents()</code> deletes all nodes and characters selected by the Range. All other nodes and characters remain in the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a> of the Range. Some examples of this deletion operation are:</p><div class="eg"><pre style="margin-left: 2em;">(1) <FOO>A<b>B<MOO>CD</MOO></b>CD</FOO>--><FOO>A<b>^</b>CD</FOO></pre></div><div class="eg"><pre style="margin-left: 2em;">(2) <FOO>A<MOO>B<b>C</MOO>D</b>E</FOO>--><FOO>A<MOO>B</MOO><b>^</b>E</FOO></pre></div><div class="eg"><pre style="margin-left: 2em;">(3) <FOO>X<b>Y<BAR>Z</b>W</BAR>Q</FOO>--><FOO>X<b>^</b><BAR>W</BAR>Q</FOO></pre></div><div class="eg"><pre style="margin-left: 2em;">(4) <FOO><BAR1>A<b>B</BAR1><BAR2/><BAR3>C</b>D</BAR3></FOO>--><FOO><BAR1>A</BAR1><b>^</b><BAR3>D</BAR3></pre></div><p>After <code>deleteContents()</code> is invoked on a Range, the Range is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a>. If no node was <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> by the Range, then it is <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a> to its original start point, as in example (1). If a node was <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> by the Range and was an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of the start of the Range and no <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-ancestor" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor</em></a> of the node satisfies these two conditions, then the Range is collapsed to the position immediately after the node, as in examples (2) and (4). If a node was <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> by the Range and was an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of the end of the Range and no ancestor of the node satisfies these two conditions, then the Range is collapsed to the position immediately before the node, as in examples (3) and (4).</p><p>Note that if deletion of a Range leaves adjacent Text nodes, they are not automatically merged, and empty Text nodes are not automatically removed. Two Text nodes should be joined only if each is the container of one of the boundary-points of a Range whose contents are deleted. To merge adjacent Text nodes, or remove empty text nodes, the <code>normalize()</code> method on the <code>Node</code>interface should be used.</p></div><div class="div2"><a id="Level-2-Range-Extracting" name="Level-2-Range-Extracting"></a><h2 id="Level-2-Range-Extracting-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.7. Extracting Content</h2><p>If the contents of a Range need to be extracted rather than deleted, the following method may be used:</p><div class="eg"><pre style="margin-left: 2em;"> DocumentFragment extractContents();</pre></div><p>The <code>extractContents()</code> method removes nodes from the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a> similarly to the <code>deleteContents()</code> method. In addition, it places the deleted contents in a new <code>DocumentFragment</code>. The following examples illustrate the contents of the returned DocumentFragment:</p><div class="eg"><pre style="margin-left: 2em;">(1) <FOO>A<b>B<MOO>CD</MOO></b>CD</FOO>-->B<MOO>CD</MOO></pre></div><div class="eg"><pre style="margin-left: 2em;">(2) <FOO>A<MOO>B<b>C</MOO>D</b>E</FOO>--><MOO>C<MOO>D</pre></div><div class="eg"><pre style="margin-left: 2em;">(3) <FOO>X<b>Y<BAR>Z</b>W</BAR>Q</FOO>-->Y<BAR>Z</BAR></pre></div><div class="eg"><pre style="margin-left: 2em;">(4)<FOO><BAR1>A<b>B</BAR1><BAR2/><BAR3>C</b>D</BAR3></FOO>--><BAR1>B</BAR1><BAR2/><BAR3>C</BAR3></pre></div><p>It is important to note that nodes that are <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> by the Range are cloned. Since part of such a node's contents must remain in the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a> and part of the contents must be moved to the new DocumentFragment, a clone of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selected</em></a> node is included in the new DocumentFragment. Note that cloning does not take place for <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>selected</em></a> elements;these nodes are moved to the new DocumentFragment.</p></div><div class="div2"><a id="Level-2-Range-Cloning" name="Level-2-Range-Cloning"></a><h2 id="Level-2-Range-Cloning-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.8. Cloning Content</h2><p>The contents of a Range may be duplicated using the following method:</p><div class="eg"><pre style="margin-left: 2em;"> DocumentFragment cloneContents();</pre></div><p>This method returns a <code>DocumentFragment</code> that is similar to the one returned by the method <code>extractContents()</code>. However, in this case, the original nodes and character data in the Range are not removed from the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a>. Instead, all of the nodes and text content within the returned <code>DocumentFragment</code> are cloned.</p></div><div class="div2"><a id="Level-2-Range-Inserting" name="Level-2-Range-Inserting"></a><h2 id="Level-2-Range-Inserting-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.9. Inserting Content</h2><p>A node may be inserted into a Range using the following method:</p><div class="eg"><pre style="margin-left: 2em;"> void insertNode(in Node n) raises(RangeException);</pre></div><p>The <code>insertNode()</code> method inserts the specified node into the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a>. The node is inserted at the start <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of the Range, without modifying it.</p><p>If the start boundary point of the Range is in a <code>Text</code> node, the <code>insertNode</code> operation splits the <code>Text</code> node at the boundary point. If the node to be inserted is also a <code>Text</code> node, the resulting adjacent<code>Text</code> nodes are not normalized automatically;this operation is left to the application.</p><p>The Node passed into this method can be a <code>DocumentFragment</code>. In that case, the contents of the <code>DocumentFragment</code> are inserted at the start <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-boundarypoint" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>boundary-point</em></a> of the Range, but the <code>DocumentFragment</code>itself is not. Note that if the Node represents the root of a sub-tree, the entire sub-tree is inserted.</p><p>The same rules that apply to the <code>insertBefore()</code> method on the Node interface apply here. Specifically, the Node passed in, if it already has a parent, will be removed from its existing position.</p></div><div class="div2"><a id="Level-2-Range-Surrounding" name="Level-2-Range-Surrounding"></a><h2 id="Level-2-Range-Surrounding-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.10. Surrounding Content</h2><p>The insertion of a single node to subsume the content selected by a Range can be performed with:</p><div class="eg"><pre style="margin-left: 2em;"> void surroundContents(in Node newParent);</pre></div><p>The <code>surroundContents()</code> method causes all of the content selected by the Range to be rooted by the specified node. The nodes may not be Attr, Entity, DocumentType, Notation, Document, or DocumentFragment nodes. Calling <code>surroundContents()</code> with the Element node FOO in the following examples yields:</p><div class="eg"><pre style="margin-left: 2em;"> Before: <BAR>A<b>B<MOO>C</MOO>D</b>E</BAR>After surroundContents(FOO):<BAR>A<b><FOO>B<MOO>C</MOO>D</FOO></b>E</BAR></pre></div><p>Another way of describing the effect of this method on the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-context-tree" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>context tree</em></a> is to decompose it in terms of other operations:</p><ol><li>Remove the contents selected by the Range with a call to <code>extractContents()</code>.</li><li>Insert the node <code>newParent</code> where the Range is collapsed (after the extraction) with <code>insertNode().</code></li><li>Insert the entire contents of the extracted DocumentFragment into <code>newParent</code>. Specifically, invoke the <code>appendChild()</code> on <code>newParent</code> passing in the DocumentFragment returned as a result of the call to <code>extractContents()</code></li><li>Select <code>newParent</code> and all of its contents with <code>selectNode()</code>.</li></ol><p>The <code>surroundContents()</code> method raises an exception if the Range <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selects</em></a> a non-Text node. An example of a Range for which <code>surroundContents()</code>raises an exception is:</p><div class="eg"><pre style="margin-left: 2em;"> <FOO>A<b>B<BAR>C</b>D</BAR>E</FOO></pre></div><p>If the node <code>newParent</code> has any children, those children are removed before its insertion. Also, if the node <code>newParent</code> already has a parent, it is removed from the original parent's <code>childNodes</code> list.</p></div><div class="div2"><a id="Level-2-Range-Misc" name="Level-2-Range-Misc"></a><h2 id="Level-2-Range-Misc-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.11. Miscellaneous Members</h2><p>One can clone a Range:</p><div class="eg"><pre style="margin-left: 2em;"> Range cloneRange();</pre></div><p>This creates a new Range which selects exactly the same content as that selected by the Range on which the method <code>cloneRange</code> was invoked. No content is affected by this operation.</p><p>Because the boundary-points of a Range do not necessarily have the same <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>s, use:</p><div class="eg"><pre style="margin-left: 2em;"> readonly attribute Node commonAncestorContainer;</pre></div><p>to get the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of both boundary-points that is furthest down from the Range's <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-root-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>root container</em></a></p><p>One can get a copy of all the character data selected or partially selected by a Range with:</p><div class="eg"><pre style="margin-left: 2em;"> DOMString toString();</pre></div><p>This does nothing more than simply concatenate all the character data selected by the Range. This includes character data in both <code>Text</code> and <code>CDATASection</code> nodes.</p></div><div class="div2"><a id="Level-2-Range-Mutation" name="Level-2-Range-Mutation"></a><h2 id="Level-2-Range-Mutation-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.12. Range modification under document mutation</h2><p>As a document is modified, the Ranges within the document need to be updated. For example, if one boundary-point of a Range is within a node and that node is removed from the document, then the Range would be invalid unless it is fixed up in some way. This section describes how Ranges are modified under document mutations so that they remain valid.</p><p>There are two general principles which apply to Ranges under document mutation: The first is that all Ranges in a document will remain valid after any mutation operation and the second is that, as much as possible, all Ranges will select the same portion of the document after any mutation operation.</p><p>Any mutation of the document tree which affect Ranges can be considered to be a combination of basic deletion and insertion operations. In fact, it can be convenient to think of those operations as being accomplished using the <code>deleteContents()</code> and <code>insertNode()</code> Range methods and, in the case of Text mutations, the <code>splitText()</code> and <code>normalize()</code> methods.</p><div class="div3"><a id="Level-2-Range-Insertions" name="Level-2-Range-Insertions"></a><h3 id="Level-2-Range-Insertions-h3" class="div3" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 19px;font-weight: normal;">2.12.1. Insertions</h3><p>An insertion occurs at a single point, the insertion point, in the document. For any Range in the document tree, consider each boundary-point. The only case in which the boundary-point will be changed after the insertion is when the boundary-point and the insertion point have the same <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> and the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of the insertion point is strictly less than the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of the Range's boundary-point. In that case the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of the Range's boundary-point will be increased so that it is between the same nodes or characters as it was before the insertion.</p><p>Note that when content is inserted at a boundary-point, it is ambiguous as to where the boundary-point should be repositioned if its relative position is to be maintained. There are two possibilities: at the start or at the end of the newly inserted content. We have chosen that in this case neither the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> nor <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-offset" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>offset</em></a> of the boundary-point is changed. As a result, the boundary-point will be positioned at the start of the newly inserted content.</p><p><em>Examples:</em></p><p>Suppose the Range selects the following:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd efgh X<b>Y blah i</b>jkl</P></pre></div><p>Consider the insertion of the text "<i>inserted text</i>" at the following positions:</p><div class="eg"><pre style="margin-left: 2em;">1. Before the 'X':<P>Abcd efgh <i>inserted text</i>X<b>Y blah i</b>jkl</P>2. After the 'X':<P>Abcd efgh X<b><i>inserted text</i>Y blah i</b>jkl</P>3. After the 'Y':<P>Abcd efgh X<b>Y<i>inserted text</i> blah i</b>jkl</P>4. After the 'h' in "Y blah":<P>Abcd efgh X<b>Y blah<i>inserted text</i> i</b>jkl</P></pre></div></div><div class="div3"><a id="Level-2-Range-Deletions" name="Level-2-Range-Deletions"></a><h3 id="Level-2-Range-Deletions-h3" class="div3" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 19px;font-weight: normal;">2.12.2. Deletions</h3><p>Any deletion from the document tree can be considered as a sequence of <code>deleteContents()</code> operations applied to a minimal set of disjoint Ranges. To specify how a Range is modified under deletions we need only consider what happens to a Range under a single <code>deleteContents()</code>operation of another Range. And, in fact, we need only consider what happens to a single boundary-point of the Range since both boundary-points are modified using the same algorithm.</p><p>If a boundary-point of the original Range is within the content being deleted, then after the deletion it will be at the same position as the resulting boundary-point of the (now <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-collapsed" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>collapsed</em></a>) Range used to delete the contents.</p><p>If a boundary-point is after the content being deleted then it is not affected by the deletion unless its <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> is also the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of one of the boundary-points of the Range being deleted. If there is such a common <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>, then the index of the boundary-point is modified so that the boundary-point maintains its position relative to the content of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>.</p><p>If a boundary-point is before the content being deleted then it is not affected by the deletion at all.</p><p><em>Examples:</em></p><p>In these examples, the Range on which <code>deleteContents()</code>is invoked is indicated by the underline.</p><p><em>Example 1.</em></p><p>Before:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <u>efgh T</u><b><u>he</u> Range i</b>jkl</P></pre></div><p>After:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <b>Range i</b>jkl</P></pre></div><p><em>Example 2.</em></p><p>Before:</p><div class="eg"><pre style="margin-left: 2em;"><p>Abcd <u>efgh T<b>he Range i</b>j</u>kl</p></pre></div><p>After:</p><div class="eg"><pre style="margin-left: 2em;"><p>Abcd <b>^</b>kl</p></pre></div><p><em>Example 3.</em></p><p>Before:</p><div class="eg"><pre style="margin-left: 2em;"><P>ABCD <u>efgh T</u><b><u>he <EM>R</u>ange</b></EM>ijkl</P></pre></div><p>After:</p><div class="eg"><pre style="margin-left: 2em;"><P>ABCD <EM><b>ange</b></EM>ijkl</P></pre></div><p>In this example, the container of the start boundary-point after the deletion is the Text node holding the string "ange".</p><p><em>Example 4.</em></p><p>Before:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <u>efgh T</u><b>he Range i</b>jkl</P></pre></div><p>After:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <b>he Range i</b>jkl</P></pre></div><p><em>Example 5.</em></p><p>Before:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <u><EM>efgh T<b>he Range i</b>j</EM></u>kl</P></pre></div><p>After:</p><div class="eg"><pre style="margin-left: 2em;"><P>Abcd <b>^</b>kl</P></pre></div></div></div><div class="div2"><a id="Level-2-Range-Interface" name="Level-2-Range-Interface"></a><h2 id="Level-2-Range-Interface-h2" class="div2" style="text-align: left;color: rgb(0, 90, 156);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: white;font-size: 22px;font-weight: normal;">2.13. Formal Description of the Range Interface</h2><p>To summarize, the complete, formal description of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>Range</code></a> interface is given below:</p><dl ><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Interface <i><a id="Level-2-Range-idl" name="Level-2-Range-idl">Range</a></i></b> (introduced in <b class="since">DOM Level 2</b>)</dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><br><b>IDL Definition</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="idl-code" style="font-family: monospace;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-left-style: solid;border-top-color: black;border-right-color: black;border-bottom-color: black;border-left-color: black;border-image: initial;white-space: pre;background-color: rgb(223, 223, 223);"><pre style="margin-left: 2em;">// Introduced in DOM Level 2:interface Range{readonly attribute Node startContainer;// raises(DOMException) on retrieval readonly attribute long startOffset;// raises(DOMException) on retrieval readonly attribute Node endContainer;// raises(DOMException) on retrieval readonly attribute long endOffset;// raises(DOMException) on retrieval readonly attribute boolean collapsed;// raises(DOMException) on retrieval readonly attribute Node commonAncestorContainer;// raises(DOMException) on retrieval void setStart(in Node refNode, in long offset) raises(RangeException, DOMException);void setEnd(in Node refNode, in long offset) raises(RangeException, DOMException);void setStartBefore(in Node refNode) raises(RangeException, DOMException);void setStartAfter(in Node refNode) raises(RangeException, DOMException);void setEndBefore(in Node refNode) raises(RangeException, DOMException);void setEndAfter(in Node refNode) raises(RangeException, DOMException);void collapse(in boolean toStart) raises(DOMException);void selectNode(in Node refNode) raises(RangeException, DOMException);void selectNodeContents(in Node refNode) raises(RangeException, DOMException);// CompareHow const unsigned short START_TO_START=0;const unsigned short START_TO_END=1;const unsigned short END_TO_END=2;const unsigned short END_TO_START=3;short compareBoundaryPoints(in unsigned short how, in Range sourceRange) raises(DOMException);void deleteContents() raises(DOMException);DocumentFragment extractContents() raises(DOMException);DocumentFragment cloneContents() raises(DOMException);void insertNode(in Node newNode) raises(DOMException, RangeException);void surroundContents(in Node newParent) raises(DOMException, RangeException);Range cloneRange() raises(DOMException);DOMString toString() raises(DOMException);void detach() raises(DOMException);};</pre></div><br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Definition group <i><a id="Level2-Range-compareHow" name="Level2-Range-compareHow">CompareHow</a></i></b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><p>Passed as a parameter to the <code>compareBoundaryPoints</code> method.</p><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Defined Constants</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">END_TO_END</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Compare end boundary-point of <code>sourceRange</code> to end boundary-point of Range on which <code>compareBoundaryPoints</code> is invoked.</dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">END_TO_START</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Compare end boundary-point of <code>sourceRange</code> to start boundary-point of Range on which <code>compareBoundaryPoints</code> is invoked.</dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">START_TO_END</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Compare start boundary-point of <code>sourceRange</code> to end boundary-point of Range on which <code>compareBoundaryPoints</code> is invoked.</dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">START_TO_START</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Compare start boundary-point of <code>sourceRange</code> to start boundary-point of Range on which <code>compareBoundaryPoints</code> is invoked.</dd></dl></dd></dl></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Attributes</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-collapsed" name="Level-2-Range-attr-collapsed">collapsed</a></code> of type <code>boolean</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">TRUE if the Range is collapsed<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-commonParent" name="Level-2-Range-attr-commonParent">commonAncestorContainer</a></code> of type <code>Node</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-deepest" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>deepest</em></a> common <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of the Range's two boundary-points.<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-endParent" name="Level-2-Range-attr-endParent">endContainer</a></code> of type <code>Node</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">Node within which the Range ends<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-endOffset" name="Level-2-Range-attr-endOffset">endOffset</a></code> of type <code>long</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">Offset within the ending node of the Range.<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-startParent" name="Level-2-Range-attr-startParent">startContainer</a></code> of type <code>Node</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">Node within which the Range begins<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="attribute-name" style="background-color: rgb(255, 255, 210);"><a id="Level-2-Range-attr-startOffset" name="Level-2-Range-attr-startOffset">startOffset</a></code> of type <code>long</code>, readonly</dt><dd style="margin-top: 0px;margin-bottom: 0px;">Offset within the starting node of the Range.<br><div class="exceptions"><b>Exceptions on retrieval</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></dd></dl></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Methods</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-cloneContents" name="Level2-Range-method-cloneContents">cloneContents</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Duplicates the contents of a Range<div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><code>DocumentFragment</code></p></td><td><p>A DocumentFragment that contains content equivalent to this Range.</p></td></tr></tbody></table></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>HIERARCHY_REQUEST_ERR: Raised if a DocumentType node would be extracted into the new DocumentFragment.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-clone" name="Level2-Range-method-clone">cloneRange</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Produces a new Range whose boundary-points are equal to the boundary-points of the Range.<div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>Range</code></a></p></td><td><p>The duplicated Range.</p></td></tr></tbody></table></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-collapse" name="Level2-Range-method-collapse">collapse</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Collapse a Range onto one of its boundary-points<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">toStart</code> of type <code>boolean</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">If TRUE, collapses the Range onto its start;if FALSE, collapses it onto its end.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-compareBoundaryPoints" name="Level2-Range-method-compareBoundaryPoints">compareBoundaryPoints</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Compare the boundary-points of two Ranges in a document.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">how</code> of type <code>unsigned short</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">A code representing the type of comparison, as defined above.<br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">sourceRange</code> of type <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>Range</code></a></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <code>Range</code> on which this current <code>Range</code> is compared to.<br></dd></dl></div></div><div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><code>short</code></p></td><td><p>-1, 0 or 1 depending on whether the corresponding boundary-point of the Range is respectively before, equal to, or after the corresponding boundary-point of<code>sourceRange</code>.</p></td></tr></tbody></table></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>WRONG_DOCUMENT_ERR: Raised if the two Ranges are not in the same Document or DocumentFragment.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-deleteContents" name="Level2-Range-method-deleteContents">deleteContents</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Removes the contents of a Range from the containing document or document fragment without returning a reference to the removed content.<div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of the content of the Range is read-only or any of the nodes that contain any of the content of the Range are read-only.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-detach" name="Level2-Range-method-detach">detach</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Called to indicate that the Range is no longer in use and that the implementation may relinquish any resources associated with this Range. Subsequent calls to any methods or attribute getters on this Range will result in a <code>DOMException</code> being thrown with an error code of <code>INVALID_STATE_ERR</code>.<div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-extractContents" name="Level2-Range-method-extractContents">extractContents</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Moves the contents of a Range from the containing document or document fragment to a new DocumentFragment.<div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><code>DocumentFragment</code></p></td><td><p>A DocumentFragment containing the extracted contents.</p></td></tr></tbody></table></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of the content of the Range is read-only or any of the nodes which contain any of the content of the Range are read-only.</p><p>HIERARCHY_REQUEST_ERR: Raised if a DocumentType node would be extracted into the new DocumentFragment.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-insertNode" name="Level2-Range-method-insertNode">insertNode</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Inserts a node into the Document or DocumentFragment at the start of the Range. If the container is a Text node, this will be split at the start of the Range (as if the Text node's splitText method was performed at the insertion point) and the insertion will occur between the two resulting Text nodes. Adjacent Text nodes will not be automatically merged. If the node to be inserted is a DocumentFragment node, the children will be inserted rather than the DocumentFragment node itself.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">newNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The node to insert at the start of the Range<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>NO_MODIFICATION_ALLOWED_ERR: Raised if an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of the start of the Range is read-only.</p><p>WRONG_DOCUMENT_ERR: Raised if <code>newNode</code> and the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of the start of the Range were not created from the same document.</p><p>HIERARCHY_REQUEST_ERR: Raised if the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of the start of the Range is of a type that does not allow children of the type of <code>newNode</code> or if <code>newNode</code>is an ancestor of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a>.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if <code>newNode</code> is an Attr, Entity, Notation, or Document node.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-selectNode" name="Level2-Range-method-selectNode">selectNode</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Select a node and its contents<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The node to select.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if an ancestor of <code>refNode</code> is an Entity, Notation or DocumentType node or if <code>refNode</code> is a Document, DocumentFragment, Attr, Entity, or Notation node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-selectNodeContents" name="Level2-Range-method-selectNodeContents">selectNodeContents</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Select the contents within a node<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Node to select from<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> or an ancestor of <code>refNode</code> is an Entity, Notation or DocumentType node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-setEnd" name="Level2-Range-method-setEnd">setEnd</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the attributes describing the end of a Range.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <code>refNode</code> value. This parameter must be different from <code>null</code>.<br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">offset</code> of type <code>long</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <code>endOffset</code> value.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> or an ancestor of <code>refNode</code> is an Entity, Notation, or DocumentType node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INDEX_SIZE_ERR: Raised if <code>offset</code> is negative or greater than the number of child units in <code>refNode</code>. Child units are <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit units</em></a> if <code>refNode</code> is a type of CharacterData node (e.g., a Text or Comment node) or a ProcessingInstruction node. Child units are Nodes in all other cases.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-setEndAfter" name="Level2-Range-method-setEndAfter">setEndAfter</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the end of a Range to be after a node<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Range ends after <code>refNode</code>.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if the root container of <code>refNode</code> is not an Attr, Document or DocumentFragment node or if <code>refNode</code> is a Document, DocumentFragment, Attr, Entity, or Notation node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-setEndBefore" name="Level2-Range-method-setEndBefore">setEndBefore</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the end position to be before a node.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Range ends before <code>refNode</code><br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if the root container of <code>refNode</code> is not an Attr, Document, or DocumentFragment node or if <code>refNode</code> is a Document, DocumentFragment, Attr, Entity, or Notation node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-setStart" name="Level2-Range-method-setStart">setStart</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the attributes describing the start of the Range.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <code>refNode</code> value. This parameter must be different from <code>null</code>.<br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">offset</code> of type <code>long</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The <code>startOffset</code> value.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> or an ancestor of <code>refNode</code> is an Entity, Notation, or DocumentType node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INDEX_SIZE_ERR: Raised if <code>offset</code> is negative or greater than the number of child units in <code>refNode</code>. Child units are <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/glossary.html#dt-16-bit-unit" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>16-bit units</em></a> if <code>refNode</code> is a type of CharacterData node (e.g., a Text or Comment node) or a ProcessingInstruction node. Child units are Nodes in all other cases.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-setStartAfter" name="Level2-Range-method-setStartAfter">setStartAfter</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the start position to be after a node<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Range starts after <code>refNode</code><br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if the root container of <code>refNode</code> is not an Attr, Document, or DocumentFragment node or if <code>refNode</code> is a Document, DocumentFragment, Attr, Entity, or Notation node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-setStartBefore" name="Level2-Range-setStartBefore">setStartBefore</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Sets the start position to be before a node<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">refNode</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">Range starts before <code>refNode</code><br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>INVALID_NODE_TYPE_ERR: Raised if the root container of <code>refNode</code> is not an Attr, Document, or DocumentFragment node or if <code>refNode</code> is a Document, DocumentFragment, Attr, Entity, or Notation node.</p></td></tr><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-surroundContents" name="Level2-Range-method-surroundContents">surroundContents</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Reparents the contents of the Range to the given node and inserts the node at the position of the start of the Range.<div class="parameters"><b>Parameters</b><div class="paramtable" style="margin-left: 1em;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="parameter-name" style="background-color: rgb(254, 230, 248);">newParent</code> of type <code>Node</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">The node to surround the contents with.<br></dd></dl></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>NO_MODIFICATION_ALLOWED_ERR: Raised if an <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-ancestor-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>ancestor container</em></a> of either boundary-point of the Range is read-only.</p><p>WRONG_DOCUMENT_ERR: Raised if <code>newParent</code> and the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of the start of the Range were not created from the same document.</p><p>HIERARCHY_REQUEST_ERR: Raised if the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of the start of the Range is of a type that does not allow children of the type of <code>newParent</code> or if<code>newParent</code> is an ancestor of the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> or if <code>node</code> would end up with a child node of a type not allowed by the type of <code>node</code>.</p><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a></p></td><td><p>BAD_BOUNDARYPOINTS_ERR: Raised if the Range <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-partially-selected" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>partially selects</em></a> a non-text node.</p><p>INVALID_NODE_TYPE_ERR: Raised if <code>node</code> is an Attr, Entity, DocumentType, Notation, Document, or DocumentFragment node.</p></td></tr></tbody></table></div></div><div><b>No Return Value</b></div></div></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-Range-method-toString" name="Level2-Range-method-toString">toString</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">Returns the contents of a Range as a string. This string contains only the data characters, not any markup.<div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMString</code></p></td><td><p>The contents of the Range.</p></td></tr></tbody></table></div></div><div class="exceptions"><b>Exceptions</b><div class="exceptiontable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the exception, the second contains the specific error code and a short description" border="0"><tbody><tr><td valign="top"><p><code>DOMException</code></p></td><td><p>INVALID_STATE_ERR: Raised if <code>detach()</code> has already been invoked on this object.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div></div></dd></dl></dd></dl></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Interface <i><a id="Level-2-DocumentRange-idl" name="Level-2-DocumentRange-idl">DocumentRange</a></i></b> (introduced in <b class="since">DOM Level 2</b>)</dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><br><b>IDL Definition</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="idl-code" style="font-family: monospace;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-left-style: solid;border-top-color: black;border-right-color: black;border-bottom-color: black;border-left-color: black;border-image: initial;white-space: pre;background-color: rgb(223, 223, 223);"><pre style="margin-left: 2em;">// Introduced in DOM Level 2:interface DocumentRange{Range createRange();};</pre></div><br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Methods</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="method-name" style="background-color: rgb(217, 230, 248);"><a id="Level2-DocumentRange-method-createRange" name="Level2-DocumentRange-method-createRange">createRange</a></code></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="method">This interface can be obtained from the object implementing the <code>Document</code> interface using binding-specific casting methods.<div class="return"><b>Return Value</b><div class="returntable" style="margin-left: 1em;"><table summary="Layout table: the first cell contains the type of the return value, the second contains a short description" border="0"><tbody><tr><td valign="top"><p><a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-idl" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>Range</code></a></p></td><td><p>The initial state of the Range returned from this method is such that both of its boundary-points are positioned at the beginning of the corresponding Document, before any content. The Range returned can only be used to select content associated with this Document, or with DocumentFragments and Attrs for which this Document is the <code>ownerDocument</code>.</p></td></tr></tbody></table></div></div><div><b>No Parameters</b></div><div><b>No Exceptions</b></div></div></dd></dl></dd></dl></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Exception <i><a id="RangeException" name="RangeException">RangeException</a></i></b> introduced in <b class="version">DOM Level 2</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><p>Range operations may throw a <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#RangeException" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><code>RangeException</code></a> as specified in their method descriptions.</p><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><br><b>IDL Definition</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><div class="idl-code" style="font-family: monospace;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-left-style: solid;border-top-color: black;border-right-color: black;border-bottom-color: black;border-left-color: black;border-image: initial;white-space: pre;background-color: rgb(223, 223, 223);"><pre style="margin-left: 2em;">// Introduced in DOM Level 2:exception RangeException{unsigned short code;};// RangeExceptionCodeconst unsigned short BAD_BOUNDARYPOINTS_ERR=1;const unsigned short INVALID_NODE_TYPE_ERR=2;</pre></div><br></dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Definition group <i><a id="RangeExceptionCode" name="RangeExceptionCode">RangeExceptionCode</a></i></b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><p>An integer indicating the type of error generated.</p><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><b>Defined Constants</b></dt><dd style="margin-top: 0px;margin-bottom: 0px;"><dl><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">BAD_BOUNDARYPOINTS_ERR</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">If the boundary-points of a Range do not meet specific requirements.</dd><dt style="margin-top: 0px;margin-bottom: 0px;font-weight: bold;"><code class="constant-name" style="background-color: rgb(221, 255, 210);">INVALID_NODE_TYPE_ERR</code></dt><dd style="margin-top: 0px;margin-bottom: 0px;">If the <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#td-container" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;"><em>container</em></a> of an boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type.</dd></dl></dd></dl></dd></dl></dd></dl></div></div><div class="navbar" align="center" style="color: rgb(0, 0, 0);font-family: sans-serif;font-size: medium;"><hr title="Navigation area separator"><a accesskey="p" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">previous</a>   <a accesskey="n" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/idl-definitions.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">next</a>   <a accesskey="c" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/Overview.html#contents" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">contents</a>   <a accesskey="i" href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/def-index.html" style="color: rgb(102, 0, 153);background-image: initial;background-attachment: initial;background-origin: initial;background-clip: initial;background-color: transparent;background-position: initial initial;background-repeat: initial initial;">index</a></div></p><dl></dl>
291 </textarea>
292
293 <h2>Deeply nested divs</h2>
294 <textarea name="editor4">
295 <p> </p><h1 id="mainHeader" style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; font-weight: normal; font-size: 26px; color: rgb(7, 130, 193); font-family: Arial, Helvetica, sans-serif; background-color: rgb(226, 226, 226); ">Jobs</h1><div id="node-438" class="node node-type-page" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 18px; color: rgb(85, 85, 85); font-family: Arial, Helvetica, sans-serif; background-color: rgb(226, 226, 226); "><div class="node-inner" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><div class="meta" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "> </div><div class="content" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><div class="contentBox" style="margin-top: 0px; margin-right: 0px; margin-bottom: 20px; margin-left: 0px; padding-top: 15px; padding-right: 15px; padding-bottom: 1px; padding-left: 15px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; background-color: rgb(239, 239, 239); border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(226, 226, 226); border-right-color: rgb(226, 226, 226); border-bottom-color: rgb(226, 226, 226); border-left-color: rgb(226, 226, 226); position: relative; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">CKSource is a successful company with thousands of customers all around the world, including top names like IBM and Oracle. Our company is growing fast, with impressive sales results. This strong growth expands our range of opportunities, followed by the growth of our team. Take this chance and&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">join us!</strong></p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Working in a&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">successful Open Source project&nbsp;</strong>is certainly a lot of fun. CKEditor is one of the most frequently used text editors out there, and this success means new responsibilities. We are providing a key component for the software that is powering the Web today. It is downloaded daily by thousands of people all around the world and used by hundreds of thousands out there.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">We are constantly looking for top-notch, creative, and enthusiastic professionals ready to join our international team.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">We offer a work culture where ideas are free to fly and diversity is our everyday life.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">There is no need to relocate. No matter where you are, as long as you love what you do, you are the right person for us!</p><div class="post joboffer" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 10px; padding-right: 0px; padding-bottom: 5px; padding-left: 0px; border-top-width: 1px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; border-top-style: solid; border-top-color: rgb(229, 230, 231); " id=""><h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; font-size: 15px; color: rgb(0, 0, 0); ">AJD - Advanced JavaScript Developer</h2><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Location:&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Europe and Its Neighbourhood</strong>&nbsp;(from GMT 0 to GMT +2).</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Employment type:&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Full time</strong>.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">We are looking for talented people to join our team. Ideal candidates will have:</p><ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-right: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Several years of experience with professional JavaScript programming, which we consider is;<ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-right: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Writing pure, object-oriented JavaScript applications.</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Ability to create complex JavaScript applications based on your own skills only (excluding usage of external libraries such as jQuery, Prototype, Dojo, or MooTools).</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Being aware and able to solving asynchronous issues.</li></ul></li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">In-depth knowledge of core Web standards, like HTML, XML, DOM, and CSS — including their intrinsic implementation differences among browsers (with IE6 also);</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Ability to understand and fix complicated DOM manipulation problems.</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Good (enough) English speaking and writing skills. This is the language used in the company.</li></ul><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">"Wow" candidates will also have (not required though):</p><ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-right: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Experience with CKEditor or FCKeditor, having possibly collaborated with the project;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Experience with rich text editors;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Experience with HTML5, CSS3 development;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Experience with Test Cases (like YUI Test);</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">A Bachelor's or Master's degree in Computer Science;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Passion for Open Source.</li></ul></div><div class="post" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 10px; padding-right: 0px; padding-bottom: 30px; padding-left: 0px; border-top-width: 1px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; border-top-style: solid; border-top-color: rgb(229, 230, 231); " id=""><h3 style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; font-size: 14px; ">In return we offer:</h3><ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-right: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Permanent full time employment contract;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Flexible working hours;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Competitive salary;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Work&nbsp;</strong>from&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">home</strong>&nbsp;(you will forget what a traffic jam is);</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Working with smart and motivated&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">professionals</strong>;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 40px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Becoming a&nbsp;<strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">part of great team</strong>&nbsp;who delivers worldwide known software.</li></ul><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Let us start talking. Tell us about the projects you have worked on and your role in them; point to your experience and anything you think might make you a perfect candidate. Contact us with your CV at:&nbsp;<a href="" title="jobs at (spam protection) cksource dot com" id="jobmail1" style="color: rgb(24, 157, 225); ">jobs@cksource.com</a>&nbsp;now!</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">We are sure you will enjoy it!</p></div><div class="post" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 10px; padding-right: 0px; padding-bottom: 30px; padding-left: 0px; border-top-width: 1px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; border-top-style: solid; border-top-color: rgb(229, 230, 231); "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">Please note we only accept CV's in English. Your application must include the following note:</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; line-height: 1.5em; ">"I hereby authorize you to process my personal data included in my job application for the needs of the recruitment process (in accordance to the Personal Data Protection Act 29.08.1997 no 133 position 883).”</p></div></div></div></div></div><dl></dl>
296 </textarea>
297
298 <h2>Line custom look</h2>
299 <div id="hood">
300 <h1>
301 <img alt="" src="http://a.cksource.com/c/1/inc/img/demo-little-red.jpg" style="margin-left: 10px; margin-right: 10px; float: left; width: 120px; height: 168px;" />Little Red Riding Hood</h1>
302 <p>
303 &quot;<b>Little Red Riding Hood</b>&quot; is a famous <a href="http://en.wikipedia.org/wiki/Fairy_tale" title="Fairy tale">fairy tale</a> about a young girl&#39;s encounter with a wolf. The story has been changed considerably in its history and subject to numerous modern adaptations and readings.</p>
304 <table align="right" border="1" cellpadding="1" cellspacing="1" style="width: 200px;">
305 <caption>
306 <strong>International Names</strong></caption>
307 <tbody>
308 <tr>
309 <td>
310 Chinese</td>
311 <td>
312 <i>小紅帽</i></td>
313 </tr>
314 <tr>
315 <td>
316 Italian</td>
317 <td>
318 <i>Cappuccetto Rosso</i></td>
319 </tr>
320 <tr>
321 <td>
322 Spanish</td>
323 <td>
324 <i>Caperucita Roja</i></td>
325 </tr>
326 </tbody>
327 </table>
328 <hr>
329 <hr>
330 <p>
331 The version most widely known today is based on the <a href="http://en.wikipedia.org/wiki/Brothers_Grimm" title="Brothers Grimm">Brothers Grimm</a> variant. It is about a girl called Little Red Riding Hood, after the red <a href="http://en.wikipedia.org/wiki/Hood_%28headgear%29" title="Hood (headgear)">hooded</a> <a href="http://en.wikipedia.org/wiki/Cape" title="Cape">cape</a> or <a href="http://en.wikipedia.org/wiki/Cloak" title="Cloak">cloak</a> she wears. The girl walks through the woods to deliver food to her sick grandmother.</p>
332 <p>
333 A wolf wants to eat the girl but is afraid to do so in public. He approaches the girl, and she na&iuml;vely tells him where she is going. He suggests the girl pick some flowers, which she does. In the meantime, he goes to the grandmother&#39;s house and gains entry by pretending to be the girl. He swallows the grandmother whole, and waits for the girl, disguised as the grandmother.</p>
334 <p>
335 When the girl arrives, she notices he looks very strange to be her grandma. In most retellings, this eventually culminates with Little Red Riding Hood saying, &quot;My, what big teeth you have!&quot;<br />
336 To which the wolf replies, &quot;The better to eat you with,&quot; and swallows her whole, too.</p>
337 <p>
338 A <a href="http://en.wikipedia.org/wiki/Hunter" title="Hunter">hunter</a>, however, comes to the rescue and cuts the wolf open. Little Red Riding Hood and her grandmother emerge unharmed. They fill the wolf&#39;s body with heavy stones, which drown him when he falls into a well. Other versions of the story have had the grandmother shut in the closet instead of eaten, and some have Little Red Riding Hood saved by the hunter as the wolf advances on her rather than after she is eaten.</p>
339 <p>
340 The tale makes the clearest contrast between the safe world of the village and the dangers of the <a href="http://en.wikipedia.org/wiki/Enchanted_forest" title="Enchanted forest">forest</a>, conventional antitheses that are essentially medieval, though no written versions are as old as that.</p>
341 </div>
342
343 <h2>Extreme inline editing</h2>
344 <div id="interpret" contenteditable="true" style="left: 123px; outline: 1px solid red; border: 15px solid green; position: relative; top: 30; left: 30px;">
345 <div style="padding: 20px; background: gray; width: 300px" class="1">Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim.</div>
346 <div style="background: violet; padding: 30px;" class="static">
347 Position static
348 <div style="background: green; padding: 30px; border: 14px solid orange">foo</div>
349 </div>
350 <dl class="2">
351 <dt>Key</dt><dd>Value</dd>
352 </dl>
353 <div>Whatever</div>
354 <hr id="hr">
355 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
356 <hr>
357 <hr>
358 <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p>
359 <div style="background: green; padding: 30px; width: 200px">foo</div>
360 </div>
361
362 <h2>Enter mode: BR</h2>
363 <textarea cols="80" id="editor5" name="editor5" rows="10">
364 Foo<br />
365 <hr style="margin: 50px" />
366 <hr style="margin: 50px" />
367 Foo
368 </textarea>
369
370 <div id="dev">
371 <p id="mouseData">
372 <span>Mouse over: <strong id="over"></strong></span>
373 <span style="display: block">Mouse Y-pos.: <span id="my"></span></span>
374 </p>
375 <p id="triggerData">
376 <span id="tr_type"></span>
377 <span id="tr_upper"></span>
378 <span id="tr_lower"></span>
379 <span id="tr_edge"></span>
380 </dl>
381 <p id="timeData">Time: <span id="time"></span></p>
382 <p id="hiddenData">Hidden state: <span id="hid"></span></p>
383 </div>
384 <script>
385
386 'use strict';
387
388 function fixedWidthNumber( text, chars ) {
389 return ( Array( chars ).join( 0 ) + text ).slice( -chars );
390 }
391
392 var DEBUG = {
393 startTimer: function() {
394 DEBUG.timer = new Date().getTime();
395 },
396
397 stopTimer: (function() {
398 var label = CKEDITOR.document.getById( 'time' ),
399 max = 0,
400 count = 0,
401 values = [],
402 mean = 0,
403 time = 0;
404
405 return function() {
406 time = new Date().getTime() - DEBUG.timer;
407 max = Math.max( time, max );
408
409 values.unshift( time );
410 ( 20 in values ) && values.pop();
411 mean = 0;
412
413 for( var i = 0 ; i < values.length ; i++ )
414 mean += values[ i ];
415
416 mean = mean / i;
417
418 label.setText( fixedWidthNumber( time, 3 ) +
419 ' ms, mean: ' + fixedWidthNumber( 0 | mean, 3 ) +
420 ' ms, max: ' + fixedWidthNumber( max, 3 ) +
421 ' ms' )
422 count++;
423 }
424 })(),
425
426 mousePos: (function( y, element )
427 {
428 var my = CKEDITOR.document.getById( 'my' ),
429 over = CKEDITOR.document.getById( 'over' ),
430 name;
431
432 return function( y, element ) {
433 my.setText( y );
434
435 if( element && element.$ && element.type == CKEDITOR.NODE_ELEMENT ) {
436 try {
437 name = element.getName();
438 over.setText( name + '.' + element.getAttribute( 'class' ) );
439 } catch( e ) {}
440 }
441 else
442 over.setText( '-' );
443 }
444 })(),
445
446 showTrigger: (function( trigger )
447 {
448 var tr_type = CKEDITOR.document.getById( 'tr_type' ),
449 tr_upper = CKEDITOR.document.getById( 'tr_upper' ),
450 tr_lower = CKEDITOR.document.getById( 'tr_lower' ),
451 tr_edge = CKEDITOR.document.getById( 'tr_edge' ),
452 tup, tbo, upper, lower;
453
454 return function( trigger ) {
455 tup && tup.removeAttribute('id') && ( tup = null );
456 tbo && tbo.removeAttribute('id') && ( tbo = null );
457
458 if ( !trigger )
459 return tr_type.setText( '-' ) &&
460 tr_upper.setText( '-' ) &&
461 tr_lower.setText( '-' ) &&
462 tr_edge.setText( '-' );
463
464 upper = trigger.upper,
465 lower = trigger.lower;
466
467 tr_type.setText( trigger.type == 2 ? 'EXPAND': 'EDGE' );
468 tr_upper.setText( upper ? upper.getName() + '.' + upper.getAttribute( 'class' ): 'NULL' );
469 tr_lower.setText( lower ? lower.getName() + '.' + lower.getAttribute( 'class' ): 'NULL' );
470 tr_edge.setText( trigger.edge ? [ 'EDGE_TOP', 'EDGE_BOTTOM', 'EDGE_MIDDLE' ][ trigger.edge - 1 ]: 'NULL' );
471
472 upper && ( tup = upper ) && tup.setAttribute( 'id', 'tup' );
473 lower && ( tbo = lower ) && tbo.setAttribute( 'id', 'tbo' );
474 }
475 })(),
476
477 showHidden: (function( state )
478 {
479 var cnt = CKEDITOR.document.getById( 'hid' );
480
481 return function( state ) {
482 cnt[ state ? 'addClass': 'removeClass' ]( 'hl' );
483 cnt.setText( state ? 'enabled': 'disabled' );
484 }
485 })(),
486
487 markElement: function( element ) {
488 if( !isHtml( element ))
489 return;
490
491 DEBUG.marked && DEBUG.marked.setStyles( {
492 'outline': 'none'
493 } );
494
495 DEBUG.marked = element;
496
497 element.setStyles( {
498 'outline': 'red solid 2px'
499 } );
500 },
501
502 // Log functions.
503 log: function() {},
504 logElements: function() {},
505 groupStart: function() {},
506 groupEnd: function() {},
507 logEnd: function() {},
508 logElementsEnd: function() {}
509 };
510
511 var logEnable = {
512 log: function() {
513 var args = [];
514 for( var i = 0; i < arguments.length ; i++ )
515 args.push( arguments[ i ] );
516
517 console.log.apply( console, args );
518 },
519
520 logElements: function( elements, labels, info ) {
521 var log = {},
522 label;
523
524 for ( var i = 0 ; i < elements.length; i++ ) {
525 label = labels ? labels [ i ] : i;
526
527 if( !elements[ i ] ) {
528 log[ label ] = {
529 'name': 'null',
530 'class': 'null'
531 }
532 }
533 else {
534 log[ labels ? labels [ i ]: i ] = {
535 'name': elements[ i ].is ? elements[ i ].getName(): 'null',
536 'class': elements[ i ].is ? elements[ i ].getAttribute( 'class' ): 'null'
537 }
538 }
539 }
540
541 typeof JSON != 'undefined' && DEBUG.log( ( info ? info.toUpperCase() + ' ': '' ) + JSON.stringify( log ) );
542 },
543
544 groupStart: function( label ) {
545 console.group( label );
546 },
547
548 groupEnd: function() {
549 console.groupEnd();
550 },
551
552 logEnd: function() {
553 DEBUG.log.apply( null, arguments );
554 DEBUG.groupEnd();
555 },
556
557 logElementsEnd: function() {
558 DEBUG.logElements.apply( null, arguments );
559 DEBUG.groupEnd();
560 }
561 }
562
563 // Enable console.log debugging with ?debug address parameter.
564 window.location.href.match( /debug$/g ) ? CKEDITOR.tools.extend( DEBUG, logEnable, true ): null;
565
566 // CKEDITOR.addCss('\
567 // #tup { outline: #FEB2B2 solid 2px; box-shadow: 3px 3px 0 #FEB2B2; } \
568 // #tbo { outline: #B2FEB2 solid 2px; box-shadow: 3px 3px 0 #B2FEB2; } \
569 // p { background: pink }\
570 // ');
571
572 CKEDITOR.replace( 'editor1' );
573
574 CKEDITOR.replace( 'editor2', { height: 150 } );
575
576 CKEDITOR.replace( 'editor3', {
577 magicline_everywhere: 1,
578 magicline_holdDistance: .2,
579 language: 'pl'
580 });
581
582 CKEDITOR.replace( 'editor4' );
583
584 CKEDITOR.replace( 'hood', {
585 magicline_color: 'green'
586 });
587
588 CKEDITOR.replace( 'editor5', {
589 enterMode : CKEDITOR.ENTER_BR
590 });
591
592 </script>
593</body>
594</html>
diff --git a/sources/plugins/magicline/images/hidpi/icon-rtl.png b/sources/plugins/magicline/images/hidpi/icon-rtl.png
new file mode 100644
index 0000000..4a8d2bf
--- /dev/null
+++ b/sources/plugins/magicline/images/hidpi/icon-rtl.png
Binary files differ
diff --git a/sources/plugins/magicline/images/hidpi/icon.png b/sources/plugins/magicline/images/hidpi/icon.png
new file mode 100644
index 0000000..b981bb5
--- /dev/null
+++ b/sources/plugins/magicline/images/hidpi/icon.png
Binary files differ
diff --git a/sources/plugins/magicline/images/icon-rtl.png b/sources/plugins/magicline/images/icon-rtl.png
new file mode 100644
index 0000000..55b5b5f
--- /dev/null
+++ b/sources/plugins/magicline/images/icon-rtl.png
Binary files differ
diff --git a/sources/plugins/magicline/images/icon.png b/sources/plugins/magicline/images/icon.png
new file mode 100644
index 0000000..e063433
--- /dev/null
+++ b/sources/plugins/magicline/images/icon.png
Binary files differ
diff --git a/sources/plugins/magicline/lang/af.js b/sources/plugins/magicline/lang/af.js
new file mode 100644
index 0000000..9b9dc2b
--- /dev/null
+++ b/sources/plugins/magicline/lang/af.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'af', {
7 title: 'Voeg paragraaf hier in'
8} );
diff --git a/sources/plugins/magicline/lang/ar.js b/sources/plugins/magicline/lang/ar.js
new file mode 100644
index 0000000..1c411f3
--- /dev/null
+++ b/sources/plugins/magicline/lang/ar.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ar', {
7 title: 'إدراج فقرة هنا'
8} );
diff --git a/sources/plugins/magicline/lang/az.js b/sources/plugins/magicline/lang/az.js
new file mode 100644
index 0000000..02664f1
--- /dev/null
+++ b/sources/plugins/magicline/lang/az.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'az', {
7 title: 'Abzası burada əlavə et'
8} );
diff --git a/sources/plugins/magicline/lang/bg.js b/sources/plugins/magicline/lang/bg.js
new file mode 100644
index 0000000..768af06
--- /dev/null
+++ b/sources/plugins/magicline/lang/bg.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'bg', {
7 title: 'Вмъкнете параграф тук'
8} );
diff --git a/sources/plugins/magicline/lang/ca.js b/sources/plugins/magicline/lang/ca.js
new file mode 100644
index 0000000..dcd9c1a
--- /dev/null
+++ b/sources/plugins/magicline/lang/ca.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ca', {
7 title: 'Insereix el paràgraf aquí'
8} );
diff --git a/sources/plugins/magicline/lang/cs.js b/sources/plugins/magicline/lang/cs.js
new file mode 100644
index 0000000..4705efd
--- /dev/null
+++ b/sources/plugins/magicline/lang/cs.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'cs', {
7 title: 'zde vložit odstavec'
8} );
diff --git a/sources/plugins/magicline/lang/cy.js b/sources/plugins/magicline/lang/cy.js
new file mode 100644
index 0000000..13e1085
--- /dev/null
+++ b/sources/plugins/magicline/lang/cy.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'cy', {
7 title: 'Mewnosod paragraff yma'
8} );
diff --git a/sources/plugins/magicline/lang/da.js b/sources/plugins/magicline/lang/da.js
new file mode 100644
index 0000000..ee4fa17
--- /dev/null
+++ b/sources/plugins/magicline/lang/da.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'da', {
7 title: 'Indsæt afsnit'
8} );
diff --git a/sources/plugins/magicline/lang/de-ch.js b/sources/plugins/magicline/lang/de-ch.js
new file mode 100644
index 0000000..d6bd3b7
--- /dev/null
+++ b/sources/plugins/magicline/lang/de-ch.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'de-ch', {
7 title: 'Absatz hier einfügen'
8} );
diff --git a/sources/plugins/magicline/lang/de.js b/sources/plugins/magicline/lang/de.js
new file mode 100644
index 0000000..189d564
--- /dev/null
+++ b/sources/plugins/magicline/lang/de.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'de', {
7 title: 'Absatz hier einfügen'
8} );
diff --git a/sources/plugins/magicline/lang/el.js b/sources/plugins/magicline/lang/el.js
new file mode 100644
index 0000000..528a554
--- /dev/null
+++ b/sources/plugins/magicline/lang/el.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'el', {
7 title: 'Εισάγετε παράγραφο εδώ'
8} );
diff --git a/sources/plugins/magicline/lang/en-gb.js b/sources/plugins/magicline/lang/en-gb.js
new file mode 100644
index 0000000..e0d3779
--- /dev/null
+++ b/sources/plugins/magicline/lang/en-gb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'en-gb', {
7 title: 'Insert paragraph here'
8} );
diff --git a/sources/plugins/magicline/lang/en.js b/sources/plugins/magicline/lang/en.js
new file mode 100644
index 0000000..37ef2ed
--- /dev/null
+++ b/sources/plugins/magicline/lang/en.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'en', {
7 title: 'Insert paragraph here'
8} );
diff --git a/sources/plugins/magicline/lang/eo.js b/sources/plugins/magicline/lang/eo.js
new file mode 100644
index 0000000..3cf6286
--- /dev/null
+++ b/sources/plugins/magicline/lang/eo.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'eo', {
7 title: 'Enmeti paragrafon ĉi-tien'
8} );
diff --git a/sources/plugins/magicline/lang/es.js b/sources/plugins/magicline/lang/es.js
new file mode 100644
index 0000000..f9a8f52
--- /dev/null
+++ b/sources/plugins/magicline/lang/es.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'es', {
7 title: 'Insertar párrafo aquí'
8} );
diff --git a/sources/plugins/magicline/lang/et.js b/sources/plugins/magicline/lang/et.js
new file mode 100644
index 0000000..9d2fe53
--- /dev/null
+++ b/sources/plugins/magicline/lang/et.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'et', {
7 title: 'Sisesta siia lõigu tekst'
8} );
diff --git a/sources/plugins/magicline/lang/eu.js b/sources/plugins/magicline/lang/eu.js
new file mode 100644
index 0000000..25daf45
--- /dev/null
+++ b/sources/plugins/magicline/lang/eu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'eu', {
7 title: 'Txertatu paragrafoa hemen'
8} );
diff --git a/sources/plugins/magicline/lang/fa.js b/sources/plugins/magicline/lang/fa.js
new file mode 100644
index 0000000..d09ddfc
--- /dev/null
+++ b/sources/plugins/magicline/lang/fa.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'fa', {
7 title: 'قرار دادن بند در اینجا'
8} );
diff --git a/sources/plugins/magicline/lang/fi.js b/sources/plugins/magicline/lang/fi.js
new file mode 100644
index 0000000..094bd9d
--- /dev/null
+++ b/sources/plugins/magicline/lang/fi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'fi', {
7 title: 'Lisää kappale tähän.'
8} );
diff --git a/sources/plugins/magicline/lang/fr-ca.js b/sources/plugins/magicline/lang/fr-ca.js
new file mode 100644
index 0000000..6319f1c
--- /dev/null
+++ b/sources/plugins/magicline/lang/fr-ca.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'fr-ca', {
7 title: 'Insérer le paragraphe ici'
8} );
diff --git a/sources/plugins/magicline/lang/fr.js b/sources/plugins/magicline/lang/fr.js
new file mode 100644
index 0000000..430fc5f
--- /dev/null
+++ b/sources/plugins/magicline/lang/fr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'fr', {
7 title: 'Insérer un paragraphe ici'
8} );
diff --git a/sources/plugins/magicline/lang/gl.js b/sources/plugins/magicline/lang/gl.js
new file mode 100644
index 0000000..5aaa968
--- /dev/null
+++ b/sources/plugins/magicline/lang/gl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'gl', {
7 title: 'Inserir aquí o parágrafo'
8} );
diff --git a/sources/plugins/magicline/lang/he.js b/sources/plugins/magicline/lang/he.js
new file mode 100644
index 0000000..9c01d48
--- /dev/null
+++ b/sources/plugins/magicline/lang/he.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'he', {
7 title: 'הכנס פסקה כאן'
8} );
diff --git a/sources/plugins/magicline/lang/hr.js b/sources/plugins/magicline/lang/hr.js
new file mode 100644
index 0000000..1916e65
--- /dev/null
+++ b/sources/plugins/magicline/lang/hr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'hr', {
7 title: 'Ubaci paragraf ovdje'
8} );
diff --git a/sources/plugins/magicline/lang/hu.js b/sources/plugins/magicline/lang/hu.js
new file mode 100644
index 0000000..86650d5
--- /dev/null
+++ b/sources/plugins/magicline/lang/hu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'hu', {
7 title: 'Szúrja be a bekezdést ide'
8} );
diff --git a/sources/plugins/magicline/lang/id.js b/sources/plugins/magicline/lang/id.js
new file mode 100644
index 0000000..3651e37
--- /dev/null
+++ b/sources/plugins/magicline/lang/id.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'id', {
7 title: 'Masukkan paragraf disini'
8} );
diff --git a/sources/plugins/magicline/lang/it.js b/sources/plugins/magicline/lang/it.js
new file mode 100644
index 0000000..9cc27e0
--- /dev/null
+++ b/sources/plugins/magicline/lang/it.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'it', {
7 title: 'Inserisci paragrafo qui'
8} );
diff --git a/sources/plugins/magicline/lang/ja.js b/sources/plugins/magicline/lang/ja.js
new file mode 100644
index 0000000..84d6b74
--- /dev/null
+++ b/sources/plugins/magicline/lang/ja.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ja', {
7 title: 'ここに段落を挿入'
8} );
diff --git a/sources/plugins/magicline/lang/km.js b/sources/plugins/magicline/lang/km.js
new file mode 100644
index 0000000..f670a7e
--- /dev/null
+++ b/sources/plugins/magicline/lang/km.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'km', {
7 title: 'បញ្ចូល​កថាខណ្ឌ​នៅ​ទីនេះ'
8} );
diff --git a/sources/plugins/magicline/lang/ko.js b/sources/plugins/magicline/lang/ko.js
new file mode 100644
index 0000000..0e718f3
--- /dev/null
+++ b/sources/plugins/magicline/lang/ko.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ko', {
7 title: '여기에 단락 삽입'
8} );
diff --git a/sources/plugins/magicline/lang/ku.js b/sources/plugins/magicline/lang/ku.js
new file mode 100644
index 0000000..cc3f3a4
--- /dev/null
+++ b/sources/plugins/magicline/lang/ku.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ku', {
7 title: 'بڕگە لێرە دابنێ'
8} );
diff --git a/sources/plugins/magicline/lang/lv.js b/sources/plugins/magicline/lang/lv.js
new file mode 100644
index 0000000..f96cc44
--- /dev/null
+++ b/sources/plugins/magicline/lang/lv.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'lv', {
7 title: 'Ievietot šeit rindkopu'
8} );
diff --git a/sources/plugins/magicline/lang/nb.js b/sources/plugins/magicline/lang/nb.js
new file mode 100644
index 0000000..297f270
--- /dev/null
+++ b/sources/plugins/magicline/lang/nb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'nb', {
7 title: 'Sett inn nytt avsnitt her'
8} );
diff --git a/sources/plugins/magicline/lang/nl.js b/sources/plugins/magicline/lang/nl.js
new file mode 100644
index 0000000..bfe36ff
--- /dev/null
+++ b/sources/plugins/magicline/lang/nl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'nl', {
7 title: 'Hier paragraaf invoeren'
8} );
diff --git a/sources/plugins/magicline/lang/no.js b/sources/plugins/magicline/lang/no.js
new file mode 100644
index 0000000..e78ca76
--- /dev/null
+++ b/sources/plugins/magicline/lang/no.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'no', {
7 title: 'Sett inn nytt avsnitt her'
8} );
diff --git a/sources/plugins/magicline/lang/oc.js b/sources/plugins/magicline/lang/oc.js
new file mode 100644
index 0000000..312f547
--- /dev/null
+++ b/sources/plugins/magicline/lang/oc.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'oc', {
7 title: 'Inserir un paragraf aicí'
8} );
diff --git a/sources/plugins/magicline/lang/pl.js b/sources/plugins/magicline/lang/pl.js
new file mode 100644
index 0000000..324bf1e
--- /dev/null
+++ b/sources/plugins/magicline/lang/pl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'pl', {
7 title: 'Wstaw nowy akapit'
8} );
diff --git a/sources/plugins/magicline/lang/pt-br.js b/sources/plugins/magicline/lang/pt-br.js
new file mode 100644
index 0000000..35f3daa
--- /dev/null
+++ b/sources/plugins/magicline/lang/pt-br.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'pt-br', {
7 title: 'Insera um parágrafo aqui'
8} );
diff --git a/sources/plugins/magicline/lang/pt.js b/sources/plugins/magicline/lang/pt.js
new file mode 100644
index 0000000..c03c48a
--- /dev/null
+++ b/sources/plugins/magicline/lang/pt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'pt', {
7 title: 'Insira aqui o parágrafo'
8} );
diff --git a/sources/plugins/magicline/lang/ru.js b/sources/plugins/magicline/lang/ru.js
new file mode 100644
index 0000000..bc41703
--- /dev/null
+++ b/sources/plugins/magicline/lang/ru.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ru', {
7 title: 'Вставить здесь параграф'
8} );
diff --git a/sources/plugins/magicline/lang/si.js b/sources/plugins/magicline/lang/si.js
new file mode 100644
index 0000000..a5cdbe8
--- /dev/null
+++ b/sources/plugins/magicline/lang/si.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'si', {
7 title: 'චේදය ඇතුලත් කරන්න'
8} );
diff --git a/sources/plugins/magicline/lang/sk.js b/sources/plugins/magicline/lang/sk.js
new file mode 100644
index 0000000..84761b2
--- /dev/null
+++ b/sources/plugins/magicline/lang/sk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'sk', {
7 title: 'Odsek vložiť sem'
8} );
diff --git a/sources/plugins/magicline/lang/sl.js b/sources/plugins/magicline/lang/sl.js
new file mode 100644
index 0000000..6d0cf76
--- /dev/null
+++ b/sources/plugins/magicline/lang/sl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'sl', {
7 title: 'Vstavite odstavek tukaj'
8} );
diff --git a/sources/plugins/magicline/lang/sq.js b/sources/plugins/magicline/lang/sq.js
new file mode 100644
index 0000000..d405596
--- /dev/null
+++ b/sources/plugins/magicline/lang/sq.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'sq', {
7 title: 'Vendos paragraf këtu'
8} );
diff --git a/sources/plugins/magicline/lang/sv.js b/sources/plugins/magicline/lang/sv.js
new file mode 100644
index 0000000..63327fd
--- /dev/null
+++ b/sources/plugins/magicline/lang/sv.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'sv', {
7 title: 'Infoga paragraf här'
8} );
diff --git a/sources/plugins/magicline/lang/tr.js b/sources/plugins/magicline/lang/tr.js
new file mode 100644
index 0000000..02dd216
--- /dev/null
+++ b/sources/plugins/magicline/lang/tr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'tr', {
7 title: 'Parağrafı buraya ekle'
8} );
diff --git a/sources/plugins/magicline/lang/tt.js b/sources/plugins/magicline/lang/tt.js
new file mode 100644
index 0000000..7de33bf
--- /dev/null
+++ b/sources/plugins/magicline/lang/tt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'tt', {
7 title: 'Бирегә параграф өстәү'
8} );
diff --git a/sources/plugins/magicline/lang/ug.js b/sources/plugins/magicline/lang/ug.js
new file mode 100644
index 0000000..0017fd4
--- /dev/null
+++ b/sources/plugins/magicline/lang/ug.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'ug', {
7 title: 'بۇ جايغا ئابزاس قىستۇر'
8} );
diff --git a/sources/plugins/magicline/lang/uk.js b/sources/plugins/magicline/lang/uk.js
new file mode 100644
index 0000000..980f0e0
--- /dev/null
+++ b/sources/plugins/magicline/lang/uk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'uk', {
7 title: 'Вставити абзац'
8} );
diff --git a/sources/plugins/magicline/lang/vi.js b/sources/plugins/magicline/lang/vi.js
new file mode 100644
index 0000000..b302bd0
--- /dev/null
+++ b/sources/plugins/magicline/lang/vi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'vi', {
7 title: 'Chèn đoạn vào đây'
8} );
diff --git a/sources/plugins/magicline/lang/zh-cn.js b/sources/plugins/magicline/lang/zh-cn.js
new file mode 100644
index 0000000..f0a0b3b
--- /dev/null
+++ b/sources/plugins/magicline/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'zh-cn', {
7 title: '在这插入段落'
8} );
diff --git a/sources/plugins/magicline/lang/zh.js b/sources/plugins/magicline/lang/zh.js
new file mode 100644
index 0000000..3ac9f68
--- /dev/null
+++ b/sources/plugins/magicline/lang/zh.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.setLang( 'magicline', 'zh', {
7 title: '在此插入段落'
8} );
diff --git a/sources/plugins/magicline/plugin.js b/sources/plugins/magicline/plugin.js
new file mode 100644
index 0000000..ac4bb78
--- /dev/null
+++ b/sources/plugins/magicline/plugin.js
@@ -0,0 +1,1874 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The [Magic Line](http://ckeditor.com/addon/magicline) plugin that makes it easier to access some document areas that
8 * are difficult to focus.
9 */
10
11'use strict';
12
13( function() {
14 CKEDITOR.plugins.add( 'magicline', {
15 lang: 'af,ar,az,bg,ca,cs,cy,da,de,de-ch,el,en,en-gb,eo,es,et,eu,fa,fi,fr,fr-ca,gl,he,hr,hu,id,it,ja,km,ko,ku,lv,nb,nl,no,oc,pl,pt,pt-br,ru,si,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
16 init: initPlugin
17 } );
18
19 // Activates the box inside of an editor.
20 function initPlugin( editor ) {
21 // Configurables
22 var config = editor.config,
23 triggerOffset = config.magicline_triggerOffset || 30,
24 enterMode = config.enterMode,
25 that = {
26 // Global stuff is being initialized here.
27 editor: editor,
28 enterMode: enterMode,
29 triggerOffset: triggerOffset,
30 holdDistance: 0 | triggerOffset * ( config.magicline_holdDistance || 0.5 ),
31 boxColor: config.magicline_color || '#ff0000',
32 rtl: config.contentsLangDirection == 'rtl',
33 tabuList: [ 'data-cke-hidden-sel' ].concat( config.magicline_tabuList || [] ),
34 triggers: config.magicline_everywhere ? DTD_BLOCK : { table: 1, hr: 1, div: 1, ul: 1, ol: 1, dl: 1, form: 1, blockquote: 1 }
35 },
36 scrollTimeout, checkMouseTimeoutPending, checkMouseTimer;
37
38 // %REMOVE_START%
39 // Internal DEBUG uses tools located in the topmost window.
40
41 // (#9701) Due to security limitations some browsers may throw
42 // errors when accessing window.top object. Do it safely first then.
43 try {
44 that.debug = window.top.DEBUG;
45 }
46 catch ( e ) {}
47
48 that.debug = that.debug || {
49 groupEnd: function() {},
50 groupStart: function() {},
51 log: function() {},
52 logElements: function() {},
53 logElementsEnd: function() {},
54 logEnd: function() {},
55 mousePos: function() {},
56 showHidden: function() {},
57 showTrigger: function() {},
58 startTimer: function() {},
59 stopTimer: function() {}
60 };
61 // %REMOVE_END%
62
63 // Simple irrelevant elements filter.
64 that.isRelevant = function( node ) {
65 return isHtml( node ) && // -> Node must be an existing HTML element.
66 !isLine( that, node ) && // -> Node can be neither the box nor its child.
67 !isFlowBreaker( node ); // -> Node can be neither floated nor positioned nor aligned.
68 };
69
70 editor.on( 'contentDom', addListeners, this );
71
72 function addListeners() {
73 var editable = editor.editable(),
74 doc = editor.document,
75 win = editor.window;
76
77 // Global stuff is being initialized here.
78 extend( that, {
79 editable: editable,
80 inInlineMode: editable.isInline(),
81 doc: doc,
82 win: win,
83 hotNode: null
84 }, true );
85
86 // This is the boundary of the editor. For inline the boundary is editable itself.
87 // For classic (`iframe`-based) editor, the HTML element is a real boundary.
88 that.boundary = that.inInlineMode ? that.editable : that.doc.getDocumentElement();
89
90 // Enabling the box inside of inline editable is pointless.
91 // There's no need to access spaces inside paragraphs, links, spans, etc.
92 if ( editable.is( dtd.$inline ) )
93 return;
94
95 // Handle in-line editing by setting appropriate position.
96 // If current position is static, make it relative and clear top/left coordinates.
97 if ( that.inInlineMode && !isPositioned( editable ) ) {
98 editable.setStyles( {
99 position: 'relative',
100 top: null,
101 left: null
102 } );
103 }
104 // Enable the box. Let it produce children elements, initialize
105 // event handlers and own methods.
106 initLine.call( this, that );
107
108 // Get view dimensions and scroll positions.
109 // At this stage (before any checkMouse call) it is used mostly
110 // by tests. Nevertheless it a crucial thing.
111 updateWindowSize( that );
112
113 // Remove the box before an undo image is created.
114 // This is important. If we didn't do that, the *undo thing* would revert the box into an editor.
115 // Thanks to that, undo doesn't even know about the existence of the box.
116 editable.attachListener( editor, 'beforeUndoImage', function() {
117 that.line.detach();
118 } );
119
120 // Removes the box HTML from editor data string if getData is called.
121 // Thanks to that, an editor never yields data polluted by the box.
122 // Listen with very high priority, so line will be removed before other
123 // listeners will see it.
124 editable.attachListener( editor, 'beforeGetData', function() {
125 // If the box is in editable, remove it.
126 if ( that.line.wrap.getParent() ) {
127 that.line.detach();
128
129 // Restore line in the last listener for 'getData'.
130 editor.once( 'getData', function() {
131 that.line.attach();
132 }, null, null, 1000 );
133 }
134 }, null, null, 0 );
135
136 // Hide the box on mouseout if mouse leaves document.
137 editable.attachListener( that.inInlineMode ? doc : doc.getWindow().getFrame(), 'mouseout', function( event ) {
138 if ( editor.mode != 'wysiwyg' )
139 return;
140
141 // Check for inline-mode editor. If so, check mouse position
142 // and remove the box if mouse outside of an editor.
143 if ( that.inInlineMode ) {
144 var mouse = {
145 x: event.data.$.clientX,
146 y: event.data.$.clientY
147 };
148
149 updateWindowSize( that );
150 updateEditableSize( that, true );
151
152 var size = that.view.editable,
153 scroll = that.view.scroll;
154
155 // If outside of an editor...
156 if ( !inBetween( mouse.x, size.left - scroll.x, size.right - scroll.x ) || !inBetween( mouse.y, size.top - scroll.y, size.bottom - scroll.y ) ) {
157 clearTimeout( checkMouseTimer );
158 checkMouseTimer = null;
159 that.line.detach();
160 }
161 }
162
163 else {
164 clearTimeout( checkMouseTimer );
165 checkMouseTimer = null;
166 that.line.detach();
167 }
168 } );
169
170 // This one deactivates hidden mode of an editor which
171 // prevents the box from being shown.
172 editable.attachListener( editable, 'keyup', function() {
173 that.hiddenMode = 0;
174 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
175 } );
176
177 editable.attachListener( editable, 'keydown', function( event ) {
178 if ( editor.mode != 'wysiwyg' )
179 return;
180
181 var keyStroke = event.data.getKeystroke();
182
183 switch ( keyStroke ) {
184 // Shift pressed
185 case 2228240: // IE
186 case 16:
187 that.hiddenMode = 1;
188 that.line.detach();
189 }
190
191 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
192 } );
193
194 // This method ensures that checkMouse aren't executed
195 // in parallel and no more frequently than specified in timeout function.
196 // In classic (`iframe`-based) editor, document is used as a trigger, to provide magicline
197 // functionality when mouse is below the body (short content, short body).
198 editable.attachListener( that.inInlineMode ? editable : doc, 'mousemove', function( event ) {
199 checkMouseTimeoutPending = true;
200
201 if ( editor.mode != 'wysiwyg' || editor.readOnly || checkMouseTimer )
202 return;
203
204 // IE<9 requires this event-driven object to be created
205 // outside of the setTimeout statement.
206 // Otherwise it loses the event object with its properties.
207 var mouse = {
208 x: event.data.$.clientX,
209 y: event.data.$.clientY
210 };
211
212 checkMouseTimer = setTimeout( function() {
213 checkMouse( mouse );
214 }, 30 ); // balances performance and accessibility
215 } );
216
217 // This one removes box on scroll event.
218 // It is to avoid box displacement.
219 editable.attachListener( win, 'scroll', function() {
220 if ( editor.mode != 'wysiwyg' )
221 return;
222
223 that.line.detach();
224
225 // To figure this out just look at the mouseup
226 // event handler below.
227 if ( env.webkit ) {
228 that.hiddenMode = 1;
229
230 clearTimeout( scrollTimeout );
231 scrollTimeout = setTimeout( function() {
232 // Don't leave hidden mode until mouse remains pressed and
233 // scroll is being used, i.e. when dragging something.
234 if ( !that.mouseDown )
235 that.hiddenMode = 0;
236 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
237 }, 50 );
238
239 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
240 }
241 } );
242
243 // Those event handlers remove the box on mousedown
244 // and don't reveal it until the mouse is released.
245 // It is to prevent box insertion e.g. while scrolling
246 // (w/ scrollbar), selecting and so on.
247 editable.attachListener( env_ie8 ? doc : win, 'mousedown', function() {
248 if ( editor.mode != 'wysiwyg' )
249 return;
250
251 that.line.detach();
252 that.hiddenMode = 1;
253 that.mouseDown = 1;
254
255 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
256 } );
257
258 // Google Chrome doesn't trigger this on the scrollbar (since 2009...)
259 // so it is totally useless to check for scroll finish
260 // see: http://code.google.com/p/chromium/issues/detail?id=14204
261 editable.attachListener( env_ie8 ? doc : win, 'mouseup', function() {
262 that.hiddenMode = 0;
263 that.mouseDown = 0;
264 that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
265 } );
266
267 // Editor commands for accessing difficult focus spaces.
268 editor.addCommand( 'accessPreviousSpace', accessFocusSpaceCmd( that ) );
269 editor.addCommand( 'accessNextSpace', accessFocusSpaceCmd( that, true ) );
270
271 editor.setKeystroke( [
272 [ config.magicline_keystrokePrevious, 'accessPreviousSpace' ],
273 [ config.magicline_keystrokeNext, 'accessNextSpace' ]
274 ] );
275
276 // Revert magicline hot node on undo/redo.
277 editor.on( 'loadSnapshot', function() {
278 var elements, element, i;
279
280 for ( var t in { p: 1, br: 1, div: 1 } ) {
281 // document.find is not available in QM (#11149).
282 elements = editor.document.getElementsByTag( t );
283
284 for ( i = elements.count(); i--; ) {
285 if ( ( element = elements.getItem( i ) ).data( 'cke-magicline-hot' ) ) {
286 // Restore hotNode
287 that.hotNode = element;
288 // Restore last access direction
289 that.lastCmdDirection = element.data( 'cke-magicline-dir' ) === 'true' ? true : false;
290
291 return;
292 }
293 }
294 }
295 } );
296
297 // This method handles mousemove mouse for box toggling.
298 // It uses mouse position to determine underlying element, then
299 // it tries to use different trigger type in order to place the box
300 // in correct place. The following procedure is executed periodically.
301 function checkMouse( mouse ) {
302 that.debug.groupStart( 'CheckMouse' ); // %REMOVE_LINE%
303 that.debug.startTimer(); // %REMOVE_LINE%
304
305 that.mouse = mouse;
306 that.trigger = null;
307
308 checkMouseTimer = null;
309 updateWindowSize( that );
310
311 if (
312 checkMouseTimeoutPending && // There must be an event pending.
313 !that.hiddenMode && // Can't be in hidden mode.
314 editor.focusManager.hasFocus && // Editor must have focus.
315 !that.line.mouseNear() && // Mouse pointer can't be close to the box.
316 ( that.element = elementFromMouse( that, true ) ) // There must be valid element.
317 ) {
318 // If trigger exists, and trigger is correct -> show the box.
319 // Don't show the line if trigger is a descendant of some tabu-list element.
320 if ( ( that.trigger = triggerEditable( that ) || triggerEdge( that ) || triggerExpand( that ) ) &&
321 !isInTabu( that, that.trigger.upper || that.trigger.lower ) ) {
322 that.line.attach().place();
323 }
324
325 // Otherwise remove the box
326 else {
327 that.trigger = null;
328 that.line.detach();
329 }
330
331 that.debug.showTrigger( that.trigger ); // %REMOVE_LINE%
332 that.debug.mousePos( mouse.y, that.element ); // %REMOVE_LINE%
333
334 checkMouseTimeoutPending = false;
335 }
336
337 that.debug.stopTimer(); // %REMOVE_LINE%
338 that.debug.groupEnd(); // %REMOVE_LINE%
339 }
340
341 // This one allows testing and debugging. It reveals some
342 // inner methods to the world.
343 this.backdoor = {
344 accessFocusSpace: accessFocusSpace,
345 boxTrigger: boxTrigger,
346 isLine: isLine,
347 getAscendantTrigger: getAscendantTrigger,
348 getNonEmptyNeighbour: getNonEmptyNeighbour,
349 getSize: getSize,
350 that: that,
351 triggerEdge: triggerEdge,
352 triggerEditable: triggerEditable,
353 triggerExpand: triggerExpand
354 };
355 }
356 }
357
358 // Some shorthands for common methods to save bytes
359 var extend = CKEDITOR.tools.extend,
360 newElement = CKEDITOR.dom.element,
361 newElementFromHtml = newElement.createFromHtml,
362 env = CKEDITOR.env,
363 env_ie8 = CKEDITOR.env.ie && CKEDITOR.env.version < 9,
364 dtd = CKEDITOR.dtd,
365
366 // Global object associating enter modes with elements.
367 enterElements = {},
368
369 // Constant values, types and so on.
370 EDGE_TOP = 128,
371 EDGE_BOTTOM = 64,
372 EDGE_MIDDLE = 32,
373 TYPE_EDGE = 16,
374 TYPE_EXPAND = 8,
375 LOOK_TOP = 4,
376 LOOK_BOTTOM = 2,
377 LOOK_NORMAL = 1,
378 WHITE_SPACE = '\u00A0',
379 DTD_LISTITEM = dtd.$listItem,
380 DTD_TABLECONTENT = dtd.$tableContent,
381 DTD_NONACCESSIBLE = extend( {}, dtd.$nonEditable, dtd.$empty ),
382 DTD_BLOCK = dtd.$block,
383
384 // Minimum time that must elapse between two update*Size calls.
385 // It prevents constant getComuptedStyle calls and improves performance.
386 CACHE_TIME = 100,
387
388 // Shared CSS stuff for box elements
389 CSS_COMMON = 'width:0px;height:0px;padding:0px;margin:0px;display:block;' + 'z-index:9999;color:#fff;position:absolute;font-size: 0px;line-height:0px;',
390 CSS_TRIANGLE = CSS_COMMON + 'border-color:transparent;display:block;border-style:solid;',
391 TRIANGLE_HTML = '<span>' + WHITE_SPACE + '</span>';
392
393 enterElements[ CKEDITOR.ENTER_BR ] = 'br';
394 enterElements[ CKEDITOR.ENTER_P ] = 'p';
395 enterElements[ CKEDITOR.ENTER_DIV ] = 'div';
396
397 function areSiblings( that, upper, lower ) {
398 return isHtml( upper ) && isHtml( lower ) && lower.equals( upper.getNext( function( node ) {
399 return !( isEmptyTextNode( node ) || isComment( node ) || isFlowBreaker( node ) );
400 } ) );
401 }
402
403 // boxTrigger is an abstract type which describes
404 // the relationship between elements that may result
405 // in showing the box.
406 //
407 // The following type is used by numerous methods
408 // to share information about the hypothetical box placement
409 // and look by referring to boxTrigger properties.
410 function boxTrigger( triggerSetup ) {
411 this.upper = triggerSetup[ 0 ];
412 this.lower = triggerSetup[ 1 ];
413 this.set.apply( this, triggerSetup.slice( 2 ) );
414 }
415
416 boxTrigger.prototype = {
417 set: function( edge, type, look ) {
418 this.properties = edge + type + ( look || LOOK_NORMAL );
419 return this;
420 },
421
422 is: function( property ) {
423 return ( this.properties & property ) == property;
424 }
425 };
426
427 var elementFromMouse = ( function() {
428 function elementFromPoint( doc, mouse ) {
429 var pointedElement = doc.$.elementFromPoint( mouse.x, mouse.y );
430
431 // IE9QM: from times to times it will return an empty object on scroll bar hover. (#12185)
432 return pointedElement && pointedElement.nodeType ?
433 new CKEDITOR.dom.element( pointedElement ) :
434 null;
435 }
436
437 return function( that, ignoreBox, forceMouse ) {
438 if ( !that.mouse )
439 return null;
440
441 var doc = that.doc,
442 lineWrap = that.line.wrap,
443 mouse = forceMouse || that.mouse,
444 // Note: element might be null.
445 element = elementFromPoint( doc, mouse );
446
447 // If ignoreBox is set and element is the box, it means that we
448 // need to hide the box for a while, repeat elementFromPoint
449 // and show it again.
450 if ( ignoreBox && isLine( that, element ) ) {
451 lineWrap.hide();
452 element = elementFromPoint( doc, mouse );
453 lineWrap.show();
454 }
455
456 // Return nothing if:
457 // \-> Element is not HTML.
458 if ( !( element && element.type == CKEDITOR.NODE_ELEMENT && element.$ ) )
459 return null;
460
461 // Also return nothing if:
462 // \-> We're IE<9 and element is out of the top-level element (editable for inline and HTML for classic (`iframe`-based)).
463 // This is due to the bug which allows IE<9 firing mouse events on element
464 // with contenteditable=true while doing selection out (far, away) of the element.
465 // Thus we must always be sure that we stay in editable or HTML.
466 if ( env.ie && env.version < 9 ) {
467 if ( !( that.boundary.equals( element ) || that.boundary.contains( element ) ) )
468 return null;
469 }
470
471 return element;
472 };
473 } )();
474
475 // Gets the closest parent node that belongs to triggers group.
476 function getAscendantTrigger( that ) {
477 var node = that.element,
478 trigger;
479
480 if ( node && isHtml( node ) ) {
481 trigger = node.getAscendant( that.triggers, true );
482
483 // If trigger is an element, neither editable nor editable's ascendant.
484 if ( trigger && that.editable.contains( trigger ) ) {
485 // Check for closest editable limit.
486 // Don't consider trigger as a limit as it may be nested editable (includeSelf=false) (#12009).
487 var limit = getClosestEditableLimit( trigger );
488
489 // Trigger in nested editable area.
490 if ( limit.getAttribute( 'contenteditable' ) == 'true' )
491 return trigger;
492 // Trigger in non-editable area.
493 else if ( limit.is( that.triggers ) )
494 return limit;
495 else
496 return null;
497 } else {
498 return null;
499 }
500 }
501
502 return null;
503 }
504
505 function getMidpoint( that, upper, lower ) {
506 updateSize( that, upper );
507 updateSize( that, lower );
508
509 var upperSizeBottom = upper.size.bottom,
510 lowerSizeTop = lower.size.top;
511
512 return upperSizeBottom && lowerSizeTop ? 0 | ( upperSizeBottom + lowerSizeTop ) / 2 : upperSizeBottom || lowerSizeTop;
513 }
514
515 // Get nearest node (either text or HTML), but:
516 // \-> Omit all empty text nodes (containing white characters only).
517 // \-> Omit BR elements
518 // \-> Omit flow breakers.
519 function getNonEmptyNeighbour( that, node, goBack ) {
520 node = node[ goBack ? 'getPrevious' : 'getNext' ]( function( node ) {
521 return ( isTextNode( node ) && !isEmptyTextNode( node ) ) ||
522 ( isHtml( node ) && !isFlowBreaker( node ) && !isLine( that, node ) );
523 } );
524
525 return node;
526 }
527
528 function inBetween( val, lower, upper ) {
529 return val > lower && val < upper;
530 }
531
532 // Returns the closest ancestor that has contenteditable attribute.
533 // Such ancestor is the limit of (non-)editable DOM branch that element
534 // belongs to. This method omits editor editable.
535 function getClosestEditableLimit( element, includeSelf ) {
536 if ( element.data( 'cke-editable' ) )
537 return null;
538
539 if ( !includeSelf )
540 element = element.getParent();
541
542 while ( element ) {
543 if ( element.data( 'cke-editable' ) )
544 return null;
545
546 if ( element.hasAttribute( 'contenteditable' ) )
547 return element;
548
549 element = element.getParent();
550 }
551
552 return null;
553 }
554
555 // Access space line consists of a few elements (spans):
556 // \-> Line wrapper.
557 // \-> Line.
558 // \-> Line triangles: left triangle (LT), right triangle (RT).
559 // \-> Button handler (BTN).
560 //
561 // +--------------------------------------------------- line.wrap (span) -----+
562 // | +---------------------------------------------------- line (span) -----+ |
563 // | | +- LT \ +- BTN -+ / RT -+ | |
564 // | | | \ | | | / | | |
565 // | | | / | <__| | \ | | |
566 // | | +-----/ +-------+ \-----+ | |
567 // | +----------------------------------------------------------------------+ |
568 // +--------------------------------------------------------------------------+
569 //
570 function initLine( that ) {
571 var doc = that.doc,
572 // This the main box element that holds triangles and the insertion button
573 line = newElementFromHtml( '<span contenteditable="false" style="' + CSS_COMMON + 'position:absolute;border-top:1px dashed ' + that.boxColor + '"></span>', doc ),
574 iconPath = CKEDITOR.getUrl( this.path + 'images/' + ( env.hidpi ? 'hidpi/' : '' ) + 'icon' + ( that.rtl ? '-rtl' : '' ) + '.png' );
575
576 extend( line, {
577
578 attach: function() {
579 // Only if not already attached
580 if ( !this.wrap.getParent() )
581 this.wrap.appendTo( that.editable, true );
582
583 return this;
584 },
585
586 // Looks are as follows: [ LOOK_TOP, LOOK_BOTTOM, LOOK_NORMAL ].
587 lineChildren: [
588 extend(
589 newElementFromHtml(
590 '<span title="' + that.editor.lang.magicline.title +
591 '" contenteditable="false">&#8629;</span>', doc
592 ), {
593 base: CSS_COMMON + 'height:17px;width:17px;' + ( that.rtl ? 'left' : 'right' ) + ':17px;' +
594 'background:url(' + iconPath + ') center no-repeat ' + that.boxColor + ';cursor:pointer;' +
595 ( env.hc ? 'font-size: 15px;line-height:14px;border:1px solid #fff;text-align:center;' : '' ) +
596 ( env.hidpi ? 'background-size: 9px 10px;' : '' ),
597 looks: [
598 'top:-8px; border-radius: 2px;',
599 'top:-17px; border-radius: 2px 2px 0px 0px;',
600 'top:-1px; border-radius: 0px 0px 2px 2px;'
601 ]
602 }
603 ),
604 extend( newElementFromHtml( TRIANGLE_HTML, doc ), {
605 base: CSS_TRIANGLE + 'left:0px;border-left-color:' + that.boxColor + ';',
606 looks: [
607 'border-width:8px 0 8px 8px;top:-8px',
608 'border-width:8px 0 0 8px;top:-8px',
609 'border-width:0 0 8px 8px;top:0px'
610 ]
611 } ),
612 extend( newElementFromHtml( TRIANGLE_HTML, doc ), {
613 base: CSS_TRIANGLE + 'right:0px;border-right-color:' + that.boxColor + ';',
614 looks: [
615 'border-width:8px 8px 8px 0;top:-8px',
616 'border-width:8px 8px 0 0;top:-8px',
617 'border-width:0 8px 8px 0;top:0px'
618 ]
619 } )
620 ],
621
622 detach: function() {
623 // Detach only if already attached.
624 if ( this.wrap.getParent() )
625 this.wrap.remove();
626
627 return this;
628 },
629
630 // Checks whether mouseY is around an element by comparing boundaries and considering
631 // an offset distance.
632 mouseNear: function() {
633 that.debug.groupStart( 'mouseNear' ); // %REMOVE_LINE%
634
635 updateSize( that, this );
636 var offset = that.holdDistance,
637 size = this.size;
638
639 // Determine neighborhood by element dimensions and offsets.
640 if ( size && inBetween( that.mouse.y, size.top - offset, size.bottom + offset ) && inBetween( that.mouse.x, size.left - offset, size.right + offset ) ) {
641 that.debug.logEnd( 'Mouse is near.' ); // %REMOVE_LINE%
642 return true;
643 }
644
645 that.debug.logEnd( 'Mouse isn\'t near.' ); // %REMOVE_LINE%
646 return false;
647 },
648
649 // Adjusts position of the box according to the trigger properties.
650 // If also affects look of the box depending on the type of the trigger.
651 place: function() {
652 var view = that.view,
653 editable = that.editable,
654 trigger = that.trigger,
655 upper = trigger.upper,
656 lower = trigger.lower,
657 any = upper || lower,
658 parent = any.getParent(),
659 styleSet = {};
660
661 // Save recent trigger for further insertion.
662 // It is necessary due to the fact, that that.trigger may
663 // contain different boxTrigger at the moment of insertion
664 // or may be even null.
665 this.trigger = trigger;
666
667 upper && updateSize( that, upper, true );
668 lower && updateSize( that, lower, true );
669 updateSize( that, parent, true );
670
671 // Yeah, that's gonna be useful in inline-mode case.
672 if ( that.inInlineMode )
673 updateEditableSize( that, true );
674
675 // Set X coordinate (left, right, width).
676 if ( parent.equals( editable ) ) {
677 styleSet.left = view.scroll.x;
678 styleSet.right = -view.scroll.x;
679 styleSet.width = '';
680 } else {
681 styleSet.left = any.size.left - any.size.margin.left + view.scroll.x - ( that.inInlineMode ? view.editable.left + view.editable.border.left : 0 );
682 styleSet.width = any.size.outerWidth + any.size.margin.left + any.size.margin.right + view.scroll.x;
683 styleSet.right = '';
684 }
685
686 // Set Y coordinate (top) for trigger consisting of two elements.
687 if ( upper && lower ) {
688 // No margins at all or they're equal. Place box right between.
689 if ( upper.size.margin.bottom === lower.size.margin.top )
690 styleSet.top = 0 | ( upper.size.bottom + upper.size.margin.bottom / 2 );
691 else {
692 // Upper margin < lower margin. Place at lower margin.
693 if ( upper.size.margin.bottom < lower.size.margin.top )
694 styleSet.top = upper.size.bottom + upper.size.margin.bottom;
695 // Upper margin > lower margin. Place at upper margin - lower margin.
696 else
697 styleSet.top = upper.size.bottom + upper.size.margin.bottom - lower.size.margin.top;
698 }
699 }
700 // Set Y coordinate (top) for single-edge trigger.
701 else if ( !upper )
702 styleSet.top = lower.size.top - lower.size.margin.top;
703 else if ( !lower ) {
704 styleSet.top = upper.size.bottom + upper.size.margin.bottom;
705 }
706
707 // Set box button modes if close to the viewport horizontal edge
708 // or look forced by the trigger.
709 if ( trigger.is( LOOK_TOP ) || inBetween( styleSet.top, view.scroll.y - 15, view.scroll.y + 5 ) ) {
710 styleSet.top = that.inInlineMode ? 0 : view.scroll.y;
711 this.look( LOOK_TOP );
712 } else if ( trigger.is( LOOK_BOTTOM ) || inBetween( styleSet.top, view.pane.bottom - 5, view.pane.bottom + 15 ) ) {
713 styleSet.top = that.inInlineMode ? (
714 view.editable.height + view.editable.padding.top + view.editable.padding.bottom
715 ) : (
716 view.pane.bottom - 1
717 );
718
719 this.look( LOOK_BOTTOM );
720 } else {
721 if ( that.inInlineMode )
722 styleSet.top -= view.editable.top + view.editable.border.top;
723
724 this.look( LOOK_NORMAL );
725 }
726
727 if ( that.inInlineMode ) {
728 // 1px bug here...
729 styleSet.top--;
730
731 // Consider the editable to be an element with overflow:scroll
732 // and non-zero scrollTop/scrollLeft value.
733 // For example: divarea editable. (#9383)
734 styleSet.top += view.editable.scroll.top;
735 styleSet.left += view.editable.scroll.left;
736 }
737
738 // Append `px` prefixes.
739 for ( var style in styleSet )
740 styleSet[ style ] = CKEDITOR.tools.cssLength( styleSet[ style ] );
741
742 this.setStyles( styleSet );
743 },
744
745 // Changes look of the box according to current needs.
746 // Three different styles are available: [ LOOK_TOP, LOOK_BOTTOM, LOOK_NORMAL ].
747 look: function( look ) {
748 if ( this.oldLook == look )
749 return;
750
751 for ( var i = this.lineChildren.length, child; i--; )
752 ( child = this.lineChildren[ i ] ).setAttribute( 'style', child.base + child.looks[ 0 | look / 2 ] );
753
754 this.oldLook = look;
755 },
756
757 wrap: new newElement( 'span', that.doc )
758
759 } );
760
761 // Insert children into the box.
762 for ( var i = line.lineChildren.length; i--; )
763 line.lineChildren[ i ].appendTo( line );
764
765 // Set default look of the box.
766 line.look( LOOK_NORMAL );
767
768 // Using that wrapper prevents IE (8,9) from resizing editable area at the moment
769 // of box insertion. This works thanks to the fact, that positioned box is wrapped by
770 // an inline element. So much tricky.
771 line.appendTo( line.wrap );
772
773 // Make the box unselectable.
774 line.unselectable();
775
776 // Handle accessSpace node insertion.
777 line.lineChildren[ 0 ].on( 'mouseup', function( event ) {
778 line.detach();
779
780 accessFocusSpace( that, function( accessNode ) {
781 // Use old trigger that was saved by 'place' method. Look: line.place
782 var trigger = that.line.trigger;
783
784 accessNode[ trigger.is( EDGE_TOP ) ? 'insertBefore' : 'insertAfter' ](
785 trigger.is( EDGE_TOP ) ? trigger.lower : trigger.upper );
786 }, true );
787
788 that.editor.focus();
789
790 if ( !env.ie && that.enterMode != CKEDITOR.ENTER_BR )
791 that.hotNode.scrollIntoView();
792
793 event.data.preventDefault( true );
794 } );
795
796 // Prevents IE9 from displaying the resize box and disables drag'n'drop functionality.
797 line.on( 'mousedown', function( event ) {
798 event.data.preventDefault( true );
799 } );
800
801 that.line = line;
802 }
803
804 // This function allows accessing any focus space according to the insert function:
805 // * For enterMode ENTER_P it creates P element filled with dummy white-space.
806 // * For enterMode ENTER_DIV it creates DIV element filled with dummy white-space.
807 // * For enterMode ENTER_BR it creates BR element or &nbsp; in IE.
808 //
809 // The node is being inserted according to insertFunction. Finally the method
810 // selects the non-breaking space making the node ready for typing.
811 function accessFocusSpace( that, insertFunction, doSave ) {
812 var range = new CKEDITOR.dom.range( that.doc ),
813 editor = that.editor,
814 accessNode;
815
816 // IE requires text node of &nbsp; in ENTER_BR mode.
817 if ( env.ie && that.enterMode == CKEDITOR.ENTER_BR )
818 accessNode = that.doc.createText( WHITE_SPACE );
819
820 // In other cases a regular element is used.
821 else {
822 // Use the enterMode of editable's limit or editor's
823 // enter mode if not in nested editable.
824 var limit = getClosestEditableLimit( that.element, true ),
825
826 // This is an enter mode for the context. We cannot use
827 // editor.activeEnterMode because the focused nested editable will
828 // have a different enterMode as editor but magicline will be inserted
829 // directly into editor's editable.
830 enterMode = limit && limit.data( 'cke-enter-mode' ) || that.enterMode;
831
832 accessNode = new newElement( enterElements[ enterMode ], that.doc );
833
834 if ( !accessNode.is( 'br' ) ) {
835 var dummy = that.doc.createText( WHITE_SPACE );
836 dummy.appendTo( accessNode );
837 }
838 }
839
840 doSave && editor.fire( 'saveSnapshot' );
841
842 insertFunction( accessNode );
843 //dummy.appendTo( accessNode );
844 range.moveToPosition( accessNode, CKEDITOR.POSITION_AFTER_START );
845 editor.getSelection().selectRanges( [ range ] );
846 that.hotNode = accessNode;
847
848 doSave && editor.fire( 'saveSnapshot' );
849 }
850
851 // Access focus space on demand by taking an element under the caret as a reference.
852 // The space is accessed provided the element under the caret is trigger AND:
853 //
854 // 1. First/last-child of its parent:
855 // +----------------------- Parent element -+
856 // | +------------------------------ DIV -+ | <-- Access before
857 // | | Foo^ | |
858 // | | | |
859 // | +------------------------------------+ | <-- Access after
860 // +----------------------------------------+
861 //
862 // OR
863 //
864 // 2. It has a direct sibling element, which is also a trigger:
865 // +-------------------------------- DIV#1 -+
866 // | Foo^ |
867 // | |
868 // +----------------------------------------+
869 // <-- Access here
870 // +-------------------------------- DIV#2 -+
871 // | Bar |
872 // | |
873 // +----------------------------------------+
874 //
875 // OR
876 //
877 // 3. It has a direct sibling, which is a trigger and has a valid neighbour trigger,
878 // but belongs to dtd.$.empty/nonEditable:
879 // +------------------------------------ P -+
880 // | Foo^ |
881 // | |
882 // +----------------------------------------+
883 // +----------------------------------- HR -+
884 // <-- Access here
885 // +-------------------------------- DIV#2 -+
886 // | Bar |
887 // | |
888 // +----------------------------------------+
889 //
890 function accessFocusSpaceCmd( that, insertAfter ) {
891 return {
892 canUndo: true,
893 modes: { wysiwyg: 1 },
894 exec: ( function() {
895
896 // Inserts line (accessNode) at the position by taking target node as a reference.
897 function doAccess( target ) {
898 // Remove old hotNode under certain circumstances.
899 var hotNodeChar = ( env.ie && env.version < 9 ? ' ' : WHITE_SPACE ),
900 removeOld = that.hotNode && // Old hotNode must exist.
901 that.hotNode.getText() == hotNodeChar && // Old hotNode hasn't been changed.
902 that.element.equals( that.hotNode ) && // Caret is inside old hotNode.
903 // Command is executed in the same direction.
904 that.lastCmdDirection === !!insertAfter; // jshint ignore:line
905
906 accessFocusSpace( that, function( accessNode ) {
907 if ( removeOld && that.hotNode )
908 that.hotNode.remove();
909
910 accessNode[ insertAfter ? 'insertAfter' : 'insertBefore' ]( target );
911
912 // Make this element distinguishable. Also remember the direction
913 // it's been inserted into document.
914 accessNode.setAttributes( {
915 'data-cke-magicline-hot': 1,
916 'data-cke-magicline-dir': !!insertAfter
917 } );
918
919 // Save last direction of the command (is insertAfter?).
920 that.lastCmdDirection = !!insertAfter;
921 } );
922
923 if ( !env.ie && that.enterMode != CKEDITOR.ENTER_BR )
924 that.hotNode.scrollIntoView();
925
926 // Detach the line if was visible (previously triggered by mouse).
927 that.line.detach();
928 }
929
930 return function( editor ) {
931 var selected = editor.getSelection().getStartElement(),
932 limit;
933
934 // (#9833) Go down to the closest non-inline element in DOM structure
935 // since inline elements don't participate in in magicline.
936 selected = selected.getAscendant( DTD_BLOCK, 1 );
937
938 // Stop if selected is a child of a tabu-list element.
939 if ( isInTabu( that, selected ) )
940 return;
941
942 // Sometimes it may happen that there's no parent block below selected element
943 // or, for example, getAscendant reaches editable or editable parent.
944 // We must avoid such pathological cases.
945 if ( !selected || selected.equals( that.editable ) || selected.contains( that.editable ) )
946 return;
947
948 // Executing the command directly in nested editable should
949 // access space before/after it.
950 if ( ( limit = getClosestEditableLimit( selected ) ) && limit.getAttribute( 'contenteditable' ) == 'false' )
951 selected = limit;
952
953 // That holds element from mouse. Replace it with the
954 // element under the caret.
955 that.element = selected;
956
957 // (3.) Handle the following cases where selected neighbour
958 // is a trigger inaccessible for the caret AND:
959 // - Is first/last-child
960 // OR
961 // - Has a sibling, which is also a trigger.
962 var neighbor = getNonEmptyNeighbour( that, selected, !insertAfter ),
963 neighborSibling;
964
965 // Check for a neighbour that belongs to triggers.
966 // Consider only non-accessible elements (they cannot have any children)
967 // since they cannot be given a caret inside, to run the command
968 // the regular way (1. & 2.).
969 if (
970 isHtml( neighbor ) && neighbor.is( that.triggers ) && neighbor.is( DTD_NONACCESSIBLE ) &&
971 (
972 // Check whether neighbor is first/last-child.
973 !getNonEmptyNeighbour( that, neighbor, !insertAfter ) ||
974 // Check for a sibling of a neighbour that also is a trigger.
975 (
976 ( neighborSibling = getNonEmptyNeighbour( that, neighbor, !insertAfter ) ) &&
977 isHtml( neighborSibling ) &&
978 neighborSibling.is( that.triggers )
979 )
980 )
981 ) {
982 doAccess( neighbor );
983 return;
984 }
985
986 // Look for possible target element DOWN "selected" DOM branch (towards editable)
987 // that belong to that.triggers
988 var target = getAscendantTrigger( that, selected );
989
990 // No HTML target -> no access.
991 if ( !isHtml( target ) )
992 return;
993
994 // (1.) Target is first/last child -> access.
995 if ( !getNonEmptyNeighbour( that, target, !insertAfter ) ) {
996 doAccess( target );
997 return;
998 }
999
1000 var sibling = getNonEmptyNeighbour( that, target, !insertAfter );
1001
1002 // (2.) Target has a sibling that belongs to that.triggers -> access.
1003 if ( sibling && isHtml( sibling ) && sibling.is( that.triggers ) ) {
1004 doAccess( target );
1005 return;
1006 }
1007 };
1008 } )()
1009 };
1010 }
1011
1012 function isLine( that, node ) {
1013 if ( !( node && node.type == CKEDITOR.NODE_ELEMENT && node.$ ) )
1014 return false;
1015
1016 var line = that.line;
1017
1018 return line.wrap.equals( node ) || line.wrap.contains( node );
1019 }
1020
1021 // Is text node containing white-spaces only?
1022 var isEmptyTextNode = CKEDITOR.dom.walker.whitespaces();
1023
1024 // Is fully visible HTML node?
1025 function isHtml( node ) {
1026 return node && node.type == CKEDITOR.NODE_ELEMENT && node.$; // IE requires that
1027 }
1028
1029 function isFloated( element ) {
1030 if ( !isHtml( element ) )
1031 return false;
1032
1033 var options = { left: 1, right: 1, center: 1 };
1034
1035 return !!( options[ element.getComputedStyle( 'float' ) ] || options[ element.getAttribute( 'align' ) ] );
1036 }
1037
1038 function isFlowBreaker( element ) {
1039 if ( !isHtml( element ) )
1040 return false;
1041
1042 return isPositioned( element ) || isFloated( element );
1043 }
1044
1045 // Isn't node of NODE_COMMENT type?
1046 var isComment = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_COMMENT );
1047
1048 function isPositioned( element ) {
1049 return !!{ absolute: 1, fixed: 1 }[ element.getComputedStyle( 'position' ) ];
1050 }
1051
1052 // Is text node?
1053 function isTextNode( node ) {
1054 return node && node.type == CKEDITOR.NODE_TEXT;
1055 }
1056
1057 function isTrigger( that, element ) {
1058 return isHtml( element ) ? element.is( that.triggers ) : null;
1059 }
1060
1061 function isInTabu( that, element ) {
1062 if ( !element )
1063 return false;
1064
1065 var parents = element.getParents( 1 );
1066
1067 for ( var i = parents.length ; i-- ; ) {
1068 for ( var j = that.tabuList.length ; j-- ; ) {
1069 if ( parents[ i ].hasAttribute( that.tabuList[ j ] ) )
1070 return true;
1071 }
1072 }
1073
1074 return false;
1075 }
1076
1077 // This function checks vertically is there's a relevant child between element's edge
1078 // and the pointer.
1079 // \-> Table contents are omitted.
1080 function isChildBetweenPointerAndEdge( that, parent, edgeBottom ) {
1081 var edgeChild = parent[ edgeBottom ? 'getLast' : 'getFirst' ]( function( node ) {
1082 return that.isRelevant( node ) && !node.is( DTD_TABLECONTENT );
1083 } );
1084
1085 if ( !edgeChild )
1086 return false;
1087
1088 updateSize( that, edgeChild );
1089
1090 return edgeBottom ? edgeChild.size.top > that.mouse.y : edgeChild.size.bottom < that.mouse.y;
1091 }
1092
1093 // This method handles edge cases:
1094 // \-> Mouse is around upper or lower edge of view pane.
1095 // \-> Also scroll position is either minimal or maximal.
1096 // \-> It's OK to show LOOK_TOP(BOTTOM) type line.
1097 //
1098 // This trigger doesn't need additional post-filtering.
1099 //
1100 // +----------------------------- Editable -+ /--
1101 // | +---------------------- First child -+ | | <-- Top edge (first child)
1102 // | | | | |
1103 // | | | | | * Mouse activation area *
1104 // | | | | |
1105 // | | ... | | \-- Top edge + trigger offset
1106 // | . . |
1107 // | |
1108 // | . . |
1109 // | | ... | | /-- Bottom edge - trigger offset
1110 // | | | | |
1111 // | | | | | * Mouse activation area *
1112 // | | | | |
1113 // | +----------------------- Last child -+ | | <-- Bottom edge (last child)
1114 // +----------------------------------------+ \--
1115 //
1116 function triggerEditable( that ) {
1117 that.debug.groupStart( 'triggerEditable' ); // %REMOVE_LINE%
1118
1119 var editable = that.editable,
1120 mouse = that.mouse,
1121 view = that.view,
1122 triggerOffset = that.triggerOffset,
1123 triggerLook;
1124
1125 // Update editable dimensions.
1126 updateEditableSize( that );
1127
1128 // This flag determines whether checking bottom trigger.
1129 var bottomTrigger = mouse.y > (
1130 that.inInlineMode ? (
1131 view.editable.top + view.editable.height / 2
1132 ) : (
1133 // This is to handle case when editable.height / 2 <<< pane.height.
1134 Math.min( view.editable.height, view.pane.height ) / 2
1135 )
1136 ),
1137
1138 // Edge node according to bottomTrigger.
1139 edgeNode = editable[ bottomTrigger ? 'getLast' : 'getFirst' ]( function( node ) {
1140 return !( isEmptyTextNode( node ) || isComment( node ) );
1141 } );
1142
1143 // There's no edge node. Abort.
1144 if ( !edgeNode ) {
1145 that.debug.logEnd( 'ABORT. No edge node found.' ); // %REMOVE_LINE%
1146 return null;
1147 }
1148
1149 // If the edgeNode in editable is ML, get the next one.
1150 if ( isLine( that, edgeNode ) ) {
1151 edgeNode = that.line.wrap[ bottomTrigger ? 'getPrevious' : 'getNext' ]( function( node ) {
1152 return !( isEmptyTextNode( node ) || isComment( node ) );
1153 } );
1154 }
1155
1156 // Exclude bad nodes (no ML needed then):
1157 // \-> Edge node is text.
1158 // \-> Edge node is floated, etc.
1159 //
1160 // Edge node *must be* a valid trigger at this stage as well.
1161 if ( !isHtml( edgeNode ) || isFlowBreaker( edgeNode ) || !isTrigger( that, edgeNode ) ) {
1162 that.debug.logEnd( 'ABORT. Invalid edge node.' ); // %REMOVE_LINE%
1163 return null;
1164 }
1165
1166 // Update size of edge node. Dimensions will be necessary.
1167 updateSize( that, edgeNode );
1168
1169 // Return appropriate trigger according to bottomTrigger.
1170 // \-> Top edge trigger case first.
1171 if ( !bottomTrigger && // Top trigger case.
1172 edgeNode.size.top >= 0 && // Check if the first element is fully visible.
1173 inBetween( mouse.y, 0, edgeNode.size.top + triggerOffset ) ) { // Check if mouse in [0, edgeNode.top + triggerOffset].
1174
1175 // Determine trigger look.
1176 triggerLook = that.inInlineMode || view.scroll.y === 0 ?
1177 LOOK_TOP : LOOK_NORMAL;
1178
1179 that.debug.logEnd( 'SUCCESS. Created box trigger. EDGE_TOP.' ); // %REMOVE_LINE%
1180
1181 return new boxTrigger( [ null, edgeNode,
1182 EDGE_TOP,
1183 TYPE_EDGE,
1184 triggerLook
1185 ] );
1186 }
1187
1188 // \-> Bottom case.
1189 else if ( bottomTrigger &&
1190 edgeNode.size.bottom <= view.pane.height && // Check if the last element is fully visible
1191 inBetween( mouse.y, // Check if mouse in...
1192 edgeNode.size.bottom - triggerOffset, view.pane.height ) ) { // [ edgeNode.bottom - triggerOffset, paneHeight ]
1193
1194 // Determine trigger look.
1195 triggerLook = that.inInlineMode ||
1196 inBetween( edgeNode.size.bottom, view.pane.height - triggerOffset, view.pane.height ) ?
1197 LOOK_BOTTOM : LOOK_NORMAL;
1198
1199 that.debug.logEnd( 'SUCCESS. Created box trigger. EDGE_BOTTOM.' ); // %REMOVE_LINE%
1200
1201 return new boxTrigger( [ edgeNode, null,
1202 EDGE_BOTTOM,
1203 TYPE_EDGE,
1204 triggerLook
1205 ] );
1206 }
1207
1208 that.debug.logEnd( 'ABORT. No trigger created.' ); // %REMOVE_LINE%
1209 return null;
1210 }
1211
1212 // This method covers cases *inside* of an element:
1213 // \-> The pointer is in the top (bottom) area of an element and there's
1214 // HTML node before (after) this element.
1215 // \-> An element being the first or last child of its parent.
1216 //
1217 // +----------------------- Parent element -+
1218 // | +----------------------- Element #1 -+ | /--
1219 // | | | | | * Mouse activation area (as first child) *
1220 // | | | | \--
1221 // | | | | /--
1222 // | | | | | * Mouse activation area (Element #2) *
1223 // | +------------------------------------+ | \--
1224 // | |
1225 // | +----------------------- Element #2 -+ | /--
1226 // | | | | | * Mouse activation area (Element #1) *
1227 // | | | | \--
1228 // | | | |
1229 // | +------------------------------------+ |
1230 // | |
1231 // | Text node is here. |
1232 // | |
1233 // | +----------------------- Element #3 -+ |
1234 // | | | |
1235 // | | | |
1236 // | | | | /--
1237 // | | | | | * Mouse activation area (as last child) *
1238 // | +------------------------------------+ | \--
1239 // +----------------------------------------+
1240 //
1241 function triggerEdge( that ) {
1242 that.debug.groupStart( 'triggerEdge' ); // %REMOVE_LINE%
1243
1244 var mouse = that.mouse,
1245 view = that.view,
1246 triggerOffset = that.triggerOffset;
1247
1248 // Get the ascendant trigger basing on elementFromMouse.
1249 var element = getAscendantTrigger( that );
1250
1251 that.debug.logElements( [ element ], [ 'Ascendant trigger' ], 'First stage' ); // %REMOVE_LINE%
1252
1253 // Abort if there's no appropriate element.
1254 if ( !element ) {
1255 that.debug.logEnd( 'ABORT. No element, element is editable or element contains editable.' ); // %REMOVE_LINE%
1256 return null;
1257 }
1258
1259 // Dimensions will be necessary.
1260 updateSize( that, element );
1261
1262 // If triggerOffset is larger than a half of element's height,
1263 // use an offset of 1/2 of element's height. If the offset wasn't reduced,
1264 // top area would cover most (all) cases.
1265 var fixedOffset = Math.min( triggerOffset,
1266 0 | ( element.size.outerHeight / 2 ) ),
1267
1268 // This variable will hold the trigger to be returned.
1269 triggerSetup = [],
1270 triggerLook,
1271
1272 // This flag determines whether dealing with a bottom trigger.
1273 bottomTrigger;
1274
1275 // \-> Top trigger.
1276 if ( inBetween( mouse.y, element.size.top - 1, element.size.top + fixedOffset ) )
1277 bottomTrigger = false;
1278 // \-> Bottom trigger.
1279 else if ( inBetween( mouse.y, element.size.bottom - fixedOffset, element.size.bottom + 1 ) )
1280 bottomTrigger = true;
1281 // \-> Abort. Not in a valid trigger space.
1282 else {
1283 that.debug.logEnd( 'ABORT. Not around of any edge.' ); // %REMOVE_LINE%
1284 return null;
1285 }
1286
1287 // Reject wrong elements.
1288 // \-> Reject an element which is a flow breaker.
1289 // \-> Reject an element which has a child above/below the mouse pointer.
1290 // \-> Reject an element which belongs to list items.
1291 if (
1292 isFlowBreaker( element ) ||
1293 isChildBetweenPointerAndEdge( that, element, bottomTrigger ) ||
1294 element.getParent().is( DTD_LISTITEM )
1295 ) {
1296 that.debug.logEnd( 'ABORT. element is wrong', element ); // %REMOVE_LINE%
1297 return null;
1298 }
1299
1300 // Get sibling according to bottomTrigger.
1301 var elementSibling = getNonEmptyNeighbour( that, element, !bottomTrigger );
1302
1303 // No sibling element.
1304 // This is a first or last child case.
1305 if ( !elementSibling ) {
1306 // No need to reject the element as it has already been done before.
1307 // Prepare a trigger.
1308
1309 // Determine trigger look.
1310 if ( element.equals( that.editable[ bottomTrigger ? 'getLast' : 'getFirst' ]( that.isRelevant ) ) ) {
1311 updateEditableSize( that );
1312
1313 if (
1314 bottomTrigger && inBetween( mouse.y,
1315 element.size.bottom - fixedOffset, view.pane.height ) &&
1316 inBetween( element.size.bottom, view.pane.height - fixedOffset, view.pane.height )
1317 ) {
1318 triggerLook = LOOK_BOTTOM;
1319 } else if ( inBetween( mouse.y, 0, element.size.top + fixedOffset ) ) {
1320 triggerLook = LOOK_TOP;
1321 }
1322 } else {
1323 triggerLook = LOOK_NORMAL;
1324 }
1325
1326 triggerSetup = [ null, element ][ bottomTrigger ? 'reverse' : 'concat' ]().concat( [
1327 bottomTrigger ? EDGE_BOTTOM : EDGE_TOP,
1328 TYPE_EDGE,
1329 triggerLook,
1330 element.equals( that.editable[ bottomTrigger ? 'getLast' : 'getFirst' ]( that.isRelevant ) ) ?
1331 ( bottomTrigger ? LOOK_BOTTOM : LOOK_TOP ) : LOOK_NORMAL
1332 ] );
1333
1334 that.debug.log( 'Configured edge trigger of ' + ( bottomTrigger ? 'EDGE_BOTTOM' : 'EDGE_TOP' ) ); // %REMOVE_LINE%
1335 }
1336
1337 // Abort. Sibling is a text element.
1338 else if ( isTextNode( elementSibling ) ) {
1339 that.debug.logEnd( 'ABORT. Sibling is non-empty text element' ); // %REMOVE_LINE%
1340 return null;
1341 }
1342
1343 // Check if the sibling is a HTML element.
1344 // If so, create an TYPE_EDGE, EDGE_MIDDLE trigger.
1345 else if ( isHtml( elementSibling ) ) {
1346 // Reject wrong elementSiblings.
1347 // \-> Reject an elementSibling which is a flow breaker.
1348 // \-> Reject an elementSibling which isn't a trigger.
1349 // \-> Reject an elementSibling which belongs to list items.
1350 if (
1351 isFlowBreaker( elementSibling ) ||
1352 !isTrigger( that, elementSibling ) ||
1353 elementSibling.getParent().is( DTD_LISTITEM )
1354 ) {
1355 that.debug.logEnd( 'ABORT. elementSibling is wrong', elementSibling ); // %REMOVE_LINE%
1356 return null;
1357 }
1358
1359 // Prepare a trigger.
1360 triggerSetup = [ elementSibling, element ][ bottomTrigger ? 'reverse' : 'concat' ]().concat( [
1361 EDGE_MIDDLE,
1362 TYPE_EDGE
1363 ] );
1364
1365 that.debug.log( 'Configured edge trigger of EDGE_MIDDLE' ); // %REMOVE_LINE%
1366 }
1367
1368 if ( 0 in triggerSetup ) {
1369 that.debug.logEnd( 'SUCCESS. Returning a trigger.' ); // %REMOVE_LINE%
1370 return new boxTrigger( triggerSetup );
1371 }
1372
1373 that.debug.logEnd( 'ABORT. No trigger generated.' ); // %REMOVE_LINE%
1374 return null;
1375 }
1376
1377 // Checks iteratively up and down in search for elements using elementFromMouse method.
1378 // Useful if between two triggers.
1379 //
1380 // +----------------------- Parent element -+
1381 // | +----------------------- Element #1 -+ |
1382 // | | | |
1383 // | | | |
1384 // | | | |
1385 // | +------------------------------------+ |
1386 // | | /--
1387 // | . | |
1388 // | . +-- Floated -+ | |
1389 // | | | | | | * Mouse activation area *
1390 // | | | IGNORE | | |
1391 // | X | | | | Method searches vertically for sibling elements.
1392 // | | +------------+ | | Start point is X (mouse-y coordinate).
1393 // | | | | Floated elements, comments and empty text nodes are omitted.
1394 // | . | |
1395 // | . | |
1396 // | | \--
1397 // | +----------------------- Element #2 -+ |
1398 // | | | |
1399 // | | | |
1400 // | | | |
1401 // | | | |
1402 // | +------------------------------------+ |
1403 // +----------------------------------------+
1404 //
1405 var triggerExpand = ( function() {
1406 // The heart of the procedure. This method creates triggers that are
1407 // filtered by expandFilter method.
1408 function expandEngine( that ) {
1409 that.debug.groupStart( 'expandEngine' ); // %REMOVE_LINE%
1410
1411 var startElement = that.element,
1412 upper, lower, trigger;
1413
1414 if ( !isHtml( startElement ) || startElement.contains( that.editable ) ) {
1415 that.debug.logEnd( 'ABORT. No start element, or start element contains editable.' ); // %REMOVE_LINE%
1416 return null;
1417 }
1418
1419 // Stop searching if element is in non-editable branch of DOM.
1420 if ( startElement.isReadOnly() )
1421 return null;
1422
1423 trigger = verticalSearch( that,
1424 function( current, startElement ) {
1425 return !startElement.equals( current ); // stop when start element and the current one differ
1426 }, function( that, mouse ) {
1427 return elementFromMouse( that, true, mouse );
1428 }, startElement ),
1429
1430 upper = trigger.upper,
1431 lower = trigger.lower;
1432
1433 that.debug.logElements( [ upper, lower ], [ 'Upper', 'Lower' ], 'Pair found' ); // %REMOVE_LINE%
1434
1435 // Success: two siblings have been found
1436 if ( areSiblings( that, upper, lower ) ) {
1437 that.debug.logEnd( 'SUCCESS. Expand trigger created.' ); // %REMOVE_LINE%
1438 return trigger.set( EDGE_MIDDLE, TYPE_EXPAND );
1439 }
1440
1441 that.debug.logElements( [ startElement, upper, lower ], // %REMOVE_LINE%
1442 [ 'Start', 'Upper', 'Lower' ], 'Post-processing' ); // %REMOVE_LINE%
1443
1444 // Danger. Dragons ahead.
1445 // No siblings have been found during previous phase, post-processing may be necessary.
1446 // We can traverse DOM until a valid pair of elements around the pointer is found.
1447
1448 // Prepare for post-processing:
1449 // 1. Determine if upper and lower are children of startElement.
1450 // 1.1. If so, find their ascendants that are closest to startElement (one level deeper than startElement).
1451 // 1.2. Otherwise use first/last-child of the startElement as upper/lower. Why?:
1452 // a) upper/lower belongs to another branch of the DOM tree.
1453 // b) verticalSearch encountered an edge of the viewport and failed.
1454 // 1.3. Make sure upper and lower still exist. Why?:
1455 // a) Upper and lower may be not belong to the branch of the startElement (may not exist at all) and
1456 // startElement has no children.
1457 // 2. Perform the post-processing.
1458 // 2.1. Gather dimensions of an upper element.
1459 // 2.2. Abort if lower edge of upper is already under the mouse pointer. Why?:
1460 // a) We expect upper to be above and lower below the mouse pointer.
1461 // 3. Perform iterative search while upper != lower.
1462 // 3.1. Find the upper-next element. If there's no such element, break current search. Why?:
1463 // a) There's no point in further search if there are only text nodes ahead.
1464 // 3.2. Calculate the distance between the middle point of ( upper, upperNext ) and mouse-y.
1465 // 3.3. If the distance is shorter than the previous best, save it (save upper, upperNext as well).
1466 // 3.4. If the optimal pair is found, assign it back to the trigger.
1467
1468 // 1.1., 1.2.
1469 if ( upper && startElement.contains( upper ) ) {
1470 while ( !upper.getParent().equals( startElement ) )
1471 upper = upper.getParent();
1472 } else {
1473 upper = startElement.getFirst( function( node ) {
1474 return expandSelector( that, node );
1475 } );
1476 }
1477
1478 if ( lower && startElement.contains( lower ) ) {
1479 while ( !lower.getParent().equals( startElement ) )
1480 lower = lower.getParent();
1481 } else {
1482 lower = startElement.getLast( function( node ) {
1483 return expandSelector( that, node );
1484 } );
1485 }
1486
1487 // 1.3.
1488 if ( !upper || !lower ) {
1489 that.debug.logEnd( 'ABORT. There is no upper or no lower element.' ); // %REMOVE_LINE%
1490 return null;
1491 }
1492
1493 // 2.1.
1494 updateSize( that, upper );
1495 updateSize( that, lower );
1496
1497 if ( !checkMouseBetweenElements( that, upper, lower ) ) {
1498 that.debug.logEnd( 'ABORT. Mouse is already above upper or below lower.' ); // %REMOVE_LINE%
1499 return null;
1500 }
1501
1502 var minDistance = Number.MAX_VALUE,
1503 currentDistance, upperNext, minElement, minElementNext;
1504
1505 while ( lower && !lower.equals( upper ) ) {
1506 // 3.1.
1507 if ( !( upperNext = upper.getNext( that.isRelevant ) ) )
1508 break;
1509
1510 // 3.2.
1511 currentDistance = Math.abs( getMidpoint( that, upper, upperNext ) - that.mouse.y );
1512
1513 // 3.3.
1514 if ( currentDistance < minDistance ) {
1515 minDistance = currentDistance;
1516 minElement = upper;
1517 minElementNext = upperNext;
1518 }
1519
1520 upper = upperNext;
1521 updateSize( that, upper );
1522 }
1523
1524 that.debug.logElements( [ minElement, minElementNext ], // %REMOVE_LINE%
1525 [ 'Min', 'MinNext' ], 'Post-processing results' ); // %REMOVE_LINE%
1526
1527 // 3.4.
1528 if ( !minElement || !minElementNext ) {
1529 that.debug.logEnd( 'ABORT. No Min or MinNext' ); // %REMOVE_LINE%
1530 return null;
1531 }
1532
1533 if ( !checkMouseBetweenElements( that, minElement, minElementNext ) ) {
1534 that.debug.logEnd( 'ABORT. Mouse is already above minElement or below minElementNext.' ); // %REMOVE_LINE%
1535 return null;
1536 }
1537
1538 // An element of minimal distance has been found. Assign it to the trigger.
1539 trigger.upper = minElement;
1540 trigger.lower = minElementNext;
1541
1542 // Success: post-processing revealed a pair of elements.
1543 that.debug.logEnd( 'SUCCESSFUL post-processing. Trigger created.' ); // %REMOVE_LINE%
1544 return trigger.set( EDGE_MIDDLE, TYPE_EXPAND );
1545 }
1546
1547 // This is default element selector used by the engine.
1548 function expandSelector( that, node ) {
1549 return !( isTextNode( node ) ||
1550 isComment( node ) ||
1551 isFlowBreaker( node ) ||
1552 isLine( that, node ) ||
1553 ( node.type == CKEDITOR.NODE_ELEMENT && node.$ && node.is( 'br' ) ) );
1554 }
1555
1556 // This method checks whether mouse-y is between the top edge of upper
1557 // and bottom edge of lower.
1558 //
1559 // NOTE: This method assumes that updateSize has already been called
1560 // for the elements and is up-to-date.
1561 //
1562 // +---------------------------- Upper -+ /--
1563 // | | |
1564 // +------------------------------------+ |
1565 // |
1566 // ... |
1567 // |
1568 // X | * Return true for mouse-y in this range *
1569 // |
1570 // ... |
1571 // |
1572 // +---------------------------- Lower -+ |
1573 // | | |
1574 // +------------------------------------+ \--
1575 //
1576 function checkMouseBetweenElements( that, upper, lower ) {
1577 return inBetween( that.mouse.y, upper.size.top, lower.size.bottom );
1578 }
1579
1580 // A method for trigger filtering. Accepts or rejects trigger pairs
1581 // by their location in DOM etc.
1582 function expandFilter( that, trigger ) {
1583 that.debug.groupStart( 'expandFilter' ); // %REMOVE_LINE%
1584
1585 var upper = trigger.upper,
1586 lower = trigger.lower;
1587
1588 if (
1589 !upper || !lower || // NOT: EDGE_MIDDLE trigger ALWAYS has two elements.
1590 isFlowBreaker( lower ) || isFlowBreaker( upper ) || // NOT: one of the elements is floated or positioned
1591 lower.equals( upper ) || upper.equals( lower ) || // NOT: two trigger elements, one equals another.
1592 lower.contains( upper ) || upper.contains( lower )
1593 ) { // NOT: two trigger elements, one contains another.
1594 that.debug.logEnd( 'REJECTED. No upper or no lower or they contain each other.' ); // %REMOVE_LINE%
1595
1596 return false;
1597 }
1598
1599 // YES: two trigger elements, pure siblings.
1600 else if ( isTrigger( that, upper ) && isTrigger( that, lower ) && areSiblings( that, upper, lower ) ) {
1601 that.debug.logElementsEnd( [ upper, lower ], // %REMOVE_LINE%
1602 [ 'upper', 'lower' ], 'APPROVED EDGE_MIDDLE' ); // %REMOVE_LINE%
1603
1604 return true;
1605 }
1606
1607 that.debug.logElementsEnd( [ upper, lower ], // %REMOVE_LINE%
1608 [ 'upper', 'lower' ], 'Rejected unknown pair' ); // %REMOVE_LINE%
1609
1610 return false;
1611 }
1612
1613 // Simple wrapper for expandEngine and expandFilter.
1614 return function( that ) {
1615 that.debug.groupStart( 'triggerExpand' ); // %REMOVE_LINE%
1616
1617 var trigger = expandEngine( that );
1618
1619 that.debug.groupEnd(); // %REMOVE_LINE%
1620 return trigger && expandFilter( that, trigger ) ? trigger : null;
1621 };
1622 } )();
1623
1624 // Collects dimensions of an element.
1625 var sizePrefixes = [ 'top', 'left', 'right', 'bottom' ];
1626
1627 function getSize( that, element, ignoreScroll, force ) {
1628 var docPosition = element.getDocumentPosition(),
1629 border = {},
1630 margin = {},
1631 padding = {},
1632 box = {};
1633
1634 for ( var i = sizePrefixes.length; i--; ) {
1635 border[ sizePrefixes[ i ] ] = parseInt( getStyle( 'border-' + sizePrefixes[ i ] + '-width' ), 10 ) || 0;
1636 padding[ sizePrefixes[ i ] ] = parseInt( getStyle( 'padding-' + sizePrefixes[ i ] ), 10 ) || 0;
1637 margin[ sizePrefixes[ i ] ] = parseInt( getStyle( 'margin-' + sizePrefixes[ i ] ), 10 ) || 0;
1638 }
1639
1640 // updateWindowSize if forced to do so OR NOT ignoring scroll.
1641 if ( !ignoreScroll || force )
1642 updateWindowSize( that, force );
1643
1644 box.top = docPosition.y - ( ignoreScroll ? 0 : that.view.scroll.y ), box.left = docPosition.x - ( ignoreScroll ? 0 : that.view.scroll.x ),
1645
1646 // w/ borders and paddings.
1647 box.outerWidth = element.$.offsetWidth, box.outerHeight = element.$.offsetHeight,
1648
1649 // w/o borders and paddings.
1650 box.height = box.outerHeight - ( padding.top + padding.bottom + border.top + border.bottom ), box.width = box.outerWidth - ( padding.left + padding.right + border.left + border.right ),
1651
1652 box.bottom = box.top + box.outerHeight, box.right = box.left + box.outerWidth;
1653
1654 if ( that.inInlineMode ) {
1655 box.scroll = {
1656 top: element.$.scrollTop,
1657 left: element.$.scrollLeft
1658 };
1659 }
1660
1661 return extend( {
1662 border: border,
1663 padding: padding,
1664 margin: margin,
1665 ignoreScroll: ignoreScroll
1666 }, box, true );
1667
1668 function getStyle( propertyName ) {
1669 return element.getComputedStyle.call( element, propertyName );
1670 }
1671 }
1672
1673 function updateSize( that, element, ignoreScroll ) {
1674 if ( !isHtml( element ) ) // i.e. an element is hidden
1675 return ( element.size = null ); // -> reset size to make it useless for other methods
1676
1677 if ( !element.size )
1678 element.size = {};
1679
1680 // Abort if there was a similar query performed recently.
1681 // This kind of caching provides great performance improvement.
1682 else if ( element.size.ignoreScroll == ignoreScroll && element.size.date > new Date() - CACHE_TIME ) {
1683 that.debug.log( 'element.size: get from cache' ); // %REMOVE_LINE%
1684 return null;
1685 }
1686
1687 that.debug.log( 'element.size: capture' ); // %REMOVE_LINE%
1688
1689 return extend( element.size, getSize( that, element, ignoreScroll ), {
1690 date: +new Date()
1691 }, true );
1692 }
1693
1694 // Updates that.view.editable object.
1695 // This one must be called separately outside of updateWindowSize
1696 // to prevent cyclic dependency getSize<->updateWindowSize.
1697 // It calls getSize with force flag to avoid getWindowSize cache (look: getSize).
1698 function updateEditableSize( that, ignoreScroll ) {
1699 that.view.editable = getSize( that, that.editable, ignoreScroll, true );
1700 }
1701
1702 function updateWindowSize( that, force ) {
1703 if ( !that.view )
1704 that.view = {};
1705
1706 var view = that.view;
1707
1708 if ( !force && view && view.date > new Date() - CACHE_TIME ) {
1709 that.debug.log( 'win.size: get from cache' ); // %REMOVE_LINE%
1710 return;
1711 }
1712
1713 that.debug.log( 'win.size: capturing' ); // %REMOVE_LINE%
1714
1715 var win = that.win,
1716 scroll = win.getScrollPosition(),
1717 paneSize = win.getViewPaneSize();
1718
1719 extend( that.view, {
1720 scroll: {
1721 x: scroll.x,
1722 y: scroll.y,
1723 width: that.doc.$.documentElement.scrollWidth - paneSize.width,
1724 height: that.doc.$.documentElement.scrollHeight - paneSize.height
1725 },
1726 pane: {
1727 width: paneSize.width,
1728 height: paneSize.height,
1729 bottom: paneSize.height + scroll.y
1730 },
1731 date: +new Date()
1732 }, true );
1733 }
1734
1735 // This method searches document vertically using given
1736 // select criterion until stop criterion is fulfilled.
1737 function verticalSearch( that, stopCondition, selectCriterion, startElement ) {
1738 var upper = startElement,
1739 lower = startElement,
1740 mouseStep = 0,
1741 upperFound = false,
1742 lowerFound = false,
1743 viewPaneHeight = that.view.pane.height,
1744 mouse = that.mouse;
1745
1746 while ( mouse.y + mouseStep < viewPaneHeight && mouse.y - mouseStep > 0 ) {
1747 if ( !upperFound )
1748 upperFound = stopCondition( upper, startElement );
1749
1750 if ( !lowerFound )
1751 lowerFound = stopCondition( lower, startElement );
1752
1753 // Still not found...
1754 if ( !upperFound && mouse.y - mouseStep > 0 )
1755 upper = selectCriterion( that, { x: mouse.x, y: mouse.y - mouseStep } );
1756
1757 if ( !lowerFound && mouse.y + mouseStep < viewPaneHeight )
1758 lower = selectCriterion( that, { x: mouse.x, y: mouse.y + mouseStep } );
1759
1760 if ( upperFound && lowerFound )
1761 break;
1762
1763 // Instead of ++ to reduce the number of invocations by half.
1764 // It's trades off accuracy in some edge cases for improved performance.
1765 mouseStep += 2;
1766 }
1767
1768 return new boxTrigger( [ upper, lower, null, null ] );
1769 }
1770
1771} )();
1772
1773/**
1774 * Sets the default vertical distance between the edge of the element and the mouse pointer that
1775 * causes the magic line to appear. This option accepts a value in pixels, without the unit (for example:
1776 * `15` for 15 pixels).
1777 *
1778 * Read more in the [documentation](#!/guide/dev_magicline)
1779 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1780 *
1781 * // Changes the offset to 15px.
1782 * CKEDITOR.config.magicline_triggerOffset = 15;
1783 *
1784 * @cfg {Number} [magicline_triggerOffset=30]
1785 * @member CKEDITOR.config
1786 * @see CKEDITOR.config#magicline_holdDistance
1787 */
1788
1789/**
1790 * Defines the distance between the mouse pointer and the box within
1791 * which the magic line stays revealed and no other focus space is offered to be accessed.
1792 * This value is relative to {@link #magicline_triggerOffset}.
1793 *
1794 * Read more in the [documentation](#!/guide/dev_magicline)
1795 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1796 *
1797 * // Increases the distance to 80% of CKEDITOR.config.magicline_triggerOffset.
1798 * CKEDITOR.config.magicline_holdDistance = .8;
1799 *
1800 * @cfg {Number} [magicline_holdDistance=0.5]
1801 * @member CKEDITOR.config
1802 * @see CKEDITOR.config#magicline_triggerOffset
1803 */
1804
1805/**
1806 * Defines the default keystroke that accesses the closest unreachable focus space **before**
1807 * the caret (start of the selection). If there is no focus space available, the selection remains unchanged.
1808 *
1809 * Read more in the [documentation](#!/guide/dev_magicline)
1810 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1811 *
1812 * // Changes the default keystroke to "Ctrl + ,".
1813 * CKEDITOR.config.magicline_keystrokePrevious = CKEDITOR.CTRL + 188;
1814 *
1815 * @cfg {Number} [magicline_keystrokePrevious=CKEDITOR.CTRL + CKEDITOR.SHIFT + 51 (CTRL + SHIFT + 3)]
1816 * @member CKEDITOR.config
1817 */
1818CKEDITOR.config.magicline_keystrokePrevious = CKEDITOR.CTRL + CKEDITOR.SHIFT + 51; // CTRL + SHIFT + 3
1819
1820/**
1821 * Defines the default keystroke that accesses the closest unreachable focus space **after**
1822 * the caret (start of the selection). If there is no focus space available, the selection remains unchanged.
1823 *
1824 * Read more in the [documentation](#!/guide/dev_magicline)
1825 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1826 *
1827 * // Changes keystroke to "Ctrl + .".
1828 * CKEDITOR.config.magicline_keystrokeNext = CKEDITOR.CTRL + 190;
1829 *
1830 * @cfg {Number} [magicline_keystrokeNext=CKEDITOR.CTRL + CKEDITOR.SHIFT + 52 (CTRL + SHIFT + 4)]
1831 * @member CKEDITOR.config
1832 */
1833CKEDITOR.config.magicline_keystrokeNext = CKEDITOR.CTRL + CKEDITOR.SHIFT + 52; // CTRL + SHIFT + 4
1834
1835/**
1836 * Defines a list of attributes that, if assigned to some elements, prevent the magic line from being
1837 * used within these elements.
1838 *
1839 * Read more in the [documentation](#!/guide/dev_magicline)
1840 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1841 *
1842 * // Adds the "data-tabu" attribute to the magic line tabu list.
1843 * CKEDITOR.config.magicline_tabuList = [ 'data-tabu' ];
1844 *
1845 * @cfg {Number} [magicline_tabuList=[ 'data-widget-wrapper' ]]
1846 * @member CKEDITOR.config
1847 */
1848
1849/**
1850 * Defines the color of the magic line. The color may be adjusted to enhance readability.
1851 *
1852 * Read more in the [documentation](#!/guide/dev_magicline)
1853 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1854 *
1855 * // Changes magic line color to blue.
1856 * CKEDITOR.config.magicline_color = '#0000FF';
1857 *
1858 * @cfg {String} [magicline_color='#FF0000']
1859 * @member CKEDITOR.config
1860 */
1861
1862/**
1863 * Activates the special all-encompassing mode that considers all focus spaces between
1864 * {@link CKEDITOR.dtd#$block} elements as accessible by the magic line.
1865 *
1866 * Read more in the [documentation](#!/guide/dev_magicline)
1867 * and see the [SDK sample](http://sdk.ckeditor.com/samples/magicline.html).
1868 *
1869 * // Enables the greedy "put everywhere" mode.
1870 * CKEDITOR.config.magicline_everywhere = true;
1871 *
1872 * @cfg {Boolean} [magicline_everywhere=false]
1873 * @member CKEDITOR.config
1874 */
diff --git a/sources/plugins/magicline/samples/magicline.html b/sources/plugins/magicline/samples/magicline.html
new file mode 100644
index 0000000..8fff40e
--- /dev/null
+++ b/sources/plugins/magicline/samples/magicline.html
@@ -0,0 +1,209 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Using Magicline plugin &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link rel="stylesheet" href="../../../samples/old/sample.css">
12 <meta name="ckeditor-sample-name" content="Magicline plugin">
13 <meta name="ckeditor-sample-group" content="Plugins">
14 <meta name="ckeditor-sample-description" content="Using the Magicline plugin to access difficult focus spaces.">
15</head>
16<body>
17 <h1 class="samples">
18 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Using Magicline plugin
19 </h1>
20 <div class="warning deprecated">
21 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/magicline.html">brand new version in CKEditor SDK</a>.
22 </div>
23 <div class="description">
24 <p>
25 This sample shows the advantages of <strong>Magicline</strong> plugin
26 which is to enhance the editing process. Thanks to this plugin,
27 a number of difficult focus spaces which are inaccessible due to
28 browser issues can now be focused.
29 </p>
30 <p>
31 <strong>Magicline</strong> plugin shows a red line with a handler
32 which, when clicked, inserts a paragraph and allows typing. To see this,
33 focus an editor and move your mouse above the focus space you want
34 to access. The plugin is enabled by default so no additional
35 configuration is necessary.
36 </p>
37 </div>
38 <div>
39 <label for="editor1">
40 Editor 1:
41 </label>
42 <div class="description">
43 <p>
44 This editor uses a default <strong>Magicline</strong> setup.
45 </p>
46 </div>
47 <textarea cols="80" id="editor1" name="editor1" rows="10">
48 &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width: 100%; &quot;&gt;
49 &lt;tbody&gt;
50 &lt;tr&gt;
51 &lt;td&gt;This table&lt;/td&gt;
52 &lt;td&gt;is the&lt;/td&gt;
53 &lt;td&gt;very first&lt;/td&gt;
54 &lt;td&gt;element of the document.&lt;/td&gt;
55 &lt;/tr&gt;
56 &lt;tr&gt;
57 &lt;td&gt;We are still&lt;/td&gt;
58 &lt;td&gt;able to acces&lt;/td&gt;
59 &lt;td&gt;the space before it.&lt;/td&gt;
60 &lt;td&gt;
61 &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width: 100%; &quot;&gt;
62 &lt;tbody&gt;
63 &lt;tr&gt;
64 &lt;td&gt;This table is inside of a cell of another table.&lt;/td&gt;
65 &lt;/tr&gt;
66 &lt;tr&gt;
67 &lt;td&gt;We can type&amp;nbsp;either before or after it though.&lt;/td&gt;
68 &lt;/tr&gt;
69 &lt;/tbody&gt;
70 &lt;/table&gt;
71 &lt;/td&gt;
72 &lt;/tr&gt;
73 &lt;/tbody&gt;
74 &lt;/table&gt;
75
76 &lt;p&gt;Two succesive horizontal lines (&lt;tt&gt;HR&lt;/tt&gt; tags). We can access the space in between:&lt;/p&gt;
77
78 &lt;hr /&gt;
79 &lt;hr /&gt;
80 &lt;ol&gt;
81 &lt;li&gt;This numbered list...&lt;/li&gt;
82 &lt;li&gt;...is a neighbour of a horizontal line...&lt;/li&gt;
83 &lt;li&gt;...and another list.&lt;/li&gt;
84 &lt;/ol&gt;
85
86 &lt;ul&gt;
87 &lt;li&gt;We can type between the lists...&lt;/li&gt;
88 &lt;li&gt;...thanks to &lt;strong&gt;Magicline&lt;/strong&gt;.&lt;/li&gt;
89 &lt;/ul&gt;
90
91 &lt;p&gt;Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.&lt;/p&gt;
92
93 &lt;p&gt;Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.&lt;/p&gt;
94
95 &lt;p&gt;Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.&lt;/p&gt;
96
97 &lt;div style=&quot;border: 2px dashed green; background: #ddd; text-align: center;&quot;&gt;
98 &lt;p&gt;This text is wrapped in a&amp;nbsp;&lt;tt&gt;DIV&lt;/tt&gt;&amp;nbsp;element. We can type after this element though.&lt;/p&gt;
99 &lt;/div&gt;
100 </textarea>
101 <script>
102
103 // This call can be placed at any point after the
104 // <textarea>, or inside a <head><script> in a
105 // window.onload event handler.
106
107 CKEDITOR.replace( 'editor1', {
108 extraPlugins: 'magicline', // Ensure that magicline plugin, which is required for this sample, is loaded.
109 allowedContent: true // Switch off the ACF, so very complex content created to
110 // show magicline's power isn't filtered.
111 } );
112
113 </script>
114 </div>
115 <br>
116 <div>
117 <label for="editor2">
118 Editor 2:
119 </label>
120 <div class="description">
121 <p>
122 This editor is using a blue line.
123 </p>
124<pre class="samples">
125CKEDITOR.replace( 'editor2', {
126 magicline_color: 'blue'
127});</pre>
128 </div>
129 <textarea cols="80" id="editor2" name="editor2" rows="10">
130 &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width: 100%; &quot;&gt;
131 &lt;tbody&gt;
132 &lt;tr&gt;
133 &lt;td&gt;This table&lt;/td&gt;
134 &lt;td&gt;is the&lt;/td&gt;
135 &lt;td&gt;very first&lt;/td&gt;
136 &lt;td&gt;element of the document.&lt;/td&gt;
137 &lt;/tr&gt;
138 &lt;tr&gt;
139 &lt;td&gt;We are still&lt;/td&gt;
140 &lt;td&gt;able to acces&lt;/td&gt;
141 &lt;td&gt;the space before it.&lt;/td&gt;
142 &lt;td&gt;
143 &lt;table border=&quot;1&quot; cellpadding=&quot;1&quot; cellspacing=&quot;1&quot; style=&quot;width: 100%; &quot;&gt;
144 &lt;tbody&gt;
145 &lt;tr&gt;
146 &lt;td&gt;This table is inside of a cell of another table.&lt;/td&gt;
147 &lt;/tr&gt;
148 &lt;tr&gt;
149 &lt;td&gt;We can type&amp;nbsp;either before or after it though.&lt;/td&gt;
150 &lt;/tr&gt;
151 &lt;/tbody&gt;
152 &lt;/table&gt;
153 &lt;/td&gt;
154 &lt;/tr&gt;
155 &lt;/tbody&gt;
156 &lt;/table&gt;
157
158 &lt;p&gt;Two succesive horizontal lines (&lt;tt&gt;HR&lt;/tt&gt; tags). We can access the space in between:&lt;/p&gt;
159
160 &lt;hr /&gt;
161 &lt;hr /&gt;
162 &lt;ol&gt;
163 &lt;li&gt;This numbered list...&lt;/li&gt;
164 &lt;li&gt;...is a neighbour of a horizontal line...&lt;/li&gt;
165 &lt;li&gt;...and another list.&lt;/li&gt;
166 &lt;/ol&gt;
167
168 &lt;ul&gt;
169 &lt;li&gt;We can type between the lists...&lt;/li&gt;
170 &lt;li&gt;...thanks to &lt;strong&gt;Magicline&lt;/strong&gt;.&lt;/li&gt;
171 &lt;/ul&gt;
172
173 &lt;p&gt;Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.&lt;/p&gt;
174
175 &lt;p&gt;Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.&lt;/p&gt;
176
177 &lt;p&gt;Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.&lt;/p&gt;
178
179 &lt;div style=&quot;border: 2px dashed green; background: #ddd; text-align: center;&quot;&gt;
180 &lt;p&gt;This text is wrapped in a&amp;nbsp;&lt;tt&gt;DIV&lt;/tt&gt;&amp;nbsp;element. We can type after this element though.&lt;/p&gt;
181 &lt;/div&gt;
182 </textarea>
183 <script>
184
185 // This call can be placed at any point after the
186 // <textarea>, or inside a <head><script> in a
187 // window.onload event handler.
188
189 CKEDITOR.replace( 'editor2', {
190 extraPlugins: 'magicline', // Ensure that magicline plugin, which is required for this sample, is loaded.
191 magicline_color: 'blue', // Blue line
192 allowedContent: true // Switch off the ACF, so very complex content created to
193 // show magicline's power isn't filtered.
194 });
195
196 </script>
197 </div>
198 <div id="footer">
199 <hr>
200 <p>
201 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
202 </p>
203 <p id="copy">
204 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
205 Knabben. All rights reserved.
206 </p>
207 </div>
208</body>
209</html>
diff --git a/sources/plugins/maximize/icons/hidpi/maximize.png b/sources/plugins/maximize/icons/hidpi/maximize.png
new file mode 100644
index 0000000..865c582
--- /dev/null
+++ b/sources/plugins/maximize/icons/hidpi/maximize.png
Binary files differ
diff --git a/sources/plugins/maximize/icons/maximize.png b/sources/plugins/maximize/icons/maximize.png
new file mode 100644
index 0000000..ab25547
--- /dev/null
+++ b/sources/plugins/maximize/icons/maximize.png
Binary files differ
diff --git a/sources/plugins/maximize/lang/af.js b/sources/plugins/maximize/lang/af.js
new file mode 100644
index 0000000..5f17e23
--- /dev/null
+++ b/sources/plugins/maximize/lang/af.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'af', {
6 maximize: 'Maksimaliseer',
7 minimize: 'Minimaliseer'
8} );
diff --git a/sources/plugins/maximize/lang/ar.js b/sources/plugins/maximize/lang/ar.js
new file mode 100644
index 0000000..cdfb258
--- /dev/null
+++ b/sources/plugins/maximize/lang/ar.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ar', {
6 maximize: 'تكبير',
7 minimize: 'تصغير'
8} );
diff --git a/sources/plugins/maximize/lang/az.js b/sources/plugins/maximize/lang/az.js
new file mode 100644
index 0000000..d3a92ac
--- /dev/null
+++ b/sources/plugins/maximize/lang/az.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'az', {
6 maximize: 'Aşkarla',
7 minimize: 'Gizlət'
8} );
diff --git a/sources/plugins/maximize/lang/bg.js b/sources/plugins/maximize/lang/bg.js
new file mode 100644
index 0000000..a56e04e
--- /dev/null
+++ b/sources/plugins/maximize/lang/bg.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'bg', {
6 maximize: 'Максимизиране',
7 minimize: 'Минимизиране'
8} );
diff --git a/sources/plugins/maximize/lang/bn.js b/sources/plugins/maximize/lang/bn.js
new file mode 100644
index 0000000..3fd4087
--- /dev/null
+++ b/sources/plugins/maximize/lang/bn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'bn', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/bs.js b/sources/plugins/maximize/lang/bs.js
new file mode 100644
index 0000000..cb49710
--- /dev/null
+++ b/sources/plugins/maximize/lang/bs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'bs', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/ca.js b/sources/plugins/maximize/lang/ca.js
new file mode 100644
index 0000000..fc88615
--- /dev/null
+++ b/sources/plugins/maximize/lang/ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ca', {
6 maximize: 'Maximitza',
7 minimize: 'Minimitza'
8} );
diff --git a/sources/plugins/maximize/lang/cs.js b/sources/plugins/maximize/lang/cs.js
new file mode 100644
index 0000000..2234af2
--- /dev/null
+++ b/sources/plugins/maximize/lang/cs.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'cs', {
6 maximize: 'Maximalizovat',
7 minimize: 'Minimalizovat'
8} );
diff --git a/sources/plugins/maximize/lang/cy.js b/sources/plugins/maximize/lang/cy.js
new file mode 100644
index 0000000..c3370b3
--- /dev/null
+++ b/sources/plugins/maximize/lang/cy.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'cy', {
6 maximize: 'Mwyhau',
7 minimize: 'Lleihau'
8} );
diff --git a/sources/plugins/maximize/lang/da.js b/sources/plugins/maximize/lang/da.js
new file mode 100644
index 0000000..8dd2d88
--- /dev/null
+++ b/sources/plugins/maximize/lang/da.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'da', {
6 maximize: 'Maksimér',
7 minimize: 'Minimér'
8} );
diff --git a/sources/plugins/maximize/lang/de-ch.js b/sources/plugins/maximize/lang/de-ch.js
new file mode 100644
index 0000000..440814b
--- /dev/null
+++ b/sources/plugins/maximize/lang/de-ch.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'de-ch', {
6 maximize: 'Maximieren',
7 minimize: 'Minimieren'
8} );
diff --git a/sources/plugins/maximize/lang/de.js b/sources/plugins/maximize/lang/de.js
new file mode 100644
index 0000000..9af6706
--- /dev/null
+++ b/sources/plugins/maximize/lang/de.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'de', {
6 maximize: 'Maximieren',
7 minimize: 'Minimieren'
8} );
diff --git a/sources/plugins/maximize/lang/el.js b/sources/plugins/maximize/lang/el.js
new file mode 100644
index 0000000..7da1b0b
--- /dev/null
+++ b/sources/plugins/maximize/lang/el.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'el', {
6 maximize: 'Μεγιστοποίηση',
7 minimize: 'Ελαχιστοποίηση'
8} );
diff --git a/sources/plugins/maximize/lang/en-au.js b/sources/plugins/maximize/lang/en-au.js
new file mode 100644
index 0000000..de0310d
--- /dev/null
+++ b/sources/plugins/maximize/lang/en-au.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'en-au', {
6 maximize: 'Maximize',
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/en-ca.js b/sources/plugins/maximize/lang/en-ca.js
new file mode 100644
index 0000000..1c48ee0
--- /dev/null
+++ b/sources/plugins/maximize/lang/en-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'en-ca', {
6 maximize: 'Maximize',
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/en-gb.js b/sources/plugins/maximize/lang/en-gb.js
new file mode 100644
index 0000000..433a065
--- /dev/null
+++ b/sources/plugins/maximize/lang/en-gb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'en-gb', {
6 maximize: 'Maximise',
7 minimize: 'Minimise'
8} );
diff --git a/sources/plugins/maximize/lang/en.js b/sources/plugins/maximize/lang/en.js
new file mode 100644
index 0000000..1e45418
--- /dev/null
+++ b/sources/plugins/maximize/lang/en.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'en', {
6 maximize: 'Maximize',
7 minimize: 'Minimize'
8} );
diff --git a/sources/plugins/maximize/lang/eo.js b/sources/plugins/maximize/lang/eo.js
new file mode 100644
index 0000000..852f529
--- /dev/null
+++ b/sources/plugins/maximize/lang/eo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'eo', {
6 maximize: 'Pligrandigi',
7 minimize: 'Malgrandigi'
8} );
diff --git a/sources/plugins/maximize/lang/es.js b/sources/plugins/maximize/lang/es.js
new file mode 100644
index 0000000..411aae5
--- /dev/null
+++ b/sources/plugins/maximize/lang/es.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'es', {
6 maximize: 'Maximizar',
7 minimize: 'Minimizar'
8} );
diff --git a/sources/plugins/maximize/lang/et.js b/sources/plugins/maximize/lang/et.js
new file mode 100644
index 0000000..1682ec9
--- /dev/null
+++ b/sources/plugins/maximize/lang/et.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'et', {
6 maximize: 'Maksimeerimine',
7 minimize: 'Minimeerimine'
8} );
diff --git a/sources/plugins/maximize/lang/eu.js b/sources/plugins/maximize/lang/eu.js
new file mode 100644
index 0000000..a25c164
--- /dev/null
+++ b/sources/plugins/maximize/lang/eu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'eu', {
6 maximize: 'Maximizatu',
7 minimize: 'Minimizatu'
8} );
diff --git a/sources/plugins/maximize/lang/fa.js b/sources/plugins/maximize/lang/fa.js
new file mode 100644
index 0000000..e08e9ea
--- /dev/null
+++ b/sources/plugins/maximize/lang/fa.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'fa', {
6 maximize: 'بیشنه کردن',
7 minimize: 'کمینه کردن'
8} );
diff --git a/sources/plugins/maximize/lang/fi.js b/sources/plugins/maximize/lang/fi.js
new file mode 100644
index 0000000..763eede
--- /dev/null
+++ b/sources/plugins/maximize/lang/fi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'fi', {
6 maximize: 'Suurenna',
7 minimize: 'Pienennä'
8} );
diff --git a/sources/plugins/maximize/lang/fo.js b/sources/plugins/maximize/lang/fo.js
new file mode 100644
index 0000000..635415a
--- /dev/null
+++ b/sources/plugins/maximize/lang/fo.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'fo', {
6 maximize: 'Maksimera',
7 minimize: 'Minimera'
8} );
diff --git a/sources/plugins/maximize/lang/fr-ca.js b/sources/plugins/maximize/lang/fr-ca.js
new file mode 100644
index 0000000..59ed278
--- /dev/null
+++ b/sources/plugins/maximize/lang/fr-ca.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'fr-ca', {
6 maximize: 'Maximizer',
7 minimize: 'Minimizer'
8} );
diff --git a/sources/plugins/maximize/lang/fr.js b/sources/plugins/maximize/lang/fr.js
new file mode 100644
index 0000000..cb3d4dd
--- /dev/null
+++ b/sources/plugins/maximize/lang/fr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'fr', {
6 maximize: 'Agrandir',
7 minimize: 'Réduire'
8} );
diff --git a/sources/plugins/maximize/lang/gl.js b/sources/plugins/maximize/lang/gl.js
new file mode 100644
index 0000000..79009f8
--- /dev/null
+++ b/sources/plugins/maximize/lang/gl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'gl', {
6 maximize: 'Maximizar',
7 minimize: 'Minimizar'
8} );
diff --git a/sources/plugins/maximize/lang/gu.js b/sources/plugins/maximize/lang/gu.js
new file mode 100644
index 0000000..bbd4b52
--- /dev/null
+++ b/sources/plugins/maximize/lang/gu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'gu', {
6 maximize: 'મોટું કરવું',
7 minimize: 'નાનું કરવું'
8} );
diff --git a/sources/plugins/maximize/lang/he.js b/sources/plugins/maximize/lang/he.js
new file mode 100644
index 0000000..d46856b
--- /dev/null
+++ b/sources/plugins/maximize/lang/he.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'he', {
6 maximize: 'הגדלה למקסימום',
7 minimize: 'הקטנה למינימום'
8} );
diff --git a/sources/plugins/maximize/lang/hi.js b/sources/plugins/maximize/lang/hi.js
new file mode 100644
index 0000000..76b0c0c
--- /dev/null
+++ b/sources/plugins/maximize/lang/hi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'hi', {
6 maximize: 'मेक्सिमाईज़',
7 minimize: 'मिनिमाईज़'
8} );
diff --git a/sources/plugins/maximize/lang/hr.js b/sources/plugins/maximize/lang/hr.js
new file mode 100644
index 0000000..4b7a7b3
--- /dev/null
+++ b/sources/plugins/maximize/lang/hr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'hr', {
6 maximize: 'Povećaj',
7 minimize: 'Smanji'
8} );
diff --git a/sources/plugins/maximize/lang/hu.js b/sources/plugins/maximize/lang/hu.js
new file mode 100644
index 0000000..3e11e22
--- /dev/null
+++ b/sources/plugins/maximize/lang/hu.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'hu', {
6 maximize: 'Teljes méret',
7 minimize: 'Kis méret'
8} );
diff --git a/sources/plugins/maximize/lang/id.js b/sources/plugins/maximize/lang/id.js
new file mode 100644
index 0000000..1a32383
--- /dev/null
+++ b/sources/plugins/maximize/lang/id.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'id', {
6 maximize: 'Memperbesar',
7 minimize: 'Memperkecil'
8} );
diff --git a/sources/plugins/maximize/lang/is.js b/sources/plugins/maximize/lang/is.js
new file mode 100644
index 0000000..dec813f
--- /dev/null
+++ b/sources/plugins/maximize/lang/is.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'is', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/it.js b/sources/plugins/maximize/lang/it.js
new file mode 100644
index 0000000..67a8a29
--- /dev/null
+++ b/sources/plugins/maximize/lang/it.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'it', {
6 maximize: 'Massimizza',
7 minimize: 'Minimizza'
8} );
diff --git a/sources/plugins/maximize/lang/ja.js b/sources/plugins/maximize/lang/ja.js
new file mode 100644
index 0000000..33184da
--- /dev/null
+++ b/sources/plugins/maximize/lang/ja.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ja', {
6 maximize: '最大化',
7 minimize: '最小化'
8} );
diff --git a/sources/plugins/maximize/lang/ka.js b/sources/plugins/maximize/lang/ka.js
new file mode 100644
index 0000000..a90fb04
--- /dev/null
+++ b/sources/plugins/maximize/lang/ka.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ka', {
6 maximize: 'გადიდება',
7 minimize: 'დაპატარავება'
8} );
diff --git a/sources/plugins/maximize/lang/km.js b/sources/plugins/maximize/lang/km.js
new file mode 100644
index 0000000..4cda2db
--- /dev/null
+++ b/sources/plugins/maximize/lang/km.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'km', {
6 maximize: 'ពង្រីក​អតិបរមា',
7 minimize: 'បង្រួម​អប្បបរមា'
8} );
diff --git a/sources/plugins/maximize/lang/ko.js b/sources/plugins/maximize/lang/ko.js
new file mode 100644
index 0000000..f4af9d4
--- /dev/null
+++ b/sources/plugins/maximize/lang/ko.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ko', {
6 maximize: '최대화',
7 minimize: '최소화'
8} );
diff --git a/sources/plugins/maximize/lang/ku.js b/sources/plugins/maximize/lang/ku.js
new file mode 100644
index 0000000..d34e588
--- /dev/null
+++ b/sources/plugins/maximize/lang/ku.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ku', {
6 maximize: 'ئەوپەڕی گەورەیی',
7 minimize: 'ئەوپەڕی بچووکی'
8} );
diff --git a/sources/plugins/maximize/lang/lt.js b/sources/plugins/maximize/lang/lt.js
new file mode 100644
index 0000000..064291b
--- /dev/null
+++ b/sources/plugins/maximize/lang/lt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'lt', {
6 maximize: 'Išdidinti',
7 minimize: 'Sumažinti'
8} );
diff --git a/sources/plugins/maximize/lang/lv.js b/sources/plugins/maximize/lang/lv.js
new file mode 100644
index 0000000..afbbbbe
--- /dev/null
+++ b/sources/plugins/maximize/lang/lv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'lv', {
6 maximize: 'Maksimizēt',
7 minimize: 'Minimizēt'
8} );
diff --git a/sources/plugins/maximize/lang/mk.js b/sources/plugins/maximize/lang/mk.js
new file mode 100644
index 0000000..69fcfe9
--- /dev/null
+++ b/sources/plugins/maximize/lang/mk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'mk', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/mn.js b/sources/plugins/maximize/lang/mn.js
new file mode 100644
index 0000000..6c4a076
--- /dev/null
+++ b/sources/plugins/maximize/lang/mn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'mn', {
6 maximize: 'Дэлгэц дүүргэх',
7 minimize: 'Цонхыг багсгаж харуулах'
8} );
diff --git a/sources/plugins/maximize/lang/ms.js b/sources/plugins/maximize/lang/ms.js
new file mode 100644
index 0000000..0f27d91
--- /dev/null
+++ b/sources/plugins/maximize/lang/ms.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ms', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/nb.js b/sources/plugins/maximize/lang/nb.js
new file mode 100644
index 0000000..a8ec9dd
--- /dev/null
+++ b/sources/plugins/maximize/lang/nb.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'nb', {
6 maximize: 'Maksimer',
7 minimize: 'Minimer'
8} );
diff --git a/sources/plugins/maximize/lang/nl.js b/sources/plugins/maximize/lang/nl.js
new file mode 100644
index 0000000..978bda0
--- /dev/null
+++ b/sources/plugins/maximize/lang/nl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'nl', {
6 maximize: 'Maximaliseren',
7 minimize: 'Minimaliseren'
8} );
diff --git a/sources/plugins/maximize/lang/no.js b/sources/plugins/maximize/lang/no.js
new file mode 100644
index 0000000..02afe8a
--- /dev/null
+++ b/sources/plugins/maximize/lang/no.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'no', {
6 maximize: 'Maksimer',
7 minimize: 'Minimer'
8} );
diff --git a/sources/plugins/maximize/lang/oc.js b/sources/plugins/maximize/lang/oc.js
new file mode 100644
index 0000000..cbd94a4
--- /dev/null
+++ b/sources/plugins/maximize/lang/oc.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'oc', {
6 maximize: 'Maximizar',
7 minimize: 'Minimizar'
8} );
diff --git a/sources/plugins/maximize/lang/pl.js b/sources/plugins/maximize/lang/pl.js
new file mode 100644
index 0000000..1bf6d07
--- /dev/null
+++ b/sources/plugins/maximize/lang/pl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'pl', {
6 maximize: 'Maksymalizuj',
7 minimize: 'Minimalizuj'
8} );
diff --git a/sources/plugins/maximize/lang/pt-br.js b/sources/plugins/maximize/lang/pt-br.js
new file mode 100644
index 0000000..e5c2a52
--- /dev/null
+++ b/sources/plugins/maximize/lang/pt-br.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'pt-br', {
6 maximize: 'Maximizar',
7 minimize: 'Minimize'
8} );
diff --git a/sources/plugins/maximize/lang/pt.js b/sources/plugins/maximize/lang/pt.js
new file mode 100644
index 0000000..a379036
--- /dev/null
+++ b/sources/plugins/maximize/lang/pt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'pt', {
6 maximize: 'Maximizar',
7 minimize: 'Minimizar'
8} );
diff --git a/sources/plugins/maximize/lang/ro.js b/sources/plugins/maximize/lang/ro.js
new file mode 100644
index 0000000..0a3ded6
--- /dev/null
+++ b/sources/plugins/maximize/lang/ro.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ro', {
6 maximize: 'Mărește',
7 minimize: 'Micșorează'
8} );
diff --git a/sources/plugins/maximize/lang/ru.js b/sources/plugins/maximize/lang/ru.js
new file mode 100644
index 0000000..30c491a
--- /dev/null
+++ b/sources/plugins/maximize/lang/ru.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ru', {
6 maximize: 'Развернуть',
7 minimize: 'Свернуть'
8} );
diff --git a/sources/plugins/maximize/lang/si.js b/sources/plugins/maximize/lang/si.js
new file mode 100644
index 0000000..a0331ab
--- /dev/null
+++ b/sources/plugins/maximize/lang/si.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'si', {
6 maximize: 'විශාල කිරීම',
7 minimize: 'කුඩා කිරීම'
8} );
diff --git a/sources/plugins/maximize/lang/sk.js b/sources/plugins/maximize/lang/sk.js
new file mode 100644
index 0000000..a9f2515
--- /dev/null
+++ b/sources/plugins/maximize/lang/sk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sk', {
6 maximize: 'Maximalizovať',
7 minimize: 'Minimalizovať'
8} );
diff --git a/sources/plugins/maximize/lang/sl.js b/sources/plugins/maximize/lang/sl.js
new file mode 100644
index 0000000..73d5e91
--- /dev/null
+++ b/sources/plugins/maximize/lang/sl.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sl', {
6 maximize: 'Maksimiraj',
7 minimize: 'Minimiraj'
8} );
diff --git a/sources/plugins/maximize/lang/sq.js b/sources/plugins/maximize/lang/sq.js
new file mode 100644
index 0000000..e6b5bc3
--- /dev/null
+++ b/sources/plugins/maximize/lang/sq.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sq', {
6 maximize: 'Zmadho',
7 minimize: 'Zvogëlo'
8} );
diff --git a/sources/plugins/maximize/lang/sr-latn.js b/sources/plugins/maximize/lang/sr-latn.js
new file mode 100644
index 0000000..33dcd9e
--- /dev/null
+++ b/sources/plugins/maximize/lang/sr-latn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sr-latn', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/sr.js b/sources/plugins/maximize/lang/sr.js
new file mode 100644
index 0000000..f1ef2d1
--- /dev/null
+++ b/sources/plugins/maximize/lang/sr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sr', {
6 maximize: 'Maximize', // MISSING
7 minimize: 'Minimize' // MISSING
8} );
diff --git a/sources/plugins/maximize/lang/sv.js b/sources/plugins/maximize/lang/sv.js
new file mode 100644
index 0000000..d14fb84
--- /dev/null
+++ b/sources/plugins/maximize/lang/sv.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'sv', {
6 maximize: 'Maximera',
7 minimize: 'Minimera'
8} );
diff --git a/sources/plugins/maximize/lang/th.js b/sources/plugins/maximize/lang/th.js
new file mode 100644
index 0000000..df09eef
--- /dev/null
+++ b/sources/plugins/maximize/lang/th.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'th', {
6 maximize: 'ขยายใหญ่',
7 minimize: 'ย่อขนาด'
8} );
diff --git a/sources/plugins/maximize/lang/tr.js b/sources/plugins/maximize/lang/tr.js
new file mode 100644
index 0000000..90724f4
--- /dev/null
+++ b/sources/plugins/maximize/lang/tr.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'tr', {
6 maximize: 'Büyült',
7 minimize: 'Küçült'
8} );
diff --git a/sources/plugins/maximize/lang/tt.js b/sources/plugins/maximize/lang/tt.js
new file mode 100644
index 0000000..cc92021
--- /dev/null
+++ b/sources/plugins/maximize/lang/tt.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'tt', {
6 maximize: 'Зурайту',
7 minimize: 'Кечерәйтү'
8} );
diff --git a/sources/plugins/maximize/lang/ug.js b/sources/plugins/maximize/lang/ug.js
new file mode 100644
index 0000000..85af046
--- /dev/null
+++ b/sources/plugins/maximize/lang/ug.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'ug', {
6 maximize: 'چوڭايت',
7 minimize: 'كىچىكلەت'
8} );
diff --git a/sources/plugins/maximize/lang/uk.js b/sources/plugins/maximize/lang/uk.js
new file mode 100644
index 0000000..5ca1021
--- /dev/null
+++ b/sources/plugins/maximize/lang/uk.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'uk', {
6 maximize: 'Максимізувати',
7 minimize: 'Мінімізувати'
8} );
diff --git a/sources/plugins/maximize/lang/vi.js b/sources/plugins/maximize/lang/vi.js
new file mode 100644
index 0000000..4ab3a6b
--- /dev/null
+++ b/sources/plugins/maximize/lang/vi.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'vi', {
6 maximize: 'Phóng to tối đa',
7 minimize: 'Thu nhỏ'
8} );
diff --git a/sources/plugins/maximize/lang/zh-cn.js b/sources/plugins/maximize/lang/zh-cn.js
new file mode 100644
index 0000000..f4ddf72
--- /dev/null
+++ b/sources/plugins/maximize/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'zh-cn', {
6 maximize: '全屏',
7 minimize: '最小化'
8} );
diff --git a/sources/plugins/maximize/lang/zh.js b/sources/plugins/maximize/lang/zh.js
new file mode 100644
index 0000000..6bca434
--- /dev/null
+++ b/sources/plugins/maximize/lang/zh.js
@@ -0,0 +1,8 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'maximize', 'zh', {
6 maximize: '最大化',
7 minimize: '最小化'
8} );
diff --git a/sources/plugins/maximize/plugin.js b/sources/plugins/maximize/plugin.js
new file mode 100644
index 0000000..16967a0
--- /dev/null
+++ b/sources/plugins/maximize/plugin.js
@@ -0,0 +1,314 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 function protectFormStyles( formElement ) {
8 if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != 'form' )
9 return [];
10
11 var hijackRecord = [],
12 hijackNames = [ 'style', 'className' ];
13 for ( var i = 0; i < hijackNames.length; i++ ) {
14 var name = hijackNames[ i ];
15 var $node = formElement.$.elements.namedItem( name );
16 if ( $node ) {
17 var hijackNode = new CKEDITOR.dom.element( $node );
18 hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] );
19 hijackNode.remove();
20 }
21 }
22
23 return hijackRecord;
24 }
25
26 function restoreFormStyles( formElement, hijackRecord ) {
27 if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != 'form' )
28 return;
29
30 if ( hijackRecord.length > 0 ) {
31 for ( var i = hijackRecord.length - 1; i >= 0; i-- ) {
32 var node = hijackRecord[ i ][ 0 ];
33 var sibling = hijackRecord[ i ][ 1 ];
34 if ( sibling )
35 node.insertBefore( sibling );
36 else
37 node.appendTo( formElement );
38 }
39 }
40 }
41
42 function saveStyles( element, isInsideEditor ) {
43 var data = protectFormStyles( element );
44 var retval = {};
45
46 var $element = element.$;
47
48 if ( !isInsideEditor ) {
49 retval[ 'class' ] = $element.className || '';
50 $element.className = '';
51 }
52
53 retval.inline = $element.style.cssText || '';
54 if ( !isInsideEditor ) // Reset any external styles that might interfere. (#2474)
55 $element.style.cssText = 'position: static; overflow: visible';
56
57 restoreFormStyles( data );
58 return retval;
59 }
60
61 function restoreStyles( element, savedStyles ) {
62 var data = protectFormStyles( element );
63 var $element = element.$;
64 if ( 'class' in savedStyles )
65 $element.className = savedStyles[ 'class' ];
66 if ( 'inline' in savedStyles )
67 $element.style.cssText = savedStyles.inline;
68 restoreFormStyles( data );
69 }
70
71 function refreshCursor( editor ) {
72 if ( editor.editable().isInline() )
73 return;
74
75 // Refresh all editor instances on the page (#5724).
76 var all = CKEDITOR.instances;
77 for ( var i in all ) {
78 var one = all[ i ];
79 if ( one.mode == 'wysiwyg' && !one.readOnly ) {
80 var body = one.document.getBody();
81 // Refresh 'contentEditable' otherwise
82 // DOM lifting breaks design mode. (#5560)
83 body.setAttribute( 'contentEditable', false );
84 body.setAttribute( 'contentEditable', true );
85 }
86 }
87
88 if ( editor.editable().hasFocus ) {
89 editor.toolbox.focus();
90 editor.focus();
91 }
92 }
93
94 CKEDITOR.plugins.add( 'maximize', {
95 // jscs:disable maximumLineLength
96 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
97 // jscs:enable maximumLineLength
98 icons: 'maximize', // %REMOVE_LINE_CORE%
99 hidpi: true, // %REMOVE_LINE_CORE%
100 init: function( editor ) {
101 // Maximize plugin isn't available in inline mode yet.
102 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE )
103 return;
104
105 var lang = editor.lang;
106 var mainDocument = CKEDITOR.document,
107 mainWindow = mainDocument.getWindow();
108
109 // Saved selection and scroll position for the editing area.
110 var savedSelection, savedScroll;
111
112 // Saved scroll position for the outer window.
113 var outerScroll;
114
115 // Saved resize handler function.
116 function resizeHandler() {
117 var viewPaneSize = mainWindow.getViewPaneSize();
118 editor.resize( viewPaneSize.width, viewPaneSize.height, null, true );
119 }
120
121 // Retain state after mode switches.
122 var savedState = CKEDITOR.TRISTATE_OFF;
123
124 editor.addCommand( 'maximize', {
125 // Disabled on iOS (#8307).
126 modes: { wysiwyg: !CKEDITOR.env.iOS, source: !CKEDITOR.env.iOS },
127 readOnly: 1,
128 editorFocus: false,
129 exec: function() {
130 var container = editor.container.getFirst( function( node ) {
131 return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_inner' );
132 } );
133 var contents = editor.ui.space( 'contents' );
134
135 // Save current selection and scroll position in editing area.
136 if ( editor.mode == 'wysiwyg' ) {
137 var selection = editor.getSelection();
138 savedSelection = selection && selection.getRanges();
139 savedScroll = mainWindow.getScrollPosition();
140 } else {
141 var $textarea = editor.editable().$;
142 savedSelection = !CKEDITOR.env.ie && [ $textarea.selectionStart, $textarea.selectionEnd ];
143 savedScroll = [ $textarea.scrollLeft, $textarea.scrollTop ];
144 }
145
146 // Go fullscreen if the state is off.
147 if ( this.state == CKEDITOR.TRISTATE_OFF ) {
148 // Add event handler for resizing.
149 mainWindow.on( 'resize', resizeHandler );
150
151 // Save the scroll bar position.
152 outerScroll = mainWindow.getScrollPosition();
153
154 // Save and reset the styles for the entire node tree.
155 var currentNode = editor.container;
156 while ( ( currentNode = currentNode.getParent() ) ) {
157 currentNode.setCustomData( 'maximize_saved_styles', saveStyles( currentNode ) );
158 // Show under floatpanels (-1) and context menu (-2).
159 currentNode.setStyle( 'z-index', editor.config.baseFloatZIndex - 5 );
160 }
161 contents.setCustomData( 'maximize_saved_styles', saveStyles( contents, true ) );
162 container.setCustomData( 'maximize_saved_styles', saveStyles( container, true ) );
163
164 // Hide scroll bars.
165 var styles = {
166 overflow: CKEDITOR.env.webkit ? '' : 'hidden', // #6896
167 width: 0,
168 height: 0
169 };
170
171 mainDocument.getDocumentElement().setStyles( styles );
172 !CKEDITOR.env.gecko && mainDocument.getDocumentElement().setStyle( 'position', 'fixed' );
173 !( CKEDITOR.env.gecko && CKEDITOR.env.quirks ) && mainDocument.getBody().setStyles( styles );
174
175 // Scroll to the top left (IE needs some time for it - #4923).
176 CKEDITOR.env.ie ? setTimeout( function() {
177 mainWindow.$.scrollTo( 0, 0 );
178 }, 0 ) : mainWindow.$.scrollTo( 0, 0 );
179
180 // Resize and move to top left.
181 // Special treatment for FF Quirks (#7284)
182 container.setStyle( 'position', CKEDITOR.env.gecko && CKEDITOR.env.quirks ? 'fixed' : 'absolute' );
183 container.$.offsetLeft; // SAFARI BUG: See #2066.
184 container.setStyles( {
185 // Show under floatpanels (-1) and context menu (-2).
186 'z-index': editor.config.baseFloatZIndex - 5,
187 left: '0px',
188 top: '0px'
189 } );
190
191 // Add cke_maximized class before resize handle since that will change things sizes (#5580)
192 container.addClass( 'cke_maximized' );
193
194 resizeHandler();
195
196 // Still not top left? Fix it. (Bug #174)
197 var offset = container.getDocumentPosition();
198 container.setStyles( {
199 left: ( -1 * offset.x ) + 'px',
200 top: ( -1 * offset.y ) + 'px'
201 } );
202
203 // Fixing positioning editor chrome in Firefox break design mode. (#5149)
204 CKEDITOR.env.gecko && refreshCursor( editor );
205 }
206 // Restore from fullscreen if the state is on.
207 else if ( this.state == CKEDITOR.TRISTATE_ON ) {
208 // Remove event handler for resizing.
209 mainWindow.removeListener( 'resize', resizeHandler );
210
211 // Restore CSS styles for the entire node tree.
212 var editorElements = [ contents, container ];
213 for ( var i = 0; i < editorElements.length; i++ ) {
214 restoreStyles( editorElements[ i ], editorElements[ i ].getCustomData( 'maximize_saved_styles' ) );
215 editorElements[ i ].removeCustomData( 'maximize_saved_styles' );
216 }
217
218 currentNode = editor.container;
219 while ( ( currentNode = currentNode.getParent() ) ) {
220 restoreStyles( currentNode, currentNode.getCustomData( 'maximize_saved_styles' ) );
221 currentNode.removeCustomData( 'maximize_saved_styles' );
222 }
223
224 // Restore the window scroll position.
225 CKEDITOR.env.ie ? setTimeout( function() {
226 mainWindow.$.scrollTo( outerScroll.x, outerScroll.y );
227 }, 0 ) : mainWindow.$.scrollTo( outerScroll.x, outerScroll.y );
228
229 // Remove cke_maximized class.
230 container.removeClass( 'cke_maximized' );
231
232 // Webkit requires a re-layout on editor chrome. (#6695)
233 if ( CKEDITOR.env.webkit ) {
234 container.setStyle( 'display', 'inline' );
235 setTimeout( function() {
236 container.setStyle( 'display', 'block' );
237 }, 0 );
238 }
239
240 // Emit a resize event, because this time the size is modified in
241 // restoreStyles.
242 editor.fire( 'resize', {
243 outerHeight: editor.container.$.offsetHeight,
244 contentsHeight: contents.$.offsetHeight,
245 outerWidth: editor.container.$.offsetWidth
246 } );
247 }
248
249 this.toggleState();
250
251 // Toggle button label.
252 var button = this.uiItems[ 0 ];
253 // Only try to change the button if it exists (#6166)
254 if ( button ) {
255 var label = ( this.state == CKEDITOR.TRISTATE_OFF ) ? lang.maximize.maximize : lang.maximize.minimize;
256 var buttonNode = CKEDITOR.document.getById( button._.id );
257 buttonNode.getChild( 1 ).setHtml( label );
258 buttonNode.setAttribute( 'title', label );
259 buttonNode.setAttribute( 'href', 'javascript:void("' + label + '");' ); // jshint ignore:line
260 }
261
262 // Restore selection and scroll position in editing area.
263 if ( editor.mode == 'wysiwyg' ) {
264 if ( savedSelection ) {
265 // Fixing positioning editor chrome in Firefox break design mode. (#5149)
266 CKEDITOR.env.gecko && refreshCursor( editor );
267
268 editor.getSelection().selectRanges( savedSelection );
269 var element = editor.getSelection().getStartElement();
270 element && element.scrollIntoView( true );
271 } else {
272 mainWindow.$.scrollTo( savedScroll.x, savedScroll.y );
273 }
274 } else {
275 if ( savedSelection ) {
276 $textarea.selectionStart = savedSelection[ 0 ];
277 $textarea.selectionEnd = savedSelection[ 1 ];
278 }
279 $textarea.scrollLeft = savedScroll[ 0 ];
280 $textarea.scrollTop = savedScroll[ 1 ];
281 }
282
283 savedSelection = savedScroll = null;
284 savedState = this.state;
285
286 editor.fire( 'maximize', this.state );
287 },
288 canUndo: false
289 } );
290
291 editor.ui.addButton && editor.ui.addButton( 'Maximize', {
292 label: lang.maximize.maximize,
293 command: 'maximize',
294 toolbar: 'tools,10'
295 } );
296
297 // Restore the command state after mode change, unless it has been changed to disabled (#6467)
298 editor.on( 'mode', function() {
299 var command = editor.getCommand( 'maximize' );
300 command.setState( command.state == CKEDITOR.TRISTATE_DISABLED ? CKEDITOR.TRISTATE_DISABLED : savedState );
301 }, null, null, 100 );
302 }
303 } );
304} )();
305
306/**
307 * Event fired when the maximize command is called.
308 * It also indicates whether an editor is maximized or not.
309 *
310 * @event maximize
311 * @member CKEDITOR.editor
312 * @param {CKEDITOR.editor} editor This editor instance.
313 * @param {Number} data Current state of the command. See {@link CKEDITOR#TRISTATE_ON} and {@link CKEDITOR#TRISTATE_OFF}.
314 */
diff --git a/sources/plugins/menu/plugin.js b/sources/plugins/menu/plugin.js
new file mode 100644
index 0000000..1312a62
--- /dev/null
+++ b/sources/plugins/menu/plugin.js
@@ -0,0 +1,572 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'menu', {
7 requires: 'floatpanel',
8
9 beforeInit: function( editor ) {
10 var groups = editor.config.menu_groups.split( ',' ),
11 groupsOrder = editor._.menuGroups = {},
12 menuItems = editor._.menuItems = {};
13
14 for ( var i = 0; i < groups.length; i++ )
15 groupsOrder[ groups[ i ] ] = i + 1;
16
17 /**
18 * Registers an item group to the editor context menu in order to make it
19 * possible to associate it with menu items later.
20 *
21 * @param {String} name Specify a group name.
22 * @param {Number} [order=100] Define the display sequence of this group
23 * inside the menu. A smaller value gets displayed first.
24 * @member CKEDITOR.editor
25 */
26 editor.addMenuGroup = function( name, order ) {
27 groupsOrder[ name ] = order || 100;
28 };
29
30 /**
31 * Adds an item from the specified definition to the editor context menu.
32 *
33 * @method
34 * @param {String} name The menu item name.
35 * @param {Object} definition The menu item definition.
36 * @member CKEDITOR.editor
37 */
38 editor.addMenuItem = function( name, definition ) {
39 if ( groupsOrder[ definition.group ] )
40 menuItems[ name ] = new CKEDITOR.menuItem( this, name, definition );
41 };
42
43 /**
44 * Adds one or more items from the specified definition object to the editor context menu.
45 *
46 * @method
47 * @param {Object} definitions Object where keys are used as itemName and corresponding values as definition for a {@link #addMenuItem} call.
48 * @member CKEDITOR.editor
49 */
50 editor.addMenuItems = function( definitions ) {
51 for ( var itemName in definitions ) {
52 this.addMenuItem( itemName, definitions[ itemName ] );
53 }
54 };
55
56 /**
57 * Retrieves a particular menu item definition from the editor context menu.
58 *
59 * @method
60 * @param {String} name The name of the desired menu item.
61 * @returns {Object}
62 * @member CKEDITOR.editor
63 */
64 editor.getMenuItem = function( name ) {
65 return menuItems[ name ];
66 };
67
68 /**
69 * Removes a particular menu item added before from the editor context menu.
70 *
71 * @since 3.6.1
72 * @method
73 * @param {String} name The name of the desired menu item.
74 * @member CKEDITOR.editor
75 */
76 editor.removeMenuItem = function( name ) {
77 delete menuItems[ name ];
78 };
79 }
80} );
81
82( function() {
83 var menuItemSource = '<span class="cke_menuitem">' +
84 '<a id="{id}"' +
85 ' class="cke_menubutton cke_menubutton__{name} cke_menubutton_{state} {cls}" href="{href}"' +
86 ' title="{title}"' +
87 ' tabindex="-1"' +
88 ' _cke_focus=1' +
89 ' hidefocus="true"' +
90 ' role="{role}"' +
91 ' aria-label="{label}"' +
92 ' aria-describedby="{id}_description"' +
93 ' aria-haspopup="{hasPopup}"' +
94 ' aria-disabled="{disabled}"' +
95 ' {ariaChecked}' +
96 ' draggable="false"';
97
98 // Some browsers don't cancel key events in the keydown but in the
99 // keypress.
100 // TODO: Check if really needed.
101 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
102 menuItemSource += ' onkeypress="return false;"';
103
104 // With Firefox, we need to force the button to redraw, otherwise it
105 // will remain in the focus state. Also we some extra help to prevent dragging (#10373).
106 if ( CKEDITOR.env.gecko ) {
107 menuItemSource += ( ' onblur="this.style.cssText = this.style.cssText;"' +
108 ' ondragstart="return false;"' );
109 }
110
111 // #188
112 menuItemSource += ' onmouseover="CKEDITOR.tools.callFunction({hoverFn},{index});"' +
113 ' onmouseout="CKEDITOR.tools.callFunction({moveOutFn},{index});" ' +
114 ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) +
115 '="CKEDITOR.tools.callFunction({clickFn},{index}); return false;"' +
116 '>';
117
118 menuItemSource +=
119 //'' +
120 '<span class="cke_menubutton_inner">' +
121 '<span class="cke_menubutton_icon">' +
122 '<span class="cke_button_icon cke_button__{iconName}_icon" style="{iconStyle}"></span>' +
123 '</span>' +
124 '<span class="cke_menubutton_label">' +
125 '{label}' +
126 '</span>' +
127 '{shortcutHtml}' +
128 '{arrowHtml}' +
129 '</span>' +
130 '</a><span id="{id}_description" class="cke_voice_label" aria-hidden="false">{ariaShortcut}</span></span>';
131
132 var menuArrowSource = '<span class="cke_menuarrow">' +
133 '<span>{label}</span>' +
134 '</span>';
135
136 var menuShortcutSource = '<span class="cke_menubutton_label cke_menubutton_shortcut">' +
137 '{shortcut}' +
138 '</span>';
139
140 var menuItemTpl = CKEDITOR.addTemplate( 'menuItem', menuItemSource ),
141 menuArrowTpl = CKEDITOR.addTemplate( 'menuArrow', menuArrowSource ),
142 menuShortcutTpl = CKEDITOR.addTemplate( 'menuShortcut', menuShortcutSource );
143
144 /**
145 * @class
146 * @todo
147 */
148 CKEDITOR.menu = CKEDITOR.tools.createClass( {
149 /**
150 * @constructor
151 */
152 $: function( editor, definition ) {
153 definition = this._.definition = definition || {};
154 this.id = CKEDITOR.tools.getNextId();
155
156 this.editor = editor;
157 this.items = [];
158 this._.listeners = [];
159
160 this._.level = definition.level || 1;
161
162 var panelDefinition = CKEDITOR.tools.extend( {}, definition.panel, {
163 css: [ CKEDITOR.skin.getPath( 'editor' ) ],
164 level: this._.level - 1,
165 block: {}
166 } );
167
168 var attrs = panelDefinition.block.attributes = ( panelDefinition.attributes || {} );
169 // Provide default role of 'menu'.
170 !attrs.role && ( attrs.role = 'menu' );
171 this._.panelDefinition = panelDefinition;
172 },
173
174 _: {
175 onShow: function() {
176 var selection = this.editor.getSelection(),
177 start = selection && selection.getStartElement(),
178 path = this.editor.elementPath(),
179 listeners = this._.listeners;
180
181 this.removeAll();
182 // Call all listeners, filling the list of items to be displayed.
183 for ( var i = 0; i < listeners.length; i++ ) {
184 var listenerItems = listeners[ i ]( start, selection, path );
185
186 if ( listenerItems ) {
187 for ( var itemName in listenerItems ) {
188 var item = this.editor.getMenuItem( itemName );
189
190 if ( item && ( !item.command || this.editor.getCommand( item.command ).state ) ) {
191 item.state = listenerItems[ itemName ];
192 this.add( item );
193 }
194 }
195 }
196 }
197 },
198
199 onClick: function( item ) {
200 this.hide();
201
202 if ( item.onClick )
203 item.onClick();
204 else if ( item.command )
205 this.editor.execCommand( item.command );
206 },
207
208 onEscape: function( keystroke ) {
209 var parent = this.parent;
210 // 1. If it's sub-menu, close it, with focus restored on this.
211 // 2. In case of a top-menu, close it, with focus returned to page.
212 if ( parent )
213 parent._.panel.hideChild( 1 );
214 else if ( keystroke == 27 )
215 this.hide( 1 );
216
217 return false;
218 },
219
220 onHide: function() {
221 this.onHide && this.onHide();
222 },
223
224 showSubMenu: function( index ) {
225 var menu = this._.subMenu,
226 item = this.items[ index ],
227 subItemDefs = item.getItems && item.getItems();
228
229 // If this item has no subitems, we just hide the submenu, if
230 // available, and return back.
231 if ( !subItemDefs ) {
232 // Hide sub menu with focus returned.
233 this._.panel.hideChild( 1 );
234 return;
235 }
236
237 // Create the submenu, if not available, or clean the existing
238 // one.
239 if ( menu )
240 menu.removeAll();
241 else {
242 menu = this._.subMenu = new CKEDITOR.menu( this.editor, CKEDITOR.tools.extend( {}, this._.definition, { level: this._.level + 1 }, true ) );
243 menu.parent = this;
244 menu._.onClick = CKEDITOR.tools.bind( this._.onClick, this );
245 }
246
247 // Add all submenu items to the menu.
248 for ( var subItemName in subItemDefs ) {
249 var subItem = this.editor.getMenuItem( subItemName );
250 if ( subItem ) {
251 subItem.state = subItemDefs[ subItemName ];
252 menu.add( subItem );
253 }
254 }
255
256 // Get the element representing the current item.
257 var element = this._.panel.getBlock( this.id ).element.getDocument().getById( this.id + String( index ) );
258
259 // Show the submenu.
260 // This timeout is needed to give time for the sub-menu get
261 // focus when JAWS is running. (#9844)
262 setTimeout( function() {
263 menu.show( element, 2 );
264 }, 0 );
265 }
266 },
267
268 proto: {
269 /**
270 * Adds an item.
271 *
272 * @param item
273 */
274 add: function( item ) {
275 // Later we may sort the items, but Array#sort is not stable in
276 // some browsers, here we're forcing the original sequence with
277 // 'order' attribute if it hasn't been assigned. (#3868)
278 if ( !item.order )
279 item.order = this.items.length;
280
281 this.items.push( item );
282 },
283
284 /**
285 * Removes all items.
286 */
287 removeAll: function() {
288 this.items = [];
289 },
290
291 /**
292 * Shows the menu in given location.
293 *
294 * @param {CKEDITOR.dom.element} offsetParent
295 * @param {Number} [corner]
296 * @param {Number} [offsetX]
297 * @param {Number} [offsetY]
298 */
299 show: function( offsetParent, corner, offsetX, offsetY ) {
300 // Not for sub menu.
301 if ( !this.parent ) {
302 this._.onShow();
303 // Don't menu with zero items.
304 if ( !this.items.length )
305 return;
306 }
307
308 corner = corner || ( this.editor.lang.dir == 'rtl' ? 2 : 1 );
309
310 var items = this.items,
311 editor = this.editor,
312 panel = this._.panel,
313 element = this._.element;
314
315 // Create the floating panel for this menu.
316 if ( !panel ) {
317 panel = this._.panel = new CKEDITOR.ui.floatPanel( this.editor, CKEDITOR.document.getBody(), this._.panelDefinition, this._.level );
318
319 panel.onEscape = CKEDITOR.tools.bind( function( keystroke ) {
320 if ( this._.onEscape( keystroke ) === false )
321 return false;
322 }, this );
323
324 panel.onShow = function() {
325 // Menu need CSS resets, compensate class name.
326 var holder = panel._.panel.getHolderElement();
327 holder.getParent().addClass( 'cke' ).addClass( 'cke_reset_all' );
328 };
329
330 panel.onHide = CKEDITOR.tools.bind( function() {
331 this._.onHide && this._.onHide();
332 }, this );
333
334 // Create an autosize block inside the panel.
335 var block = panel.addBlock( this.id, this._.panelDefinition.block );
336 block.autoSize = true;
337
338 var keys = block.keys;
339 keys[ 40 ] = 'next'; // ARROW-DOWN
340 keys[ 9 ] = 'next'; // TAB
341 keys[ 38 ] = 'prev'; // ARROW-UP
342 keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
343 keys[ ( editor.lang.dir == 'rtl' ? 37 : 39 ) ] = CKEDITOR.env.ie ? 'mouseup' : 'click'; // ARROW-RIGHT/ARROW-LEFT(rtl)
344 keys[ 32 ] = CKEDITOR.env.ie ? 'mouseup' : 'click'; // SPACE
345 CKEDITOR.env.ie && ( keys[ 13 ] = 'mouseup' ); // Manage ENTER, since onclick is blocked in IE (#8041).
346
347 element = this._.element = block.element;
348
349 var elementDoc = element.getDocument();
350 elementDoc.getBody().setStyle( 'overflow', 'hidden' );
351 elementDoc.getElementsByTag( 'html' ).getItem( 0 ).setStyle( 'overflow', 'hidden' );
352
353 this._.itemOverFn = CKEDITOR.tools.addFunction( function( index ) {
354 clearTimeout( this._.showSubTimeout );
355 this._.showSubTimeout = CKEDITOR.tools.setTimeout( this._.showSubMenu, editor.config.menu_subMenuDelay || 400, this, [ index ] );
356 }, this );
357
358 this._.itemOutFn = CKEDITOR.tools.addFunction( function() {
359 clearTimeout( this._.showSubTimeout );
360 }, this );
361
362 this._.itemClickFn = CKEDITOR.tools.addFunction( function( index ) {
363 var item = this.items[ index ];
364
365 if ( item.state == CKEDITOR.TRISTATE_DISABLED ) {
366 this.hide( 1 );
367 return;
368 }
369
370 if ( item.getItems )
371 this._.showSubMenu( index );
372 else
373 this._.onClick( item );
374 }, this );
375 }
376
377 // Put the items in the right order.
378 sortItems( items );
379
380 // Apply the editor mixed direction status to menu.
381 var path = editor.elementPath(),
382 mixedDirCls = ( path && path.direction() != editor.lang.dir ) ? ' cke_mixed_dir_content' : '';
383
384 // Build the HTML that composes the menu and its items.
385 var output = [ '<div class="cke_menu' + mixedDirCls + '" role="presentation">' ];
386
387 var length = items.length,
388 lastGroup = length && items[ 0 ].group;
389
390 for ( var i = 0; i < length; i++ ) {
391 var item = items[ i ];
392 if ( lastGroup != item.group ) {
393 output.push( '<div class="cke_menuseparator" role="separator"></div>' );
394 lastGroup = item.group;
395 }
396
397 item.render( this, i, output );
398 }
399
400 output.push( '</div>' );
401
402 // Inject the HTML inside the panel.
403 element.setHtml( output.join( '' ) );
404
405 CKEDITOR.ui.fire( 'ready', this );
406
407 // Show the panel.
408 if ( this.parent )
409 this.parent._.panel.showAsChild( panel, this.id, offsetParent, corner, offsetX, offsetY );
410 else
411 panel.showBlock( this.id, offsetParent, corner, offsetX, offsetY );
412
413 editor.fire( 'menuShow', [ panel ] );
414 },
415
416 /**
417 * Adds a callback executed on opening the menu. Items
418 * returned by that callback are added to the menu.
419 *
420 * @param {Function} listenerFn
421 * @param {CKEDITOR.dom.element} listenerFn.startElement The selection start anchor element.
422 * @param {CKEDITOR.dom.selection} listenerFn.selection The current selection.
423 * @param {CKEDITOR.dom.elementPath} listenerFn.path The current elements path.
424 * @param listenerFn.return Object (`commandName` => `state`) of items that should be added to the menu.
425 */
426 addListener: function( listenerFn ) {
427 this._.listeners.push( listenerFn );
428 },
429
430 /**
431 * Hides the menu.
432 *
433 * @param {Boolean} [returnFocus]
434 */
435 hide: function( returnFocus ) {
436 this._.onHide && this._.onHide();
437 this._.panel && this._.panel.hide( returnFocus );
438 }
439 }
440 } );
441
442 function sortItems( items ) {
443 items.sort( function( itemA, itemB ) {
444 if ( itemA.group < itemB.group )
445 return -1;
446 else if ( itemA.group > itemB.group )
447 return 1;
448
449 return itemA.order < itemB.order ? -1 : itemA.order > itemB.order ? 1 : 0;
450 } );
451 }
452
453 /**
454 * @class
455 * @todo
456 */
457 CKEDITOR.menuItem = CKEDITOR.tools.createClass( {
458 $: function( editor, name, definition ) {
459 CKEDITOR.tools.extend( this, definition,
460 // Defaults
461 {
462 order: 0,
463 className: 'cke_menubutton__' + name
464 } );
465
466 // Transform the group name into its order number.
467 this.group = editor._.menuGroups[ this.group ];
468
469 this.editor = editor;
470 this.name = name;
471 },
472
473 proto: {
474 render: function( menu, index, output ) {
475 var id = menu.id + String( index ),
476 state = ( typeof this.state == 'undefined' ) ? CKEDITOR.TRISTATE_OFF : this.state,
477 ariaChecked = '',
478 editor = this.editor,
479 keystroke,
480 command,
481 shortcut;
482
483 var stateName = state == CKEDITOR.TRISTATE_ON ? 'on' : state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' : 'off';
484
485 if ( this.role in { menuitemcheckbox: 1, menuitemradio: 1 } )
486 ariaChecked = ' aria-checked="' + ( state == CKEDITOR.TRISTATE_ON ? 'true' : 'false' ) + '"';
487
488 var hasSubMenu = this.getItems;
489 // ltr: BLACK LEFT-POINTING POINTER
490 // rtl: BLACK RIGHT-POINTING POINTER
491 var arrowLabel = '&#' + ( this.editor.lang.dir == 'rtl' ? '9668' : '9658' ) + ';';
492
493 var iconName = this.name;
494 if ( this.icon && !( /\./ ).test( this.icon ) )
495 iconName = this.icon;
496
497 if ( this.command ) {
498 command = editor.getCommand( this.command );
499 keystroke = editor.getCommandKeystroke( command );
500
501 if ( keystroke ) {
502 shortcut = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard, keystroke );
503 }
504 }
505
506 var params = {
507 id: id,
508 name: this.name,
509 iconName: iconName,
510 label: this.label,
511 cls: this.className || '',
512 state: stateName,
513 hasPopup: hasSubMenu ? 'true' : 'false',
514 disabled: state == CKEDITOR.TRISTATE_DISABLED,
515 title: this.label + ( shortcut ? ' (' + shortcut.display + ')' : '' ),
516 ariaShortcut: shortcut ? editor.lang.common.keyboardShortcut + ' ' + shortcut.aria : '',
517 href: 'javascript:void(\'' + ( this.label || '' ).replace( "'" + '' ) + '\')', // jshint ignore:line
518 hoverFn: menu._.itemOverFn,
519 moveOutFn: menu._.itemOutFn,
520 clickFn: menu._.itemClickFn,
521 index: index,
522 iconStyle: CKEDITOR.skin.getIconStyle( iconName, ( this.editor.lang.dir == 'rtl' ), iconName == this.icon ? null : this.icon, this.iconOffset ),
523 shortcutHtml: shortcut ? menuShortcutTpl.output( { shortcut: shortcut.display } ) : '',
524 arrowHtml: hasSubMenu ? menuArrowTpl.output( { label: arrowLabel } ) : '',
525 role: this.role ? this.role : 'menuitem',
526 ariaChecked: ariaChecked
527 };
528
529 menuItemTpl.output( params, output );
530 }
531 }
532 } );
533
534} )();
535
536
537/**
538 * The amount of time, in milliseconds, the editor waits before displaying submenu
539 * options when moving the mouse over options that contain submenus, like the
540 * "Cell Properties" entry for tables.
541 *
542 * // Remove the submenu delay.
543 * config.menu_subMenuDelay = 0;
544 *
545 * @cfg {Number} [menu_subMenuDelay=400]
546 * @member CKEDITOR.config
547 */
548
549/**
550 * Fired when a menu is shown.
551 *
552 * @event menuShow
553 * @member CKEDITOR.editor
554 * @param {CKEDITOR.editor} editor This editor instance.
555 * @param {CKEDITOR.ui.panel[]} data
556 */
557
558/**
559 * A comma separated list of items group names to be displayed in the context
560 * menu. The order of items will reflect the order specified in this list if
561 * no priority was defined in the groups.
562 *
563 * config.menu_groups = 'clipboard,table,anchor,link,image';
564 *
565 * @cfg {String} [menu_groups=see source]
566 * @member CKEDITOR.config
567 */
568CKEDITOR.config.menu_groups = 'clipboard,' +
569 'form,' +
570 'tablecell,tablecellproperties,tablerow,tablecolumn,table,' +
571 'anchor,link,image,flash,' +
572 'checkbox,radio,textfield,hiddenfield,imagebutton,button,select,textarea,div';
diff --git a/sources/plugins/oembed/LICENSE.md b/sources/plugins/oembed/LICENSE.md
new file mode 100644
index 0000000..be0064f
--- /dev/null
+++ b/sources/plugins/oembed/LICENSE.md
@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) Ingo Herbote
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/sources/plugins/oembed/README.md b/sources/plugins/oembed/README.md
new file mode 100644
index 0000000..64c729c
--- /dev/null
+++ b/sources/plugins/oembed/README.md
@@ -0,0 +1,201 @@
1CKEditor-oEmbed-Plugin
2======================
3
4oEmbed Plugin for CKEditor
5
6This Plugin allows to insert embedded content (such as photos, videos, audio, and other rich media) via the OEmbed API. You only have to provide the url to the site (It works also when the url is shortened) you want to embed and the plugin does the rest.
7
8This Plugin uses the jquery-oembed-all Plugin located at https://github.com/starfishmod/jquery-oembed-all.
9
10####Demo
11
12http://w8tcha.github.com/CKEditor-oEmbed-Plugin/
13
14####Currently Supported Sites...
15
16###Video
17* Youtube - oembed - YQL
18* Blip - oEmbed
19* Hulu - oEmbed
20* Vimeo - oEmbed
21* National film board of Canada - oEmbed
22* Qik - oEmbed
23* Dotsub - oEmbed
24* Clikthrough - oEmbed
25* Kino Map - oEmbed
26* Funny Or Die - Embedded
27* College Humour - Embedded
28* Metacafe - Embedded
29* embedr - Embedded
30* 5min - oEmbed is XML only - using YQL to translate it
31* ustream.tv - oEmbed is not JSONP enabled - using YQL to translate it
32* viddler - OGP
33* twitvid - Embedded
34* bambuser - Embedded
35* xtranormal - Embedded
36* Gametrailers - Embedded
37* Vzarr - Embedded
38* VHX - oembed
39* bambuser - oembed
40* dailymotion.com - oembed
41* animoto - oembed
42* justin.tv - YQL JSON
43* livestream - OGP
44* scivee - embedded
45* veoh - embedded
46* minoto-video - oembed using YQL
47* TrailerAddict - OGP
48* vodpod - oembed YQL - broken as the oembed has absolute positioning which breaks the display
49* fora.tv -OGP YQL
50* TED - OGP YQL
51* Aniboom - embedded
52* Comedy Central - OGP
53* snotr - embedded
54* zapiks - OGP
55* youku - embedded
56* wistia - Oembed
57
58###Audio
59* Soundcloud - oEmbed
60* HuffDuffer - oEmbed
61* BandCamp - YQL and Embedded
62* podomatic - OGP
63* rdio.com - oEmbed
64* hark.com - OGP
65* chirb.it - YQL and oembed
66* official.fm - YQL and oembed
67* mixcloud - YQL and oembed
68* shoudio - oembed
69* audioboo.fm - OGP
70* Spotify - OGP YQL
71
72###Photo
73* flickr - oEmbed
74* photobucket - oEmbed
75* instagram - oEmbed
76* yfrog - oEmbed
77* 23HQ - oEmbed
78* Smugmug - oEmbed
79* twitpic - OGP YQL
80* 500px.com - OGP
81* visual.ly - YQL Lookup
82* img.ly - Thumbnail view
83* imgur.com - Thumbnail view
84* twitgoo.com - Thumbnail view
85* gravatar - Thumbnail view when using mailto
86* pintrest - YQL - Embedded view of a sort.
87* circuitlab - image view
88* skitch - YQL oembed
89* graphic.ly - OGP
90* dribble - jsonp lookup
91* Lockerz - YQL lookup
92* AsciiArtFarts - YQL Lookup
93* lego cusoo - OGP over YQL
94* plannary - OGP over YQL
95* propic - OGP
96* avairy.com - OGP
97* lomography - ogp
98* weheartit - ogp
99* glogster - ogp
100* chart.ly - embedded
101* twitrpix - OGP
102* chictopia - OGP
103
104###Rich
105* Meetup - oEmbed
106* gigapans - Embedded
107* Slideshare - oEmbed
108* ebay - Embedded
109* scribd - Embedded
110* screenr - Embedded
111* tumblr- JSONP lookup
112* imdb - JSONP lookup via imdbapi.com
113* wikipedia- JSONP lookup
114* github- JSONP lookup (CSS)
115* eventful - OGP
116* myspace - OGP
117* live Journal - JSONP Lookup (CSS)
118* wordpress - oEmbed (wordpress.com, wp.me, blogs.cnn.com, techcrunch.com). I can add other wordpress sites as well.
119* circuitbee -Embedded
120* stack overflow - JSONP Lookup (CSS)
121* Facebook - JSONP Lookup (CSS)
122* Pastebin - Embedded
123* Pastie - YQL lookup
124* kickstarter - Embedded
125* issuu - OGP
126* reelapp.com - Embedded
127* Etsy - OGP over YQL
128* Amazon - Embedded - Requires Affiliate code
129* linkedin - Embedded IFRAME - found a link that works :)
130* Lanyrd - YQL (CSS)
131* twitter - Oembed - status only - but that is ok I think
132* github gist - oembed
133* speakerdeck - yql oembed
134* dipity - yql oembed
135* dailymile - oembed
136* deviantart - oembed
137* Roomshare Japan - oembed
138* mobypictures - oembed
139* prezi - embedded
140* popplet - embedded
141* authorstream - OGP
142* googlecalendar - Iframe
143* cacoo - oembed
144* pearltrees - embedded
145* urtak - oembed - is broken in iframe return atm -seems to be an embed.ly issue??
146* jotform - embedded
147* Urban Dictionary - YQL lookup
148* Ars Technica - YQL Lookup
149* Eventbrite - OGP YQL
150* last.fm OGP YQL
151* Rotten Tomatoes - OGP YQL
152* iFixit - OGP
153* qwiki - OGP
154* brighttalk - Meta info
155* tinychat - OGP
156* tourwrist - embedded
157* bnter - OGP
158* bigthink - OGP
159* wirewax - OGP
160* whosay - OGP
161* timetoast - embedded
162* tripline - OGP
163* jsfiddle - embedded
164
165
166####License
167
168Licensed under the terms of the MIT License.
169
170####Dependencies
171This Plugin requires the following plugins to work: Widget, Dialog.
172
173####Installation
174
175 1. Before you can use the plugin you also need to download & install the widget plugin, if you have it not installed. http://ckeditor.com/addon/widget
176 2. Extract the contents of the file into the "plugins" folder of CKEditor.
177 3. In the CKEditor configuration file (config.js) add the following code:
178
179````js
180config.extraPlugins = 'oembed,widget';
181````
182
1832a. Additionally you can also set the default values vor the Max. Width/Height Values
184
185````js
186config.oembed_maxWidth = '560';
187config.oembed_maxHeight = '315';
188````
189
190and also you can define an css class for the embeded content wrapper (div), by default there is no Class defined
191
192````js
193config.oembed_WrapperClass = 'embededContent';
194````
195
196
1973. and also include the plugin in the toolbar
198
199````js
200toolbar :[ ... ['oembed']...]
201````
diff --git a/sources/plugins/oembed/icons/hidpi/oembed.png b/sources/plugins/oembed/icons/hidpi/oembed.png
new file mode 100644
index 0000000..a568d17
--- /dev/null
+++ b/sources/plugins/oembed/icons/hidpi/oembed.png
Binary files differ
diff --git a/sources/plugins/oembed/icons/oembed.png b/sources/plugins/oembed/icons/oembed.png
new file mode 100644
index 0000000..2ba7cce
--- /dev/null
+++ b/sources/plugins/oembed/icons/oembed.png
Binary files differ
diff --git a/sources/plugins/oembed/lang/de.js b/sources/plugins/oembed/lang/de.js
new file mode 100644
index 0000000..69422ae
--- /dev/null
+++ b/sources/plugins/oembed/lang/de.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'de', {
2 title : "Medien Inhalt einbinden (Bilder, Video, Inhalt)",
3 button : "Medien Inhalt von Verschiedenen Seiten einbinden",
4 pasteUrl : "Fügen Sie eine Url (Gekürzte Urls werden auch erkannt) ein von einer Seite die Unterstützt wird (z.B.: YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.) ...",
5 invalidUrl : "Sie müssem eine korrekte URL an!",
6 noEmbedCode : "Kein embed Code gefunden, oder Seite wird nicht Unterstützt!",
7 url : "URL:",
8 width: "Breite:",
9 height: "Höhe:",
10 widthTitle: "Breite für den eingebundenen Inhalt",
11 heightTitle: "Höhe für den eingebundenen Inhalt",
12 maxWidth: "Max. Breite:",
13 maxHeight: "Max. Höhe:",
14 maxWidthTitle: "Maximale Breite für den eingebundenen Inhalt",
15 maxHeightTitle: "Maximale Höhe für den eingebundenen Inhalt",
16 resizeType: "Größenveränderungsmodus (Nur Video's):",
17 none:'None',
18 noresize: "Keine Veränderung (Standardgröße)",
19 responsive: "Responsive",
20 custom: "Eigene Größe",
21 noVimeo: "Der Eigentümber dieses Videos hat Domain einschränkungen für dieses Video gesetzt das Video kann nicht in die Webseite eingebunden werden.",
22 Error: "Inhalt konnte nicht gefunden werden, bitte Versuchen sie eine Andere URL."
23});
diff --git a/sources/plugins/oembed/lang/en.js b/sources/plugins/oembed/lang/en.js
new file mode 100644
index 0000000..e461f03
--- /dev/null
+++ b/sources/plugins/oembed/lang/en.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'en', {
2 title: "Embed Media Content (Photo, Video, Audio or Rich Content)",
3 button: "Embed Media from External Sites",
4 pasteUrl: "Paste a URL (shorted URLs are also supported) from one of the supported sites (e.g. YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.).",
5 invalidUrl: "Please provide a valid URL.",
6 noEmbedCode: "No embed code found, or site is not supported.",
7 url: "URL:",
8 width: "Width:",
9 height: "Height:",
10 widthTitle: "Width for the embeded content",
11 heightTitle: "Height for the embeded content",
12 maxWidth: "Max. Width:",
13 maxHeight: "Max. Height:",
14 maxWidthTitle: "Maximum Width for the embeded Content",
15 maxHeightTitle: "Maximum Height for the embeded Content",
16 none:'None',
17 resizeType: "Resize Type (videos only):",
18 noresize: "No Resize (use default)",
19 responsive: "Responsive Resize",
20 custom: "Specific Resize",
21 noVimeo: "The owner of this video has set domain restrictions and you will not be able to embed it on your website.",
22 Error: "Media Content could not been retrieved, please try a different URL."
23});
diff --git a/sources/plugins/oembed/lang/fr.js b/sources/plugins/oembed/lang/fr.js
new file mode 100644
index 0000000..c1e0650
--- /dev/null
+++ b/sources/plugins/oembed/lang/fr.js
@@ -0,0 +1,25 @@
1// French Translation by https://github.com/wissim
2
3CKEDITOR.plugins.setLang('oembed', 'fr', {
4 title : "Intégrer des contenus multimédia externes. (Photo, Video, Audio, ...)",
5 button : "Insérer des contenus multimédia provenant de nombreux sites.",
6 pasteUrl : "Coller l'URL de partage que vous voulez publier. De nombreux services sont pris en charge tels que : (YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.). Vous pouvez aussi utiliser les URLs courtes.",
7 invalidUrl : "Merci de fournir une URL valide !",
8 noEmbedCode : "Aucun code d'intégration trouvé ou le site n'est pas supporté !",
9 url : "URL:",
10 width: "Largeur:",
11 height: "Hauteur:",
12 widthTitle: "Largeur du conteneur.",
13 heightTitle: "Hauteur du conteneur.",
14 maxWidth: "Max. Largeur:",
15 maxHeight: "Max. Hauteur:",
16 maxWidthTitle: "Largeur maximale du conteneur.",
17 maxHeightTitle: "Hauteur maximale du conteneur.",
18 resizeType: "Resize Type (Only Video's):",
19 none:'None',
20 noresize: "No Resize (use default)",
21 responsive: "Responsive Resize",
22 custom: "Specific Resize",
23 noVimeo: "The owner of this video has set domain restrictions and you will not be able to embed it on your website.",
24 Error: "Media Content could not been retrieved, please try a different URL."
25});
diff --git a/sources/plugins/oembed/lang/nl.js b/sources/plugins/oembed/lang/nl.js
new file mode 100644
index 0000000..94cf8ad
--- /dev/null
+++ b/sources/plugins/oembed/lang/nl.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'nl', {
2 title : "Integratie van media-inhoud (foto's, video, content)",
3 button : "Media-inhoud van externe websites",
4 pasteUrl : "Geef een URL van een pagina in dat ondersteund wordt (Bijv.: YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.) ...",
5 invalidUrl : "Gelieve een geldige URL op te geven!",
6 noEmbedCode : "Geen embed code gevonden, of de website wordt niet ondersteund!",
7 url : "URL:",
8 width: "Breedte:",
9 height: "Hoogte:",
10 widthTitle: "Breedte voor de ingevoegde inhoud",
11 heightTitle: "Hoogte voor de ingevoegde inhoud",
12 maxWidth: "Maximale breedte:",
13 maxHeight: "Maximale hoogte:",
14 maxWidthTitle: "Maximum breedte voor de ingevoegde inhoud",
15 maxHeightTitle: "Maximum hoogte voor de ingevoegde inhoud",
16 none:'None',
17 resizeType: "Type formaat aanpassing (enkel video's):",
18 noresize: "Geen formaat aanpassing (gebruik standaard)",
19 responsive: "Responsieve formaat aanpassing",
20 custom: "Specifieke formaat aanpassing",
21 noVimeo: "De eigenaar van deze video heeft restricties ingesteld waardoor je deze video niet kunt invoegen op je eigen website.",
22 Error: "Media inhoud kon niet worden opgehaald, gelieve een andere URL te proberen."
23});
diff --git a/sources/plugins/oembed/lang/pl.js b/sources/plugins/oembed/lang/pl.js
new file mode 100644
index 0000000..a7d7b92
--- /dev/null
+++ b/sources/plugins/oembed/lang/pl.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'pl', {
2 title: "Osadzanie multimediów (zdjęć, filmów, dźwięku, bogatych treści)",
3 button: "Osadzanie multimediów z witryn zewnętrznych",
4 pasteUrl: "Wklej tutaj adres URL (adresy skrócone są również obsługiwane) z jednej z obsługiwanych stron (YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, itp.).",
5 invalidUrl: "Proszę wprowadzić prawidłowy adres URL!",
6 noEmbedCode: "Odnośnik nieprawidłowy lub nieobsługiwany!",
7 url: "URL:",
8 width: "szerokość:",
9 height: "wysokość:",
10 widthTitle: "Szerokość osadzanej zawartości",
11 heightTitle: "Wysokość osadzanej zawartości",
12 maxWidth: "Maks. szerokość:",
13 maxHeight: "Maks. wysokość:",
14 maxWidthTitle: "Maksymalna szerokość osadzanej zawartości",
15 maxHeightTitle: "Maksymalna wysokość osadzanej zawartości",
16 resizeType: "Typ zmiany rozmiaru (tylko nagrania wideo):",
17 none:'None',
18 noresize: "Bez zmiany rozmiaru (domyślne)",
19 responsive: "Responsywna zmiana rozmiaru",
20 custom: "Narzucona zmiana rozmiaru",
21 noVimeo: "Właściciel nagrania wideo nałożył ograniczenia domenowe, nagrania nie można osadzić w witrynie.",
22 Error: "Nie można uzyskać zawartości multimedialnej, proszę spróbować inny adres URL."
23});
diff --git a/sources/plugins/oembed/lang/pt-br.js b/sources/plugins/oembed/lang/pt-br.js
new file mode 100644
index 0000000..6616432
--- /dev/null
+++ b/sources/plugins/oembed/lang/pt-br.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'pt-br', {
2 title: "Conteúdo embed de mídia (foto, vídeo, audio, rich)",
3 button: "Conteúdo embed de mídia de vários sites",
4 pasteUrl: "Cole aqui a URL (inclusive URLs encurtadas) de um dos sites que o plugin suporta (ex. YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.) ...",
5 invalidUrl: "Por favor informe uma URL válida!",
6 noEmbedCode: "Nenhum código embed foi encontrado, ou esse site não está na lista dos sites suportados pelo plugin!",
7 url: "URL:",
8 width: "Largura:",
9 height: "Altura:",
10 widthTitle: "Largura do conteúdo embebed",
11 heightTitle: "Altura do conteúdo embeded",
12 maxWidth: "Largura máx.:",
13 maxHeight: "Altura máx.:",
14 maxWidthTitle: "Largura máxima do conteúdo embeded",
15 maxHeightTitle: "Altura máxima do conteúdo embeded",
16 resizeType: "Tipo de redimensionamento (Somente para video):",
17 none:'None',
18 noresize: "Sem redimensionamento (default)",
19 responsive: "Redimensionamento responsivo",
20 custom: "Redimensionamento específico",
21 noVimeo: "O dono desse vídeo tem restrições de domínio a você não poderá utilizá-lo em seu site.",
22 Error: "Esse conteúdo de mídia não foi encontrado, por favor tente uma URL diferente."
23});
diff --git a/sources/plugins/oembed/lang/ru.js b/sources/plugins/oembed/lang/ru.js
new file mode 100644
index 0000000..f2a1e53
--- /dev/null
+++ b/sources/plugins/oembed/lang/ru.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'ru', {
2 title: "Внедрить медиа-контент (видео, аудио, фото и т.д.)",
3 button: "Внедрить медиа-контент с различных сайтов",
4 pasteUrl: "Вставьте ссылку на страницу с медиа-контентом (например YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, и т.д.)",
5 invalidUrl: "Вы ввели некорректный URL",
6 noEmbedCode: "Не обнаружен код для вставки. Возможно, вы ввели ссылку с неподдерживаемого сайта.",
7 url: "URL:",
8 width: "Ширина:",
9 height: "Высота:",
10 widthTitle: "Ширина внедряемого медиа-контента",
11 heightTitle: "Высота внедряемого медиа-контента",
12 maxWidth: "Макс. ширина:",
13 maxHeight: "Макс. высота:",
14 maxWidthTitle: "Максимальная ширина внедряемого медиа-контента",
15 maxHeightTitle: "Максимальная высота внедряемого медиа-контента",
16 resizeType: "Изменение размера (только для видео):",
17 none:'None',
18 noresize: "Без изменения (стандартный размер)",
19 responsive: "Задать максимальный размер",
20 custom: "Задать конкретный размер",
21 noVimeo: "Владелец этого видео установил ограничения на домен, и вы не можете его встроить на ваш сайт.",
22 Error: "Невозможно получить медиа-контент. Попробуйте другой URL."
23});
diff --git a/sources/plugins/oembed/lang/tr.js b/sources/plugins/oembed/lang/tr.js
new file mode 100644
index 0000000..f027106
--- /dev/null
+++ b/sources/plugins/oembed/lang/tr.js
@@ -0,0 +1,23 @@
1CKEDITOR.plugins.setLang('oembed', 'tr', {
2 title: "Medya içeriği ekle (Fotoğraf, Video, Ses Dosyası, Zengin Medya İçeriği)",
3 button: "Farklı sitelerden medya içeriği ekle",
4 pasteUrl: "Desteklenen sitelerden bir URL ekleyin (Kısaltılmış URL de olabilir) (örnek: YouTube, Flickr, Qik, Vimeo, Hulu, Viddler, MyOpera, etc.)...",
5 invalidUrl: "Lütfen geçerli bir URL adresi tanımlayın!",
6 noEmbedCode: "Embed kodu bulunamadı veya site desteklenmiyor!",
7 url: "URL:",
8 width: "Genişlik:",
9 height: "Yükseklik:",
10 widthTitle: "Eklenecek içerik için genişlik",
11 heightTitle: "Eklenecek içerik için yükseklik",
12 maxWidth: "Max. genişlik:",
13 maxHeight: "Max. yükseklik:",
14 maxWidthTitle: "Eklenecek içerik için max. genişlik",
15 maxHeightTitle: "Eklenecek içerik için max. yükseklik",
16 resizeType: "Boyutlandır (sadece videolarda geçerli):",
17 none:'None',
18 noresize: "Boyutlandırma yapma (default kullan)",
19 responsive: "Esnek (Responsive) boyutlandırma",
20 custom: "Özel boyutlandırma",
21 noVimeo: "Bu videonun sahibi alan adı kısıtlaması ayarlamış, web sitenizde bu video çalışmayacaktır.",
22 Error: "Medya içeriği alınamadı, farklı bir URL deneyin."
23});
diff --git a/sources/plugins/oembed/libs/jquery.oembed.min.js b/sources/plugins/oembed/libs/jquery.oembed.min.js
new file mode 100644
index 0000000..e5bd1c5
--- /dev/null
+++ b/sources/plugins/oembed/libs/jquery.oembed.min.js
@@ -0,0 +1 @@
(function(n){function r(){var n=window.location.protocol;return n==="file:"?"http://":"//"}function f(n,t){return t=t?t:"",n?f(--n,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(Math.random()*60))+t):t}function s(n,t){var i=n.apiendpoint,u="",r;i+=i.indexOf("?")<=0?"?":"&";i=i.replace("#","%23");n.maxWidth!==null&&(typeof n.params.maxwidth=="undefined"||n.params.maxwidth===null)&&(n.params.maxwidth=n.maxWidth);n.maxHeight!==null&&(typeof n.params.maxheight=="undefined"||n.params.maxheight===null)&&(n.params.maxheight=n.maxHeight);for(r in n.params)r!=n.callbackparameter&&n.params[r]!==null&&(u+="&"+escape(r)+"="+n.params[r]);return i+="format="+n.format+"&url="+escape(t)+u,n.dataType!="json"&&(i+="&"+n.callbackparameter+"=?"),i}function u(i,r,u){n("#jqoembeddata").data(r,i.code);t.beforeEmbed.call(u,i);t.onEmbed.call(u,i);t.afterEmbed.call(u,i)}function e(i,e,o){var p,a,tt,v;if(n("#jqoembeddata").data(e)!=undefined&&o.embedtag.tag!="iframe")a={code:n("#jqoembeddata").data(e)},u(a,e,i);else if(o.yql){var w=o.yql.from||"htmlstring",g=o.yql.url?o.yql.url(e):e,nt="SELECT * FROM "+w+' WHERE url="'+g+'" and '+(/html/.test(w)?"xpath":"itemPath")+"='"+(o.yql.xpath||"/")+"'";w=="html"&&(nt+=" and compat='html5'");v=n.extend({url:r()+"query.yahooapis.com/v1/public/yql",dataType:"jsonp",data:{q:nt,format:"json",env:"store://datatables.org/alltableswithkeys",callback:"?"},success:function(t){var s,f,c,r,h,l;if(o.yql.xpath&&o.yql.xpath=="//meta|//title|//link"){for(f={},t.query.results==null&&(t.query.results={meta:[]}),r=0,h=t.query.results.meta.length;r<h;r++)(c=t.query.results.meta[r].name||t.query.results.meta[r].property||null,c!=null)&&(f[c.toLowerCase()]=t.query.results.meta[r].content);if(f.hasOwnProperty("title")&&f.hasOwnProperty("og:title")||t.query.results.title!=null&&(f.title=t.query.results.title),!f.hasOwnProperty("og:image")&&t.query.results.hasOwnProperty("link"))for(r=0,h=t.query.results.link.length;r<h;r++)t.query.results.link[r].hasOwnProperty("rel")&&t.query.results.link[r].rel=="apple-touch-icon"&&(f["og:image"]=t.query.results.link[r].href.charAt(0)=="/"?g.match(/^(([a-z]+:)?(\/\/)?[^\/]+\/).*$/)[1]+t.query.results.link[r].href:t.query.results.link[r].href);s=o.yql.datareturn(f)}else s=o.yql.datareturn?o.yql.datareturn(t.query.results):t.query.results.result;s!==!1&&(l=n.extend({},s),l.code=s,u(l,e,i))},error:function(){t.onError.call(i,e,o)}},t.ajaxOptions||{});n.ajax(v)}else if(o.templateRegex)if(o.embedtag.tag!==""){var it=o.embedtag.flashvars||"",b=o.embedtag.tag||"embed",h=o.embedtag.width||"auto",rt=o.embedtag.nocache||0,c=o.embedtag.height||"auto",y=e.replace(o.templateRegex,o.apiendpoint);if(o.nocache||(y+="&jqoemcache="+f(5)),o.apikey&&(y=y.replace("_APIKEY_",t.apikeys[o.name])),t.maxHeight&&t.maxWidth)if(t.useResponsiveResize){var l=0,k=h,d=c;h>t.maxWidth&&(l=t.maxWidth/h,k=t.maxWidth,d=c*l,c=c*l,h=h*l);c>t.maxHeight&&(l=t.maxHeight/c,d=t.maxHeight,k=h*l,h=h*l);c=d;h=k}else c=t.maxHeight,h=t.maxWidth;p=n("<"+b+"/>").attr("src",y).attr("width",h).attr("height",c).attr("allowfullscreen",o.embedtag.allowfullscreen||"true").attr("allowscriptaccess",o.embedtag.allowfullscreen||"always").css("max-height",t.maxHeight||"auto").css("max-width",t.maxWidth||"auto");b=="embed"&&p.attr("type",o.embedtag.type||"application/x-shockwave-flash").attr("flashvars",e.replace(o.templateRegex,it));b=="iframe"&&p.attr("scrolling",o.embedtag.scrolling||"no").attr("frameborder",o.embedtag.frameborder||"0");a={code:p};u(a,e,i)}else o.apiendpoint?(o.apikey&&(o.apiendpoint=o.apiendpoint.replace("_APIKEY_",t.apikeys[o.name])),v=n.extend({url:e.replace(o.templateRegex,o.apiendpoint),dataType:"jsonp",success:function(t){var r=n.extend({},t);r.code=o.templateData(t);u(r,e,i)},error:function(){t.onError.call(i,e,o)}},t.ajaxOptions||{}),n.ajax(v)):(a={code:e.replace(o.templateRegex,o.template)},u(a,e,i));else tt=s(o,e),v=n.extend({url:tt,dataType:o.dataType||"jsonp",success:function(t){var r=n.extend({},t);switch(r.type){case"file":case"photo":r.code=n.fn.oembed.getPhotoCode(e,r);break;case"link":r.code=r.provider_name=="Flickr"?n.fn.oembed.getPhotoCode(e,r):n.fn.oembed.getGenericCode(e,r);break;case"video":case"rich":r.code=n.fn.oembed.getRichCode(e,r);break;default:r.code=n.fn.oembed.getGenericCode(e,r)}u(r,e,i)},error:function(){t.onError.call(i,e,o)}},t.ajaxOptions||{}),n.ajax(v)}function o(n){if(n===null)return null;var t,i={};for(t in n)t!==null&&(i[t.toLowerCase()]=n[t]);return i}n.fn.oembed=function(i,r,u){t=n.extend(!0,n.fn.oembed.defaults,r);var f=["0rz.tw","1link.in","1url.com","2.gp","2big.at","2tu.us","3.ly","307.to","4ms.me","4sq.com","4url.cc","6url.com","7.ly","a.gg","a.nf","aa.cx","abcurl.net","ad.vu","adf.ly","adjix.com","afx.cc","all.fuseurl.com","alturl.com","amzn.to","ar.gy","arst.ch","atu.ca","azc.cc","b23.ru","b2l.me","bacn.me","bcool.bz","binged.it","bit.ly","bizj.us","bloat.me","bravo.ly","bsa.ly","budurl.com","canurl.com","chilp.it","chzb.gr","cl.lk","cl.ly","clck.ru","cli.gs","cliccami.info","clickthru.ca","clop.in","conta.cc","cort.as","cot.ag","crks.me","ctvr.us","cutt.us","dai.ly","decenturl.com","dfl8.me","digbig.com","http://digg.com/[^/]+$","disq.us","dld.bz","dlvr.it","do.my","doiop.com","dopen.us","easyuri.com","easyurl.net","eepurl.com","eweri.com","fa.by","fav.me","fb.me","fbshare.me","ff.im","fff.to","fire.to","firsturl.de","firsturl.net","flic.kr","flq.us","fly2.ws","fon.gs","freak.to","fuseurl.com","fuzzy.to","fwd4.me","fwib.net","g.ro.lt","gizmo.do","gl.am","go.9nl.com","go.ign.com","go.usa.gov","goo.gl","goshrink.com","gurl.es","hex.io","hiderefer.com","hmm.ph","href.in","hsblinks.com","htxt.it","huff.to","hulu.com","hurl.me","hurl.ws","icanhaz.com","idek.net","ilix.in","is.gd","its.my","ix.lt","j.mp","jijr.com","kl.am","klck.me","korta.nu","krunchd.com","l9k.net","lat.ms","liip.to","liltext.com","linkbee.com","linkbun.ch","liurl.cn","ln-s.net","ln-s.ru","lnk.gd","lnk.ms","lnkd.in","lnkurl.com","lru.jp","lt.tl","lurl.no","macte.ch","mash.to","merky.de","migre.me","miniurl.com","minurl.fr","mke.me","moby.to","moourl.com","mrte.ch","myloc.me","myurl.in","n.pr","nbc.co","nblo.gs","nn.nf","not.my","notlong.com","nsfw.in","nutshellurl.com","nxy.in","nyti.ms","o-x.fr","oc1.us","om.ly","omf.gd","omoikane.net","on.cnn.com","on.mktw.net","onforb.es","orz.se","ow.ly","ping.fm","pli.gs","pnt.me","politi.co","post.ly","pp.gg","profile.to","ptiturl.com","pub.vitrue.com","qlnk.net","qte.me","qu.tc","qy.fi","r.ebay.com","r.im","rb6.me","read.bi","readthis.ca","reallytinyurl.com","redir.ec","redirects.ca","redirx.com","retwt.me","ri.ms","rickroll.it","riz.gd","rt.nu","ru.ly","rubyurl.com","rurl.org","rww.tw","s4c.in","s7y.us","safe.mn","sameurl.com","sdut.us","shar.es","shink.de","shorl.com","short.ie","short.to","shortlinks.co.uk","shorturl.com","shout.to","show.my","shrinkify.com","shrinkr.com","shrt.fr","shrt.st","shrten.com","shrunkin.com","simurl.com","slate.me","smallr.com","smsh.me","smurl.name","sn.im","snipr.com","snipurl.com","snurl.com","sp2.ro","spedr.com","srnk.net","srs.li","starturl.com","stks.co","su.pr","surl.co.uk","surl.hu","t.cn","t.co","t.lh.com","ta.gd","tbd.ly","tcrn.ch","tgr.me","tgr.ph","tighturl.com","tiniuri.com","tiny.cc","tiny.ly","tiny.pl","tinylink.in","tinyuri.ca","tinyurl.com","tk.","tl.gd","tmi.me","tnij.org","tnw.to","tny.com","to.ly","togoto.us","totc.us","toysr.us","tpm.ly","tr.im","tra.kz","trunc.it","twhub.com","twirl.at","twitclicks.com","twitterurl.net","twitterurl.org","twiturl.de","twurl.cc","twurl.nl","u.mavrev.com","u.nu","u76.org","ub0.cc","ulu.lu","updating.me","ur1.ca","url.az","url.co.uk","url.ie","url360.me","url4.eu","urlborg.com","urlbrief.com","urlcover.com","urlcut.com","urlenco.de","urli.nl","urls.im","urlshorteningservicefortwitter.com","urlx.ie","urlzen.com","usat.ly","use.my","vb.ly","vevo.ly","vgn.am","vl.am","vm.lc","w55.de","wapo.st","wapurl.co.uk","wipi.es","wp.me","x.vu","xr.com","xrl.in","xrl.us","xurl.es","xurl.jp","y.ahoo.it","yatuc.com","ye.pe","yep.it","yfrog.com","yhoo.it","yiyd.com","youtu.be","yuarel.com","z0p.de","zi.ma","zi.mu","zipmyurl.com","zud.me","zurl.ws","zz.gd","zzang.kr","›.ws","✩.ws","✿.ws","❥.ws","➔.ws","➞.ws","➡.ws","➨.ws","➯.ws","➹.ws","➽.ws"];return n("#jqoembeddata").length===0&&n('<span id="jqoembeddata"><\/span>').appendTo("body"),this.each(function(){var h=n(this),s=i&&(!i.indexOf("http://")||!i.indexOf("https://"))?i:h.attr("href"),r,c,l,a,v;if(u?t.onEmbed=u:t.onEmbed||(t.onEmbed=function(i){n.fn.oembed.insertCode(this,t.embedMethod,i)}),s!==null&&s!==undefined){for(c=0,l=f.length;c<l;c++)if(a=new RegExp("://"+f[c]+"/","i"),s.match(a)!==null)return v=n.extend({url:"http://api.longurl.org/v2/expand",dataType:"jsonp",data:{url:s,format:"json"},success:function(i){s=i["long-url"];r=n.fn.oembed.getOEmbedProvider(i["long-url"]);r!==null?(r.params=o(t[r.name])||{},r.maxWidth=t.maxWidth,r.maxHeight=t.maxHeight,e(h,s,r)):t.onProviderNotFound.call(h,s)}},t.ajaxOptions||{}),n.ajax(v),h;r=n.fn.oembed.getOEmbedProvider(s);r!==null?(r.params=o(t[r.name])||{},r.maxWidth=t.maxWidth,r.maxHeight=t.maxHeight,e(h,s,r)):t.onProviderNotFound.call(h,s)}return h})};var t;n.fn.oembed.defaults={maxWidth:null,maxHeight:null,useResponsiveResize:!1,includeHandle:!0,embedMethod:"auto",onProviderNotFound:function(){},beforeEmbed:function(){},afterEmbed:function(){},onEmbed:!1,onError:function(){},ajaxOptions:{timeout:2e3}};n.fn.oembed.insertCode=function(i,r,u){if(u!==null){r=="auto"&&i.attr("href")!==null?r="append":r=="auto"&&(r="replace");switch(r){case"replace":i.replaceWith(u.code);break;case"fill":i.html(u.code);break;case"append":i.wrap('<div class="oembedall-container"><\/div>');var f=i.parent();t.includeHandle&&n('<span class="oembedall-closehide">&darr;<\/span>').insertBefore(i).click(function(){var t=encodeURIComponent(n(this).text());n(this).html(t=="%E2%86%91"?"&darr;":"&uarr;");n(this).parent().children().last().toggle()});f.append("<br/>");try{u.code.clone().appendTo(f)}catch(e){f.append(u.code)}}}};n.fn.oembed.getPhotoCode=function(n,t){var i,r=t.title?t.title:"",u;return r+=t.author_name?" - "+t.author_name:"",r+=t.provider_name?" - "+t.provider_name:"",t.url?i='<div><a href="'+n+"\" target='_blank'><img src=\""+t.url+'" alt="'+r+'"/><\/a><\/div>':t.thumbnail_url?(u=t.thumbnail_url.replace("_s","_b"),i='<div><a href="'+n+"\" target='_blank'><img src=\""+u+'" alt="'+r+'"/><\/a><\/div>'):i=t.provider_name=="Flickr"?'<p><a href="'+n+"\" target='_blank'>"+n+"<\/a><\/p>":"<div>Error loading this picture<\/div>",i};n.fn.oembed.getRichCode=function(n,t){return t.html};n.fn.oembed.getGenericCode=function(n,t){var r=t.title!==null?t.title:n,i='<a href="'+n+'">'+r+"<\/a>";return t.html&&(i+="<div>"+t.html+"<\/div>"),i};n.fn.oembed.getOEmbedProvider=function(t){for(var r,u,f,i=0;i<n.fn.oembed.providers.length;i++)for(r=0,u=n.fn.oembed.providers[i].urlschemes.length;r<u;r++)if(f=new RegExp(n.fn.oembed.providers[i].urlschemes[r],"i"),t.match(f)!==null)return n.fn.oembed.providers[i];return null};n.fn.oembed.OEmbedProvider=function(i,r,u,f,e){this.name=i;this.type=r;this.urlschemes=u;this.apiendpoint=f;this.maxWidth=500;this.maxHeight=400;e=e||{};e.useYQL&&(e.yql=e.useYQL=="xml"?{xpath:"//oembed/html",from:"xml",apiendpoint:this.apiendpoint,url:function(n){return this.apiendpoint+"?format=xml&url="+n},datareturn:function(n){return n.html.replace(/.*\[CDATA\[(.*)\]\]>$/,"$1")||""}}:{from:"json",apiendpoint:this.apiendpoint,url:function(n){return this.apiendpoint+"?format=json&url="+n},datareturn:function(i){var f,o,s;if(i.json.type!="video"&&(i.json.url||i.json.thumbnail_url)&&!i.json.html.indexOf("iframe"))return'<img src="'+(i.json.url||i.json.thumbnail_url)+'" />';if(i.json.html.indexOf("iframe")){i.json.html.indexOf("allowfullscreen>")&&(i.json.html=i.json.html.replace("allowfullscreen>",'allowfullscreen="false">'));var e=n.parseHTML(i.json.html),r=e[0].width,u=e[0].height;return t.maxHeight&&t.maxWidth&&(t.useResponsiveResize?(o=r,s=u,r>t.maxWidth&&(f=t.maxWidth/r,o=t.maxWidth,s=u*f,u=u*f,r=r*f),u>t.maxHeight&&(f=t.maxHeight/u,s=t.maxHeight,o=r*f),u=s,r=o):(u=t.maxHeight,r=t.maxWidth)),e[0].width=r,e[0].height=u,e[0].outerHTML}return i.json.html||""}},this.apiendpoint=null);for(var o in e)this[o]=e[o];this.format=this.format||"json";this.callbackparameter=this.callbackparameter||"callback";this.embedtag=this.embedtag||{tag:""}};n.fn.updateOEmbedProvider=function(t,i,r,u,f){for(var o,e=0;e<n.fn.oembed.providers.length;e++)if(n.fn.oembed.providers[e].name===t&&(i!==null&&(n.fn.oembed.providers[e].type=i),r!==null&&(n.fn.oembed.providers[e].urlschemes=r),u!==null&&(n.fn.oembed.providers[e].apiendpoint=u),f!==null)){n.fn.oembed.providers[e].extraSettings=f;for(o in f)f[o]!==null&&(n.fn.oembed.providers[e][o]=f[o])}};n.fn.oembed.providers=[new n.fn.oembed.OEmbedProvider("youtube","video",["youtube\\.com/watch.+v=[\\w-]+&?","youtu\\.be/[\\w-]+","youtube.com/embed"],r()+"www.youtube.com/embed/$1?wmode=transparent",{templateRegex:/.*(?:v\=|be\/|embed\/)([\w\-]+)&?.*/,embedtag:{tag:"iframe",width:"425",height:"349"}}),new n.fn.oembed.OEmbedProvider("youtubeiframe","video",["youtube.com/embed"],"$1?wmode=transparent",{templateRegex:/(.*)/,embedtag:{tag:"iframe",width:"425",height:"349"}}),new n.fn.oembed.OEmbedProvider("wistia","video",["wistia.com/m/.+","wistia.com/embed/.+","wi.st/m/.+","wi.st/embed/.+"],"http://fast.wistia.com/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("xtranormal","video",["xtranormal\\.com/watch/.+"],"http://www.xtranormal.com/xtraplayr/$1/$2",{templateRegex:/.*com\/watch\/([\w\-]+)\/([\w\-]+).*/,embedtag:{tag:"iframe",width:"320",height:"269"}}),new n.fn.oembed.OEmbedProvider("scivee","video",["scivee.tv/node/.+"],"http://www.scivee.tv/flash/embedCast.swf?",{templateRegex:/.*tv\/node\/(.+)/,embedtag:{width:"480",height:"400",flashvars:"id=$1&type=3"}}),new n.fn.oembed.OEmbedProvider("veoh","video",["veoh.com/watch/.+"],"http://www.veoh.com/swf/webplayer/WebPlayer.swf?version=AFrontend.5.7.0.1337&permalinkId=$1&player=videodetailsembedded&videoAutoPlay=0&id=anonymous",{templateRegex:/.*watch\/([^\?]+).*/,embedtag:{width:"410",height:"341"}}),new n.fn.oembed.OEmbedProvider("gametrailers","video",["gametrailers\\.com/video/.+"],"http://media.mtvnservices.com/mgid:moses:video:gametrailers.com:$2",{templateRegex:/.*com\/video\/([\w\-]+)\/([\w\-]+).*/,embedtag:{width:"512",height:"288"}}),new n.fn.oembed.OEmbedProvider("funnyordie","video",["funnyordie\\.com/videos/.+"],"http://player.ordienetworks.com/flash/fodplayer.swf?",{templateRegex:/.*videos\/([^\/]+)\/([^\/]+)?/,embedtag:{width:512,height:328,flashvars:"key=$1"}}),new n.fn.oembed.OEmbedProvider("colledgehumour","video",["collegehumor\\.com/video/.+"],"http://www.collegehumor.com/moogaloop/moogaloop.swf?clip_id=$1&use_node_id=true&fullscreen=1",{templateRegex:/.*video\/([^\/]+).*/,embedtag:{width:600,height:338}}),new n.fn.oembed.OEmbedProvider("metacafe","video",["metacafe\\.com/watch/.+"],"http://www.metacafe.com/fplayer/$1/$2.swf",{templateRegex:/.*watch\/(\d+)\/(\w+)\/.*/,embedtag:{width:400,height:345}}),new n.fn.oembed.OEmbedProvider("bambuser","video",["bambuser\\.com/channel/.*/broadcast/.*"],"http://static.bambuser.com/r/player.swf?vid=$1",{templateRegex:/.*bambuser\.com\/channel\/.*\/broadcast\/(\w+).*/,embedtag:{width:512,height:339}}),new n.fn.oembed.OEmbedProvider("twitvid","video",["twitvid\\.com/.+"],"http://www.twitvid.com/embed.php?guid=$1&autoplay=0",{templateRegex:/.*twitvid\.com\/(\w+).*/,embedtag:{tag:"iframe",width:480,height:360}}),new n.fn.oembed.OEmbedProvider("aniboom","video",["aniboom\\.com/animation-video/.+"],"http://api.aniboom.com/e/$1",{templateRegex:/.*animation-video\/(\d+).*/,embedtag:{width:594,height:334}}),new n.fn.oembed.OEmbedProvider("vzaar","video",["vzaar\\.com/videos/.+","vzaar.tv/.+"],"http://view.vzaar.com/$1/player?",{templateRegex:/.*\/(\d+).*/,embedtag:{tag:"iframe",width:576,height:324}}),new n.fn.oembed.OEmbedProvider("snotr","video",["snotr\\.com/video/.+"],"http://www.snotr.com/embed/$1",{templateRegex:/.*\/(\d+).*/,embedtag:{tag:"iframe",width:400,height:330,nocache:1}}),new n.fn.oembed.OEmbedProvider("youku","video",["v.youku.com/v_show/id_.+"],"http://player.youku.com/player.php/sid/$1/v.swf",{templateRegex:/.*id_(.+)\.html.*/,embedtag:{width:480,height:400,nocache:1}}),new n.fn.oembed.OEmbedProvider("tudou","video",["tudou.com/programs/view/.+/"],"http://www.tudou.com/v/$1/v.swf",{templateRegex:/.*view\/(.+)\//,embedtag:{width:480,height:400,nocache:1}}),new n.fn.oembed.OEmbedProvider("embedr","video",["embedr\\.com/playlist/.+"],"http://embedr.com/swf/slider/$1/425/520/default/false/std?",{templateRegex:/.*playlist\/([^\/]+).*/,embedtag:{width:425,height:520}}),new n.fn.oembed.OEmbedProvider("blip","video",["blip\\.tv/.+"],"http://blip.tv/oembed/"),new n.fn.oembed.OEmbedProvider("minoto-video","video",["http://api.minoto-video.com/publishers/.+/videos/.+","http://dashboard.minoto-video.com/main/video/details/.+","http://embed.minoto-video.com/.+"],"http://api.minoto-video.com/services/oembed.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("animoto","video",["animoto.com/play/.+"],"http://animoto.com/services/oembed"),new n.fn.oembed.OEmbedProvider("hulu","video",["hulu\\.com/watch/.*"],"http://www.hulu.com/api/oembed.json"),new n.fn.oembed.OEmbedProvider("ustream","video",["ustream\\.tv/recorded/.*"],"http://www.ustream.tv/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("videojug","video",["videojug\\.com/(film|payer|interview).*"],"http://www.videojug.com/oembed.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("sapo","video",["videos\\.sapo\\.pt/.*"],"http://videos.sapo.pt/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("vodpod","video",["vodpod.com/watch/.*"],"http://vodpod.com/oembed.js",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("vimeo","video",["www.vimeo.com/groups/.*/videos/.*","www.vimeo.com/.*","vimeo.com/groups/.*/videos/.*","vimeo.com/.*"],"//vimeo.com/api/oembed.json"),new n.fn.oembed.OEmbedProvider("dailymotion","video",["dailymotion\\.com/.+"],"http://www.dailymotion.com/services/oembed"),new n.fn.oembed.OEmbedProvider("5min","video",["www\\.5min\\.com/.+"],"http://api.5min.com/oembed.xml",{useYQL:"xml"}),new n.fn.oembed.OEmbedProvider("National Film Board of Canada","video",["nfb\\.ca/film/.+"],"http://www.nfb.ca/remote/services/oembed/",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("qik","video",["qik\\.com/\\w+"],"http://qik.com/api/oembed.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("revision3","video",["revision3\\.com"],"http://revision3.com/api/oembed/"),new n.fn.oembed.OEmbedProvider("dotsub","video",["dotsub\\.com/view/.+"],"http://dotsub.com/services/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("clikthrough","video",["clikthrough\\.com/theater/video/\\d+"],"http://clikthrough.com/services/oembed"),new n.fn.oembed.OEmbedProvider("Kinomap","video",["kinomap\\.com/.+"],"http://www.kinomap.com/oembed"),new n.fn.oembed.OEmbedProvider("VHX","video",["vhx.tv/.+"],"http://vhx.tv/services/oembed.json"),new n.fn.oembed.OEmbedProvider("bambuser","video",["bambuser.com/.+"],"http://api.bambuser.com/oembed/iframe.json"),new n.fn.oembed.OEmbedProvider("justin.tv","video",["justin.tv/.+"],"http://api.justin.tv/api/embed/from_url.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("official.fm","rich",["official.fm/.+"],"http://official.fm/services/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("chirbit","rich",["chirb.it/.+"],"http://chirb.it/oembed.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("Huffduffer","rich",["huffduffer.com/[-.\\w@]+/\\d+"],"http://huffduffer.com/oembed"),new n.fn.oembed.OEmbedProvider("Spotify","rich",["open.spotify.com/(track|album|user)/"],"https://embed.spotify.com/oembed/"),new n.fn.oembed.OEmbedProvider("shoudio","rich",["shoudio.com/.+","shoud.io/.+"],"http://shoudio.com/api/oembed"),new n.fn.oembed.OEmbedProvider("mixcloud","rich",["mixcloud.com/.+"],r()+"www.mixcloud.com/oembed/",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("rdio.com","rich",["rd.io/.+","rdio.com"],r()+"www.rdio.com/api/oembed/"),new n.fn.oembed.OEmbedProvider("Soundcloud","rich",["soundcloud.com/.+","snd.sc/.+"],r()+"soundcloud.com/oembed",{format:"js"}),new n.fn.oembed.OEmbedProvider("bandcamp","rich",["bandcamp\\.com/album/.+"],null,{yql:{xpath:"//meta[contains(@content, \\'EmbeddedPlayer\\')]",from:"html",datareturn:function(n){return n.meta?'<iframe width="400" height="100" src="'+n.meta.content+'" allowtransparency="true" frameborder="0"><\/iframe>':!1}}}),new n.fn.oembed.OEmbedProvider("deviantart","photo",["deviantart.com/.+","fav.me/.+","deviantart.com/.+"],"http://backend.deviantart.com/oembed",{format:"jsonp"}),new n.fn.oembed.OEmbedProvider("skitch","photo",["skitch.com/.+"],null,{yql:{xpath:"json",from:"json",url:function(n){return"http://skitch.com/oembed/?format=json&url="+n},datareturn:function(t){return n.fn.oembed.getPhotoCode(t.json.url,t.json)}}}),new n.fn.oembed.OEmbedProvider("mobypicture","photo",["mobypicture.com/user/.+/view/.+","moby.to/.+"],"http://api.mobypicture.com/oEmbed"),new n.fn.oembed.OEmbedProvider("flickr","photo",["flickr\\.com/photos/.+"],"http://flickr.com/services/oembed",{callbackparameter:"jsoncallback"}),new n.fn.oembed.OEmbedProvider("photobucket","photo",["photobucket\\.com/(albums|groups)/.+"],r()+"photobucket.com/oembed/"),new n.fn.oembed.OEmbedProvider("instagram","photo",["instagr\\.?am(\\.com)?/.+"],r()+"api.instagram.com/oembed"),new n.fn.oembed.OEmbedProvider("SmugMug","photo",["smugmug.com/[-.\\w@]+/.+"],"http://api.smugmug.com/services/oembed/"),new n.fn.oembed.OEmbedProvider("dribbble","photo",["dribbble.com/shots/.+"],"http://api.dribbble.com/shots/$1?callback=?",{templateRegex:/.*shots\/([\d]+).*/,templateData:function(n){return n.image_teaser_url?'<img src="'+n.image_teaser_url+'"/>':!1}}),new n.fn.oembed.OEmbedProvider("chart.ly","photo",["chart\\.ly/[a-z0-9]{6,8}"],"http://chart.ly/uploads/large_$1.png",{templateRegex:/.*ly\/([^\/]+).*/,embedtag:{tag:"img"},nocache:1}),new n.fn.oembed.OEmbedProvider("circuitlab","photo",["circuitlab.com/circuit/.+"],"https://www.circuitlab.com/circuit/$1/screenshot/540x405/",{templateRegex:/.*circuit\/([^\/]+).*/,embedtag:{tag:"img"},nocache:1}),new n.fn.oembed.OEmbedProvider("23hq","photo",["23hq.com/[-.\\w@]+/photo/.+"],"http://www.23hq.com/23/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("img.ly","photo",["img\\.ly/.+"],"http://img.ly/show/thumb/$1",{templateRegex:/.*ly\/([^\/]+).*/,embedtag:{tag:"img"},nocache:1}),new n.fn.oembed.OEmbedProvider("twitgoo.com","photo",["twitgoo\\.com/.+"],"http://twitgoo.com/show/thumb/$1",{templateRegex:/.*com\/([^\/]+).*/,embedtag:{tag:"img"},nocache:1}),new n.fn.oembed.OEmbedProvider("imgur.com","photo",["imgur\\.com/gallery/.+"],r()+"imgur.com/$1l.jpg",{templateRegex:/.*gallery\/([^\/]+).*/,embedtag:{tag:"img"},nocache:1}),new n.fn.oembed.OEmbedProvider("visual.ly","rich",["visual\\.ly/.+"],null,{yql:{xpath:"//a[@id=\\'gc_article_graphic_image\\']/img",from:"htmlstring"}}),new n.fn.oembed.OEmbedProvider("gravtar","photo",["mailto:.+"],null,{templateRegex:/mailto:([^\/]+).*/,template:function(n,t){return'<img src="http://gravatar.com/avatar/'+t.md5()+'.jpg" alt="on Gravtar" class="jqoaImg">'}}),new n.fn.oembed.OEmbedProvider("twitter","rich",["twitter.com/.+"],"https://api.twitter.com/1/statuses/oembed.json?id="),new n.fn.oembed.OEmbedProvider("gmep","rich",["gmep.imeducate.com/.*","gmep.org/.*"],"http://gmep.org/oembed.json"),new n.fn.oembed.OEmbedProvider("urtak","rich",["urtak.com/(u|clr)/.+"],"http://oembed.urtak.com/1/oembed"),new n.fn.oembed.OEmbedProvider("cacoo","rich",["cacoo.com/.+"],"http://cacoo.com/oembed.json"),new n.fn.oembed.OEmbedProvider("dailymile","rich",["dailymile.com/people/.*/entries/.*"],"http://api.dailymile.com/oembed"),new n.fn.oembed.OEmbedProvider("dipity","rich",["dipity.com/timeline/.+"],"http://www.dipity.com/oembed/timeline/",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("sketchfab","rich",["sketchfab.com/show/.+"],"http://sketchfab.com/oembed",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("speakerdeck","rich",["speakerdeck.com/.+"],"http://speakerdeck.com/oembed.json",{useYQL:"json"}),new n.fn.oembed.OEmbedProvider("popplet","rich",["popplet.com/app/.*"],"http://popplet.com/app/Popplet_Alpha.swf?page_id=$1&em=1",{templateRegex:/.*#\/([^\/]+).*/,embedtag:{width:460,height:460}}),new n.fn.oembed.OEmbedProvider("pearltrees","rich",["pearltrees.com/.*"],"http://cdn.pearltrees.com/s/embed/getApp?",{templateRegex:/.*N-f=1_(\d+).*N-p=(\d+).*/,embedtag:{width:460,height:460,flashvars:"lang=en_US&amp;embedId=pt-embed-$1-693&amp;treeId=$1&amp;pearlId=$2&amp;treeTitle=Diagrams%2FVisualization&amp;site=www.pearltrees.com%2FF"}}),new n.fn.oembed.OEmbedProvider("prezi","rich",["prezi.com/.*"],"http://prezi.com/bin/preziloader.swf?",{templateRegex:/.*com\/([^\/]+)\/.*/,embedtag:{width:550,height:400,flashvars:"prezi_id=$1&amp;lock_to_path=0&amp;color=ffffff&amp;autoplay=no&amp;autohide_ctrls=0"}}),new n.fn.oembed.OEmbedProvider("tourwrist","rich",["tourwrist.com/tours/.+"],null,{templateRegex:/.*tours.([\d]+).*/,template:function(n,t){return setTimeout(function(){loadEmbeds&&loadEmbeds()},2e3),"<div id='"+t+"' class='tourwrist-tour-embed direct'><\/div> <script type='text/javascript' src='http://tourwrist.com/tour_embed.js'><\/script>"}}),new n.fn.oembed.OEmbedProvider("meetup","rich",["meetup\\.(com|ps)/.+"],r()+"api.meetup.com/oembed"),new n.fn.oembed.OEmbedProvider("ebay","rich",["ebay\\.*"],r()+"togo.ebay.com/togo/togo.swf?2008013100",{templateRegex:/.*\/([^\/]+)\/(\d{10,13}).*/,embedtag:{width:355,height:300,flashvars:"base=http://togo.ebay.com/togo/&lang=en-us&mode=normal&itemid=$2&query=$1"}}),new n.fn.oembed.OEmbedProvider("wikipedia","rich",["wikipedia.org/wiki/.+"],"http://$1.wikipedia.org/w/api.php?action=parse&page=$2&format=json&section=0&callback=?",{templateRegex:/.*\/\/([\w]+).*\/wiki\/([^\/]+).*/,templateData:function(n){if(!n.parse)return!1;var t=n.parse.text["*"].replace(/href="\/wiki/g,'href="http://en.wikipedia.org/wiki');return'<div id="content"><h3><a class="nav-link" href="http://en.wikipedia.org/wiki/'+n.parse.displaytitle+'">'+n.parse.displaytitle+"<\/a><\/h3>"+t+"<\/div>"}}),new n.fn.oembed.OEmbedProvider("imdb","rich",["imdb.com/title/.+"],"http://www.imdbapi.com/?i=$1&callback=?",{templateRegex:/.*\/title\/([^\/]+).*/,templateData:function(n){return n.Title?'<div id="content"><h3><a class="nav-link" href="http://imdb.com/title/'+n.ID+'/">'+n.Title+"<\/a> ("+n.Year+")<\/h3><p>Starring: "+n.Actors+'<\/p><div id="photo-wrap" style="margin: auto;width:600px;height:450px;"><img class="photo" id="photo-display" src="'+n.Poster+'" alt="'+n.Title+'"><\/div> <div id="view-photo-caption">'+n.Plot+"<\/div><\/div>":!1}}),new n.fn.oembed.OEmbedProvider("livejournal","rich",["livejournal.com/"],"http://ljpic.seacrow.com/json/$2$4?jsonp=?",{templateRegex:/(http:\/\/(((?!users).)+)\.livejournal\.com|.*users\.livejournal\.com\/([^\/]+)).*/,templateData:function(n){return!!n.username&&'<div><img src="'+n.image+'" align="left" style="margin-right: 1em;" /><span class="oembedall-ljuser"><a href="http://'+n.username+'.livejournal.com/profile"><img src="http://www.livejournal.com/img/userinfo.gif" alt="[info]" width="17" height="17" /><\/a><a href="http://'+n.username+'.livejournal.com/">'+n.username+"<\/a><\/span><br />"+n.name+"<\/div>"}}),new n.fn.oembed.OEmbedProvider("circuitbee","rich",["circuitbee\\.com/circuit/view/.+"],"http://c.circuitbee.com/build/r/schematic-embed.html?id=$1",{templateRegex:/.*circuit\/view\/(\d+).*/,embedtag:{tag:"iframe",width:"500",height:"350"}}),new n.fn.oembed.OEmbedProvider("googlecalendar","rich",["www.google.com/calendar/embed?.+"],"$1",{templateRegex:/(.*)/,embedtag:{tag:"iframe",width:"800",height:"600"}}),new n.fn.oembed.OEmbedProvider("jsfiddle","rich",["jsfiddle.net/[^/]+/?"],"http://jsfiddle.net/$1/embedded/result,js,resources,html,css/?",{templateRegex:/.*net\/([^\/]+).*/,embedtag:{tag:"iframe",width:"100%",height:"300"}}),new n.fn.oembed.OEmbedProvider("jsbin","rich",["jsbin.com/.+"],"http://jsbin.com/$1/?",{templateRegex:/.*com\/([^\/]+).*/,embedtag:{tag:"iframe",width:"100%",height:"300"}}),new n.fn.oembed.OEmbedProvider("jotform","rich",["form.jotform.co/form/.+"],"$1?",{templateRegex:/(.*)/,embedtag:{tag:"iframe",width:"100%",height:"507"}}),new n.fn.oembed.OEmbedProvider("reelapp","rich",["reelapp\\.com/.+"],"http://www.reelapp.com/$1/embed",{templateRegex:/.*com\/(\S{6}).*/,embedtag:{tag:"iframe",width:"400",height:"338"}}),new n.fn.oembed.OEmbedProvider("linkedin","rich",["linkedin.com/pub/.+"],"https://www.linkedin.com/cws/member/public_profile?public_profile_url=$1&format=inline&isFramed=true",{templateRegex:/(.*)/,embedtag:{tag:"iframe",width:"368px",height:"auto"}}),new n.fn.oembed.OEmbedProvider("timetoast","rich",["timetoast.com/timelines/[0-9]+"],"http://www.timetoast.com/flash/TimelineViewer.swf?passedTimelines=$1",{templateRegex:/.*timelines\/([0-9]*)/,embedtag:{width:550,height:400,nocache:1}}),new n.fn.oembed.OEmbedProvider("pastebin","rich",["pastebin\\.com/[\\S]{8}"],"http://pastebin.com/embed_iframe.php?i=$1",{templateRegex:/.*\/(\S{8}).*/,embedtag:{tag:"iframe",width:"100%",height:"auto"}}),new n.fn.oembed.OEmbedProvider("mixlr","rich",["mixlr.com/.+"],"http://mixlr.com/embed/$1?autoplay=ae",{templateRegex:/.*com\/([^\/]+).*/,embedtag:{tag:"iframe",width:"100%",height:"auto"}}),new n.fn.oembed.OEmbedProvider("pastie","rich",["pastie\\.org/pastes/.+"],null,{yql:{xpath:'//pre[@class="textmate-source"]'}}),new n.fn.oembed.OEmbedProvider("github","rich",["gist.github.com/.+"],"https://github.com/api/oembed"),new n.fn.oembed.OEmbedProvider("github","rich",["github.com/[-.\\w@]+/[-.\\w@]+"],"https://api.github.com/repos/$1/$2?callback=?",{templateRegex:/.*\/([^\/]+)\/([^\/]+).*/,templateData:function(n){return n.data.html_url?'<div class="oembedall-githubrepos"><ul class="oembedall-repo-stats"><li>'+n.data.language+'<\/li><li class="oembedall-watchers"><a title="Watchers" href="'+n.data.html_url+'/watchers">&#x25c9; '+n.data.watchers+'<\/a><\/li><li class="oembedall-forks"><a title="Forks" href="'+n.data.html_url+'/network">&#x0265; '+n.data.forks+'<\/a><\/li><\/ul><h3><a href="'+n.data.html_url+'">'+n.data.name+'<\/a><\/h3><div class="oembedall-body"><p class="oembedall-description">'+n.data.description+'<\/p><p class="oembedall-updated-at">Last updated: '+n.data.pushed_at+"<\/p><\/div><\/div>":!1}}),new n.fn.oembed.OEmbedProvider("facebook","rich",["facebook.com/(people/[^\\/]+/\\d+|[^\\/]+$)"],"https://graph.facebook.com/$2$3/?callback=?",{templateRegex:/.*facebook.com\/(people\/[^\/]+\/(\d+).*|([^\/]+$))/,templateData:function(n){if(!n.id)return!1;var t='<div class="oembedall-facebook1"><div class="oembedall-facebook2"><a href="http://www.facebook.com/">facebook<\/a> ';return t+=n.from?'<a href="http://www.facebook.com/'+n.from.id+'">'+n.from.name+"<\/a>":n.link?'<a href="'+n.link+'">'+n.name+"<\/a>":n.username?'<a href="http://www.facebook.com/'+n.username+'">'+n.name+"<\/a>":'<a href="http://www.facebook.com/'+n.id+'">'+n.name+"<\/a>",t+='<\/div><div class="oembedall-facebookBody"><div class="contents">',t+=n.picture?'<a href="'+n.link+'"><img src="'+n.picture+'"><\/a>':'<img src="https://graph.facebook.com/'+n.id+'/picture">',n.from&&(t+='<a href="'+n.link+'">'+n.name+"<\/a>"),n.founded&&(t+="Founded: <strong>"+n.founded+"<\/strong><br>"),n.category&&(t+="Category: <strong>"+n.category+"<\/strong><br>"),n.website&&(t+='Website: <strong><a href="'+n.website+'">'+n.website+"<\/a><\/strong><br>"),n.gender&&(t+="Gender: <strong>"+n.gender+"<\/strong><br>"),n.description&&(t+=n.description+"<br>"),t+"<\/div><\/div>"}}),new n.fn.oembed.OEmbedProvider("stackoverflow","rich",["stackoverflow.com/questions/[\\d]+"],"http://api.stackoverflow.com/1.1/questions/$1?body=true&jsonp=?",{templateRegex:/.*questions\/([\d]+).*/,templateData:function(t){if(!t.questions)return!1;var r=t.questions[0],f=n(r.body).text(),u='<div class="oembedall-stoqembed"><div class="oembedall-statscontainer"><div class="oembedall-statsarrow"><\/div><div class="oembedall-stats"><div class="oembedall-vote"><div class="oembedall-votes"><span class="oembedall-vote-count-post"><strong>'+(r.up_vote_count-r.down_vote_count)+'<\/strong><\/span><div class="oembedall-viewcount">vote(s)<\/div><\/div><\/div><div class="oembedall-status"><strong>'+r.answer_count+'<\/strong>answer<\/div><\/div><div class="oembedall-views">'+r.view_count+' view(s)<\/div><\/div><div class="oembedall-summary"><h3><a class="oembedall-question-hyperlink" href="http://stackoverflow.com/questions/'+r.question_id+'/">'+r.title+'<\/a><\/h3><div class="oembedall-excerpt">'+f.substring(0,100)+'...<\/div><div class="oembedall-tags">';for(i in r.tags)u+='<a title="" class="oembedall-post-tag" href="http://stackoverflow.com/questions/tagged/'+r.tags[i]+'">'+r.tags[i]+"<\/a>";return u+('<\/div><div class="oembedall-fr"><div class="oembedall-user-info"><div class="oembedall-user-gravatar32"><a href="http://stackoverflow.com/users/'+r.owner.user_id+"/"+r.owner.display_name+'"><img width="32" height="32" alt="" src="http://www.gravatar.com/avatar/'+r.owner.email_hash+'?s=32&amp;d=identicon&amp;r=PG"><\/a><\/div><div class="oembedall-user-details"><a href="http://stackoverflow.com/users/'+r.owner.user_id+"/"+r.owner.display_name+'">'+r.owner.display_name+'<\/a><br><span title="reputation score" class="oembedall-reputation-score">'+r.owner.reputation+"<\/span><\/div><\/div><\/div><\/div><\/div>")}}),new n.fn.oembed.OEmbedProvider("wordpress","rich",["wordpress\\.com/.+","blogs\\.cnn\\.com/.+","techcrunch\\.com/.+","wp\\.me/.+"],"http://public-api.wordpress.com/oembed/1.0/?for=jquery-oembed-all"),new n.fn.oembed.OEmbedProvider("screenr","rich",["screenr.com"],"http://www.screenr.com/embed/$1",{templateRegex:/.*\/([^\/]+).*/,embedtag:{tag:"iframe",width:"650",height:396}}),new n.fn.oembed.OEmbedProvider("gigpans","rich",["gigapan\\.org/[-.\\w@]+/\\d+"],"http://gigapan.org/gigapans/$1/options/nosnapshots/iframe/flash.html",{templateRegex:/.*\/(\d+)\/?.*/,embedtag:{tag:"iframe",width:"100%",height:400}}),new n.fn.oembed.OEmbedProvider("scribd","rich",["scribd\\.com/.+"],r()+"www.scribd.com/embeds/$1/content?start_page=1&view_mode=list",{templateRegex:/.*doc\/([^\/]+).*/,embedtag:{tag:"iframe",width:"100%",height:600}}),new n.fn.oembed.OEmbedProvider("kickstarter","rich",["kickstarter\\.com/projects/.+"],"$1/widget/card.html",{templateRegex:/([^\?]+).*/,embedtag:{tag:"iframe",width:"220",height:380}}),new n.fn.oembed.OEmbedProvider("amazon","rich",["amzn.com/B+","amazon.com.*/(B\\S+)($|\\/.*)"],r()+"rcm.amazon.com/e/cm?t=_APIKEY_&o=1&p=8&l=as1&asins=$1&ref=qf_br_asin_til&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr",{apikey:!0,templateRegex:/.*\/(B[0-9A-Z]+)($|\/.*)/,embedtag:{tag:"iframe",width:"120px",height:"240px"}}),new n.fn.oembed.OEmbedProvider("slideshare","rich",["slideshare.net"],r()+"www.slideshare.net/api/oembed/2",{format:"jsonp"}),new n.fn.oembed.OEmbedProvider("roomsharejp","rich",["roomshare\\.jp/(en/)?post/.*"],"http://roomshare.jp/oembed.json"),new n.fn.oembed.OEmbedProvider("lanyard","rich",["lanyrd.com/\\d+/.+"],null,{yql:{xpath:'(//div[@class="primary"])[1]',from:"htmlstring",datareturn:function(n){return n.result?'<div class="oembedall-lanyard">'+n.result+"<\/div>":!1}}}),new n.fn.oembed.OEmbedProvider("asciiartfarts","rich",["asciiartfarts.com/\\d+.html"],null,{yql:{xpath:"//pre/font",from:"htmlstring",datareturn:function(n){return n.result?'<pre style="background-color:000;">'+n.result+"<\/div>":!1}}}),new n.fn.oembed.OEmbedProvider("opengraph","rich",[".*"],null,{yql:{xpath:"//meta|//title|//link",from:"html",datareturn:function(i){var r,u,f;return(!i["og:title"]&&i.title&&i.description&&(i["og:title"]=i.title),!i["og:title"]&&!i.title)?!1:(r=n("<p/>"),i["og:video"]?(u=n('<embed src="'+i["og:video"]+'"/>'),u.attr("type",i["og:video:type"]||"application/x-shockwave-flash").css("max-height",t.maxHeight||"auto").css("max-width",t.maxWidth||"auto"),i["og:video:width"]&&u.attr("width",i["og:video:width"]),i["og:video:height"]&&u.attr("height",i["og:video:height"]),r.append(u)):i["og:image"]&&(f=n('<img src="'+i["og:image"]+'">'),f.css("max-height",t.maxHeight||"auto").css("max-width",t.maxWidth||"auto"),i["og:image:width"]&&f.attr("width",i["og:image:width"]),i["og:image:height"]&&f.attr("height",i["og:image:height"]),r.append(f)),i["og:title"]&&r.append("<b>"+i["og:title"]+"<\/b><br/>"),i["og:description"]?r.append(i["og:description"]+"<br/>"):i.description&&r.append(i.description+"<br/>"),r)}}})]})(jQuery);String.prototype.md5=function(){var u=function(n,t){var i=(n&65535)+(t&65535),r=(n>>16)+(t>>16)+(i>>16);return r<<16|i&65535},e=function(n,t){return n<<t|n>>>32-t},f=function(n,t,i,r,f,o){return u(e(u(u(t,n),u(r,o)),f),i)},n=function(n,t,i,r,u,e,o){return f(t&i|~t&r,n,t,u,e,o)},t=function(n,t,i,r,u,e,o){return f(t&r|i&~r,n,t,u,e,o)},i=function(n,t,i,r,u,e,o){return f(t^i^r,n,t,u,e,o)},r=function(n,t,i,r,u,e,o){return f(i^(t|~r),n,t,u,e,o)},o=function(f){for(var l,a,v,y,p=f.length,e=1732584193,o=-271733879,s=-1732584194,h=271733878,c=0;c<p;c+=16)l=e,a=o,v=s,y=h,e=n(e,o,s,h,f[c+0],7,-680876936),h=n(h,e,o,s,f[c+1],12,-389564586),s=n(s,h,e,o,f[c+2],17,606105819),o=n(o,s,h,e,f[c+3],22,-1044525330),e=n(e,o,s,h,f[c+4],7,-176418897),h=n(h,e,o,s,f[c+5],12,1200080426),s=n(s,h,e,o,f[c+6],17,-1473231341),o=n(o,s,h,e,f[c+7],22,-45705983),e=n(e,o,s,h,f[c+8],7,1770035416),h=n(h,e,o,s,f[c+9],12,-1958414417),s=n(s,h,e,o,f[c+10],17,-42063),o=n(o,s,h,e,f[c+11],22,-1990404162),e=n(e,o,s,h,f[c+12],7,1804603682),h=n(h,e,o,s,f[c+13],12,-40341101),s=n(s,h,e,o,f[c+14],17,-1502002290),o=n(o,s,h,e,f[c+15],22,1236535329),e=t(e,o,s,h,f[c+1],5,-165796510),h=t(h,e,o,s,f[c+6],9,-1069501632),s=t(s,h,e,o,f[c+11],14,643717713),o=t(o,s,h,e,f[c+0],20,-373897302),e=t(e,o,s,h,f[c+5],5,-701558691),h=t(h,e,o,s,f[c+10],9,38016083),s=t(s,h,e,o,f[c+15],14,-660478335),o=t(o,s,h,e,f[c+4],20,-405537848),e=t(e,o,s,h,f[c+9],5,568446438),h=t(h,e,o,s,f[c+14],9,-1019803690),s=t(s,h,e,o,f[c+3],14,-187363961),o=t(o,s,h,e,f[c+8],20,1163531501),e=t(e,o,s,h,f[c+13],5,-1444681467),h=t(h,e,o,s,f[c+2],9,-51403784),s=t(s,h,e,o,f[c+7],14,1735328473),o=t(o,s,h,e,f[c+12],20,-1926607734),e=i(e,o,s,h,f[c+5],4,-378558),h=i(h,e,o,s,f[c+8],11,-2022574463),s=i(s,h,e,o,f[c+11],16,1839030562),o=i(o,s,h,e,f[c+14],23,-35309556),e=i(e,o,s,h,f[c+1],4,-1530992060),h=i(h,e,o,s,f[c+4],11,1272893353),s=i(s,h,e,o,f[c+7],16,-155497632),o=i(o,s,h,e,f[c+10],23,-1094730640),e=i(e,o,s,h,f[c+13],4,681279174),h=i(h,e,o,s,f[c+0],11,-358537222),s=i(s,h,e,o,f[c+3],16,-722521979),o=i(o,s,h,e,f[c+6],23,76029189),e=i(e,o,s,h,f[c+9],4,-640364487),h=i(h,e,o,s,f[c+12],11,-421815835),s=i(s,h,e,o,f[c+15],16,530742520),o=i(o,s,h,e,f[c+2],23,-995338651),e=r(e,o,s,h,f[c+0],6,-198630844),h=r(h,e,o,s,f[c+7],10,1126891415),s=r(s,h,e,o,f[c+14],15,-1416354905),o=r(o,s,h,e,f[c+5],21,-57434055),e=r(e,o,s,h,f[c+12],6,1700485571),h=r(h,e,o,s,f[c+3],10,-1894986606),s=r(s,h,e,o,f[c+10],15,-1051523),o=r(o,s,h,e,f[c+1],21,-2054922799),e=r(e,o,s,h,f[c+8],6,1873313359),h=r(h,e,o,s,f[c+15],10,-30611744),s=r(s,h,e,o,f[c+6],15,-1560198380),o=r(o,s,h,e,f[c+13],21,1309151649),e=r(e,o,s,h,f[c+4],6,-145523070),h=r(h,e,o,s,f[c+11],10,-1120210379),s=r(s,h,e,o,f[c+2],15,718787259),o=r(o,s,h,e,f[c+9],21,-343485551),e=u(e,l),o=u(o,a),s=u(s,v),h=u(h,y);return[e,o,s,h]},s=function(n){for(var i="0123456789abcdef",r="",u=n.length*4,t=0;t<u;t++)r+=i.charAt(n[t>>2]>>t%4*8+4&15)+i.charAt(n[t>>2]>>t%4*8&15);return r},h=function(n){for(var u=(n.length+8>>6)+1,i=[],e=u*16,t,f=n.length,r=0;r<e;r++)i.push(0);for(t=0;t<f;t++)i[t>>2]|=(n.charCodeAt(t)&255)<<t%4*8;return i[t>>2]|=128<<t%4*8,i[u*16-2]=f*8,i};return s(o(h(this)))};
diff --git a/sources/plugins/oembed/plugin.js b/sources/plugins/oembed/plugin.js
new file mode 100644
index 0000000..9ad1ead
--- /dev/null
+++ b/sources/plugins/oembed/plugin.js
@@ -0,0 +1,446 @@
1/**
2* oEmbed Plugin plugin
3* Licensed under the MIT license
4* jQuery Embed Plugin: http://code.google.com/p/jquery-oembed/ (MIT License)
5* Plugin for: http://ckeditor.com/license (GPL/LGPL/MPL: http://ckeditor.com/license)
6*/
7
8(function() {
9 CKEDITOR.plugins.add('oembed', {
10 icons: 'oembed',
11 hidpi: true,
12 requires: 'widget,dialog',
13 lang: 'de,en,fr,nl,pl,pt-br,ru,tr', // %REMOVE_LINE_CORE%
14 version: 1.17,
15 init: function(editor) {
16 // Load jquery?
17 loadjQueryLibaries();
18
19 CKEDITOR.tools.extend(CKEDITOR.editor.prototype, {
20 oEmbed: function(url, maxWidth, maxHeight, responsiveResize) {
21
22 if (url.length < 1 || url.indexOf('http') < 0) {
23 alert(editor.lang.oembed.invalidUrl);
24 return false;
25 }
26
27 function embed() {
28 if (maxWidth == null || maxWidth == 'undefined') {
29 maxWidth = null;
30 }
31
32 if (maxHeight == null || maxHeight == 'undefined') {
33 maxHeight = null;
34 }
35
36 if (responsiveResize == null || responsiveResize == 'undefined') {
37 responsiveResize = false;
38 }
39
40 embedCode(url, editor, false, maxWidth, maxHeight, responsiveResize);
41 }
42
43 if (typeof(jQuery.fn.oembed) === 'undefined') {
44 CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('oembed') + 'libs/jquery.oembed.min.js'), function() {
45 embed();
46 });
47 } else {
48 embed();
49 }
50
51 return true;
52 }
53 });
54
55 editor.widgets.add('oembed', {
56 draggable: false,
57 mask: true,
58 dialog: 'oembed',
59 allowedContent: {
60 div: {
61 styles: 'text-align,float',
62 attributes: '*',
63 classes: editor.config.oembed_WrapperClass != null ? editor.config.oembed_WrapperClass : "embeddedContent"
64 },
65 'div(embeddedContent,oembed-provider-*) iframe': {
66 attributes: '*'
67 },
68 'div(embeddedContent,oembed-provider-*) blockquote': {
69 attributes: '*'
70 },
71 'div(embeddedContent,oembed-provider-*) script': {
72 attributes: '*'
73 }
74 },
75 template:
76 '<div class="' + (editor.config.oembed_WrapperClass != null ? editor.config.oembed_WrapperClass : "embeddedContent") + '">' +
77 '</div>',
78 upcast: function(element) {
79 return element.name == 'div' && element.hasClass(editor.config.oembed_WrapperClass != null ? editor.config.oembed_WrapperClass : "embeddedContent");
80 },
81 init: function() {
82 var data = {
83 oembed: this.element.data('oembed') || '',
84 resizeType: this.element.data('resizeType') || 'noresize',
85 maxWidth: this.element.data('maxWidth') || 560,
86 maxHeight: this.element.data('maxHeight') || 315,
87 align: this.element.data('align') || 'none',
88 oembed_provider: this.element.data('oembed_provider') || ''
89 };
90
91 this.setData(data);
92 this.element.addClass('oembed-provider-' + data.oembed_provider);
93
94 this.on('dialog', function(evt) {
95 evt.data.widget = this;
96 }, this);
97 }
98 });
99
100 editor.ui.addButton('oembed', {
101 label: editor.lang.oembed.button,
102 command: 'oembed',
103 toolbar: 'insert,10',
104 icon: this.path + "icons/" + (CKEDITOR.env.hidpi ? "hidpi/" : "") + "oembed.png"
105 });
106
107 var resizeTypeChanged = function() {
108 var dialog = this.getDialog(),
109 resizetype = this.getValue(),
110 maxSizeBox = dialog.getContentElement('general', 'maxSizeBox').getElement(),
111 sizeBox = dialog.getContentElement('general', 'sizeBox').getElement();
112
113 if (resizetype == 'noresize') {
114 maxSizeBox.hide();
115
116 sizeBox.hide();
117 } else if (resizetype == "custom") {
118 maxSizeBox.hide();
119
120 sizeBox.show();
121 } else {
122 maxSizeBox.show();
123
124 sizeBox.hide();
125 }
126
127 };
128
129 String.prototype.beginsWith = function(string) {
130 return (this.indexOf(string) === 0);
131 };
132
133 function loadjQueryLibaries() {
134 if (typeof(jQuery) === 'undefined') {
135 CKEDITOR.scriptLoader.load('//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js', function() {
136 jQuery.noConflict();
137 if (typeof(jQuery.fn.oembed) === 'undefined') {
138 CKEDITOR.scriptLoader.load(
139 CKEDITOR.getUrl(CKEDITOR.plugins.getPath('oembed') + 'libs/jquery.oembed.min.js')
140 );
141 }
142 });
143
144 } else if (typeof(jQuery.fn.oembed) === 'undefined') {
145 CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('oembed') + 'libs/jquery.oembed.min.js'));
146 }
147 }
148
149 function embedCode(url, instance, maxWidth, maxHeight, responsiveResize, resizeType, align, widget) {
150 jQuery('body').oembed(url, {
151 onEmbed: function(e) {
152 var elementAdded = false,
153 provider = jQuery.fn.oembed.getOEmbedProvider(url);
154
155 widget.element.data('resizeType', resizeType);
156 if (resizeType == "responsive" || resizeType == "custom") {
157 widget.element.data('maxWidth', maxWidth);
158 widget.element.data('maxHeight', maxHeight);
159 }
160
161 widget.element.data('align', align);
162
163 // TODO handle align
164 if (align == 'center') {
165 if (!widget.inline)
166 widget.element.setStyle('text-align', 'center');
167
168 widget.element.removeStyle('float');
169 } else {
170 if (!widget.inline)
171 widget.element.removeStyle('text-align');
172
173 if (align == 'none')
174 widget.element.removeStyle('float');
175 else
176 widget.element.setStyle('float', align);
177 }
178
179 if (typeof e.code === 'string') {
180 if (widget.element.$.firstChild) {
181 widget.element.$.removeChild(widget.element.$.firstChild);
182 }
183
184 widget.element.appendHtml(e.code);
185 widget.element.data('oembed', url);
186 widget.element.data('oembed_provider', provider.name);
187 widget.element.addClass('oembed-provider-' + provider.name);
188
189 elementAdded = true;
190 } else if (typeof e.code[0].outerHTML === 'string') {
191
192 if (widget.element.$.firstChild) {
193 widget.element.$.removeChild(widget.element.$.firstChild);
194 }
195
196 widget.element.appendHtml(e.code[0].outerHTML);
197 widget.element.data('oembed', url);
198 widget.element.data('oembed_provider', provider.name);
199 widget.element.addClass('oembed-provider-' + provider.name);
200
201 elementAdded = true;
202 } else {
203 alert(editor.lang.oembed.noEmbedCode);
204 }
205 },
206 onError: function(externalUrl) {
207 if (externalUrl.indexOf("vimeo.com") > 0) {
208 alert(editor.lang.oembed.noVimeo);
209 } else {
210 alert(editor.lang.oembed.Error);
211 }
212
213 },
214 maxHeight: maxHeight,
215 maxWidth: maxWidth,
216 useResponsiveResize: responsiveResize,
217 embedMethod: 'editor'
218 });
219 }
220
221 CKEDITOR.dialog.add('oembed', function(editor) {
222 return {
223 title: editor.lang.oembed.title,
224 minWidth: CKEDITOR.env.ie && CKEDITOR.env.quirks ? 568 : 550,
225 minHeight: 155,
226 onShow: function() {
227 var data = {
228 oembed: this.widget.element.data('oembed') || '',
229 resizeType: this.widget.element.data('resizeType') || 'noresize',
230 maxWidth: this.widget.element.data('maxWidth'),
231 maxHeight: this.widget.element.data('maxHeight'),
232 align: this.widget.element.data('align') || 'none'
233 };
234
235 this.widget.setData(data);
236
237 this.getContentElement('general', 'resizeType').setValue(data.resizeType);
238
239 this.getContentElement('general', 'align').setValue(data.align);
240
241 var resizetype = this.getContentElement('general', 'resizeType').getValue(),
242 maxSizeBox = this.getContentElement('general', 'maxSizeBox').getElement(),
243 sizeBox = this.getContentElement('general', 'sizeBox').getElement();
244
245 if (resizetype == 'noresize') {
246 maxSizeBox.hide();
247 sizeBox.hide();
248 } else if (resizetype == "custom") {
249 maxSizeBox.hide();
250
251 sizeBox.show();
252 } else {
253 maxSizeBox.show();
254
255 sizeBox.hide();
256 }
257 },
258
259 onOk: function() {
260 },
261 contents: [
262 {
263 label: editor.lang.common.generalTab,
264 id: 'general',
265 elements: [
266 {
267 type: 'html',
268 id: 'oembedHeader',
269 html: '<div style="white-space:normal;width:500px;padding-bottom:10px">' + editor.lang.oembed.pasteUrl + '</div>'
270 }, {
271 type: 'text',
272 id: 'embedCode',
273 focus: function() {
274 this.getElement().focus();
275 },
276 label: editor.lang.oembed.url,
277 title: editor.lang.oembed.pasteUrl,
278 setup: function(widget) {
279 if (widget.data.oembed) {
280 this.setValue(widget.data.oembed);
281 }
282 },
283 commit: function(widget) {
284 var dialog = CKEDITOR.dialog.getCurrent(),
285 inputCode = dialog.getValueOf('general', 'embedCode').replace(/\s/g, ""),
286 resizeType = dialog.getContentElement('general', 'resizeType').
287 getValue(),
288 align = dialog.getContentElement('general', 'align').
289 getValue(),
290 maxWidth = null,
291 maxHeight = null,
292 responsiveResize = false,
293 editorInstance = dialog.getParentEditor();
294
295 if (inputCode.length < 1 || inputCode.indexOf('http') < 0) {
296 alert(editor.lang.oembed.invalidUrl);
297 return false;
298 }
299
300 if (resizeType == "noresize") {
301 responsiveResize = false;
302 maxWidth = null;
303 maxHeight = null;
304 } else if (resizeType == "responsive") {
305 maxWidth = dialog.getContentElement('general', 'maxWidth').
306 getInputElement().
307 getValue();
308 maxHeight = dialog.getContentElement('general', 'maxHeight').
309 getInputElement().
310 getValue();
311
312 responsiveResize = true;
313 } else if (resizeType == "custom") {
314 maxWidth = dialog.getContentElement('general', 'width').
315 getInputElement().
316 getValue();
317 maxHeight = dialog.getContentElement('general', 'height').
318 getInputElement().
319 getValue();
320
321 responsiveResize = false;
322 }
323
324 embedCode(inputCode, editorInstance, maxWidth, maxHeight, responsiveResize, resizeType, align, widget);
325
326 widget.setData('oembed', inputCode);
327 widget.setData('resizeType', resizeType);
328 widget.setData('align', align);
329 widget.setData('maxWidth', maxWidth);
330 widget.setData('maxHeight', maxHeight);
331 }
332 }, {
333 type: 'hbox',
334 widths: ['50%', '50%'],
335 children: [
336 {
337 id: 'resizeType',
338 type: 'select',
339 label: editor.lang.oembed.resizeType,
340 'default': 'noresize',
341 setup: function(widget) {
342 if (widget.data.resizeType) {
343 this.setValue(widget.data.resizeType);
344 }
345 },
346 items: [
347 [editor.lang.oembed.noresize, 'noresize'],
348 [editor.lang.oembed.responsive, 'responsive'],
349 [editor.lang.oembed.custom, 'custom']
350 ],
351 onChange: resizeTypeChanged
352 }, {
353 type: 'hbox',
354 id: 'maxSizeBox',
355 widths: ['120px', '120px'],
356 style: 'float:left;position:absolute;left:58%;width:200px',
357 children: [
358 {
359 type: 'text',
360 width: '100px',
361 id: 'maxWidth',
362 'default': editor.config.oembed_maxWidth != null ? editor.config.oembed_maxWidth : '560',
363 label: editor.lang.oembed.maxWidth,
364 title: editor.lang.oembed.maxWidthTitle,
365 setup: function(widget) {
366 if (widget.data.maxWidth) {
367 this.setValue(widget.data.maxWidth);
368 }
369 }
370 }, {
371 type: 'text',
372 id: 'maxHeight',
373 width: '120px',
374 'default': editor.config.oembed_maxHeight != null ? editor.config.oembed_maxHeight : '315',
375 label: editor.lang.oembed.maxHeight,
376 title: editor.lang.oembed.maxHeightTitle,
377 setup: function(widget) {
378 if (widget.data.maxHeight) {
379 this.setValue(widget.data.maxHeight);
380 }
381 }
382 }
383 ]
384 }, {
385 type: 'hbox',
386 id: 'sizeBox',
387 widths: ['120px', '120px'],
388 style: 'float:left;position:absolute;left:58%;width:200px',
389 children: [
390 {
391 type: 'text',
392 id: 'width',
393 width: '100px',
394 'default': editor.config.oembed_maxWidth != null ? editor.config.oembed_maxWidth : '560',
395 label: editor.lang.oembed.width,
396 title: editor.lang.oembed.widthTitle,
397 setup: function(widget) {
398 if (widget.data.maxWidth) {
399 this.setValue(widget.data.maxWidth);
400 }
401 }
402 }, {
403 type: 'text',
404 id: 'height',
405 width: '120px',
406 'default': editor.config.oembed_maxHeight != null ? editor.config.oembed_maxHeight : '315',
407 label: editor.lang.oembed.height,
408 title: editor.lang.oembed.heightTitle,
409 setup: function(widget) {
410 if (widget.data.maxHeight) {
411 this.setValue(widget.data.maxHeight);
412 }
413 }
414 }
415 ]
416 }
417 ]
418 }, {
419 type: 'hbox',
420 id: 'alignment',
421 children: [
422 {
423 id: 'align',
424 type: 'radio',
425 items: [
426 [editor.lang.oembed.none, 'none'],
427 [editor.lang.common.alignLeft, 'left'],
428 [editor.lang.common.alignCenter, 'center'],
429 [editor.lang.common.alignRight, 'right']
430 ],
431 label: editor.lang.common.align,
432 setup: function(widget) {
433 this.setValue(widget.data.align);
434 }
435 }
436 ]
437 }
438 ]
439 }
440 ]
441 };
442 });
443 }
444 });
445 }
446)();
diff --git a/sources/plugins/panel/plugin.js b/sources/plugins/panel/plugin.js
new file mode 100644
index 0000000..b64c540
--- /dev/null
+++ b/sources/plugins/panel/plugin.js
@@ -0,0 +1,403 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 CKEDITOR.plugins.add( 'panel', {
8 beforeInit: function( editor ) {
9 editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
10 }
11 } );
12
13 /**
14 * Panel UI element.
15 *
16 * @readonly
17 * @property {String} [='panel']
18 * @member CKEDITOR
19 */
20 CKEDITOR.UI_PANEL = 'panel';
21
22 /**
23 * @class
24 * @constructor Creates a panel class instance.
25 * @param {CKEDITOR.dom.document} document
26 * @param {Object} definition
27 */
28 CKEDITOR.ui.panel = function( document, definition ) {
29 // Copy all definition properties to this object.
30 if ( definition )
31 CKEDITOR.tools.extend( this, definition );
32
33 // Set defaults.
34 CKEDITOR.tools.extend( this, {
35 className: '',
36 css: []
37 } );
38
39 this.id = CKEDITOR.tools.getNextId();
40 this.document = document;
41 this.isFramed = this.forceIFrame || this.css.length;
42
43 this._ = {
44 blocks: {}
45 };
46 };
47
48 /**
49 * Represents panel handler object.
50 *
51 * @class
52 * @singleton
53 * @extends CKEDITOR.ui.handlerDefinition
54 */
55 CKEDITOR.ui.panel.handler = {
56 /**
57 * Transforms a panel definition in a {@link CKEDITOR.ui.panel} instance.
58 *
59 * @param {Object} definition
60 * @returns {CKEDITOR.ui.panel}
61 */
62 create: function( definition ) {
63 return new CKEDITOR.ui.panel( definition );
64 }
65 };
66
67 var panelTpl = CKEDITOR.addTemplate( 'panel', '<div lang="{langCode}" id="{id}" dir={dir}' +
68 ' class="cke cke_reset_all {editorId} cke_panel cke_panel {cls} cke_{dir}"' +
69 ' style="z-index:{z-index}" role="presentation">' +
70 '{frame}' +
71 '</div>' );
72
73 var frameTpl = CKEDITOR.addTemplate( 'panel-frame', '<iframe id="{id}" class="cke_panel_frame" role="presentation" frameborder="0" src="{src}"></iframe>' );
74
75 var frameDocTpl = CKEDITOR.addTemplate( 'panel-frame-inner', '<!DOCTYPE html>' +
76 '<html class="cke_panel_container {env}" dir="{dir}" lang="{langCode}">' +
77 '<head>{css}</head>' +
78 '<body class="cke_{dir}"' +
79 ' style="margin:0;padding:0" onload="{onload}"></body>' +
80 '<\/html>' );
81
82 /** @class CKEDITOR.ui.panel */
83 CKEDITOR.ui.panel.prototype = {
84 /**
85 * Renders the combo.
86 *
87 * @param {CKEDITOR.editor} editor The editor instance which this button is
88 * to be used by.
89 * @param {Array} [output] The output array to which append the HTML relative
90 * to this button.
91 */
92 render: function( editor, output ) {
93 this.getHolderElement = function() {
94 var holder = this._.holder;
95
96 if ( !holder ) {
97 if ( this.isFramed ) {
98 var iframe = this.document.getById( this.id + '_frame' ),
99 parentDiv = iframe.getParent(),
100 doc = iframe.getFrameDocument();
101
102 // Make it scrollable on iOS. (#8308)
103 CKEDITOR.env.iOS && parentDiv.setStyles( {
104 'overflow': 'scroll',
105 '-webkit-overflow-scrolling': 'touch'
106 } );
107
108 var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function() {
109 this.isLoaded = true;
110 if ( this.onLoad )
111 this.onLoad();
112 }, this ) );
113
114 doc.write( frameDocTpl.output( CKEDITOR.tools.extend( {
115 css: CKEDITOR.tools.buildStyleHtml( this.css ),
116 onload: 'window.parent.CKEDITOR.tools.callFunction(' + onLoad + ');'
117 }, data ) ) );
118
119 var win = doc.getWindow();
120
121 // Register the CKEDITOR global.
122 win.$.CKEDITOR = CKEDITOR;
123
124 // Arrow keys for scrolling is only preventable with 'keypress' event in Opera (#4534).
125 doc.on( 'keydown', function( evt ) {
126 var keystroke = evt.data.getKeystroke(),
127 dir = this.document.getById( this.id ).getAttribute( 'dir' );
128
129 // Delegate key processing to block.
130 if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false ) {
131 evt.data.preventDefault();
132 return;
133 }
134
135 // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl)
136 if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) ) {
137 if ( this.onEscape && this.onEscape( keystroke ) === false )
138 evt.data.preventDefault();
139 }
140 }, this );
141
142 holder = doc.getBody();
143 holder.unselectable();
144 CKEDITOR.env.air && CKEDITOR.tools.callFunction( onLoad );
145 } else {
146 holder = this.document.getById( this.id );
147 }
148
149 this._.holder = holder;
150 }
151
152 return holder;
153 };
154
155 var data = {
156 editorId: editor.id,
157 id: this.id,
158 langCode: editor.langCode,
159 dir: editor.lang.dir,
160 cls: this.className,
161 frame: '',
162 env: CKEDITOR.env.cssClass,
163 'z-index': editor.config.baseFloatZIndex + 1
164 };
165
166 if ( this.isFramed ) {
167 // With IE, the custom domain has to be taken care at first,
168 // for other browers, the 'src' attribute should be left empty to
169 // trigger iframe's 'load' event.
170 var src =
171 CKEDITOR.env.air ? 'javascript:void(0)' : // jshint ignore:line
172 CKEDITOR.env.ie ? 'javascript:void(function(){' + encodeURIComponent( // jshint ignore:line
173 'document.open();' +
174 // In IE, the document domain must be set any time we call document.open().
175 '(' + CKEDITOR.tools.fixDomain + ')();' +
176 'document.close();'
177 ) + '}())' :
178 '';
179
180 data.frame = frameTpl.output( {
181 id: this.id + '_frame',
182 src: src
183 } );
184 }
185
186 var html = panelTpl.output( data );
187
188 if ( output )
189 output.push( html );
190
191 return html;
192 },
193
194 /**
195 * @todo
196 */
197 addBlock: function( name, block ) {
198 block = this._.blocks[ name ] = block instanceof CKEDITOR.ui.panel.block ? block : new CKEDITOR.ui.panel.block( this.getHolderElement(), block );
199
200 if ( !this._.currentBlock )
201 this.showBlock( name );
202
203 return block;
204 },
205
206 /**
207 * @todo
208 */
209 getBlock: function( name ) {
210 return this._.blocks[ name ];
211 },
212
213 /**
214 * @todo
215 */
216 showBlock: function( name ) {
217 var blocks = this._.blocks,
218 block = blocks[ name ],
219 current = this._.currentBlock;
220
221 // ARIA role works better in IE on the body element, while on the iframe
222 // for FF. (#8864)
223 var holder = !this.forceIFrame || CKEDITOR.env.ie ? this._.holder : this.document.getById( this.id + '_frame' );
224
225 if ( current )
226 current.hide();
227
228 this._.currentBlock = block;
229
230 CKEDITOR.fire( 'ariaWidget', holder );
231
232 // Reset the focus index, so it will always go into the first one.
233 block._.focusIndex = -1;
234
235 this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
236
237 block.show();
238
239 return block;
240 },
241
242 /**
243 * @todo
244 */
245 destroy: function() {
246 this.element && this.element.remove();
247 }
248 };
249
250 /**
251 * @class
252 *
253 * @todo class and all methods
254 */
255 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass( {
256 /**
257 * Creates a block class instances.
258 *
259 * @constructor
260 * @todo
261 */
262 $: function( blockHolder, blockDefinition ) {
263 this.element = blockHolder.append( blockHolder.getDocument().createElement( 'div', {
264 attributes: {
265 'tabindex': -1,
266 'class': 'cke_panel_block'
267 },
268 styles: {
269 display: 'none'
270 }
271 } ) );
272
273 // Copy all definition properties to this object.
274 if ( blockDefinition )
275 CKEDITOR.tools.extend( this, blockDefinition );
276
277 // Set the a11y attributes of this element ...
278 this.element.setAttributes( {
279 'role': this.attributes.role || 'presentation',
280 'aria-label': this.attributes[ 'aria-label' ],
281 'title': this.attributes.title || this.attributes[ 'aria-label' ]
282 } );
283
284 this.keys = {};
285
286 this._.focusIndex = -1;
287
288 // Disable context menu for panels.
289 this.element.disableContextMenu();
290 },
291
292 _: {
293
294 /**
295 * Mark the item specified by the index as current activated.
296 */
297 markItem: function( index ) {
298 if ( index == -1 )
299 return;
300 var links = this.element.getElementsByTag( 'a' );
301 var item = links.getItem( this._.focusIndex = index );
302
303 // Safari need focus on the iframe window first(#3389), but we need
304 // lock the blur to avoid hiding the panel.
305 if ( CKEDITOR.env.webkit )
306 item.getDocument().getWindow().focus();
307 item.focus();
308
309 this.onMark && this.onMark( item );
310 }
311 },
312
313 proto: {
314 show: function() {
315 this.element.setStyle( 'display', '' );
316 },
317
318 hide: function() {
319 if ( !this.onHide || this.onHide.call( this ) !== true )
320 this.element.setStyle( 'display', 'none' );
321 },
322
323 onKeyDown: function( keystroke, noCycle ) {
324 var keyAction = this.keys[ keystroke ];
325 switch ( keyAction ) {
326 // Move forward.
327 case 'next':
328 var index = this._.focusIndex,
329 links = this.element.getElementsByTag( 'a' ),
330 link;
331
332 while ( ( link = links.getItem( ++index ) ) ) {
333 // Move the focus only if the element is marked with
334 // the _cke_focus and it it's visible (check if it has
335 // width).
336 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth ) {
337 this._.focusIndex = index;
338 link.focus();
339 break;
340 }
341 }
342
343 // If no link was found, cycle and restart from the top. (#11125)
344 if ( !link && !noCycle ) {
345 this._.focusIndex = -1;
346 return this.onKeyDown( keystroke, 1 );
347 }
348
349 return false;
350
351 // Move backward.
352 case 'prev':
353 index = this._.focusIndex;
354 links = this.element.getElementsByTag( 'a' );
355
356 while ( index > 0 && ( link = links.getItem( --index ) ) ) {
357 // Move the focus only if the element is marked with
358 // the _cke_focus and it it's visible (check if it has
359 // width).
360 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth ) {
361 this._.focusIndex = index;
362 link.focus();
363 break;
364 }
365
366 // Make sure link is null when the loop ends and nothing was
367 // found (#11125).
368 link = null;
369 }
370
371 // If no link was found, cycle and restart from the bottom. (#11125)
372 if ( !link && !noCycle ) {
373 this._.focusIndex = links.count();
374 return this.onKeyDown( keystroke, 1 );
375 }
376
377 return false;
378
379 case 'click':
380 case 'mouseup':
381 index = this._.focusIndex;
382 link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
383
384 if ( link )
385 link.$[ keyAction ] ? link.$[ keyAction ]() : link.$[ 'on' + keyAction ]();
386
387 return false;
388 }
389
390 return true;
391 }
392 }
393 } );
394
395} )();
396
397/**
398 * Fired when a panel is added to the document.
399 *
400 * @event ariaWidget
401 * @member CKEDITOR
402 * @param {Object} data The element wrapping the panel.
403 */
diff --git a/sources/plugins/popup/plugin.js b/sources/plugins/popup/plugin.js
new file mode 100644
index 0000000..352d239
--- /dev/null
+++ b/sources/plugins/popup/plugin.js
@@ -0,0 +1,65 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'popup' );
7
8CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
9 /**
10 * Opens Browser in a popup. The `width` and `height` parameters accept
11 * numbers (pixels) or percent (of screen size) values.
12 *
13 * @member CKEDITOR.editor
14 * @param {String} url The url of the external file browser.
15 * @param {Number/String} [width='80%'] Popup window width.
16 * @param {Number/String} [height='70%'] Popup window height.
17 * @param {String} [options='location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes,scrollbars=yes']
18 * Popup window features.
19 */
20 popup: function( url, width, height, options ) {
21 width = width || '80%';
22 height = height || '70%';
23
24 if ( typeof width == 'string' && width.length > 1 && width.substr( width.length - 1, 1 ) == '%' )
25 width = parseInt( window.screen.width * parseInt( width, 10 ) / 100, 10 );
26
27 if ( typeof height == 'string' && height.length > 1 && height.substr( height.length - 1, 1 ) == '%' )
28 height = parseInt( window.screen.height * parseInt( height, 10 ) / 100, 10 );
29
30 if ( width < 640 )
31 width = 640;
32
33 if ( height < 420 )
34 height = 420;
35
36 var top = parseInt( ( window.screen.height - height ) / 2, 10 ),
37 left = parseInt( ( window.screen.width - width ) / 2, 10 );
38
39 options = ( options || 'location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes,scrollbars=yes' ) + ',width=' + width +
40 ',height=' + height +
41 ',top=' + top +
42 ',left=' + left;
43
44 var popupWindow = window.open( '', null, options, true );
45
46 // Blocked by a popup blocker.
47 if ( !popupWindow )
48 return false;
49
50 try {
51 // Chrome is problematic with moveTo/resizeTo, but it's not really needed here (#8855).
52 var ua = navigator.userAgent.toLowerCase();
53 if ( ua.indexOf( ' chrome/' ) == -1 ) {
54 popupWindow.moveTo( left, top );
55 popupWindow.resizeTo( width, height );
56 }
57 popupWindow.focus();
58 popupWindow.location.href = url;
59 } catch ( e ) {
60 popupWindow = window.open( url, null, options, true );
61 }
62
63 return true;
64 }
65} );
diff --git a/sources/plugins/removeformat/icons/hidpi/removeformat.png b/sources/plugins/removeformat/icons/hidpi/removeformat.png
new file mode 100644
index 0000000..0695878
--- /dev/null
+++ b/sources/plugins/removeformat/icons/hidpi/removeformat.png
Binary files differ
diff --git a/sources/plugins/removeformat/icons/removeformat.png b/sources/plugins/removeformat/icons/removeformat.png
new file mode 100644
index 0000000..f4597bf
--- /dev/null
+++ b/sources/plugins/removeformat/icons/removeformat.png
Binary files differ
diff --git a/sources/plugins/removeformat/lang/af.js b/sources/plugins/removeformat/lang/af.js
new file mode 100644
index 0000000..4904945
--- /dev/null
+++ b/sources/plugins/removeformat/lang/af.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'af', {
6 toolbar: 'Verwyder opmaak'
7} );
diff --git a/sources/plugins/removeformat/lang/ar.js b/sources/plugins/removeformat/lang/ar.js
new file mode 100644
index 0000000..661e851
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ar.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ar', {
6 toolbar: 'إزالة التنسيقات'
7} );
diff --git a/sources/plugins/removeformat/lang/az.js b/sources/plugins/removeformat/lang/az.js
new file mode 100644
index 0000000..948837e
--- /dev/null
+++ b/sources/plugins/removeformat/lang/az.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'az', {
6 toolbar: 'Formatı sil'
7} );
diff --git a/sources/plugins/removeformat/lang/bg.js b/sources/plugins/removeformat/lang/bg.js
new file mode 100644
index 0000000..a96dc60
--- /dev/null
+++ b/sources/plugins/removeformat/lang/bg.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'bg', {
6 toolbar: 'Премахване на форматирането'
7} );
diff --git a/sources/plugins/removeformat/lang/bn.js b/sources/plugins/removeformat/lang/bn.js
new file mode 100644
index 0000000..0c59c81
--- /dev/null
+++ b/sources/plugins/removeformat/lang/bn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'bn', {
6 toolbar: 'ধরন-প্রকৃতি অপসারণ করি'
7} );
diff --git a/sources/plugins/removeformat/lang/bs.js b/sources/plugins/removeformat/lang/bs.js
new file mode 100644
index 0000000..83fd723
--- /dev/null
+++ b/sources/plugins/removeformat/lang/bs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'bs', {
6 toolbar: 'Poništi format'
7} );
diff --git a/sources/plugins/removeformat/lang/ca.js b/sources/plugins/removeformat/lang/ca.js
new file mode 100644
index 0000000..01ead3b
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ca', {
6 toolbar: 'Elimina Format'
7} );
diff --git a/sources/plugins/removeformat/lang/cs.js b/sources/plugins/removeformat/lang/cs.js
new file mode 100644
index 0000000..cab8cfc
--- /dev/null
+++ b/sources/plugins/removeformat/lang/cs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'cs', {
6 toolbar: 'Odstranit formátování'
7} );
diff --git a/sources/plugins/removeformat/lang/cy.js b/sources/plugins/removeformat/lang/cy.js
new file mode 100644
index 0000000..7908104
--- /dev/null
+++ b/sources/plugins/removeformat/lang/cy.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'cy', {
6 toolbar: 'Tynnu Fformat'
7} );
diff --git a/sources/plugins/removeformat/lang/da.js b/sources/plugins/removeformat/lang/da.js
new file mode 100644
index 0000000..6f35909
--- /dev/null
+++ b/sources/plugins/removeformat/lang/da.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'da', {
6 toolbar: 'Fjern formatering'
7} );
diff --git a/sources/plugins/removeformat/lang/de-ch.js b/sources/plugins/removeformat/lang/de-ch.js
new file mode 100644
index 0000000..37d1ccd
--- /dev/null
+++ b/sources/plugins/removeformat/lang/de-ch.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'de-ch', {
6 toolbar: 'Formatierung entfernen'
7} );
diff --git a/sources/plugins/removeformat/lang/de.js b/sources/plugins/removeformat/lang/de.js
new file mode 100644
index 0000000..5d8901b
--- /dev/null
+++ b/sources/plugins/removeformat/lang/de.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'de', {
6 toolbar: 'Formatierung entfernen'
7} );
diff --git a/sources/plugins/removeformat/lang/el.js b/sources/plugins/removeformat/lang/el.js
new file mode 100644
index 0000000..e0da8c6
--- /dev/null
+++ b/sources/plugins/removeformat/lang/el.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'el', {
6 toolbar: 'Εκκαθάριση Μορφοποίησης'
7} );
diff --git a/sources/plugins/removeformat/lang/en-au.js b/sources/plugins/removeformat/lang/en-au.js
new file mode 100644
index 0000000..4d98f6d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/en-au.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'en-au', {
6 toolbar: 'Remove Format'
7} );
diff --git a/sources/plugins/removeformat/lang/en-ca.js b/sources/plugins/removeformat/lang/en-ca.js
new file mode 100644
index 0000000..998eb01
--- /dev/null
+++ b/sources/plugins/removeformat/lang/en-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'en-ca', {
6 toolbar: 'Remove Format'
7} );
diff --git a/sources/plugins/removeformat/lang/en-gb.js b/sources/plugins/removeformat/lang/en-gb.js
new file mode 100644
index 0000000..f40ca18
--- /dev/null
+++ b/sources/plugins/removeformat/lang/en-gb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'en-gb', {
6 toolbar: 'Remove Format'
7} );
diff --git a/sources/plugins/removeformat/lang/en.js b/sources/plugins/removeformat/lang/en.js
new file mode 100644
index 0000000..ed26343
--- /dev/null
+++ b/sources/plugins/removeformat/lang/en.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'en', {
6 toolbar: 'Remove Format'
7} );
diff --git a/sources/plugins/removeformat/lang/eo.js b/sources/plugins/removeformat/lang/eo.js
new file mode 100644
index 0000000..bb25f96
--- /dev/null
+++ b/sources/plugins/removeformat/lang/eo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'eo', {
6 toolbar: 'Forigi Formaton'
7} );
diff --git a/sources/plugins/removeformat/lang/es.js b/sources/plugins/removeformat/lang/es.js
new file mode 100644
index 0000000..d097bdb
--- /dev/null
+++ b/sources/plugins/removeformat/lang/es.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'es', {
6 toolbar: 'Eliminar Formato'
7} );
diff --git a/sources/plugins/removeformat/lang/et.js b/sources/plugins/removeformat/lang/et.js
new file mode 100644
index 0000000..823749d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/et.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'et', {
6 toolbar: 'Vormingu eemaldamine'
7} );
diff --git a/sources/plugins/removeformat/lang/eu.js b/sources/plugins/removeformat/lang/eu.js
new file mode 100644
index 0000000..bc487f7
--- /dev/null
+++ b/sources/plugins/removeformat/lang/eu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'eu', {
6 toolbar: 'Kendu formatua'
7} );
diff --git a/sources/plugins/removeformat/lang/fa.js b/sources/plugins/removeformat/lang/fa.js
new file mode 100644
index 0000000..8fc6b93
--- /dev/null
+++ b/sources/plugins/removeformat/lang/fa.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'fa', {
6 toolbar: 'برداشتن فرمت'
7} );
diff --git a/sources/plugins/removeformat/lang/fi.js b/sources/plugins/removeformat/lang/fi.js
new file mode 100644
index 0000000..c61a093
--- /dev/null
+++ b/sources/plugins/removeformat/lang/fi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'fi', {
6 toolbar: 'Poista muotoilu'
7} );
diff --git a/sources/plugins/removeformat/lang/fo.js b/sources/plugins/removeformat/lang/fo.js
new file mode 100644
index 0000000..b80c158
--- /dev/null
+++ b/sources/plugins/removeformat/lang/fo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'fo', {
6 toolbar: 'Strika sniðgeving'
7} );
diff --git a/sources/plugins/removeformat/lang/fr-ca.js b/sources/plugins/removeformat/lang/fr-ca.js
new file mode 100644
index 0000000..fe3534d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/fr-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'fr-ca', {
6 toolbar: 'Supprimer le formatage'
7} );
diff --git a/sources/plugins/removeformat/lang/fr.js b/sources/plugins/removeformat/lang/fr.js
new file mode 100644
index 0000000..e18fd83
--- /dev/null
+++ b/sources/plugins/removeformat/lang/fr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'fr', {
6 toolbar: 'Supprimer la mise en forme'
7} );
diff --git a/sources/plugins/removeformat/lang/gl.js b/sources/plugins/removeformat/lang/gl.js
new file mode 100644
index 0000000..8190cca
--- /dev/null
+++ b/sources/plugins/removeformat/lang/gl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'gl', {
6 toolbar: 'Retirar o formato'
7} );
diff --git a/sources/plugins/removeformat/lang/gu.js b/sources/plugins/removeformat/lang/gu.js
new file mode 100644
index 0000000..621ad9d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/gu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'gu', {
6 toolbar: 'ફૉર્મટ કાઢવું'
7} );
diff --git a/sources/plugins/removeformat/lang/he.js b/sources/plugins/removeformat/lang/he.js
new file mode 100644
index 0000000..bcdc1bd
--- /dev/null
+++ b/sources/plugins/removeformat/lang/he.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'he', {
6 toolbar: 'הסרת העיצוב'
7} );
diff --git a/sources/plugins/removeformat/lang/hi.js b/sources/plugins/removeformat/lang/hi.js
new file mode 100644
index 0000000..ab15f5d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/hi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'hi', {
6 toolbar: 'फ़ॉर्मैट हटायें'
7} );
diff --git a/sources/plugins/removeformat/lang/hr.js b/sources/plugins/removeformat/lang/hr.js
new file mode 100644
index 0000000..c061400
--- /dev/null
+++ b/sources/plugins/removeformat/lang/hr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'hr', {
6 toolbar: 'Ukloni formatiranje'
7} );
diff --git a/sources/plugins/removeformat/lang/hu.js b/sources/plugins/removeformat/lang/hu.js
new file mode 100644
index 0000000..fe1c099
--- /dev/null
+++ b/sources/plugins/removeformat/lang/hu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'hu', {
6 toolbar: 'Formázás eltávolítása'
7} );
diff --git a/sources/plugins/removeformat/lang/id.js b/sources/plugins/removeformat/lang/id.js
new file mode 100644
index 0000000..e7eded0
--- /dev/null
+++ b/sources/plugins/removeformat/lang/id.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'id', {
6 toolbar: 'Hapus Format'
7} );
diff --git a/sources/plugins/removeformat/lang/is.js b/sources/plugins/removeformat/lang/is.js
new file mode 100644
index 0000000..98b9b4d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/is.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'is', {
6 toolbar: 'Fjarlægja snið'
7} );
diff --git a/sources/plugins/removeformat/lang/it.js b/sources/plugins/removeformat/lang/it.js
new file mode 100644
index 0000000..0ea8fb9
--- /dev/null
+++ b/sources/plugins/removeformat/lang/it.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'it', {
6 toolbar: 'Elimina formattazione'
7} );
diff --git a/sources/plugins/removeformat/lang/ja.js b/sources/plugins/removeformat/lang/ja.js
new file mode 100644
index 0000000..ca0970f
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ja.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ja', {
6 toolbar: '書式を解除'
7} );
diff --git a/sources/plugins/removeformat/lang/ka.js b/sources/plugins/removeformat/lang/ka.js
new file mode 100644
index 0000000..b624c5d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ka.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ka', {
6 toolbar: 'ფორმატირების მოხსნა'
7} );
diff --git a/sources/plugins/removeformat/lang/km.js b/sources/plugins/removeformat/lang/km.js
new file mode 100644
index 0000000..cacd321
--- /dev/null
+++ b/sources/plugins/removeformat/lang/km.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'km', {
6 toolbar: 'ជម្រះ​ទ្រង់​ទ្រាយ'
7} );
diff --git a/sources/plugins/removeformat/lang/ko.js b/sources/plugins/removeformat/lang/ko.js
new file mode 100644
index 0000000..a594ccc
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ko.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ko', {
6 toolbar: '형식 지우기'
7} );
diff --git a/sources/plugins/removeformat/lang/ku.js b/sources/plugins/removeformat/lang/ku.js
new file mode 100644
index 0000000..51ae15a
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ku.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ku', {
6 toolbar: 'لابردنی داڕشتەکە'
7} );
diff --git a/sources/plugins/removeformat/lang/lt.js b/sources/plugins/removeformat/lang/lt.js
new file mode 100644
index 0000000..1e7f2df
--- /dev/null
+++ b/sources/plugins/removeformat/lang/lt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'lt', {
6 toolbar: 'Panaikinti formatą'
7} );
diff --git a/sources/plugins/removeformat/lang/lv.js b/sources/plugins/removeformat/lang/lv.js
new file mode 100644
index 0000000..f382171
--- /dev/null
+++ b/sources/plugins/removeformat/lang/lv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'lv', {
6 toolbar: 'Noņemt stilus'
7} );
diff --git a/sources/plugins/removeformat/lang/mk.js b/sources/plugins/removeformat/lang/mk.js
new file mode 100644
index 0000000..be04ba4
--- /dev/null
+++ b/sources/plugins/removeformat/lang/mk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'mk', {
6 toolbar: 'Remove Format' // MISSING
7} );
diff --git a/sources/plugins/removeformat/lang/mn.js b/sources/plugins/removeformat/lang/mn.js
new file mode 100644
index 0000000..378a898
--- /dev/null
+++ b/sources/plugins/removeformat/lang/mn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'mn', {
6 toolbar: 'Параргафын загварыг авч хаях'
7} );
diff --git a/sources/plugins/removeformat/lang/ms.js b/sources/plugins/removeformat/lang/ms.js
new file mode 100644
index 0000000..ee81ba1
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ms.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ms', {
6 toolbar: 'Buang Format'
7} );
diff --git a/sources/plugins/removeformat/lang/nb.js b/sources/plugins/removeformat/lang/nb.js
new file mode 100644
index 0000000..19f093d
--- /dev/null
+++ b/sources/plugins/removeformat/lang/nb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'nb', {
6 toolbar: 'Fjern formatering'
7} );
diff --git a/sources/plugins/removeformat/lang/nl.js b/sources/plugins/removeformat/lang/nl.js
new file mode 100644
index 0000000..46be61b
--- /dev/null
+++ b/sources/plugins/removeformat/lang/nl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'nl', {
6 toolbar: 'Opmaak verwijderen'
7} );
diff --git a/sources/plugins/removeformat/lang/no.js b/sources/plugins/removeformat/lang/no.js
new file mode 100644
index 0000000..84d38af
--- /dev/null
+++ b/sources/plugins/removeformat/lang/no.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'no', {
6 toolbar: 'Fjern formatering'
7} );
diff --git a/sources/plugins/removeformat/lang/oc.js b/sources/plugins/removeformat/lang/oc.js
new file mode 100644
index 0000000..7dda966
--- /dev/null
+++ b/sources/plugins/removeformat/lang/oc.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'oc', {
6 toolbar: 'Suprimir la mesa en forma'
7} );
diff --git a/sources/plugins/removeformat/lang/pl.js b/sources/plugins/removeformat/lang/pl.js
new file mode 100644
index 0000000..41e7034
--- /dev/null
+++ b/sources/plugins/removeformat/lang/pl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'pl', {
6 toolbar: 'Usuń formatowanie'
7} );
diff --git a/sources/plugins/removeformat/lang/pt-br.js b/sources/plugins/removeformat/lang/pt-br.js
new file mode 100644
index 0000000..61b44c0
--- /dev/null
+++ b/sources/plugins/removeformat/lang/pt-br.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'pt-br', {
6 toolbar: 'Remover Formatação'
7} );
diff --git a/sources/plugins/removeformat/lang/pt.js b/sources/plugins/removeformat/lang/pt.js
new file mode 100644
index 0000000..b54dbce
--- /dev/null
+++ b/sources/plugins/removeformat/lang/pt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'pt', {
6 toolbar: 'Limpar formatação'
7} );
diff --git a/sources/plugins/removeformat/lang/ro.js b/sources/plugins/removeformat/lang/ro.js
new file mode 100644
index 0000000..649bced
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ro.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ro', {
6 toolbar: 'Înlătură formatarea'
7} );
diff --git a/sources/plugins/removeformat/lang/ru.js b/sources/plugins/removeformat/lang/ru.js
new file mode 100644
index 0000000..ea05d6e
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ru.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ru', {
6 toolbar: 'Убрать форматирование'
7} );
diff --git a/sources/plugins/removeformat/lang/si.js b/sources/plugins/removeformat/lang/si.js
new file mode 100644
index 0000000..db5d715
--- /dev/null
+++ b/sources/plugins/removeformat/lang/si.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'si', {
6 toolbar: 'සැකසීම වෙනස් කරන්න'
7} );
diff --git a/sources/plugins/removeformat/lang/sk.js b/sources/plugins/removeformat/lang/sk.js
new file mode 100644
index 0000000..625c8d6
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sk', {
6 toolbar: 'Odstrániť formátovanie'
7} );
diff --git a/sources/plugins/removeformat/lang/sl.js b/sources/plugins/removeformat/lang/sl.js
new file mode 100644
index 0000000..895c1e7
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sl', {
6 toolbar: 'Odstrani oblikovanje'
7} );
diff --git a/sources/plugins/removeformat/lang/sq.js b/sources/plugins/removeformat/lang/sq.js
new file mode 100644
index 0000000..45f455a
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sq.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sq', {
6 toolbar: 'Largo Formatin'
7} );
diff --git a/sources/plugins/removeformat/lang/sr-latn.js b/sources/plugins/removeformat/lang/sr-latn.js
new file mode 100644
index 0000000..51f34a7
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sr-latn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sr-latn', {
6 toolbar: 'Ukloni formatiranje'
7} );
diff --git a/sources/plugins/removeformat/lang/sr.js b/sources/plugins/removeformat/lang/sr.js
new file mode 100644
index 0000000..c6080dd
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sr', {
6 toolbar: 'Уклони форматирање'
7} );
diff --git a/sources/plugins/removeformat/lang/sv.js b/sources/plugins/removeformat/lang/sv.js
new file mode 100644
index 0000000..2dd7edc
--- /dev/null
+++ b/sources/plugins/removeformat/lang/sv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'sv', {
6 toolbar: 'Radera formatering'
7} );
diff --git a/sources/plugins/removeformat/lang/th.js b/sources/plugins/removeformat/lang/th.js
new file mode 100644
index 0000000..0bc74e2
--- /dev/null
+++ b/sources/plugins/removeformat/lang/th.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'th', {
6 toolbar: 'ล้างรูปแบบ'
7} );
diff --git a/sources/plugins/removeformat/lang/tr.js b/sources/plugins/removeformat/lang/tr.js
new file mode 100644
index 0000000..2c961c5
--- /dev/null
+++ b/sources/plugins/removeformat/lang/tr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'tr', {
6 toolbar: 'Biçimi Kaldır'
7} );
diff --git a/sources/plugins/removeformat/lang/tt.js b/sources/plugins/removeformat/lang/tt.js
new file mode 100644
index 0000000..b3afbda
--- /dev/null
+++ b/sources/plugins/removeformat/lang/tt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'tt', {
6 toolbar: 'Форматлауны бетерү'
7} );
diff --git a/sources/plugins/removeformat/lang/ug.js b/sources/plugins/removeformat/lang/ug.js
new file mode 100644
index 0000000..07e5daf
--- /dev/null
+++ b/sources/plugins/removeformat/lang/ug.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'ug', {
6 toolbar: 'پىچىمنى چىقىرىۋەت'
7} );
diff --git a/sources/plugins/removeformat/lang/uk.js b/sources/plugins/removeformat/lang/uk.js
new file mode 100644
index 0000000..7ef1f1c
--- /dev/null
+++ b/sources/plugins/removeformat/lang/uk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'uk', {
6 toolbar: 'Видалити форматування'
7} );
diff --git a/sources/plugins/removeformat/lang/vi.js b/sources/plugins/removeformat/lang/vi.js
new file mode 100644
index 0000000..38316bf
--- /dev/null
+++ b/sources/plugins/removeformat/lang/vi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'vi', {
6 toolbar: 'Xoá định dạng'
7} );
diff --git a/sources/plugins/removeformat/lang/zh-cn.js b/sources/plugins/removeformat/lang/zh-cn.js
new file mode 100644
index 0000000..ec833f1
--- /dev/null
+++ b/sources/plugins/removeformat/lang/zh-cn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'zh-cn', {
6 toolbar: '清除格式'
7} );
diff --git a/sources/plugins/removeformat/lang/zh.js b/sources/plugins/removeformat/lang/zh.js
new file mode 100644
index 0000000..dd23488
--- /dev/null
+++ b/sources/plugins/removeformat/lang/zh.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'removeformat', 'zh', {
6 toolbar: '移除格式'
7} );
diff --git a/sources/plugins/removeformat/plugin.js b/sources/plugins/removeformat/plugin.js
new file mode 100644
index 0000000..20f7ecb
--- /dev/null
+++ b/sources/plugins/removeformat/plugin.js
@@ -0,0 +1,193 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'removeformat', {
7 // jscs:disable maximumLineLength
8 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
9 // jscs:enable maximumLineLength
10 icons: 'removeformat', // %REMOVE_LINE_CORE%
11 hidpi: true, // %REMOVE_LINE_CORE%
12 init: function( editor ) {
13 editor.addCommand( 'removeFormat', CKEDITOR.plugins.removeformat.commands.removeformat );
14 editor.ui.addButton && editor.ui.addButton( 'RemoveFormat', {
15 label: editor.lang.removeformat.toolbar,
16 command: 'removeFormat',
17 toolbar: 'cleanup,10'
18 } );
19 }
20} );
21
22CKEDITOR.plugins.removeformat = {
23 commands: {
24 removeformat: {
25 exec: function( editor ) {
26 var tagsRegex = editor._.removeFormatRegex || ( editor._.removeFormatRegex = new RegExp( '^(?:' + editor.config.removeFormatTags.replace( /,/g, '|' ) + ')$', 'i' ) );
27
28 var removeAttributes = editor._.removeAttributes || ( editor._.removeAttributes = editor.config.removeFormatAttributes.split( ',' ) ),
29 filter = CKEDITOR.plugins.removeformat.filter,
30 ranges = editor.getSelection().getRanges(),
31 iterator = ranges.createIterator(),
32 isElement = function( element ) {
33 return element.type == CKEDITOR.NODE_ELEMENT;
34 },
35 range;
36
37 while ( ( range = iterator.getNextRange() ) ) {
38 if ( !range.collapsed )
39 range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
40
41 // Bookmark the range so we can re-select it after processing.
42 var bookmark = range.createBookmark(),
43 // The style will be applied within the bookmark boundaries.
44 startNode = bookmark.startNode,
45 endNode = bookmark.endNode,
46 currentNode;
47
48 // We need to check the selection boundaries (bookmark spans) to break
49 // the code in a way that we can properly remove partially selected nodes.
50 // For example, removing a <b> style from
51 // <b>This is [some text</b> to show <b>the] problem</b>
52 // ... where [ and ] represent the selection, must result:
53 // <b>This is </b>[some text to show the]<b> problem</b>
54 // The strategy is simple, we just break the partial nodes before the
55 // removal logic, having something that could be represented this way:
56 // <b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
57
58 var breakParent = function( node ) {
59 // Let's start checking the start boundary.
60 var path = editor.elementPath( node ),
61 pathElements = path.elements;
62
63 for ( var i = 1, pathElement; pathElement = pathElements[ i ]; i++ ) {
64 if ( pathElement.equals( path.block ) || pathElement.equals( path.blockLimit ) )
65 break;
66
67 // If this element can be removed (even partially).
68 if ( tagsRegex.test( pathElement.getName() ) && filter( editor, pathElement ) )
69 node.breakParent( pathElement );
70 }
71 };
72
73 breakParent( startNode );
74 if ( endNode ) {
75 breakParent( endNode );
76
77 // Navigate through all nodes between the bookmarks.
78 currentNode = startNode.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT );
79
80 while ( currentNode ) {
81 // If we have reached the end of the selection, stop looping.
82 if ( currentNode.equals( endNode ) )
83 break;
84
85 if ( currentNode.isReadOnly() ) {
86 // In case of non-editable we're skipping to the next sibling *elmenet*.
87
88 // We need to be aware that endNode can be nested within current non-editable.
89 // This condition tests if currentNode (non-editable) contains endNode. If it does
90 // then we should break the filtering
91 if ( currentNode.getPosition( endNode ) & CKEDITOR.POSITION_CONTAINS ) {
92 break;
93 }
94
95 currentNode = currentNode.getNext( isElement );
96 continue;
97 }
98
99 // Cache the next node to be processed. Do it now, because
100 // currentNode may be removed.
101 var nextNode = currentNode.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ),
102 isFakeElement = currentNode.getName() == 'img' && currentNode.data( 'cke-realelement' );
103
104 // This node must not be a fake element, and must not be read-only.
105 if ( !isFakeElement && filter( editor, currentNode ) ) {
106 // Remove elements nodes that match with this style rules.
107 if ( tagsRegex.test( currentNode.getName() ) )
108 currentNode.remove( 1 );
109 else {
110 currentNode.removeAttributes( removeAttributes );
111 editor.fire( 'removeFormatCleanup', currentNode );
112 }
113 }
114
115 currentNode = nextNode;
116 }
117 }
118
119 range.moveToBookmark( bookmark );
120 }
121
122 // The selection path may not changed, but we should force a selection
123 // change event to refresh command states, due to the above attribution change. (#9238)
124 editor.forceNextSelectionCheck();
125 editor.getSelection().selectRanges( ranges );
126 }
127 }
128 },
129
130 // Perform the remove format filters on the passed element.
131 // @param {CKEDITOR.editor} editor
132 // @param {CKEDITOR.dom.element} element
133 filter: function( editor, element ) {
134 // If editor#addRemoveFotmatFilter hasn't been executed yet value is not initialized.
135 var filters = editor._.removeFormatFilters || [];
136 for ( var i = 0; i < filters.length; i++ ) {
137 if ( filters[ i ]( element ) === false )
138 return false;
139 }
140 return true;
141 }
142};
143
144/**
145 * Add to a collection of functions to decide whether a specific
146 * element should be considered as formatting element and thus
147 * could be removed during `removeFormat` command.
148 *
149 * **Note:** Only available with the existence of `removeformat` plugin.
150 *
151 * // Don't remove empty span.
152 * editor.addRemoveFormatFilter( function( element ) {
153 * return !( element.is( 'span' ) && CKEDITOR.tools.isEmpty( element.getAttributes() ) );
154 * } );
155 *
156 * @since 3.3
157 * @member CKEDITOR.editor
158 * @param {Function} func The function to be called, which will be passed a {CKEDITOR.dom.element} element to test.
159 */
160CKEDITOR.editor.prototype.addRemoveFormatFilter = function( func ) {
161 if ( !this._.removeFormatFilters )
162 this._.removeFormatFilters = [];
163
164 this._.removeFormatFilters.push( func );
165};
166
167/**
168 * A comma separated list of elements to be removed when executing the `remove
169 * format` command. Note that only inline elements are allowed.
170 *
171 * @cfg
172 * @member CKEDITOR.config
173 */
174CKEDITOR.config.removeFormatTags = 'b,big,cite,code,del,dfn,em,font,i,ins,kbd,q,s,samp,small,span,strike,strong,sub,sup,tt,u,var';
175
176/**
177 * A comma separated list of elements attributes to be removed when executing
178 * the `remove format` command.
179 *
180 * @cfg
181 * @member CKEDITOR.config
182 */
183CKEDITOR.config.removeFormatAttributes = 'class,style,lang,width,height,align,hspace,valign';
184
185/**
186 * Fired after an element was cleaned by the removeFormat plugin.
187 *
188 * @event removeFormatCleanup
189 * @member CKEDITOR.editor
190 * @param {CKEDITOR.editor} editor This editor instance.
191 * @param data
192 * @param {CKEDITOR.dom.element} data.element The element that was cleaned up.
193 */
diff --git a/sources/plugins/resize/plugin.js b/sources/plugins/resize/plugin.js
new file mode 100644
index 0000000..095ee12
--- /dev/null
+++ b/sources/plugins/resize/plugin.js
@@ -0,0 +1,187 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'resize', {
7 init: function( editor ) {
8 function dragHandler( evt ) {
9 var dx = evt.data.$.screenX - origin.x,
10 dy = evt.data.$.screenY - origin.y,
11 width = startSize.width,
12 height = startSize.height,
13 internalWidth = width + dx * ( resizeDir == 'rtl' ? -1 : 1 ),
14 internalHeight = height + dy;
15
16 if ( resizeHorizontal )
17 width = Math.max( config.resize_minWidth, Math.min( internalWidth, config.resize_maxWidth ) );
18
19 if ( resizeVertical )
20 height = Math.max( config.resize_minHeight, Math.min( internalHeight, config.resize_maxHeight ) );
21
22 // DO NOT impose fixed size with single direction resize. (#6308)
23 editor.resize( resizeHorizontal ? width : null, height );
24 }
25
26 function dragEndHandler() {
27 CKEDITOR.document.removeListener( 'mousemove', dragHandler );
28 CKEDITOR.document.removeListener( 'mouseup', dragEndHandler );
29
30 if ( editor.document ) {
31 editor.document.removeListener( 'mousemove', dragHandler );
32 editor.document.removeListener( 'mouseup', dragEndHandler );
33 }
34 }
35
36 var config = editor.config;
37 var spaceId = editor.ui.spaceId( 'resizer' );
38
39 // Resize in the same direction of chrome,
40 // which is identical to dir of editor element. (#6614)
41 var resizeDir = editor.element ? editor.element.getDirection( 1 ) : 'ltr';
42
43 !config.resize_dir && ( config.resize_dir = 'vertical' );
44 ( config.resize_maxWidth === undefined ) && ( config.resize_maxWidth = 3000 );
45 ( config.resize_maxHeight === undefined ) && ( config.resize_maxHeight = 3000 );
46 ( config.resize_minWidth === undefined ) && ( config.resize_minWidth = 750 );
47 ( config.resize_minHeight === undefined ) && ( config.resize_minHeight = 250 );
48
49 if ( config.resize_enabled !== false ) {
50 var container = null,
51 origin, startSize,
52 resizeHorizontal = ( config.resize_dir == 'both' || config.resize_dir == 'horizontal' ) && ( config.resize_minWidth != config.resize_maxWidth ),
53 resizeVertical = ( config.resize_dir == 'both' || config.resize_dir == 'vertical' ) && ( config.resize_minHeight != config.resize_maxHeight );
54
55 var mouseDownFn = CKEDITOR.tools.addFunction( function( $event ) {
56 if ( !container )
57 container = editor.getResizable();
58
59 startSize = { width: container.$.offsetWidth || 0, height: container.$.offsetHeight || 0 };
60 origin = { x: $event.screenX, y: $event.screenY };
61
62 config.resize_minWidth > startSize.width && ( config.resize_minWidth = startSize.width );
63 config.resize_minHeight > startSize.height && ( config.resize_minHeight = startSize.height );
64
65 CKEDITOR.document.on( 'mousemove', dragHandler );
66 CKEDITOR.document.on( 'mouseup', dragEndHandler );
67
68 if ( editor.document ) {
69 editor.document.on( 'mousemove', dragHandler );
70 editor.document.on( 'mouseup', dragEndHandler );
71 }
72
73 $event.preventDefault && $event.preventDefault();
74 } );
75
76 editor.on( 'destroy', function() {
77 CKEDITOR.tools.removeFunction( mouseDownFn );
78 } );
79
80 editor.on( 'uiSpace', function( event ) {
81 if ( event.data.space == 'bottom' ) {
82 var direction = '';
83 if ( resizeHorizontal && !resizeVertical )
84 direction = ' cke_resizer_horizontal';
85 if ( !resizeHorizontal && resizeVertical )
86 direction = ' cke_resizer_vertical';
87
88 var resizerHtml =
89 '<span' +
90 ' id="' + spaceId + '"' +
91 ' class="cke_resizer' + direction + ' cke_resizer_' + resizeDir + '"' +
92 ' title="' + CKEDITOR.tools.htmlEncode( editor.lang.common.resize ) + '"' +
93 ' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event)"' +
94 '>' +
95 // BLACK LOWER RIGHT TRIANGLE (ltr)
96 // BLACK LOWER LEFT TRIANGLE (rtl)
97 ( resizeDir == 'ltr' ? '\u25E2' : '\u25E3' ) +
98 '</span>';
99
100 // Always sticks the corner of botttom space.
101 resizeDir == 'ltr' && direction == 'ltr' ? event.data.html += resizerHtml : event.data.html = resizerHtml + event.data.html;
102 }
103 }, editor, null, 100 );
104
105 // Toggle the visibility of the resizer when an editor is being maximized or minimized.
106 editor.on( 'maximize', function( event ) {
107 editor.ui.space( 'resizer' )[ event.data == CKEDITOR.TRISTATE_ON ? 'hide' : 'show' ]();
108 } );
109 }
110 }
111} );
112
113/**
114 * The minimum editor width, in pixels, when resizing the editor interface by using the resize handle.
115 * Note: It falls back to editor's actual width if it is smaller than the default value.
116 *
117 * Read more in the [documentation](#!/guide/dev_resize)
118 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
119 *
120 * config.resize_minWidth = 500;
121 *
122 * @cfg {Number} [resize_minWidth=750]
123 * @member CKEDITOR.config
124 */
125
126/**
127 * The minimum editor height, in pixels, when resizing the editor interface by using the resize handle.
128 * Note: It falls back to editor's actual height if it is smaller than the default value.
129 *
130 * Read more in the [documentation](#!/guide/dev_resize)
131 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
132 *
133 * config.resize_minHeight = 600;
134 *
135 * @cfg {Number} [resize_minHeight=250]
136 * @member CKEDITOR.config
137 */
138
139/**
140 * The maximum editor width, in pixels, when resizing the editor interface by using the resize handle.
141 *
142 * Read more in the [documentation](#!/guide/dev_resize)
143 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
144 *
145 * config.resize_maxWidth = 750;
146 *
147 * @cfg {Number} [resize_maxWidth=3000]
148 * @member CKEDITOR.config
149 */
150
151/**
152 * The maximum editor height, in pixels, when resizing the editor interface by using the resize handle.
153 *
154 * Read more in the [documentation](#!/guide/dev_resize)
155 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
156 *
157 * config.resize_maxHeight = 600;
158 *
159 * @cfg {Number} [resize_maxHeight=3000]
160 * @member CKEDITOR.config
161 */
162
163/**
164 * Whether to enable the resizing feature. If this feature is disabled, the resize handle will not be visible.
165 *
166 * Read more in the [documentation](#!/guide/dev_resize)
167 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
168 *
169 * config.resize_enabled = false;
170 *
171 * @cfg {Boolean} [resize_enabled=true]
172 * @member CKEDITOR.config
173 */
174
175/**
176 * The dimensions for which the editor resizing is enabled. Possible values
177 * are `both`, `vertical`, and `horizontal`.
178 *
179 * Read more in the [documentation](#!/guide/dev_resize)
180 * and see the [SDK sample](http://sdk.ckeditor.com/samples/resize.html).
181 *
182 * config.resize_dir = 'both';
183 *
184 * @since 3.3
185 * @cfg {String} [resize_dir='vertical']
186 * @member CKEDITOR.config
187 */
diff --git a/sources/plugins/richcombo/plugin.js b/sources/plugins/richcombo/plugin.js
new file mode 100644
index 0000000..231a7c7
--- /dev/null
+++ b/sources/plugins/richcombo/plugin.js
@@ -0,0 +1,434 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6CKEDITOR.plugins.add( 'richcombo', {
7 requires: 'floatpanel,listblock,button',
8
9 beforeInit: function( editor ) {
10 editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );
11 }
12} );
13
14( function() {
15 var template = '<span id="{id}"' +
16 ' class="cke_combo cke_combo__{name} {cls}"' +
17 ' role="presentation">' +
18 '<span id="{id}_label" class="cke_combo_label">{label}</span>' +
19 '<a class="cke_combo_button" title="{title}" tabindex="-1"' +
20 ( CKEDITOR.env.gecko && !CKEDITOR.env.hc ? '' : ' href="javascript:void(\'{titleJs}\')"' ) +
21 ' hidefocus="true"' +
22 ' role="button"' +
23 ' aria-labelledby="{id}_label"' +
24 ' aria-haspopup="true"';
25
26 // Some browsers don't cancel key events in the keydown but in the
27 // keypress.
28 // TODO: Check if really needed.
29 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
30 template += ' onkeypress="return false;"';
31
32 // With Firefox, we need to force the button to redraw, otherwise it
33 // will remain in the focus state.
34 if ( CKEDITOR.env.gecko )
35 template += ' onblur="this.style.cssText = this.style.cssText;"';
36
37 template +=
38 ' onkeydown="return CKEDITOR.tools.callFunction({keydownFn},event,this);"' +
39 ' onfocus="return CKEDITOR.tools.callFunction({focusFn},event);" ' +
40 ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188
41 '="CKEDITOR.tools.callFunction({clickFn},this);return false;">' +
42 '<span id="{id}_text" class="cke_combo_text cke_combo_inlinelabel">{label}</span>' +
43 '<span class="cke_combo_open">' +
44 '<span class="cke_combo_arrow">' +
45 // BLACK DOWN-POINTING TRIANGLE
46 ( CKEDITOR.env.hc ? '&#9660;' : CKEDITOR.env.air ? '&nbsp;' : '' ) +
47 '</span>' +
48 '</span>' +
49 '</a>' +
50 '</span>';
51
52 var rcomboTpl = CKEDITOR.addTemplate( 'combo', template );
53
54 /**
55 * Button UI element.
56 *
57 * @readonly
58 * @property {String} [='richcombo']
59 * @member CKEDITOR
60 */
61 CKEDITOR.UI_RICHCOMBO = 'richcombo';
62
63 /**
64 * @class
65 * @todo
66 */
67 CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass( {
68 $: function( definition ) {
69 // Copy all definition properties to this object.
70 CKEDITOR.tools.extend( this, definition,
71 // Set defaults.
72 {
73 // The combo won't participate in toolbar grouping.
74 canGroup: false,
75 title: definition.label,
76 modes: { wysiwyg: 1 },
77 editorFocus: 1
78 } );
79
80 // We don't want the panel definition in this object.
81 var panelDefinition = this.panel || {};
82 delete this.panel;
83
84 this.id = CKEDITOR.tools.getNextNumber();
85
86 this.document = ( panelDefinition.parent && panelDefinition.parent.getDocument() ) || CKEDITOR.document;
87
88 panelDefinition.className = 'cke_combopanel';
89 panelDefinition.block = {
90 multiSelect: panelDefinition.multiSelect,
91 attributes: panelDefinition.attributes
92 };
93 panelDefinition.toolbarRelated = true;
94
95 this._ = {
96 panelDefinition: panelDefinition,
97 items: {}
98 };
99 },
100
101 proto: {
102 renderHtml: function( editor ) {
103 var output = [];
104 this.render( editor, output );
105 return output.join( '' );
106 },
107
108 /**
109 * Renders the combo.
110 *
111 * @param {CKEDITOR.editor} editor The editor instance which this button is
112 * to be used by.
113 * @param {Array} output The output array to which append the HTML relative
114 * to this button.
115 */
116 render: function( editor, output ) {
117 var env = CKEDITOR.env;
118
119 var id = 'cke_' + this.id;
120 var clickFn = CKEDITOR.tools.addFunction( function( el ) {
121 // Restore locked selection in Opera.
122 if ( selLocked ) {
123 editor.unlockSelection( 1 );
124 selLocked = 0;
125 }
126 instance.execute( el );
127 }, this );
128
129 var combo = this;
130 var instance = {
131 id: id,
132 combo: this,
133 focus: function() {
134 var element = CKEDITOR.document.getById( id ).getChild( 1 );
135 element.focus();
136 },
137 execute: function( el ) {
138 var _ = combo._;
139
140 if ( _.state == CKEDITOR.TRISTATE_DISABLED )
141 return;
142
143 combo.createPanel( editor );
144
145 if ( _.on ) {
146 _.panel.hide();
147 return;
148 }
149
150 combo.commit();
151 var value = combo.getValue();
152 if ( value )
153 _.list.mark( value );
154 else
155 _.list.unmarkAll();
156
157 _.panel.showBlock( combo.id, new CKEDITOR.dom.element( el ), 4 );
158 },
159 clickFn: clickFn
160 };
161
162 function updateState() {
163 // Don't change state while richcombo is active (#11793).
164 if ( this.getState() == CKEDITOR.TRISTATE_ON )
165 return;
166
167 var state = this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
168
169 if ( editor.readOnly && !this.readOnly )
170 state = CKEDITOR.TRISTATE_DISABLED;
171
172 this.setState( state );
173 this.setValue( '' );
174
175 // Let plugin to disable button.
176 if ( state != CKEDITOR.TRISTATE_DISABLED && this.refresh )
177 this.refresh();
178 }
179
180 // Update status when activeFilter, mode, selection or readOnly changes.
181 editor.on( 'activeFilterChange', updateState, this );
182 editor.on( 'mode', updateState, this );
183 editor.on( 'selectionChange', updateState, this );
184 // If this combo is sensitive to readOnly state, update it accordingly.
185 !this.readOnly && editor.on( 'readOnly', updateState, this );
186
187 var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element ) {
188 ev = new CKEDITOR.dom.event( ev );
189
190 var keystroke = ev.getKeystroke();
191
192 // ARROW-DOWN
193 // This call is duplicated in plugins/toolbar/plugin.js in itemKeystroke().
194 // Move focus to the first element after drop down was opened by the arrow down key.
195 if ( keystroke == 40 ) {
196 editor.once( 'panelShow', function( evt ) {
197 evt.data._.panel._.currentBlock.onKeyDown( 40 );
198 } );
199 }
200
201 switch ( keystroke ) {
202 case 13: // ENTER
203 case 32: // SPACE
204 case 40: // ARROW-DOWN
205 // Show panel
206 CKEDITOR.tools.callFunction( clickFn, element );
207 break;
208 default:
209 // Delegate the default behavior to toolbar button key handling.
210 instance.onkey( instance, keystroke );
211 }
212
213 // Avoid subsequent focus grab on editor document.
214 ev.preventDefault();
215 } );
216
217 var focusFn = CKEDITOR.tools.addFunction( function() {
218 instance.onfocus && instance.onfocus();
219 } );
220
221 var selLocked = 0;
222
223 // For clean up
224 instance.keyDownFn = keyDownFn;
225
226 var params = {
227 id: id,
228 name: this.name || this.command,
229 label: this.label,
230 title: this.title,
231 cls: this.className || '',
232 titleJs: env.gecko && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),
233 keydownFn: keyDownFn,
234 focusFn: focusFn,
235 clickFn: clickFn
236 };
237
238 rcomboTpl.output( params, output );
239
240 if ( this.onRender )
241 this.onRender();
242
243 return instance;
244 },
245
246 createPanel: function( editor ) {
247 if ( this._.panel )
248 return;
249
250 var panelDefinition = this._.panelDefinition,
251 panelBlockDefinition = this._.panelDefinition.block,
252 panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
253 namedPanelCls = 'cke_combopanel__' + this.name,
254 panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
255 list = panel.addListBlock( this.id, panelBlockDefinition ),
256 me = this;
257
258 panel.onShow = function() {
259 this.element.addClass( namedPanelCls );
260
261 me.setState( CKEDITOR.TRISTATE_ON );
262
263 me._.on = 1;
264
265 me.editorFocus && !editor.focusManager.hasFocus && editor.focus();
266
267 if ( me.onOpen )
268 me.onOpen();
269
270 // The "panelShow" event is fired assinchronously, after the
271 // onShow method call.
272 editor.once( 'panelShow', function() {
273 list.focus( !list.multiSelect && me.getValue() );
274 } );
275 };
276
277 panel.onHide = function( preventOnClose ) {
278 this.element.removeClass( namedPanelCls );
279
280 me.setState( me.modes && me.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
281
282 me._.on = 0;
283
284 if ( !preventOnClose && me.onClose )
285 me.onClose();
286 };
287
288 panel.onEscape = function() {
289 // Hide drop-down with focus returned.
290 panel.hide( 1 );
291 };
292
293 list.onClick = function( value, marked ) {
294
295 if ( me.onClick )
296 me.onClick.call( me, value, marked );
297
298 panel.hide();
299 };
300
301 this._.panel = panel;
302 this._.list = list;
303
304 panel.getBlock( this.id ).onHide = function() {
305 me._.on = 0;
306 me.setState( CKEDITOR.TRISTATE_OFF );
307 };
308
309 if ( this.init )
310 this.init();
311 },
312
313 setValue: function( value, text ) {
314 this._.value = value;
315
316 var textElement = this.document.getById( 'cke_' + this.id + '_text' );
317 if ( textElement ) {
318 if ( !( value || text ) ) {
319 text = this.label;
320 textElement.addClass( 'cke_combo_inlinelabel' );
321 } else {
322 textElement.removeClass( 'cke_combo_inlinelabel' );
323 }
324
325 textElement.setText( typeof text != 'undefined' ? text : value );
326 }
327 },
328
329 getValue: function() {
330 return this._.value || '';
331 },
332
333 unmarkAll: function() {
334 this._.list.unmarkAll();
335 },
336
337 mark: function( value ) {
338 this._.list.mark( value );
339 },
340
341 hideItem: function( value ) {
342 this._.list.hideItem( value );
343 },
344
345 hideGroup: function( groupTitle ) {
346 this._.list.hideGroup( groupTitle );
347 },
348
349 showAll: function() {
350 this._.list.showAll();
351 },
352
353 add: function( value, html, text ) {
354 this._.items[ value ] = text || value;
355 this._.list.add( value, html, text );
356 },
357
358 startGroup: function( title ) {
359 this._.list.startGroup( title );
360 },
361
362 commit: function() {
363 if ( !this._.committed ) {
364 this._.list.commit();
365 this._.committed = 1;
366 CKEDITOR.ui.fire( 'ready', this );
367 }
368 this._.committed = 1;
369 },
370
371 setState: function( state ) {
372 if ( this._.state == state )
373 return;
374
375 var el = this.document.getById( 'cke_' + this.id );
376 el.setState( state, 'cke_combo' );
377
378 state == CKEDITOR.TRISTATE_DISABLED ?
379 el.setAttribute( 'aria-disabled', true ) :
380 el.removeAttribute( 'aria-disabled' );
381
382 this._.state = state;
383 },
384
385 getState: function() {
386 return this._.state;
387 },
388
389 enable: function() {
390 if ( this._.state == CKEDITOR.TRISTATE_DISABLED )
391 this.setState( this._.lastState );
392 },
393
394 disable: function() {
395 if ( this._.state != CKEDITOR.TRISTATE_DISABLED ) {
396 this._.lastState = this._.state;
397 this.setState( CKEDITOR.TRISTATE_DISABLED );
398 }
399 }
400 },
401
402 /**
403 * Represents richCombo handler object.
404 *
405 * @class CKEDITOR.ui.richCombo.handler
406 * @singleton
407 * @extends CKEDITOR.ui.handlerDefinition
408 */
409 statics: {
410 handler: {
411 /**
412 * Transforms a richCombo definition in a {@link CKEDITOR.ui.richCombo} instance.
413 *
414 * @param {Object} definition
415 * @returns {CKEDITOR.ui.richCombo}
416 */
417 create: function( definition ) {
418 return new CKEDITOR.ui.richCombo( definition );
419 }
420 }
421 }
422 } );
423
424 /**
425 * @param {String} name
426 * @param {Object} definition
427 * @member CKEDITOR.ui
428 * @todo
429 */
430 CKEDITOR.ui.prototype.addRichCombo = function( name, definition ) {
431 this.add( name, CKEDITOR.UI_RICHCOMBO, definition );
432 };
433
434} )();
diff --git a/sources/plugins/showborders/plugin.js b/sources/plugins/showborders/plugin.js
new file mode 100644
index 0000000..7dbfb59
--- /dev/null
+++ b/sources/plugins/showborders/plugin.js
@@ -0,0 +1,174 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The "show border" plugin. The command display visible outline
8 * border line around all table elements if table doesn't have a none-zero 'border' attribute specified.
9 */
10
11( function() {
12 var commandDefinition = {
13 preserveState: true,
14 editorFocus: false,
15 readOnly: 1,
16
17 exec: function( editor ) {
18 this.toggleState();
19 this.refresh( editor );
20 },
21
22 refresh: function( editor ) {
23 if ( editor.document ) {
24 var funcName = ( this.state == CKEDITOR.TRISTATE_ON ) ? 'attachClass' : 'removeClass';
25 editor.editable()[ funcName ]( 'cke_show_borders' );
26 }
27 }
28 };
29
30 var showBorderClassName = 'cke_show_border';
31
32 CKEDITOR.plugins.add( 'showborders', {
33 modes: { 'wysiwyg': 1 },
34
35 onLoad: function() {
36 var cssStyleText,
37 cssTemplate =
38 // TODO: For IE6, we don't have child selector support,
39 // where nested table cells could be incorrect.
40 ( CKEDITOR.env.ie6Compat ? [
41 '.%1 table.%2,',
42 '.%1 table.%2 td, .%1 table.%2 th',
43 '{',
44 'border : #d3d3d3 1px dotted',
45 '}'
46 ] : [
47 '.%1 table.%2,',
48 '.%1 table.%2 > tr > td, .%1 table.%2 > tr > th,',
49 '.%1 table.%2 > tbody > tr > td, .%1 table.%2 > tbody > tr > th,',
50 '.%1 table.%2 > thead > tr > td, .%1 table.%2 > thead > tr > th,',
51 '.%1 table.%2 > tfoot > tr > td, .%1 table.%2 > tfoot > tr > th',
52 '{',
53 'border : #d3d3d3 1px dotted',
54 '}'
55 ] ).join( '' );
56
57 cssStyleText = cssTemplate.replace( /%2/g, showBorderClassName ).replace( /%1/g, 'cke_show_borders ' );
58
59 CKEDITOR.addCss( cssStyleText );
60 },
61
62 init: function( editor ) {
63
64 var command = editor.addCommand( 'showborders', commandDefinition );
65 command.canUndo = false;
66
67 if ( editor.config.startupShowBorders !== false )
68 command.setState( CKEDITOR.TRISTATE_ON );
69
70 // Refresh the command on setData.
71 editor.on( 'mode', function() {
72 if ( command.state != CKEDITOR.TRISTATE_DISABLED )
73 command.refresh( editor );
74 }, null, null, 100 );
75
76 // Refresh the command on wysiwyg frame reloads.
77 editor.on( 'contentDom', function() {
78 if ( command.state != CKEDITOR.TRISTATE_DISABLED )
79 command.refresh( editor );
80 } );
81
82 editor.on( 'removeFormatCleanup', function( evt ) {
83 var element = evt.data;
84 if ( editor.getCommand( 'showborders' ).state == CKEDITOR.TRISTATE_ON && element.is( 'table' ) && ( !element.hasAttribute( 'border' ) || parseInt( element.getAttribute( 'border' ), 10 ) <= 0 ) )
85 element.addClass( showBorderClassName );
86 } );
87 },
88
89 afterInit: function( editor ) {
90 var dataProcessor = editor.dataProcessor,
91 dataFilter = dataProcessor && dataProcessor.dataFilter,
92 htmlFilter = dataProcessor && dataProcessor.htmlFilter;
93
94 if ( dataFilter ) {
95 dataFilter.addRules( {
96 elements: {
97 'table': function( element ) {
98 var attributes = element.attributes,
99 cssClass = attributes[ 'class' ],
100 border = parseInt( attributes.border, 10 );
101
102 if ( ( !border || border <= 0 ) && ( !cssClass || cssClass.indexOf( showBorderClassName ) == -1 ) )
103 attributes[ 'class' ] = ( cssClass || '' ) + ' ' + showBorderClassName;
104 }
105 }
106 } );
107 }
108
109 if ( htmlFilter ) {
110 htmlFilter.addRules( {
111 elements: {
112 'table': function( table ) {
113 var attributes = table.attributes,
114 cssClass = attributes[ 'class' ];
115
116 cssClass && ( attributes[ 'class' ] = cssClass.replace( showBorderClassName, '' ).replace( /\s{2}/, ' ' ).replace( /^\s+|\s+$/, '' ) );
117 }
118 }
119 } );
120 }
121 }
122 } );
123
124 // Table dialog must be aware of it.
125 CKEDITOR.on( 'dialogDefinition', function( ev ) {
126 var dialogName = ev.data.name;
127
128 if ( dialogName == 'table' || dialogName == 'tableProperties' ) {
129 var dialogDefinition = ev.data.definition,
130 infoTab = dialogDefinition.getContents( 'info' ),
131 borderField = infoTab.get( 'txtBorder' ),
132 originalCommit = borderField.commit;
133
134 borderField.commit = CKEDITOR.tools.override( originalCommit, function( org ) {
135 return function( data, selectedTable ) {
136 org.apply( this, arguments );
137 var value = parseInt( this.getValue(), 10 );
138 selectedTable[ ( !value || value <= 0 ) ? 'addClass' : 'removeClass' ]( showBorderClassName );
139 };
140 } );
141
142 var advTab = dialogDefinition.getContents( 'advanced' ),
143 classField = advTab && advTab.get( 'advCSSClasses' );
144
145 if ( classField ) {
146 classField.setup = CKEDITOR.tools.override( classField.setup, function( originalSetup ) {
147 return function() {
148 originalSetup.apply( this, arguments );
149 this.setValue( this.getValue().replace( /cke_show_border/, '' ) );
150 };
151 } );
152
153 classField.commit = CKEDITOR.tools.override( classField.commit, function( originalCommit ) {
154 return function( data, element ) {
155 originalCommit.apply( this, arguments );
156
157 if ( !parseInt( element.getAttribute( 'border' ), 10 ) )
158 element.addClass( 'cke_show_border' );
159 };
160 } );
161 }
162 }
163 } );
164
165} )();
166
167/**
168 * Whether to automatically enable the "show borders" command when the editor loads.
169 *
170 * config.startupShowBorders = false;
171 *
172 * @cfg {Boolean} [startupShowBorders=true]
173 * @member CKEDITOR.config
174 */
diff --git a/sources/plugins/sourcearea/icons/hidpi/source-rtl.png b/sources/plugins/sourcearea/icons/hidpi/source-rtl.png
new file mode 100644
index 0000000..c95da32
--- /dev/null
+++ b/sources/plugins/sourcearea/icons/hidpi/source-rtl.png
Binary files differ
diff --git a/sources/plugins/sourcearea/icons/hidpi/source.png b/sources/plugins/sourcearea/icons/hidpi/source.png
new file mode 100644
index 0000000..2f3eae1
--- /dev/null
+++ b/sources/plugins/sourcearea/icons/hidpi/source.png
Binary files differ
diff --git a/sources/plugins/sourcearea/icons/source-rtl.png b/sources/plugins/sourcearea/icons/source-rtl.png
new file mode 100644
index 0000000..5353eee
--- /dev/null
+++ b/sources/plugins/sourcearea/icons/source-rtl.png
Binary files differ
diff --git a/sources/plugins/sourcearea/icons/source.png b/sources/plugins/sourcearea/icons/source.png
new file mode 100644
index 0000000..0783e85
--- /dev/null
+++ b/sources/plugins/sourcearea/icons/source.png
Binary files differ
diff --git a/sources/plugins/sourcearea/lang/af.js b/sources/plugins/sourcearea/lang/af.js
new file mode 100644
index 0000000..a5a499e
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/af.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'af', {
6 toolbar: 'Bron'
7} );
diff --git a/sources/plugins/sourcearea/lang/ar.js b/sources/plugins/sourcearea/lang/ar.js
new file mode 100644
index 0000000..40808ac
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ar.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ar', {
6 toolbar: 'المصدر'
7} );
diff --git a/sources/plugins/sourcearea/lang/az.js b/sources/plugins/sourcearea/lang/az.js
new file mode 100644
index 0000000..9aeff4b
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/az.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'az', {
6 toolbar: 'HTML mənbəyini göstər'
7} );
diff --git a/sources/plugins/sourcearea/lang/bg.js b/sources/plugins/sourcearea/lang/bg.js
new file mode 100644
index 0000000..4902635
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/bg.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'bg', {
6 toolbar: 'Изходен код'
7} );
diff --git a/sources/plugins/sourcearea/lang/bn.js b/sources/plugins/sourcearea/lang/bn.js
new file mode 100644
index 0000000..b050458
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/bn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'bn', {
6 toolbar: 'উৎস'
7} );
diff --git a/sources/plugins/sourcearea/lang/bs.js b/sources/plugins/sourcearea/lang/bs.js
new file mode 100644
index 0000000..c0b5e09
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/bs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'bs', {
6 toolbar: 'HTML kôd'
7} );
diff --git a/sources/plugins/sourcearea/lang/ca.js b/sources/plugins/sourcearea/lang/ca.js
new file mode 100644
index 0000000..c958e9b
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ca', {
6 toolbar: 'Codi font'
7} );
diff --git a/sources/plugins/sourcearea/lang/cs.js b/sources/plugins/sourcearea/lang/cs.js
new file mode 100644
index 0000000..dccf574
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/cs.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'cs', {
6 toolbar: 'Zdroj'
7} );
diff --git a/sources/plugins/sourcearea/lang/cy.js b/sources/plugins/sourcearea/lang/cy.js
new file mode 100644
index 0000000..b8ce201
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/cy.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'cy', {
6 toolbar: 'HTML'
7} );
diff --git a/sources/plugins/sourcearea/lang/da.js b/sources/plugins/sourcearea/lang/da.js
new file mode 100644
index 0000000..bf02c14
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/da.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'da', {
6 toolbar: 'Kilde'
7} );
diff --git a/sources/plugins/sourcearea/lang/de-ch.js b/sources/plugins/sourcearea/lang/de-ch.js
new file mode 100644
index 0000000..c039623
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/de-ch.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'de-ch', {
6 toolbar: 'Quellcode'
7} );
diff --git a/sources/plugins/sourcearea/lang/de.js b/sources/plugins/sourcearea/lang/de.js
new file mode 100644
index 0000000..dfa995f
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/de.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'de', {
6 toolbar: 'Quellcode'
7} );
diff --git a/sources/plugins/sourcearea/lang/el.js b/sources/plugins/sourcearea/lang/el.js
new file mode 100644
index 0000000..0a8d8a8
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/el.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'el', {
6 toolbar: 'Κώδικας'
7} );
diff --git a/sources/plugins/sourcearea/lang/en-au.js b/sources/plugins/sourcearea/lang/en-au.js
new file mode 100644
index 0000000..10e7843
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/en-au.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'en-au', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/en-ca.js b/sources/plugins/sourcearea/lang/en-ca.js
new file mode 100644
index 0000000..f5e61da
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/en-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'en-ca', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/en-gb.js b/sources/plugins/sourcearea/lang/en-gb.js
new file mode 100644
index 0000000..5d876aa
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/en-gb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'en-gb', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/en.js b/sources/plugins/sourcearea/lang/en.js
new file mode 100644
index 0000000..90a24e9
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/en.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'en', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/eo.js b/sources/plugins/sourcearea/lang/eo.js
new file mode 100644
index 0000000..613de63
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/eo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'eo', {
6 toolbar: 'Fonto'
7} );
diff --git a/sources/plugins/sourcearea/lang/es.js b/sources/plugins/sourcearea/lang/es.js
new file mode 100644
index 0000000..014a967
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/es.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'es', {
6 toolbar: 'Fuente HTML'
7} );
diff --git a/sources/plugins/sourcearea/lang/et.js b/sources/plugins/sourcearea/lang/et.js
new file mode 100644
index 0000000..9a73ece
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/et.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'et', {
6 toolbar: 'Lähtekood'
7} );
diff --git a/sources/plugins/sourcearea/lang/eu.js b/sources/plugins/sourcearea/lang/eu.js
new file mode 100644
index 0000000..350b3e2
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/eu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'eu', {
6 toolbar: 'Iturburua'
7} );
diff --git a/sources/plugins/sourcearea/lang/fa.js b/sources/plugins/sourcearea/lang/fa.js
new file mode 100644
index 0000000..40757c0
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/fa.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'fa', {
6 toolbar: 'منبع'
7} );
diff --git a/sources/plugins/sourcearea/lang/fi.js b/sources/plugins/sourcearea/lang/fi.js
new file mode 100644
index 0000000..fba260e
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/fi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'fi', {
6 toolbar: 'Koodi'
7} );
diff --git a/sources/plugins/sourcearea/lang/fo.js b/sources/plugins/sourcearea/lang/fo.js
new file mode 100644
index 0000000..f384c40
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/fo.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'fo', {
6 toolbar: 'Kelda'
7} );
diff --git a/sources/plugins/sourcearea/lang/fr-ca.js b/sources/plugins/sourcearea/lang/fr-ca.js
new file mode 100644
index 0000000..707686f
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/fr-ca.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'fr-ca', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/fr.js b/sources/plugins/sourcearea/lang/fr.js
new file mode 100644
index 0000000..57d4f5f
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/fr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'fr', {
6 toolbar: 'Source'
7} );
diff --git a/sources/plugins/sourcearea/lang/gl.js b/sources/plugins/sourcearea/lang/gl.js
new file mode 100644
index 0000000..c68a1da
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/gl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'gl', {
6 toolbar: 'Orixe'
7} );
diff --git a/sources/plugins/sourcearea/lang/gu.js b/sources/plugins/sourcearea/lang/gu.js
new file mode 100644
index 0000000..a1c9b66
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/gu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'gu', {
6 toolbar: 'મૂળ કે પ્રાથમિક દસ્તાવેજ'
7} );
diff --git a/sources/plugins/sourcearea/lang/he.js b/sources/plugins/sourcearea/lang/he.js
new file mode 100644
index 0000000..8b0f28d
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/he.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'he', {
6 toolbar: 'מקור'
7} );
diff --git a/sources/plugins/sourcearea/lang/hi.js b/sources/plugins/sourcearea/lang/hi.js
new file mode 100644
index 0000000..0d8cc1b
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/hi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'hi', {
6 toolbar: 'सोर्स'
7} );
diff --git a/sources/plugins/sourcearea/lang/hr.js b/sources/plugins/sourcearea/lang/hr.js
new file mode 100644
index 0000000..dca2202
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/hr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'hr', {
6 toolbar: 'Kôd'
7} );
diff --git a/sources/plugins/sourcearea/lang/hu.js b/sources/plugins/sourcearea/lang/hu.js
new file mode 100644
index 0000000..9628fe4
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/hu.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'hu', {
6 toolbar: 'Forráskód'
7} );
diff --git a/sources/plugins/sourcearea/lang/id.js b/sources/plugins/sourcearea/lang/id.js
new file mode 100644
index 0000000..f8e25c5
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/id.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'id', {
6 toolbar: 'Sumber'
7} );
diff --git a/sources/plugins/sourcearea/lang/is.js b/sources/plugins/sourcearea/lang/is.js
new file mode 100644
index 0000000..a90207d
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/is.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'is', {
6 toolbar: 'Kóði'
7} );
diff --git a/sources/plugins/sourcearea/lang/it.js b/sources/plugins/sourcearea/lang/it.js
new file mode 100644
index 0000000..b445a21
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/it.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'it', {
6 toolbar: 'Sorgente'
7} );
diff --git a/sources/plugins/sourcearea/lang/ja.js b/sources/plugins/sourcearea/lang/ja.js
new file mode 100644
index 0000000..3f026b6
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ja.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ja', {
6 toolbar: 'ソース'
7} );
diff --git a/sources/plugins/sourcearea/lang/ka.js b/sources/plugins/sourcearea/lang/ka.js
new file mode 100644
index 0000000..f06b130
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ka.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ka', {
6 toolbar: 'კოდები'
7} );
diff --git a/sources/plugins/sourcearea/lang/km.js b/sources/plugins/sourcearea/lang/km.js
new file mode 100644
index 0000000..9cd4769
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/km.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'km', {
6 toolbar: 'អក្សរ​កូដ'
7} );
diff --git a/sources/plugins/sourcearea/lang/ko.js b/sources/plugins/sourcearea/lang/ko.js
new file mode 100644
index 0000000..26fe7ff
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ko.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ko', {
6 toolbar: '소스'
7} );
diff --git a/sources/plugins/sourcearea/lang/ku.js b/sources/plugins/sourcearea/lang/ku.js
new file mode 100644
index 0000000..a3f1263
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ku.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ku', {
6 toolbar: 'سەرچاوە'
7} );
diff --git a/sources/plugins/sourcearea/lang/lt.js b/sources/plugins/sourcearea/lang/lt.js
new file mode 100644
index 0000000..c3304dc
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/lt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'lt', {
6 toolbar: 'Šaltinis'
7} );
diff --git a/sources/plugins/sourcearea/lang/lv.js b/sources/plugins/sourcearea/lang/lv.js
new file mode 100644
index 0000000..c3ef246
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/lv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'lv', {
6 toolbar: 'HTML kods'
7} );
diff --git a/sources/plugins/sourcearea/lang/mk.js b/sources/plugins/sourcearea/lang/mk.js
new file mode 100644
index 0000000..eeccabd
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/mk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'mk', {
6 toolbar: 'Source' // MISSING
7} );
diff --git a/sources/plugins/sourcearea/lang/mn.js b/sources/plugins/sourcearea/lang/mn.js
new file mode 100644
index 0000000..a7c1288
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/mn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'mn', {
6 toolbar: 'Код'
7} );
diff --git a/sources/plugins/sourcearea/lang/ms.js b/sources/plugins/sourcearea/lang/ms.js
new file mode 100644
index 0000000..f09ac53
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ms.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ms', {
6 toolbar: 'Sumber'
7} );
diff --git a/sources/plugins/sourcearea/lang/nb.js b/sources/plugins/sourcearea/lang/nb.js
new file mode 100644
index 0000000..87b75a8
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/nb.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'nb', {
6 toolbar: 'Kilde'
7} );
diff --git a/sources/plugins/sourcearea/lang/nl.js b/sources/plugins/sourcearea/lang/nl.js
new file mode 100644
index 0000000..dc61f34
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/nl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'nl', {
6 toolbar: 'Broncode'
7} );
diff --git a/sources/plugins/sourcearea/lang/no.js b/sources/plugins/sourcearea/lang/no.js
new file mode 100644
index 0000000..86f386d
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/no.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'no', {
6 toolbar: 'Kilde'
7} );
diff --git a/sources/plugins/sourcearea/lang/oc.js b/sources/plugins/sourcearea/lang/oc.js
new file mode 100644
index 0000000..90f418f
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/oc.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'oc', {
6 toolbar: 'Font'
7} );
diff --git a/sources/plugins/sourcearea/lang/pl.js b/sources/plugins/sourcearea/lang/pl.js
new file mode 100644
index 0000000..48734a8
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/pl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'pl', {
6 toolbar: 'Źródło dokumentu'
7} );
diff --git a/sources/plugins/sourcearea/lang/pt-br.js b/sources/plugins/sourcearea/lang/pt-br.js
new file mode 100644
index 0000000..54e3ce1
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/pt-br.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'pt-br', {
6 toolbar: 'Código-Fonte'
7} );
diff --git a/sources/plugins/sourcearea/lang/pt.js b/sources/plugins/sourcearea/lang/pt.js
new file mode 100644
index 0000000..7fd6c23
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/pt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'pt', {
6 toolbar: 'Fonte'
7} );
diff --git a/sources/plugins/sourcearea/lang/ro.js b/sources/plugins/sourcearea/lang/ro.js
new file mode 100644
index 0000000..5eb00c4
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ro.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ro', {
6 toolbar: 'Sursa'
7} );
diff --git a/sources/plugins/sourcearea/lang/ru.js b/sources/plugins/sourcearea/lang/ru.js
new file mode 100644
index 0000000..304695c
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ru.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ru', {
6 toolbar: 'Источник'
7} );
diff --git a/sources/plugins/sourcearea/lang/si.js b/sources/plugins/sourcearea/lang/si.js
new file mode 100644
index 0000000..22996eb
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/si.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'si', {
6 toolbar: 'මුලාශ්‍රය'
7} );
diff --git a/sources/plugins/sourcearea/lang/sk.js b/sources/plugins/sourcearea/lang/sk.js
new file mode 100644
index 0000000..aed1c61
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sk', {
6 toolbar: 'Zdroj'
7} );
diff --git a/sources/plugins/sourcearea/lang/sl.js b/sources/plugins/sourcearea/lang/sl.js
new file mode 100644
index 0000000..b9a2b5f
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sl.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sl', {
6 toolbar: 'Izvorna koda'
7} );
diff --git a/sources/plugins/sourcearea/lang/sq.js b/sources/plugins/sourcearea/lang/sq.js
new file mode 100644
index 0000000..f4512ce
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sq.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sq', {
6 toolbar: 'Burimi'
7} );
diff --git a/sources/plugins/sourcearea/lang/sr-latn.js b/sources/plugins/sourcearea/lang/sr-latn.js
new file mode 100644
index 0000000..0d8ebd7
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sr-latn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sr-latn', {
6 toolbar: 'Kôd'
7} );
diff --git a/sources/plugins/sourcearea/lang/sr.js b/sources/plugins/sourcearea/lang/sr.js
new file mode 100644
index 0000000..a872556
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sr', {
6 toolbar: 'Kôд'
7} );
diff --git a/sources/plugins/sourcearea/lang/sv.js b/sources/plugins/sourcearea/lang/sv.js
new file mode 100644
index 0000000..a05d49d
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/sv.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'sv', {
6 toolbar: 'Källa'
7} );
diff --git a/sources/plugins/sourcearea/lang/th.js b/sources/plugins/sourcearea/lang/th.js
new file mode 100644
index 0000000..4afb9bc
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/th.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'th', {
6 toolbar: 'ดูรหัส HTML'
7} );
diff --git a/sources/plugins/sourcearea/lang/tr.js b/sources/plugins/sourcearea/lang/tr.js
new file mode 100644
index 0000000..7a9f70a
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/tr.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'tr', {
6 toolbar: 'Kaynak'
7} );
diff --git a/sources/plugins/sourcearea/lang/tt.js b/sources/plugins/sourcearea/lang/tt.js
new file mode 100644
index 0000000..ca05df1
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/tt.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'tt', {
6 toolbar: 'Чыганак'
7} );
diff --git a/sources/plugins/sourcearea/lang/ug.js b/sources/plugins/sourcearea/lang/ug.js
new file mode 100644
index 0000000..791c596
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/ug.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'ug', {
6 toolbar: 'مەنبە'
7} );
diff --git a/sources/plugins/sourcearea/lang/uk.js b/sources/plugins/sourcearea/lang/uk.js
new file mode 100644
index 0000000..905af47
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/uk.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'uk', {
6 toolbar: 'Джерело'
7} );
diff --git a/sources/plugins/sourcearea/lang/vi.js b/sources/plugins/sourcearea/lang/vi.js
new file mode 100644
index 0000000..df7eb93
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/vi.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'vi', {
6 toolbar: 'Mã HTML'
7} );
diff --git a/sources/plugins/sourcearea/lang/zh-cn.js b/sources/plugins/sourcearea/lang/zh-cn.js
new file mode 100644
index 0000000..a98c869
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/zh-cn.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'zh-cn', {
6 toolbar: '源码'
7} );
diff --git a/sources/plugins/sourcearea/lang/zh.js b/sources/plugins/sourcearea/lang/zh.js
new file mode 100644
index 0000000..043dd11
--- /dev/null
+++ b/sources/plugins/sourcearea/lang/zh.js
@@ -0,0 +1,7 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'sourcearea', 'zh', {
6 toolbar: '原始碼'
7} );
diff --git a/sources/plugins/sourcearea/plugin.js b/sources/plugins/sourcearea/plugin.js
new file mode 100644
index 0000000..837bc30
--- /dev/null
+++ b/sources/plugins/sourcearea/plugin.js
@@ -0,0 +1,168 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The Source Editing Area plugin. It registers the "source" editing
8 * mode, which displays raw HTML data being edited in the editor.
9 */
10
11( function() {
12 CKEDITOR.plugins.add( 'sourcearea', {
13 // jscs:disable maximumLineLength
14 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
15 // jscs:enable maximumLineLength
16 icons: 'source,source-rtl', // %REMOVE_LINE_CORE%
17 hidpi: true, // %REMOVE_LINE_CORE%
18 init: function( editor ) {
19 // Source mode in inline editors is only available through the "sourcedialog" plugin.
20 if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE )
21 return;
22
23 var sourcearea = CKEDITOR.plugins.sourcearea;
24
25 editor.addMode( 'source', function( callback ) {
26 var contentsSpace = editor.ui.space( 'contents' ),
27 textarea = contentsSpace.getDocument().createElement( 'textarea' );
28
29 textarea.setStyles(
30 CKEDITOR.tools.extend( {
31 // IE7 has overflow the <textarea> from wrapping table cell.
32 width: CKEDITOR.env.ie7Compat ? '99%' : '100%',
33 height: '100%',
34 resize: 'none',
35 outline: 'none',
36 'text-align': 'left'
37 },
38 CKEDITOR.tools.cssVendorPrefix( 'tab-size', editor.config.sourceAreaTabSize || 4 ) ) );
39
40 // Make sure that source code is always displayed LTR,
41 // regardless of editor language (#10105).
42 textarea.setAttribute( 'dir', 'ltr' );
43
44 textarea.addClass( 'cke_source' ).addClass( 'cke_reset' ).addClass( 'cke_enable_context_menu' );
45
46 editor.ui.space( 'contents' ).append( textarea );
47
48 var editable = editor.editable( new sourceEditable( editor, textarea ) );
49
50 // Fill the textarea with the current editor data.
51 editable.setData( editor.getData( 1 ) );
52
53 // Having to make <textarea> fixed sized to conquer the following bugs:
54 // 1. The textarea height/width='100%' doesn't constraint to the 'td' in IE6/7.
55 // 2. Unexpected vertical-scrolling behavior happens whenever focus is moving out of editor
56 // if text content within it has overflowed. (#4762)
57 if ( CKEDITOR.env.ie ) {
58 editable.attachListener( editor, 'resize', onResize, editable );
59 editable.attachListener( CKEDITOR.document.getWindow(), 'resize', onResize, editable );
60 CKEDITOR.tools.setTimeout( onResize, 0, editable );
61 }
62
63 editor.fire( 'ariaWidget', this );
64
65 callback();
66 } );
67
68 editor.addCommand( 'source', sourcearea.commands.source );
69
70 if ( editor.ui.addButton ) {
71 editor.ui.addButton( 'Source', {
72 label: editor.lang.sourcearea.toolbar,
73 command: 'source',
74 toolbar: 'mode,10'
75 } );
76 }
77
78 editor.on( 'mode', function() {
79 editor.getCommand( 'source' ).setState( editor.mode == 'source' ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
80 } );
81
82 var needsFocusHack = CKEDITOR.env.ie && CKEDITOR.env.version == 9;
83
84 function onResize() {
85 // We have to do something with focus on IE9, because if sourcearea had focus
86 // before being resized, the caret ends somewhere in the editor UI (#11839).
87 var wasActive = needsFocusHack && this.equals( CKEDITOR.document.getActive() );
88
89 // Holder rectange size is stretched by textarea,
90 // so hide it just for a moment.
91 this.hide();
92 this.setStyle( 'height', this.getParent().$.clientHeight + 'px' );
93 this.setStyle( 'width', this.getParent().$.clientWidth + 'px' );
94 // When we have proper holder size, show textarea again.
95 this.show();
96
97 if ( wasActive )
98 this.focus();
99 }
100 }
101 } );
102
103 var sourceEditable = CKEDITOR.tools.createClass( {
104 base: CKEDITOR.editable,
105 proto: {
106 setData: function( data ) {
107 this.setValue( data );
108 this.status = 'ready';
109 this.editor.fire( 'dataReady' );
110 },
111
112 getData: function() {
113 return this.getValue();
114 },
115
116 // Insertions are not supported in source editable.
117 insertHtml: function() {},
118 insertElement: function() {},
119 insertText: function() {},
120
121 // Read-only support for textarea.
122 setReadOnly: function( isReadOnly ) {
123 this[ ( isReadOnly ? 'set' : 'remove' ) + 'Attribute' ]( 'readOnly', 'readonly' );
124 },
125
126 detach: function() {
127 sourceEditable.baseProto.detach.call( this );
128 this.clearCustomData();
129 this.remove();
130 }
131 }
132 } );
133} )();
134
135CKEDITOR.plugins.sourcearea = {
136 commands: {
137 source: {
138 modes: { wysiwyg: 1, source: 1 },
139 editorFocus: false,
140 readOnly: 1,
141 exec: function( editor ) {
142 if ( editor.mode == 'wysiwyg' )
143 editor.fire( 'saveSnapshot' );
144 editor.getCommand( 'source' ).setState( CKEDITOR.TRISTATE_DISABLED );
145 editor.setMode( editor.mode == 'source' ? 'wysiwyg' : 'source' );
146 },
147
148 canUndo: false
149 }
150 }
151};
152
153/**
154 * Controls the `tab-size` CSS property of the source editing area. Use it to set the width
155 * of the tab character in the source view. Enter an integer to denote the number of spaces
156 * that the tab will contain.
157 *
158 * **Note:** Works only with {@link #dataIndentationChars}
159 * set to `'\t'`. Please consider that not all browsers support the `tab-size` CSS
160 * property yet.
161 *
162 * // Set tab-size to 10 characters.
163 * config.sourceAreaTabSize = 10;
164 *
165 * @cfg {Number} [sourceAreaTabSize=4]
166 * @member CKEDITOR.config
167 * @see CKEDITOR.config#dataIndentationChars
168 */
diff --git a/sources/plugins/tab/plugin.js b/sources/plugins/tab/plugin.js
new file mode 100644
index 0000000..98acb2e
--- /dev/null
+++ b/sources/plugins/tab/plugin.js
@@ -0,0 +1,302 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6( function() {
7 var meta = {
8 editorFocus: false,
9 modes: { wysiwyg: 1, source: 1 }
10 };
11
12 var blurCommand = {
13 exec: function( editor ) {
14 editor.container.focusNext( true, editor.tabIndex );
15 }
16 };
17
18 var blurBackCommand = {
19 exec: function( editor ) {
20 editor.container.focusPrevious( true, editor.tabIndex );
21 }
22 };
23
24 function selectNextCellCommand( backward ) {
25 return {
26 editorFocus: false,
27 canUndo: false,
28 modes: { wysiwyg: 1 },
29 exec: function( editor ) {
30 if ( editor.editable().hasFocus ) {
31 var sel = editor.getSelection(),
32 path = new CKEDITOR.dom.elementPath( sel.getCommonAncestor(), sel.root ),
33 cell;
34
35 if ( ( cell = path.contains( { td: 1, th: 1 }, 1 ) ) ) {
36 var resultRange = editor.createRange(),
37 next = CKEDITOR.tools.tryThese( function() {
38 var row = cell.getParent(),
39 next = row.$.cells[ cell.$.cellIndex + ( backward ? -1 : 1 ) ];
40
41 // Invalid any empty value.
42 next.parentNode.parentNode;
43 return next;
44 }, function() {
45 var row = cell.getParent(),
46 table = row.getAscendant( 'table' ),
47 nextRow = table.$.rows[ row.$.rowIndex + ( backward ? -1 : 1 ) ];
48
49 return nextRow.cells[ backward ? nextRow.cells.length - 1 : 0 ];
50 } );
51
52 // Clone one more row at the end of table and select the first newly established cell.
53 if ( !( next || backward ) ) {
54 var table = cell.getAscendant( 'table' ).$,
55 cells = cell.getParent().$.cells;
56
57 var newRow = new CKEDITOR.dom.element( table.insertRow( -1 ), editor.document );
58
59 for ( var i = 0, count = cells.length; i < count; i++ ) {
60 var newCell = newRow.append( new CKEDITOR.dom.element( cells[ i ], editor.document ).clone( false, false ) );
61 newCell.appendBogus();
62 }
63
64 resultRange.moveToElementEditStart( newRow );
65 } else if ( next ) {
66 next = new CKEDITOR.dom.element( next );
67 resultRange.moveToElementEditStart( next );
68 // Avoid selecting empty block makes the cursor blind.
69 if ( !( resultRange.checkStartOfBlock() && resultRange.checkEndOfBlock() ) )
70 resultRange.selectNodeContents( next );
71 } else {
72 return true;
73 }
74
75 resultRange.select( true );
76 return true;
77 }
78 }
79
80 return false;
81 }
82 };
83 }
84
85 CKEDITOR.plugins.add( 'tab', {
86 init: function( editor ) {
87 var tabTools = editor.config.enableTabKeyTools !== false,
88 tabSpaces = editor.config.tabSpaces || 0,
89 tabText = '';
90
91 while ( tabSpaces-- )
92 tabText += '\xa0';
93
94 if ( tabText ) {
95 editor.on( 'key', function( ev ) {
96 // TAB.
97 if ( ev.data.keyCode == 9 ) {
98 editor.insertText( tabText );
99 ev.cancel();
100 }
101 } );
102 }
103
104 if ( tabTools ) {
105 editor.on( 'key', function( ev ) {
106 if ( ev.data.keyCode == 9 && editor.execCommand( 'selectNextCell' ) || // TAB
107 ev.data.keyCode == ( CKEDITOR.SHIFT + 9 ) && editor.execCommand( 'selectPreviousCell' ) ) // SHIFT+TAB
108 ev.cancel();
109 } );
110 }
111
112 editor.addCommand( 'blur', CKEDITOR.tools.extend( blurCommand, meta ) );
113 editor.addCommand( 'blurBack', CKEDITOR.tools.extend( blurBackCommand, meta ) );
114 editor.addCommand( 'selectNextCell', selectNextCellCommand() );
115 editor.addCommand( 'selectPreviousCell', selectNextCellCommand( true ) );
116 }
117 } );
118} )();
119
120/**
121 * Moves the UI focus to the element following this element in the tabindex order.
122 *
123 * var element = CKEDITOR.document.getById( 'example' );
124 * element.focusNext();
125 *
126 * @param {Boolean} [ignoreChildren=false]
127 * @param {Number} [indexToUse]
128 * @member CKEDITOR.dom.element
129 */
130CKEDITOR.dom.element.prototype.focusNext = function( ignoreChildren, indexToUse ) {
131 var curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),
132 passedCurrent, enteredCurrent, elected, electedTabIndex, element, elementTabIndex;
133
134 if ( curTabIndex <= 0 ) {
135 // If this element has tabindex <= 0 then we must simply look for any
136 // element following it containing tabindex=0.
137
138 element = this.getNextSourceNode( ignoreChildren, CKEDITOR.NODE_ELEMENT );
139
140 while ( element ) {
141 if ( element.isVisible() && element.getTabIndex() === 0 ) {
142 elected = element;
143 break;
144 }
145
146 element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );
147 }
148 } else {
149 // If this element has tabindex > 0 then we must look for:
150 // 1. An element following this element with the same tabindex.
151 // 2. The first element in source other with the lowest tabindex
152 // that is higher than this element tabindex.
153 // 3. The first element with tabindex=0.
154
155 element = this.getDocument().getBody().getFirst();
156
157 while ( ( element = element.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) ) {
158 if ( !passedCurrent ) {
159 if ( !enteredCurrent && element.equals( this ) ) {
160 enteredCurrent = true;
161
162 // Ignore this element, if required.
163 if ( ignoreChildren ) {
164 if ( !( element = element.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )
165 break;
166 passedCurrent = 1;
167 }
168 } else if ( enteredCurrent && !this.contains( element ) ) {
169 passedCurrent = 1;
170 }
171 }
172
173 if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )
174 continue;
175
176 if ( passedCurrent && elementTabIndex == curTabIndex ) {
177 elected = element;
178 break;
179 }
180
181 if ( elementTabIndex > curTabIndex && ( !elected || !electedTabIndex || elementTabIndex < electedTabIndex ) ) {
182 elected = element;
183 electedTabIndex = elementTabIndex;
184 } else if ( !elected && elementTabIndex === 0 ) {
185 elected = element;
186 electedTabIndex = elementTabIndex;
187 }
188 }
189 }
190
191 if ( elected )
192 elected.focus();
193};
194
195/**
196 * Moves the UI focus to the element before this element in the tabindex order.
197 *
198 * var element = CKEDITOR.document.getById( 'example' );
199 * element.focusPrevious();
200 *
201 * @param {Boolean} [ignoreChildren=false]
202 * @param {Number} [indexToUse]
203 * @member CKEDITOR.dom.element
204 */
205CKEDITOR.dom.element.prototype.focusPrevious = function( ignoreChildren, indexToUse ) {
206 var curTabIndex = ( indexToUse === undefined ? this.getTabIndex() : indexToUse ),
207 passedCurrent, enteredCurrent, elected,
208 electedTabIndex = 0,
209 elementTabIndex;
210
211 var element = this.getDocument().getBody().getLast();
212
213 while ( ( element = element.getPreviousSourceNode( false, CKEDITOR.NODE_ELEMENT ) ) ) {
214 if ( !passedCurrent ) {
215 if ( !enteredCurrent && element.equals( this ) ) {
216 enteredCurrent = true;
217
218 // Ignore this element, if required.
219 if ( ignoreChildren ) {
220 if ( !( element = element.getPreviousSourceNode( true, CKEDITOR.NODE_ELEMENT ) ) )
221 break;
222 passedCurrent = 1;
223 }
224 } else if ( enteredCurrent && !this.contains( element ) ) {
225 passedCurrent = 1;
226 }
227 }
228
229 if ( !element.isVisible() || ( elementTabIndex = element.getTabIndex() ) < 0 )
230 continue;
231
232 if ( curTabIndex <= 0 ) {
233 // If this element has tabindex <= 0 then we must look for:
234 // 1. An element before this one containing tabindex=0.
235 // 2. The last element with the highest tabindex.
236
237 if ( passedCurrent && elementTabIndex === 0 ) {
238 elected = element;
239 break;
240 }
241
242 if ( elementTabIndex > electedTabIndex ) {
243 elected = element;
244 electedTabIndex = elementTabIndex;
245 }
246 } else {
247 // If this element has tabindex > 0 we must look for:
248 // 1. An element preceeding this one, with the same tabindex.
249 // 2. The last element in source other with the highest tabindex
250 // that is lower than this element tabindex.
251
252 if ( passedCurrent && elementTabIndex == curTabIndex ) {
253 elected = element;
254 break;
255 }
256
257 if ( elementTabIndex < curTabIndex && ( !elected || elementTabIndex > electedTabIndex ) ) {
258 elected = element;
259 electedTabIndex = elementTabIndex;
260 }
261 }
262 }
263
264 if ( elected )
265 elected.focus();
266};
267
268/**
269 * Intructs the editor to add a number of spaces (`&nbsp;`) to the text when
270 * hitting the <kbd>Tab</kbd> key. If set to zero, the <kbd>Tab</kbd> key will be used to move the
271 * cursor focus to the next element in the page, out of the editor focus.
272 *
273 * config.tabSpaces = 4;
274 *
275 * @cfg {Number} [tabSpaces=0]
276 * @member CKEDITOR.config
277 */
278
279/**
280 * Allow context-sensitive <kbd>Tab</kbd> key behaviors, including the following scenarios:
281 *
282 * When selection is anchored inside **table cells**:
283 *
284 * * If <kbd>Tab</kbd> is pressed, select the content of the "next" cell. If in the last
285 * cell in the table, add a new row to it and focus its first cell.
286 * * If <kbd>Shift+Tab</kbd> is pressed, select the content of the "previous" cell.
287 * Do nothing when it is in the first cell.
288 *
289 * Example:
290 *
291 * config.enableTabKeyTools = false;
292 *
293 * @cfg {Boolean} [enableTabKeyTools=true]
294 * @member CKEDITOR.config
295 */
296
297// If the <kbd>Tab</kbd> key is not supposed to be enabled for navigation, the following
298// settings could be used alternatively:
299// config.keystrokes.push(
300// [ CKEDITOR.ALT + 38 /*Arrow Up*/, 'selectPreviousCell' ],
301// [ CKEDITOR.ALT + 40 /*Arrow Down*/, 'selectNextCell' ]
302// );
diff --git a/sources/plugins/toolbar/lang/af.js b/sources/plugins/toolbar/lang/af.js
new file mode 100644
index 0000000..8a3b1cd
--- /dev/null
+++ b/sources/plugins/toolbar/lang/af.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'af', {
6 toolbarCollapse: 'Verklein werkbalk',
7 toolbarExpand: 'Vergroot werkbalk',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Knipbord/Undo',
11 editing: 'Verander',
12 forms: 'Vorms',
13 basicstyles: 'Eenvoudige Styl',
14 paragraph: 'Paragraaf',
15 links: 'Skakels',
16 insert: 'Toevoeg',
17 styles: 'Style',
18 colors: 'Kleure',
19 tools: 'Gereedskap'
20 },
21 toolbars: 'Werkbalke'
22} );
diff --git a/sources/plugins/toolbar/lang/ar.js b/sources/plugins/toolbar/lang/ar.js
new file mode 100644
index 0000000..8cef5e7
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ar.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ar', {
6 toolbarCollapse: 'تقليص شريط الأدوت',
7 toolbarExpand: 'تمديد شريط الأدوات',
8 toolbarGroups: {
9 document: 'مستند',
10 clipboard: 'الحافظة/الرجوع',
11 editing: 'تحرير',
12 forms: 'نماذج',
13 basicstyles: 'نمط بسيط',
14 paragraph: 'فقرة',
15 links: 'روابط',
16 insert: 'إدراج',
17 styles: 'أنماط',
18 colors: 'ألوان',
19 tools: 'أدوات'
20 },
21 toolbars: 'أشرطة أدوات المحرر'
22} );
diff --git a/sources/plugins/toolbar/lang/az.js b/sources/plugins/toolbar/lang/az.js
new file mode 100644
index 0000000..25c4a53
--- /dev/null
+++ b/sources/plugins/toolbar/lang/az.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'az', {
6 toolbarCollapse: 'Paneli gizlət',
7 toolbarExpand: 'Paneli göstər',
8 toolbarGroups: {
9 document: 'Mətn',
10 clipboard: 'Mübadilə buferi/İmtina et',
11 editing: 'Redaktə edilməsi',
12 forms: 'Formalar',
13 basicstyles: 'Əsas üslublar',
14 paragraph: 'Abzas',
15 links: 'Link',
16 insert: 'Əlavə et',
17 styles: 'Üslublar',
18 colors: 'Rənqlər',
19 tools: 'Alətləri'
20 },
21 toolbars: 'Redaktorun panelləri'
22} );
diff --git a/sources/plugins/toolbar/lang/bg.js b/sources/plugins/toolbar/lang/bg.js
new file mode 100644
index 0000000..0fb4384
--- /dev/null
+++ b/sources/plugins/toolbar/lang/bg.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'bg', {
6 toolbarCollapse: 'Свиване на лентата с инструменти',
7 toolbarExpand: 'Разширяване на лентата с инструменти',
8 toolbarGroups: {
9 document: 'Документ',
10 clipboard: 'Клипборд/Отмяна',
11 editing: 'Промяна',
12 forms: 'Форми',
13 basicstyles: 'Базови стилове',
14 paragraph: 'Параграф',
15 links: 'Връзки',
16 insert: 'Вмъкване',
17 styles: 'Стилове',
18 colors: 'Цветове',
19 tools: 'Инструменти'
20 },
21 toolbars: 'Ленти с инструменти'
22} );
diff --git a/sources/plugins/toolbar/lang/bn.js b/sources/plugins/toolbar/lang/bn.js
new file mode 100644
index 0000000..dc9697e
--- /dev/null
+++ b/sources/plugins/toolbar/lang/bn.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'bn', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/bs.js b/sources/plugins/toolbar/lang/bs.js
new file mode 100644
index 0000000..00f46d0
--- /dev/null
+++ b/sources/plugins/toolbar/lang/bs.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'bs', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/ca.js b/sources/plugins/toolbar/lang/ca.js
new file mode 100644
index 0000000..82e4413
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ca.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ca', {
6 toolbarCollapse: 'Redueix la barra d\'eines',
7 toolbarExpand: 'Amplia la barra d\'eines',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor de barra d\'eines'
22} );
diff --git a/sources/plugins/toolbar/lang/cs.js b/sources/plugins/toolbar/lang/cs.js
new file mode 100644
index 0000000..f8e650f
--- /dev/null
+++ b/sources/plugins/toolbar/lang/cs.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'cs', {
6 toolbarCollapse: 'Skrýt panel nástrojů',
7 toolbarExpand: 'Zobrazit panel nástrojů',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Schránka/Zpět',
11 editing: 'Úpravy',
12 forms: 'Formuláře',
13 basicstyles: 'Základní styly',
14 paragraph: 'Odstavec',
15 links: 'Odkazy',
16 insert: 'Vložit',
17 styles: 'Styly',
18 colors: 'Barvy',
19 tools: 'Nástroje'
20 },
21 toolbars: 'Panely nástrojů editoru'
22} );
diff --git a/sources/plugins/toolbar/lang/cy.js b/sources/plugins/toolbar/lang/cy.js
new file mode 100644
index 0000000..faebd1b
--- /dev/null
+++ b/sources/plugins/toolbar/lang/cy.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'cy', {
6 toolbarCollapse: 'Cyfangu\'r Bar Offer',
7 toolbarExpand: 'Ehangu\'r Bar Offer',
8 toolbarGroups: {
9 document: 'Dogfen',
10 clipboard: 'Clipfwrdd/Dadwneud',
11 editing: 'Golygu',
12 forms: 'Ffurflenni',
13 basicstyles: 'Arddulliau Sylfaenol',
14 paragraph: 'Paragraff',
15 links: 'Dolenni',
16 insert: 'Mewnosod',
17 styles: 'Arddulliau',
18 colors: 'Lliwiau',
19 tools: 'Offer'
20 },
21 toolbars: 'Bariau offer y golygydd'
22} );
diff --git a/sources/plugins/toolbar/lang/da.js b/sources/plugins/toolbar/lang/da.js
new file mode 100644
index 0000000..750bc64
--- /dev/null
+++ b/sources/plugins/toolbar/lang/da.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'da', {
6 toolbarCollapse: 'Sammenklap værktøjslinje',
7 toolbarExpand: 'Udvid værktøjslinje',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Udklipsholder/Fortryd',
11 editing: 'Redigering',
12 forms: 'Formularer',
13 basicstyles: 'Basis styles',
14 paragraph: 'Paragraf',
15 links: 'Links',
16 insert: 'Indsæt',
17 styles: 'Typografier',
18 colors: 'Farver',
19 tools: 'Værktøjer'
20 },
21 toolbars: 'Editors værktøjslinjer'
22} );
diff --git a/sources/plugins/toolbar/lang/de-ch.js b/sources/plugins/toolbar/lang/de-ch.js
new file mode 100644
index 0000000..399aa63
--- /dev/null
+++ b/sources/plugins/toolbar/lang/de-ch.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'de-ch', {
6 toolbarCollapse: 'Werkzeugleiste einklappen',
7 toolbarExpand: 'Werkzeugleiste ausklappen',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Zwischenablage/Rückgängig',
11 editing: 'Editieren',
12 forms: 'Formulare',
13 basicstyles: 'Grundstile',
14 paragraph: 'Absatz',
15 links: 'Links',
16 insert: 'Einfügen',
17 styles: 'Stile',
18 colors: 'Farben',
19 tools: 'Werkzeuge'
20 },
21 toolbars: 'Editor Werkzeugleisten'
22} );
diff --git a/sources/plugins/toolbar/lang/de.js b/sources/plugins/toolbar/lang/de.js
new file mode 100644
index 0000000..fab73aa
--- /dev/null
+++ b/sources/plugins/toolbar/lang/de.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'de', {
6 toolbarCollapse: 'Werkzeugleiste einklappen',
7 toolbarExpand: 'Werkzeugleiste ausklappen',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Zwischenablage/Rückgängig',
11 editing: 'Editieren',
12 forms: 'Formulare',
13 basicstyles: 'Grundstile',
14 paragraph: 'Absatz',
15 links: 'Links',
16 insert: 'Einfügen',
17 styles: 'Stile',
18 colors: 'Farben',
19 tools: 'Werkzeuge'
20 },
21 toolbars: 'Editor Werkzeugleisten'
22} );
diff --git a/sources/plugins/toolbar/lang/el.js b/sources/plugins/toolbar/lang/el.js
new file mode 100644
index 0000000..ce46898
--- /dev/null
+++ b/sources/plugins/toolbar/lang/el.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'el', {
6 toolbarCollapse: 'Σύμπτυξη Εργαλειοθήκης',
7 toolbarExpand: 'Ανάπτυξη Εργαλειοθήκης',
8 toolbarGroups: {
9 document: 'Έγγραφο',
10 clipboard: 'Πρόχειρο/Αναίρεση',
11 editing: 'Επεξεργασία',
12 forms: 'Φόρμες',
13 basicstyles: 'Βασικά Στυλ',
14 paragraph: 'Παράγραφος',
15 links: 'Σύνδεσμοι',
16 insert: 'Εισαγωγή',
17 styles: 'Στυλ',
18 colors: 'Χρώματα',
19 tools: 'Εργαλεία'
20 },
21 toolbars: 'Εργαλειοθήκες επεξεργαστή'
22} );
diff --git a/sources/plugins/toolbar/lang/en-au.js b/sources/plugins/toolbar/lang/en-au.js
new file mode 100644
index 0000000..8517e62
--- /dev/null
+++ b/sources/plugins/toolbar/lang/en-au.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'en-au', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars'
22} );
diff --git a/sources/plugins/toolbar/lang/en-ca.js b/sources/plugins/toolbar/lang/en-ca.js
new file mode 100644
index 0000000..fb2049a
--- /dev/null
+++ b/sources/plugins/toolbar/lang/en-ca.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'en-ca', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/en-gb.js b/sources/plugins/toolbar/lang/en-gb.js
new file mode 100644
index 0000000..df7198e
--- /dev/null
+++ b/sources/plugins/toolbar/lang/en-gb.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'en-gb', {
6 toolbarCollapse: 'Collapse Toolbar',
7 toolbarExpand: 'Expand Toolbar',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars'
22} );
diff --git a/sources/plugins/toolbar/lang/en.js b/sources/plugins/toolbar/lang/en.js
new file mode 100644
index 0000000..263ac0e
--- /dev/null
+++ b/sources/plugins/toolbar/lang/en.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'en', {
6 toolbarCollapse: 'Collapse Toolbar',
7 toolbarExpand: 'Expand Toolbar',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars'
22} );
diff --git a/sources/plugins/toolbar/lang/eo.js b/sources/plugins/toolbar/lang/eo.js
new file mode 100644
index 0000000..902a613
--- /dev/null
+++ b/sources/plugins/toolbar/lang/eo.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'eo', {
6 toolbarCollapse: 'Faldi la ilbreton',
7 toolbarExpand: 'Malfaldi la ilbreton',
8 toolbarGroups: {
9 document: 'Dokumento',
10 clipboard: 'Poŝo/Malfari',
11 editing: 'Redaktado',
12 forms: 'Formularoj',
13 basicstyles: 'Bazaj stiloj',
14 paragraph: 'Paragrafo',
15 links: 'Ligiloj',
16 insert: 'Enmeti',
17 styles: 'Stiloj',
18 colors: 'Koloroj',
19 tools: 'Iloj'
20 },
21 toolbars: 'Ilobretoj de la redaktilo'
22} );
diff --git a/sources/plugins/toolbar/lang/es.js b/sources/plugins/toolbar/lang/es.js
new file mode 100644
index 0000000..bf5b457
--- /dev/null
+++ b/sources/plugins/toolbar/lang/es.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'es', {
6 toolbarCollapse: 'Contraer barra de herramientas',
7 toolbarExpand: 'Expandir barra de herramientas',
8 toolbarGroups: {
9 document: 'Documento',
10 clipboard: 'Portapapeles/Deshacer',
11 editing: 'Edición',
12 forms: 'Formularios',
13 basicstyles: 'Estilos básicos',
14 paragraph: 'Párrafo',
15 links: 'Enlaces',
16 insert: 'Insertar',
17 styles: 'Estilos',
18 colors: 'Colores',
19 tools: 'Herramientas'
20 },
21 toolbars: 'Barras de herramientas del editor'
22} );
diff --git a/sources/plugins/toolbar/lang/et.js b/sources/plugins/toolbar/lang/et.js
new file mode 100644
index 0000000..b83473f
--- /dev/null
+++ b/sources/plugins/toolbar/lang/et.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'et', {
6 toolbarCollapse: 'Tööriistariba peitmine',
7 toolbarExpand: 'Tööriistariba näitamine',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Lõikelaud/tagasivõtmine',
11 editing: 'Muutmine',
12 forms: 'Vormid',
13 basicstyles: 'Põhistiilid',
14 paragraph: 'Lõik',
15 links: 'Lingid',
16 insert: 'Sisesta',
17 styles: 'Stiilid',
18 colors: 'Värvid',
19 tools: 'Tööriistad'
20 },
21 toolbars: 'Redaktori tööriistaribad'
22} );
diff --git a/sources/plugins/toolbar/lang/eu.js b/sources/plugins/toolbar/lang/eu.js
new file mode 100644
index 0000000..831d285
--- /dev/null
+++ b/sources/plugins/toolbar/lang/eu.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'eu', {
6 toolbarCollapse: 'Tolestu tresna-barra',
7 toolbarExpand: 'Zabaldu tresna-barra',
8 toolbarGroups: {
9 document: 'Dokumentua',
10 clipboard: 'Arbela/Desegin',
11 editing: 'Editatu',
12 forms: 'Formularioak',
13 basicstyles: 'Oinarrizko estiloak',
14 paragraph: 'Paragrafoa',
15 links: 'Estekak',
16 insert: 'Txertatu',
17 styles: 'Estiloak',
18 colors: 'Koloreak',
19 tools: 'Tresnak'
20 },
21 toolbars: 'Editorearen tresna-barrak'
22} );
diff --git a/sources/plugins/toolbar/lang/fa.js b/sources/plugins/toolbar/lang/fa.js
new file mode 100644
index 0000000..2d1bc5d
--- /dev/null
+++ b/sources/plugins/toolbar/lang/fa.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'fa', {
6 toolbarCollapse: 'بستن نوار ابزار',
7 toolbarExpand: 'بازکردن نوار ابزار',
8 toolbarGroups: {
9 document: 'سند',
10 clipboard: 'حافظه موقت/برگشت',
11 editing: 'در حال ویرایش',
12 forms: 'فرم​ها',
13 basicstyles: 'سبک‌های پایه',
14 paragraph: 'بند',
15 links: 'پیوندها',
16 insert: 'ورود',
17 styles: 'سبک‌ها',
18 colors: 'رنگ​ها',
19 tools: 'ابزارها'
20 },
21 toolbars: 'نوار ابزارهای ویرایش‌گر'
22} );
diff --git a/sources/plugins/toolbar/lang/fi.js b/sources/plugins/toolbar/lang/fi.js
new file mode 100644
index 0000000..9e12ad4
--- /dev/null
+++ b/sources/plugins/toolbar/lang/fi.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'fi', {
6 toolbarCollapse: 'Kutista työkalupalkki',
7 toolbarExpand: 'Laajenna työkalupalkki',
8 toolbarGroups: {
9 document: 'Dokumentti',
10 clipboard: 'Leikepöytä/Kumoa',
11 editing: 'Muokkaus',
12 forms: 'Lomakkeet',
13 basicstyles: 'Perustyylit',
14 paragraph: 'Kappale',
15 links: 'Linkit',
16 insert: 'Lisää',
17 styles: 'Tyylit',
18 colors: 'Värit',
19 tools: 'Työkalut'
20 },
21 toolbars: 'Editorin työkalupalkit'
22} );
diff --git a/sources/plugins/toolbar/lang/fo.js b/sources/plugins/toolbar/lang/fo.js
new file mode 100644
index 0000000..4628b5d
--- /dev/null
+++ b/sources/plugins/toolbar/lang/fo.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'fo', {
6 toolbarCollapse: 'Lat Toolbar aftur',
7 toolbarExpand: 'Vís Toolbar',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editering',
12 forms: 'Formar',
13 basicstyles: 'Grundleggjandi Styles',
14 paragraph: 'Reglubrot',
15 links: 'Leinkjur',
16 insert: 'Set inn',
17 styles: 'Styles',
18 colors: 'Litir',
19 tools: 'Tól'
20 },
21 toolbars: 'Editor toolbars'
22} );
diff --git a/sources/plugins/toolbar/lang/fr-ca.js b/sources/plugins/toolbar/lang/fr-ca.js
new file mode 100644
index 0000000..4aae863
--- /dev/null
+++ b/sources/plugins/toolbar/lang/fr-ca.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'fr-ca', {
6 toolbarCollapse: 'Enrouler la barre d\'outils',
7 toolbarExpand: 'Dérouler la barre d\'outils',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Presse papier/Annuler',
11 editing: 'Édition',
12 forms: 'Formulaires',
13 basicstyles: 'Styles de base',
14 paragraph: 'Paragraphe',
15 links: 'Liens',
16 insert: 'Insérer',
17 styles: 'Styles',
18 colors: 'Couleurs',
19 tools: 'Outils'
20 },
21 toolbars: 'Barre d\'outils de l\'éditeur'
22} );
diff --git a/sources/plugins/toolbar/lang/fr.js b/sources/plugins/toolbar/lang/fr.js
new file mode 100644
index 0000000..9861866
--- /dev/null
+++ b/sources/plugins/toolbar/lang/fr.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'fr', {
6 toolbarCollapse: 'Enrouler la barre d\'outils',
7 toolbarExpand: 'Dérouler la barre d\'outils',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Presse-papier/Défaire',
11 editing: 'Édition',
12 forms: 'Formulaires',
13 basicstyles: 'Styles de base',
14 paragraph: 'Paragraphe',
15 links: 'Liens',
16 insert: 'Insérer',
17 styles: 'Styles',
18 colors: 'Couleurs',
19 tools: 'Outils'
20 },
21 toolbars: 'Barres d\'outils de l\'éditeur'
22} );
diff --git a/sources/plugins/toolbar/lang/gl.js b/sources/plugins/toolbar/lang/gl.js
new file mode 100644
index 0000000..f81c10a
--- /dev/null
+++ b/sources/plugins/toolbar/lang/gl.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'gl', {
6 toolbarCollapse: 'Contraer a barra de ferramentas',
7 toolbarExpand: 'Expandir a barra de ferramentas',
8 toolbarGroups: {
9 document: 'Documento',
10 clipboard: 'Portapapeis/desfacer',
11 editing: 'Edición',
12 forms: 'Formularios',
13 basicstyles: 'Estilos básicos',
14 paragraph: 'Paragrafo',
15 links: 'Ligazóns',
16 insert: 'Inserir',
17 styles: 'Estilos',
18 colors: 'Cores',
19 tools: 'Ferramentas'
20 },
21 toolbars: 'Barras de ferramentas do editor'
22} );
diff --git a/sources/plugins/toolbar/lang/gu.js b/sources/plugins/toolbar/lang/gu.js
new file mode 100644
index 0000000..f34879b
--- /dev/null
+++ b/sources/plugins/toolbar/lang/gu.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'gu', {
6 toolbarCollapse: 'ટૂલબાર નાનું કરવું',
7 toolbarExpand: 'ટૂલબાર મોટું કરવું',
8 toolbarGroups: {
9 document: 'દસ્તાવેજ',
10 clipboard: 'ક્લિપબોર્ડ/અન',
11 editing: 'એડીટ કરવું',
12 forms: 'ફોર્મ',
13 basicstyles: 'બેસિક્ સ્ટાઇલ',
14 paragraph: 'ફકરો',
15 links: 'લીંક',
16 insert: 'ઉમેરવું',
17 styles: 'સ્ટાઇલ',
18 colors: 'રંગ',
19 tools: 'ટૂલ્સ'
20 },
21 toolbars: 'એડીટર ટૂલ બાર'
22} );
diff --git a/sources/plugins/toolbar/lang/he.js b/sources/plugins/toolbar/lang/he.js
new file mode 100644
index 0000000..8e6f343
--- /dev/null
+++ b/sources/plugins/toolbar/lang/he.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'he', {
6 toolbarCollapse: 'מזעור סרגל כלים',
7 toolbarExpand: 'הרחבת סרגל כלים',
8 toolbarGroups: {
9 document: 'מסמך',
10 clipboard: 'לוח הגזירים (Clipboard)/צעד אחרון',
11 editing: 'עריכה',
12 forms: 'טפסים',
13 basicstyles: 'עיצוב בסיסי',
14 paragraph: 'פסקה',
15 links: 'קישורים',
16 insert: 'הכנסה',
17 styles: 'עיצוב',
18 colors: 'צבעים',
19 tools: 'כלים'
20 },
21 toolbars: 'סרגלי כלים של העורך'
22} );
diff --git a/sources/plugins/toolbar/lang/hi.js b/sources/plugins/toolbar/lang/hi.js
new file mode 100644
index 0000000..7693fa1
--- /dev/null
+++ b/sources/plugins/toolbar/lang/hi.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'hi', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'एडिटर टूलबार'
22} );
diff --git a/sources/plugins/toolbar/lang/hr.js b/sources/plugins/toolbar/lang/hr.js
new file mode 100644
index 0000000..1928251
--- /dev/null
+++ b/sources/plugins/toolbar/lang/hr.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'hr', {
6 toolbarCollapse: 'Smanji alatnu traku',
7 toolbarExpand: 'Proširi alatnu traku',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Međuspremnik/Poništi',
11 editing: 'Uređivanje',
12 forms: 'Forme',
13 basicstyles: 'Osnovni stilovi',
14 paragraph: 'Paragraf',
15 links: 'Veze',
16 insert: 'Umetni',
17 styles: 'Stilovi',
18 colors: 'Boje',
19 tools: 'Alatke'
20 },
21 toolbars: 'Alatne trake uređivača teksta'
22} );
diff --git a/sources/plugins/toolbar/lang/hu.js b/sources/plugins/toolbar/lang/hu.js
new file mode 100644
index 0000000..fb67175
--- /dev/null
+++ b/sources/plugins/toolbar/lang/hu.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'hu', {
6 toolbarCollapse: 'Eszköztár összecsukása',
7 toolbarExpand: 'Eszköztár szétnyitása',
8 toolbarGroups: {
9 document: 'Dokumentum',
10 clipboard: 'Vágólap/Visszavonás',
11 editing: 'Szerkesztés',
12 forms: 'Űrlapok',
13 basicstyles: 'Alapstílusok',
14 paragraph: 'Bekezdés',
15 links: 'Hivatkozások',
16 insert: 'Beszúrás',
17 styles: 'Stílusok',
18 colors: 'Színek',
19 tools: 'Eszközök'
20 },
21 toolbars: 'Szerkesztő Eszköztár'
22} );
diff --git a/sources/plugins/toolbar/lang/id.js b/sources/plugins/toolbar/lang/id.js
new file mode 100644
index 0000000..c993a72
--- /dev/null
+++ b/sources/plugins/toolbar/lang/id.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'id', {
6 toolbarCollapse: 'Ciutkan Toolbar',
7 toolbarExpand: 'Bentangkan Toolbar',
8 toolbarGroups: {
9 document: 'Dokumen',
10 clipboard: 'Papan klip / Kembalikan perlakuan',
11 editing: 'Sunting',
12 forms: 'Formulir',
13 basicstyles: 'Gaya Dasar',
14 paragraph: 'Paragraf',
15 links: 'Tautan',
16 insert: 'Sisip',
17 styles: 'Gaya',
18 colors: 'Warna',
19 tools: 'Alat'
20 },
21 toolbars: 'Toolbar Penyunting'
22} );
diff --git a/sources/plugins/toolbar/lang/is.js b/sources/plugins/toolbar/lang/is.js
new file mode 100644
index 0000000..a5fc159
--- /dev/null
+++ b/sources/plugins/toolbar/lang/is.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'is', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/it.js b/sources/plugins/toolbar/lang/it.js
new file mode 100644
index 0000000..42099cd
--- /dev/null
+++ b/sources/plugins/toolbar/lang/it.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'it', {
6 toolbarCollapse: 'Minimizza Toolbar',
7 toolbarExpand: 'Espandi Toolbar',
8 toolbarGroups: {
9 document: 'Documento',
10 clipboard: 'Copia negli appunti/Annulla',
11 editing: 'Modifica',
12 forms: 'Form',
13 basicstyles: 'Stili di base',
14 paragraph: 'Paragrafo',
15 links: 'Link',
16 insert: 'Inserisci',
17 styles: 'Stili',
18 colors: 'Colori',
19 tools: 'Strumenti'
20 },
21 toolbars: 'Editor toolbar'
22} );
diff --git a/sources/plugins/toolbar/lang/ja.js b/sources/plugins/toolbar/lang/ja.js
new file mode 100644
index 0000000..49bfcd0
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ja.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ja', {
6 toolbarCollapse: 'ツールバーを閉じる',
7 toolbarExpand: 'ツールバーを開く',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: '編集ツールバー'
22} );
diff --git a/sources/plugins/toolbar/lang/ka.js b/sources/plugins/toolbar/lang/ka.js
new file mode 100644
index 0000000..f1a46cb
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ka.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ka', {
6 toolbarCollapse: 'ხელსაწყოთა ზოლის შეწევა',
7 toolbarExpand: 'ხელსაწყოთა ზოლის გამოწევა',
8 toolbarGroups: {
9 document: 'დოკუმენტი',
10 clipboard: 'Clipboard/გაუქმება',
11 editing: 'რედაქტირება',
12 forms: 'ფორმები',
13 basicstyles: 'ძირითადი სტილები',
14 paragraph: 'აბზაცი',
15 links: 'ბმულები',
16 insert: 'ჩასმა',
17 styles: 'სტილები',
18 colors: 'ფერები',
19 tools: 'ხელსაწყოები'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/km.js b/sources/plugins/toolbar/lang/km.js
new file mode 100644
index 0000000..3b0eb05
--- /dev/null
+++ b/sources/plugins/toolbar/lang/km.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'km', {
6 toolbarCollapse: 'បង្រួម​របារ​ឧបករណ៍',
7 toolbarExpand: 'ពង្រីក​របារ​ឧបករណ៍',
8 toolbarGroups: {
9 document: 'ឯកសារ',
10 clipboard: 'Clipboard/មិន​ធ្វើ​វិញ',
11 editing: 'ការ​កែ​សម្រួល',
12 forms: 'បែបបទ',
13 basicstyles: 'រចនាបថ​មូលដ្ឋាន',
14 paragraph: 'កថាខណ្ឌ',
15 links: 'តំណ',
16 insert: 'បញ្ចូល',
17 styles: 'រចនាបថ',
18 colors: 'ពណ៌',
19 tools: 'ឧបករណ៍'
20 },
21 toolbars: 'របារ​ឧបករណ៍​កែ​សម្រួល'
22} );
diff --git a/sources/plugins/toolbar/lang/ko.js b/sources/plugins/toolbar/lang/ko.js
new file mode 100644
index 0000000..dc5a674
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ko.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ko', {
6 toolbarCollapse: '툴바 줄이기',
7 toolbarExpand: '툴바 확장',
8 toolbarGroups: {
9 document: '문서',
10 clipboard: '클립보드/실행 취소',
11 editing: '편집',
12 forms: '폼',
13 basicstyles: '기본 스타일',
14 paragraph: '단락',
15 links: '링크',
16 insert: '삽입',
17 styles: '스타일',
18 colors: '색상',
19 tools: '도구'
20 },
21 toolbars: '에디터 툴바'
22} );
diff --git a/sources/plugins/toolbar/lang/ku.js b/sources/plugins/toolbar/lang/ku.js
new file mode 100644
index 0000000..02f8f91
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ku.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ku', {
6 toolbarCollapse: 'شاردنەوی هێڵی تووڵامراز',
7 toolbarExpand: 'نیشاندانی هێڵی تووڵامراز',
8 toolbarGroups: {
9 document: 'پەڕه',
10 clipboard: 'بڕین/پووچکردنەوە',
11 editing: 'چاکسازی',
12 forms: 'داڕشتە',
13 basicstyles: 'شێوازی بنچینەیی',
14 paragraph: 'بڕگە',
15 links: 'بەستەر',
16 insert: 'خستنە ناو',
17 styles: 'شێواز',
18 colors: 'ڕەنگەکان',
19 tools: 'ئامرازەکان'
20 },
21 toolbars: 'تووڵامرازی دەسکاریکەر'
22} );
diff --git a/sources/plugins/toolbar/lang/lt.js b/sources/plugins/toolbar/lang/lt.js
new file mode 100644
index 0000000..b705d6f
--- /dev/null
+++ b/sources/plugins/toolbar/lang/lt.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'lt', {
6 toolbarCollapse: 'Apjungti įrankių juostą',
7 toolbarExpand: 'Išplėsti įrankių juostą',
8 toolbarGroups: {
9 document: 'Dokumentas',
10 clipboard: 'Atmintinė/Atgal',
11 editing: 'Redagavimas',
12 forms: 'Formos',
13 basicstyles: 'Pagrindiniai stiliai',
14 paragraph: 'Paragrafas',
15 links: 'Nuorodos',
16 insert: 'Įterpti',
17 styles: 'Stiliai',
18 colors: 'Spalvos',
19 tools: 'Įrankiai'
20 },
21 toolbars: 'Redaktoriaus įrankiai'
22} );
diff --git a/sources/plugins/toolbar/lang/lv.js b/sources/plugins/toolbar/lang/lv.js
new file mode 100644
index 0000000..20dd345
--- /dev/null
+++ b/sources/plugins/toolbar/lang/lv.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'lv', {
6 toolbarCollapse: 'Aizvērt rīkjoslu',
7 toolbarExpand: 'Atvērt rīkjoslu',
8 toolbarGroups: {
9 document: 'Dokuments',
10 clipboard: 'Starpliktuve/Atcelt',
11 editing: 'Labošana',
12 forms: 'Formas',
13 basicstyles: 'Pamata stili',
14 paragraph: 'Paragrāfs',
15 links: 'Saites',
16 insert: 'Ievietot',
17 styles: 'Stili',
18 colors: 'Krāsas',
19 tools: 'Rīki'
20 },
21 toolbars: 'Redaktora rīkjoslas'
22} );
diff --git a/sources/plugins/toolbar/lang/mk.js b/sources/plugins/toolbar/lang/mk.js
new file mode 100644
index 0000000..e85581d
--- /dev/null
+++ b/sources/plugins/toolbar/lang/mk.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'mk', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/mn.js b/sources/plugins/toolbar/lang/mn.js
new file mode 100644
index 0000000..5aeb46b
--- /dev/null
+++ b/sources/plugins/toolbar/lang/mn.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'mn', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Холбоосууд',
16 insert: 'Оруулах',
17 styles: 'Загварууд',
18 colors: 'Онгөнүүд',
19 tools: 'Хэрэгслүүд'
20 },
21 toolbars: 'Болосруулагчийн хэрэгслийн самбар'
22} );
diff --git a/sources/plugins/toolbar/lang/ms.js b/sources/plugins/toolbar/lang/ms.js
new file mode 100644
index 0000000..7b78dc6
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ms.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ms', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/nb.js b/sources/plugins/toolbar/lang/nb.js
new file mode 100644
index 0000000..830143a
--- /dev/null
+++ b/sources/plugins/toolbar/lang/nb.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'nb', {
6 toolbarCollapse: 'Skjul verktøylinje',
7 toolbarExpand: 'Vis verktøylinje',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Utklippstavle/Angre',
11 editing: 'Redigering',
12 forms: 'Skjema',
13 basicstyles: 'Basisstiler',
14 paragraph: 'Avsnitt',
15 links: 'Lenker',
16 insert: 'Innsetting',
17 styles: 'Stiler',
18 colors: 'Farger',
19 tools: 'Verktøy'
20 },
21 toolbars: 'Verktøylinjer for editor'
22} );
diff --git a/sources/plugins/toolbar/lang/nl.js b/sources/plugins/toolbar/lang/nl.js
new file mode 100644
index 0000000..84ac147
--- /dev/null
+++ b/sources/plugins/toolbar/lang/nl.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'nl', {
6 toolbarCollapse: 'Werkbalk inklappen',
7 toolbarExpand: 'Werkbalk uitklappen',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Klembord/Ongedaan maken',
11 editing: 'Bewerken',
12 forms: 'Formulieren',
13 basicstyles: 'Basisstijlen',
14 paragraph: 'Paragraaf',
15 links: 'Links',
16 insert: 'Invoegen',
17 styles: 'Stijlen',
18 colors: 'Kleuren',
19 tools: 'Toepassingen'
20 },
21 toolbars: 'Werkbalken'
22} );
diff --git a/sources/plugins/toolbar/lang/no.js b/sources/plugins/toolbar/lang/no.js
new file mode 100644
index 0000000..c1a3445
--- /dev/null
+++ b/sources/plugins/toolbar/lang/no.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'no', {
6 toolbarCollapse: 'Skjul verktøylinje',
7 toolbarExpand: 'Vis verktøylinje',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Utklippstavle/Angre',
11 editing: 'Redigering',
12 forms: 'Skjema',
13 basicstyles: 'Basisstiler',
14 paragraph: 'Avsnitt',
15 links: 'Lenker',
16 insert: 'Innsetting',
17 styles: 'Stiler',
18 colors: 'Farger',
19 tools: 'Verktøy'
20 },
21 toolbars: 'Verktøylinjer for editor'
22} );
diff --git a/sources/plugins/toolbar/lang/oc.js b/sources/plugins/toolbar/lang/oc.js
new file mode 100644
index 0000000..bfd8044
--- /dev/null
+++ b/sources/plugins/toolbar/lang/oc.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'oc', {
6 toolbarCollapse: 'Enrotlar la barra d\'aisinas',
7 toolbarExpand: 'Desenrotlar la barra d\'aisinas',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Quichapapièr/Desfar',
11 editing: 'Edicion',
12 forms: 'Formularis',
13 basicstyles: 'Estils de basa',
14 paragraph: 'Paragraf',
15 links: 'Ligams',
16 insert: 'Inserir',
17 styles: 'Estils',
18 colors: 'Colors',
19 tools: 'Aisinas'
20 },
21 toolbars: 'Barras d\'aisinas de l\'editor'
22} );
diff --git a/sources/plugins/toolbar/lang/pl.js b/sources/plugins/toolbar/lang/pl.js
new file mode 100644
index 0000000..07571c9
--- /dev/null
+++ b/sources/plugins/toolbar/lang/pl.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'pl', {
6 toolbarCollapse: 'Zwiń pasek narzędzi',
7 toolbarExpand: 'Rozwiń pasek narzędzi',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Schowek/Wstecz',
11 editing: 'Edycja',
12 forms: 'Formularze',
13 basicstyles: 'Style podstawowe',
14 paragraph: 'Akapit',
15 links: 'Hiperłącza',
16 insert: 'Wstawianie',
17 styles: 'Style',
18 colors: 'Kolory',
19 tools: 'Narzędzia'
20 },
21 toolbars: 'Paski narzędzi edytora'
22} );
diff --git a/sources/plugins/toolbar/lang/pt-br.js b/sources/plugins/toolbar/lang/pt-br.js
new file mode 100644
index 0000000..c897bef
--- /dev/null
+++ b/sources/plugins/toolbar/lang/pt-br.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'pt-br', {
6 toolbarCollapse: 'Diminuir Barra de Ferramentas',
7 toolbarExpand: 'Aumentar Barra de Ferramentas',
8 toolbarGroups: {
9 document: 'Documento',
10 clipboard: 'Clipboard/Desfazer',
11 editing: 'Edição',
12 forms: 'Formulários',
13 basicstyles: 'Estilos Básicos',
14 paragraph: 'Paragrafo',
15 links: 'Links',
16 insert: 'Inserir',
17 styles: 'Estilos',
18 colors: 'Cores',
19 tools: 'Ferramentas'
20 },
21 toolbars: 'Barra de Ferramentas do Editor'
22} );
diff --git a/sources/plugins/toolbar/lang/pt.js b/sources/plugins/toolbar/lang/pt.js
new file mode 100644
index 0000000..d684ede
--- /dev/null
+++ b/sources/plugins/toolbar/lang/pt.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'pt', {
6 toolbarCollapse: 'Ocultar barra de ferramentas',
7 toolbarExpand: 'Expandir barra de ferramentas',
8 toolbarGroups: {
9 document: 'Documento',
10 clipboard: 'Área de transferência/Anular',
11 editing: 'Edição',
12 forms: 'Formulários',
13 basicstyles: 'Estilos básicos',
14 paragraph: 'Parágrafo',
15 links: 'Hiperligações',
16 insert: 'Inserir',
17 styles: 'Estilos',
18 colors: 'Cores',
19 tools: 'Ferramentas'
20 },
21 toolbars: 'Editor de barras de ferramentas'
22} );
diff --git a/sources/plugins/toolbar/lang/ro.js b/sources/plugins/toolbar/lang/ro.js
new file mode 100644
index 0000000..cb1b1e1
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ro.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ro', {
6 toolbarCollapse: 'Micșorează Bara',
7 toolbarExpand: 'Mărește Bara',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Editează bara de unelte'
22} );
diff --git a/sources/plugins/toolbar/lang/ru.js b/sources/plugins/toolbar/lang/ru.js
new file mode 100644
index 0000000..88f9462
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ru.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ru', {
6 toolbarCollapse: 'Свернуть панель инструментов',
7 toolbarExpand: 'Развернуть панель инструментов',
8 toolbarGroups: {
9 document: 'Документ',
10 clipboard: 'Буфер обмена / Отмена действий',
11 editing: 'Корректировка',
12 forms: 'Формы',
13 basicstyles: 'Простые стили',
14 paragraph: 'Абзац',
15 links: 'Ссылки',
16 insert: 'Вставка',
17 styles: 'Стили',
18 colors: 'Цвета',
19 tools: 'Инструменты'
20 },
21 toolbars: 'Панели инструментов редактора'
22} );
diff --git a/sources/plugins/toolbar/lang/si.js b/sources/plugins/toolbar/lang/si.js
new file mode 100644
index 0000000..b57a088
--- /dev/null
+++ b/sources/plugins/toolbar/lang/si.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'si', {
6 toolbarCollapse: 'මෙවලම් තීරුව හැකුලුම.',
7 toolbarExpand: 'මෙවලම් තීරුව දීගහැරුම',
8 toolbarGroups: {
9 document: 'ලිපිය',
10 clipboard: 'ඇමිණුම වෙනස් කිරීම',
11 editing: 'සංස්කරණය',
12 forms: 'පෝරමය',
13 basicstyles: 'මුලික විලාසය',
14 paragraph: 'චේදය',
15 links: 'සබැඳිය',
16 insert: 'ඇතුලත් කිරීම',
17 styles: 'විලාසය',
18 colors: 'වර්ණය',
19 tools: 'මෙවලම්'
20 },
21 toolbars: 'සංස්කරණ මෙවලම් තීරුව'
22} );
diff --git a/sources/plugins/toolbar/lang/sk.js b/sources/plugins/toolbar/lang/sk.js
new file mode 100644
index 0000000..fc9f3db
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sk.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sk', {
6 toolbarCollapse: 'Zbaliť lištu nástrojov',
7 toolbarExpand: 'Rozbaliť lištu nástrojov',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Schránka pre kopírovanie/Späť',
11 editing: 'Upravovanie',
12 forms: 'Formuláre',
13 basicstyles: 'Základné štýly',
14 paragraph: 'Odsek',
15 links: 'Odkazy',
16 insert: 'Vložiť',
17 styles: 'Štýly',
18 colors: 'Farby',
19 tools: 'Nástroje'
20 },
21 toolbars: 'Lišty nástrojov editora'
22} );
diff --git a/sources/plugins/toolbar/lang/sl.js b/sources/plugins/toolbar/lang/sl.js
new file mode 100644
index 0000000..b17eee4
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sl.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sl', {
6 toolbarCollapse: 'Skrči orodno vrstico',
7 toolbarExpand: 'Razširi orodno vrstico',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Odložišče/Razveljavi',
11 editing: 'Urejanje',
12 forms: 'Obrazci',
13 basicstyles: 'Osnovni slogi',
14 paragraph: 'Odstavek',
15 links: 'Povezave',
16 insert: 'Vstavi',
17 styles: 'Slogi',
18 colors: 'Barve',
19 tools: 'Orodja'
20 },
21 toolbars: 'Orodne vrstice urejevalnika'
22} );
diff --git a/sources/plugins/toolbar/lang/sq.js b/sources/plugins/toolbar/lang/sq.js
new file mode 100644
index 0000000..0ca8add
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sq.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sq', {
6 toolbarCollapse: 'Zvogëlo Shiritin',
7 toolbarExpand: 'Zgjero Shiritin',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Tabela Punës/Ribëje',
11 editing: 'Duke Redaktuar',
12 forms: 'Formular',
13 basicstyles: 'Stili Bazë',
14 paragraph: 'Paragraf',
15 links: 'Nyjet',
16 insert: 'Shto',
17 styles: 'Stil',
18 colors: 'Ngjyrat',
19 tools: 'Mjetet'
20 },
21 toolbars: 'Shiritet e Redaktuesit'
22} );
diff --git a/sources/plugins/toolbar/lang/sr-latn.js b/sources/plugins/toolbar/lang/sr-latn.js
new file mode 100644
index 0000000..d746aac
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sr-latn.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sr-latn', {
6 toolbarCollapse: 'Suzi alatnu traku',
7 toolbarExpand: 'Proširi alatnu traku',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Alatne trake'
22} );
diff --git a/sources/plugins/toolbar/lang/sr.js b/sources/plugins/toolbar/lang/sr.js
new file mode 100644
index 0000000..d02f20f
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sr.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sr', {
6 toolbarCollapse: 'Склопи алатну траку',
7 toolbarExpand: 'Прошири алатну траку',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'Едитор алатне траке'
22} );
diff --git a/sources/plugins/toolbar/lang/sv.js b/sources/plugins/toolbar/lang/sv.js
new file mode 100644
index 0000000..0a45e88
--- /dev/null
+++ b/sources/plugins/toolbar/lang/sv.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'sv', {
6 toolbarCollapse: 'Dölj verktygsfält',
7 toolbarExpand: 'Visa verktygsfält',
8 toolbarGroups: {
9 document: 'Dokument',
10 clipboard: 'Urklipp/ångra',
11 editing: 'Redigering',
12 forms: 'Formulär',
13 basicstyles: 'Basstilar',
14 paragraph: 'Paragraf',
15 links: 'Länkar',
16 insert: 'Infoga',
17 styles: 'Stilar',
18 colors: 'Färger',
19 tools: 'Verktyg'
20 },
21 toolbars: 'Editorns verktygsfält'
22} );
diff --git a/sources/plugins/toolbar/lang/th.js b/sources/plugins/toolbar/lang/th.js
new file mode 100644
index 0000000..c4ae55e
--- /dev/null
+++ b/sources/plugins/toolbar/lang/th.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'th', {
6 toolbarCollapse: 'ซ่อนแถบเครื่องมือ',
7 toolbarExpand: 'เปิดแถบเครื่องมือ',
8 toolbarGroups: {
9 document: 'Document',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Editing',
12 forms: 'Forms',
13 basicstyles: 'Basic Styles',
14 paragraph: 'Paragraph',
15 links: 'Links',
16 insert: 'Insert',
17 styles: 'Styles',
18 colors: 'Colors',
19 tools: 'Tools'
20 },
21 toolbars: 'แถบเครื่องมือช่วยพิมพ์ข้อความ'
22} );
diff --git a/sources/plugins/toolbar/lang/tr.js b/sources/plugins/toolbar/lang/tr.js
new file mode 100644
index 0000000..cf7f944
--- /dev/null
+++ b/sources/plugins/toolbar/lang/tr.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'tr', {
6 toolbarCollapse: 'Araç çubuklarını topla',
7 toolbarExpand: 'Araç çubuklarını aç',
8 toolbarGroups: {
9 document: 'Belge',
10 clipboard: 'Pano/Geri al',
11 editing: 'Düzenleme',
12 forms: 'Formlar',
13 basicstyles: 'Temel Stiller',
14 paragraph: 'Paragraf',
15 links: 'Bağlantılar',
16 insert: 'Ekle',
17 styles: 'Stiller',
18 colors: 'Renkler',
19 tools: 'Araçlar'
20 },
21 toolbars: 'Araç çubukları Editörü'
22} );
diff --git a/sources/plugins/toolbar/lang/tt.js b/sources/plugins/toolbar/lang/tt.js
new file mode 100644
index 0000000..8eb0542
--- /dev/null
+++ b/sources/plugins/toolbar/lang/tt.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'tt', {
6 toolbarCollapse: 'Collapse Toolbar', // MISSING
7 toolbarExpand: 'Expand Toolbar', // MISSING
8 toolbarGroups: {
9 document: 'Документ',
10 clipboard: 'Алмашу буферы/Кайтару',
11 editing: 'Төзәтү',
12 forms: 'Формалар',
13 basicstyles: 'Төп стильләр',
14 paragraph: 'Параграф',
15 links: 'Сылталамалар',
16 insert: 'Өстәү',
17 styles: 'Стильләр',
18 colors: 'Төсләр',
19 tools: 'Кораллар'
20 },
21 toolbars: 'Editor toolbars' // MISSING
22} );
diff --git a/sources/plugins/toolbar/lang/ug.js b/sources/plugins/toolbar/lang/ug.js
new file mode 100644
index 0000000..95c7c1b
--- /dev/null
+++ b/sources/plugins/toolbar/lang/ug.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'ug', {
6 toolbarCollapse: 'قورال بالداقنى قاتلا',
7 toolbarExpand: 'قورال بالداقنى ياي',
8 toolbarGroups: {
9 document: 'پۈتۈك',
10 clipboard: 'چاپلاش تاختىسى/يېنىۋال',
11 editing: 'تەھرىر',
12 forms: 'جەدۋەل',
13 basicstyles: 'ئاساسىي ئۇسلۇب',
14 paragraph: 'ئابزاس',
15 links: 'ئۇلانما',
16 insert: 'قىستۇر',
17 styles: 'ئۇسلۇب',
18 colors: 'رەڭ',
19 tools: 'قورال'
20 },
21 toolbars: 'قورال بالداق'
22} );
diff --git a/sources/plugins/toolbar/lang/uk.js b/sources/plugins/toolbar/lang/uk.js
new file mode 100644
index 0000000..3f1f1c7
--- /dev/null
+++ b/sources/plugins/toolbar/lang/uk.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'uk', {
6 toolbarCollapse: 'Згорнути панель інструментів',
7 toolbarExpand: 'Розгорнути панель інструментів',
8 toolbarGroups: {
9 document: 'Документ',
10 clipboard: 'Буфер обміну / Скасувати',
11 editing: 'Редагування',
12 forms: 'Форми',
13 basicstyles: 'Основний Стиль',
14 paragraph: 'Параграф',
15 links: 'Посилання',
16 insert: 'Вставити',
17 styles: 'Стилі',
18 colors: 'Кольори',
19 tools: 'Інструменти'
20 },
21 toolbars: 'Панель інструментів редактора'
22} );
diff --git a/sources/plugins/toolbar/lang/vi.js b/sources/plugins/toolbar/lang/vi.js
new file mode 100644
index 0000000..8ff76fd
--- /dev/null
+++ b/sources/plugins/toolbar/lang/vi.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'vi', {
6 toolbarCollapse: 'Thu gọn thanh công cụ',
7 toolbarExpand: 'Mở rộng thnah công cụ',
8 toolbarGroups: {
9 document: 'Tài liệu',
10 clipboard: 'Clipboard/Undo',
11 editing: 'Chỉnh sửa',
12 forms: 'Bảng biểu',
13 basicstyles: 'Kiểu cơ bản',
14 paragraph: 'Đoạn',
15 links: 'Liên kết',
16 insert: 'Chèn',
17 styles: 'Kiểu',
18 colors: 'Màu sắc',
19 tools: 'Công cụ'
20 },
21 toolbars: 'Thanh công cụ'
22} );
diff --git a/sources/plugins/toolbar/lang/zh-cn.js b/sources/plugins/toolbar/lang/zh-cn.js
new file mode 100644
index 0000000..6c3a5ed
--- /dev/null
+++ b/sources/plugins/toolbar/lang/zh-cn.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'zh-cn', {
6 toolbarCollapse: '折叠工具栏',
7 toolbarExpand: '展开工具栏',
8 toolbarGroups: {
9 document: '文档',
10 clipboard: '剪贴板/撤销',
11 editing: '编辑',
12 forms: '表单',
13 basicstyles: '基本格式',
14 paragraph: '段落',
15 links: '链接',
16 insert: '插入',
17 styles: '样式',
18 colors: '颜色',
19 tools: '工具'
20 },
21 toolbars: '工具栏'
22} );
diff --git a/sources/plugins/toolbar/lang/zh.js b/sources/plugins/toolbar/lang/zh.js
new file mode 100644
index 0000000..0a9f5de
--- /dev/null
+++ b/sources/plugins/toolbar/lang/zh.js
@@ -0,0 +1,22 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'toolbar', 'zh', {
6 toolbarCollapse: '摺疊工具列',
7 toolbarExpand: '展開工具列',
8 toolbarGroups: {
9 document: '文件',
10 clipboard: '剪貼簿/復原',
11 editing: '編輯選項',
12 forms: '格式',
13 basicstyles: '基本樣式',
14 paragraph: '段落',
15 links: '連結',
16 insert: '插入',
17 styles: '樣式',
18 colors: '顏色',
19 tools: '工具'
20 },
21 toolbars: '編輯器工具列'
22} );
diff --git a/sources/plugins/toolbar/plugin.js b/sources/plugins/toolbar/plugin.js
new file mode 100644
index 0000000..b267b51
--- /dev/null
+++ b/sources/plugins/toolbar/plugin.js
@@ -0,0 +1,806 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The "toolbar" plugin. Renders the default toolbar interface in
8 * the editor.
9 */
10
11( function() {
12 var toolbox = function() {
13 this.toolbars = [];
14 this.focusCommandExecuted = false;
15 };
16
17 toolbox.prototype.focus = function() {
18 for ( var t = 0, toolbar; toolbar = this.toolbars[ t++ ]; ) {
19 for ( var i = 0, item; item = toolbar.items[ i++ ]; ) {
20 if ( item.focus ) {
21 item.focus();
22 return;
23 }
24 }
25 }
26 };
27
28 var commands = {
29 toolbarFocus: {
30 modes: { wysiwyg: 1, source: 1 },
31 readOnly: 1,
32
33 exec: function( editor ) {
34 if ( editor.toolbox ) {
35 editor.toolbox.focusCommandExecuted = true;
36
37 // Make the first button focus accessible for IE. (#3417)
38 // Adobe AIR instead need while of delay.
39 if ( CKEDITOR.env.ie || CKEDITOR.env.air ) {
40 setTimeout( function() {
41 editor.toolbox.focus();
42 }, 100 );
43 } else {
44 editor.toolbox.focus();
45 }
46 }
47 }
48 }
49 };
50
51 CKEDITOR.plugins.add( 'toolbar', {
52 requires: 'button',
53 // jscs:disable maximumLineLength
54 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
55 // jscs:enable maximumLineLength
56
57 init: function( editor ) {
58 var endFlag;
59
60 var itemKeystroke = function( item, keystroke ) {
61 var next, toolbar;
62 var rtl = editor.lang.dir == 'rtl',
63 toolbarGroupCycling = editor.config.toolbarGroupCycling,
64 // Picking right/left key codes.
65 rightKeyCode = rtl ? 37 : 39,
66 leftKeyCode = rtl ? 39 : 37;
67
68 toolbarGroupCycling = toolbarGroupCycling === undefined || toolbarGroupCycling;
69
70 switch ( keystroke ) {
71 case 9: // TAB
72 case CKEDITOR.SHIFT + 9: // SHIFT + TAB
73 // Cycle through the toolbars, starting from the one
74 // closest to the current item.
75 while ( !toolbar || !toolbar.items.length ) {
76 if ( keystroke == 9 ) {
77 toolbar = ( ( toolbar ? toolbar.next : item.toolbar.next ) || editor.toolbox.toolbars[ 0 ] );
78 } else {
79 toolbar = ( ( toolbar ? toolbar.previous : item.toolbar.previous ) || editor.toolbox.toolbars[ editor.toolbox.toolbars.length - 1 ] );
80 }
81
82 // Look for the first item that accepts focus.
83 if ( toolbar.items.length ) {
84 item = toolbar.items[ endFlag ? ( toolbar.items.length - 1 ) : 0 ];
85 while ( item && !item.focus ) {
86 item = endFlag ? item.previous : item.next;
87
88 if ( !item )
89 toolbar = 0;
90 }
91 }
92 }
93
94 if ( item )
95 item.focus();
96
97 return false;
98
99 case rightKeyCode:
100 next = item;
101 do {
102 // Look for the next item in the toolbar.
103 next = next.next;
104
105 // If it's the last item, cycle to the first one.
106 if ( !next && toolbarGroupCycling ) next = item.toolbar.items[ 0 ];
107 }
108 while ( next && !next.focus );
109
110 // If available, just focus it, otherwise focus the
111 // first one.
112 if ( next )
113 next.focus();
114 else
115 // Send a TAB.
116 itemKeystroke( item, 9 );
117
118 return false;
119 case 40: // DOWN-ARROW
120 if ( item.button && item.button.hasArrow ) {
121 // Note: code is duplicated in plugins\richcombo\plugin.js in keyDownFn().
122 editor.once( 'panelShow', function( evt ) {
123 evt.data._.panel._.currentBlock.onKeyDown( 40 );
124 } );
125 item.execute();
126 } else {
127 // Send left arrow key.
128 itemKeystroke( item, keystroke == 40 ? rightKeyCode : leftKeyCode );
129 }
130 return false;
131 case leftKeyCode:
132 case 38: // UP-ARROW
133 next = item;
134 do {
135 // Look for the previous item in the toolbar.
136 next = next.previous;
137
138 // If it's the first item, cycle to the last one.
139 if ( !next && toolbarGroupCycling ) next = item.toolbar.items[ item.toolbar.items.length - 1 ];
140 }
141 while ( next && !next.focus );
142
143 // If available, just focus it, otherwise focus the
144 // last one.
145 if ( next )
146 next.focus();
147 else {
148 endFlag = 1;
149 // Send a SHIFT + TAB.
150 itemKeystroke( item, CKEDITOR.SHIFT + 9 );
151 endFlag = 0;
152 }
153
154 return false;
155
156 case 27: // ESC
157 editor.focus();
158 return false;
159
160 case 13: // ENTER
161 case 32: // SPACE
162 item.execute();
163 return false;
164 }
165 return true;
166 };
167
168 editor.on( 'uiSpace', function( event ) {
169 if ( event.data.space != editor.config.toolbarLocation )
170 return;
171
172 // Create toolbar only once.
173 event.removeListener();
174
175 editor.toolbox = new toolbox();
176
177 var labelId = CKEDITOR.tools.getNextId();
178
179 var output = [
180 '<span id="', labelId, '" class="cke_voice_label">', editor.lang.toolbar.toolbars, '</span>',
181 '<span id="' + editor.ui.spaceId( 'toolbox' ) + '" class="cke_toolbox" role="group" aria-labelledby="', labelId, '" onmousedown="return false;">'
182 ];
183
184 var expanded = editor.config.toolbarStartupExpanded !== false,
185 groupStarted, pendingSeparator;
186
187 // If the toolbar collapser will be available, we'll have
188 // an additional container for all toolbars.
189 if ( editor.config.toolbarCanCollapse && editor.elementMode != CKEDITOR.ELEMENT_MODE_INLINE )
190 output.push( '<span class="cke_toolbox_main"' + ( expanded ? '>' : ' style="display:none">' ) );
191
192 var toolbars = editor.toolbox.toolbars,
193 toolbar = getToolbarConfig( editor ),
194 toolbarLength = toolbar.length;
195
196 for ( var r = 0; r < toolbarLength; r++ ) {
197 var toolbarId,
198 toolbarObj = 0,
199 toolbarName,
200 row = toolbar[ r ],
201 lastToolbarInRow = row !== '/' && ( toolbar[ r + 1 ] === '/' || r == toolbarLength - 1 ),
202 items;
203
204 // It's better to check if the row object is really
205 // available because it's a common mistake to leave
206 // an extra comma in the toolbar definition
207 // settings, which leads on the editor not loading
208 // at all in IE. (#3983)
209 if ( !row )
210 continue;
211
212 if ( groupStarted ) {
213 output.push( '</span>' );
214 groupStarted = 0;
215 pendingSeparator = 0;
216 }
217
218 if ( row === '/' ) {
219 output.push( '<span class="cke_toolbar_break"></span>' );
220 continue;
221 }
222
223 items = row.items || row;
224
225 // Create all items defined for this toolbar.
226 for ( var i = 0; i < items.length; i++ ) {
227 var item = items[ i ],
228 canGroup;
229
230 if ( item ) {
231 if ( item.type == CKEDITOR.UI_SEPARATOR ) {
232 // Do not add the separator immediately. Just save
233 // it be included if we already have something in
234 // the toolbar and if a new item is to be added (later).
235 pendingSeparator = groupStarted && item;
236 continue;
237 }
238
239 canGroup = item.canGroup !== false;
240
241 // Initialize the toolbar first, if needed.
242 if ( !toolbarObj ) {
243 // Create the basic toolbar object.
244 toolbarId = CKEDITOR.tools.getNextId();
245 toolbarObj = { id: toolbarId, items: [] };
246 toolbarName = row.name && ( editor.lang.toolbar.toolbarGroups[ row.name ] || row.name );
247
248 // Output the toolbar opener.
249 output.push( '<span id="', toolbarId, '" class="cke_toolbar' + ( lastToolbarInRow ? ' cke_toolbar_last"' : '"' ),
250 ( toolbarName ? ' aria-labelledby="' + toolbarId + '_label"' : '' ), ' role="toolbar">' );
251
252 // If a toolbar name is available, send the voice label.
253 toolbarName && output.push( '<span id="', toolbarId, '_label" class="cke_voice_label">', toolbarName, '</span>' );
254
255 output.push( '<span class="cke_toolbar_start"></span>' );
256
257 // Add the toolbar to the "editor.toolbox.toolbars"
258 // array.
259 var index = toolbars.push( toolbarObj ) - 1;
260
261 // Create the next/previous reference.
262 if ( index > 0 ) {
263 toolbarObj.previous = toolbars[ index - 1 ];
264 toolbarObj.previous.next = toolbarObj;
265 }
266 }
267
268 if ( canGroup ) {
269 if ( !groupStarted ) {
270 output.push( '<span class="cke_toolgroup" role="presentation">' );
271 groupStarted = 1;
272 }
273 } else if ( groupStarted ) {
274 output.push( '</span>' );
275 groupStarted = 0;
276 }
277
278 function addItem( item ) { // jshint ignore:line
279 var itemObj = item.render( editor, output );
280 index = toolbarObj.items.push( itemObj ) - 1;
281
282 if ( index > 0 ) {
283 itemObj.previous = toolbarObj.items[ index - 1 ];
284 itemObj.previous.next = itemObj;
285 }
286
287 itemObj.toolbar = toolbarObj;
288 itemObj.onkey = itemKeystroke;
289
290 // Fix for #3052:
291 // Prevent JAWS from focusing the toolbar after document load.
292 itemObj.onfocus = function() {
293 if ( !editor.toolbox.focusCommandExecuted )
294 editor.focus();
295 };
296 }
297
298 if ( pendingSeparator ) {
299 addItem( pendingSeparator );
300 pendingSeparator = 0;
301 }
302
303 addItem( item );
304 }
305 }
306
307 if ( groupStarted ) {
308 output.push( '</span>' );
309 groupStarted = 0;
310 pendingSeparator = 0;
311 }
312
313 if ( toolbarObj )
314 output.push( '<span class="cke_toolbar_end"></span></span>' );
315 }
316
317 if ( editor.config.toolbarCanCollapse )
318 output.push( '</span>' );
319
320 // Not toolbar collapser for inline mode.
321 if ( editor.config.toolbarCanCollapse && editor.elementMode != CKEDITOR.ELEMENT_MODE_INLINE ) {
322 var collapserFn = CKEDITOR.tools.addFunction( function() {
323 editor.execCommand( 'toolbarCollapse' );
324 } );
325
326 editor.on( 'destroy', function() {
327 CKEDITOR.tools.removeFunction( collapserFn );
328 } );
329
330 editor.addCommand( 'toolbarCollapse', {
331 readOnly: 1,
332 exec: function( editor ) {
333 var collapser = editor.ui.space( 'toolbar_collapser' ),
334 toolbox = collapser.getPrevious(),
335 contents = editor.ui.space( 'contents' ),
336 toolboxContainer = toolbox.getParent(),
337 contentHeight = parseInt( contents.$.style.height, 10 ),
338 previousHeight = toolboxContainer.$.offsetHeight,
339 minClass = 'cke_toolbox_collapser_min',
340 collapsed = collapser.hasClass( minClass );
341
342 if ( !collapsed ) {
343 toolbox.hide();
344 collapser.addClass( minClass );
345 collapser.setAttribute( 'title', editor.lang.toolbar.toolbarExpand );
346 } else {
347 toolbox.show();
348 collapser.removeClass( minClass );
349 collapser.setAttribute( 'title', editor.lang.toolbar.toolbarCollapse );
350 }
351
352 // Update collapser symbol.
353 collapser.getFirst().setText( collapsed ? '\u25B2' : // BLACK UP-POINTING TRIANGLE
354 '\u25C0' ); // BLACK LEFT-POINTING TRIANGLE
355
356 var dy = toolboxContainer.$.offsetHeight - previousHeight;
357 contents.setStyle( 'height', ( contentHeight - dy ) + 'px' );
358
359 editor.fire( 'resize', {
360 outerHeight: editor.container.$.offsetHeight,
361 contentsHeight: contents.$.offsetHeight,
362 outerWidth: editor.container.$.offsetWidth
363 } );
364 },
365
366 modes: { wysiwyg: 1, source: 1 }
367 } );
368
369 editor.setKeystroke( CKEDITOR.ALT + ( CKEDITOR.env.ie || CKEDITOR.env.webkit ? 189 : 109 ) /*-*/, 'toolbarCollapse' );
370
371 output.push( '<a title="' + ( expanded ? editor.lang.toolbar.toolbarCollapse : editor.lang.toolbar.toolbarExpand ) +
372 '" id="' + editor.ui.spaceId( 'toolbar_collapser' ) +
373 '" tabIndex="-1" class="cke_toolbox_collapser' );
374
375 if ( !expanded )
376 output.push( ' cke_toolbox_collapser_min' );
377
378 output.push( '" onclick="CKEDITOR.tools.callFunction(' + collapserFn + ')">', '<span class="cke_arrow">&#9650;</span>', // BLACK UP-POINTING TRIANGLE
379 '</a>' );
380 }
381
382 output.push( '</span>' );
383 event.data.html += output.join( '' );
384 } );
385
386 editor.on( 'destroy', function() {
387 if ( this.toolbox ) {
388 var toolbars,
389 index = 0,
390 i, items, instance;
391 toolbars = this.toolbox.toolbars;
392 for ( ; index < toolbars.length; index++ ) {
393 items = toolbars[ index ].items;
394 for ( i = 0; i < items.length; i++ ) {
395 instance = items[ i ];
396 if ( instance.clickFn )
397 CKEDITOR.tools.removeFunction( instance.clickFn );
398 if ( instance.keyDownFn )
399 CKEDITOR.tools.removeFunction( instance.keyDownFn );
400 }
401 }
402 }
403 } );
404
405 // Manage editor focus when navigating the toolbar.
406 editor.on( 'uiReady', function() {
407 var toolbox = editor.ui.space( 'toolbox' );
408 toolbox && editor.focusManager.add( toolbox, 1 );
409 } );
410
411 editor.addCommand( 'toolbarFocus', commands.toolbarFocus );
412 editor.setKeystroke( CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus' );
413
414 editor.ui.add( '-', CKEDITOR.UI_SEPARATOR, {} );
415 editor.ui.addHandler( CKEDITOR.UI_SEPARATOR, {
416 create: function() {
417 return {
418 render: function( editor, output ) {
419 output.push( '<span class="cke_toolbar_separator" role="separator"></span>' );
420 return {};
421 }
422 };
423 }
424 } );
425 }
426 } );
427
428 function getToolbarConfig( editor ) {
429 var removeButtons = editor.config.removeButtons;
430
431 removeButtons = removeButtons && removeButtons.split( ',' );
432
433 function buildToolbarConfig() {
434
435 // Object containing all toolbar groups used by ui items.
436 var lookup = getItemDefinedGroups();
437
438 // Take the base for the new toolbar, which is basically a toolbar
439 // definition without items.
440 var toolbar = CKEDITOR.tools.clone( editor.config.toolbarGroups ) || getPrivateToolbarGroups( editor );
441
442 // Fill the toolbar groups with the available ui items.
443 for ( var i = 0; i < toolbar.length; i++ ) {
444 var toolbarGroup = toolbar[ i ];
445
446 // Skip toolbar break.
447 if ( toolbarGroup == '/' )
448 continue;
449 // Handle simply group name item.
450 else if ( typeof toolbarGroup == 'string' )
451 toolbarGroup = toolbar[ i ] = { name: toolbarGroup };
452
453 var items, subGroups = toolbarGroup.groups;
454
455 // Look for items that match sub groups.
456 if ( subGroups ) {
457 for ( var j = 0, sub; j < subGroups.length; j++ ) {
458 sub = subGroups[ j ];
459
460 // If any ui item is registered for this subgroup.
461 items = lookup[ sub ];
462 items && fillGroup( toolbarGroup, items );
463 }
464 }
465
466 // Add the main group items as well.
467 items = lookup[ toolbarGroup.name ];
468 items && fillGroup( toolbarGroup, items );
469 }
470
471 return toolbar;
472 }
473
474 // Returns an object containing all toolbar groups used by ui items.
475 function getItemDefinedGroups() {
476 var groups = {},
477 itemName, item, itemToolbar, group, order;
478
479 for ( itemName in editor.ui.items ) {
480 item = editor.ui.items[ itemName ];
481 itemToolbar = item.toolbar || 'others';
482 if ( itemToolbar ) {
483 // Break the toolbar property into its parts: "group_name[,order]".
484 itemToolbar = itemToolbar.split( ',' );
485 group = itemToolbar[ 0 ];
486 order = parseInt( itemToolbar[ 1 ] || -1, 10 );
487
488 // Initialize the group, if necessary.
489 groups[ group ] || ( groups[ group ] = [] );
490
491 // Push the data used to build the toolbar later.
492 groups[ group ].push( { name: itemName, order: order } );
493 }
494 }
495
496 // Put the items in the right order.
497 for ( group in groups ) {
498 groups[ group ] = groups[ group ].sort( function( a, b ) {
499 return a.order == b.order ? 0 :
500 b.order < 0 ? -1 :
501 a.order < 0 ? 1 :
502 a.order < b.order ? -1 :
503 1;
504 } );
505 }
506
507 return groups;
508 }
509
510 function fillGroup( toolbarGroup, uiItems ) {
511 if ( uiItems.length ) {
512 if ( toolbarGroup.items )
513 toolbarGroup.items.push( editor.ui.create( '-' ) );
514 else
515 toolbarGroup.items = [];
516
517 var item, name;
518 while ( ( item = uiItems.shift() ) ) {
519 name = typeof item == 'string' ? item : item.name;
520
521 // Ignore items that are configured to be removed.
522 if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) {
523 item = editor.ui.create( name );
524
525 if ( !item )
526 continue;
527
528 if ( !editor.addFeature( item ) )
529 continue;
530
531 toolbarGroup.items.push( item );
532 }
533 }
534 }
535 }
536
537 function populateToolbarConfig( config ) {
538 var toolbar = [],
539 i, group, newGroup;
540
541 for ( i = 0; i < config.length; ++i ) {
542 group = config[ i ];
543 newGroup = {};
544
545 if ( group == '/' )
546 toolbar.push( group );
547 else if ( CKEDITOR.tools.isArray( group ) ) {
548 fillGroup( newGroup, CKEDITOR.tools.clone( group ) );
549 toolbar.push( newGroup );
550 }
551 else if ( group.items ) {
552 fillGroup( newGroup, CKEDITOR.tools.clone( group.items ) );
553 newGroup.name = group.name;
554 toolbar.push( newGroup );
555 }
556 }
557
558 return toolbar;
559 }
560
561 var toolbar = editor.config.toolbar;
562
563 // If it is a string, return the relative "toolbar_name" config.
564 if ( typeof toolbar == 'string' )
565 toolbar = editor.config[ 'toolbar_' + toolbar ];
566
567 return ( editor.toolbar = toolbar ? populateToolbarConfig( toolbar ) : buildToolbarConfig() );
568 }
569
570 /**
571 * Adds a toolbar group. See {@link CKEDITOR.config#toolbarGroups} for more details.
572 *
573 * **Note:** This method will not modify toolbar groups set explicitly by
574 * {@link CKEDITOR.config#toolbarGroups}. It will only extend the default setting.
575 *
576 * @param {String} name Toolbar group name.
577 * @param {Number/String} previous The name of the toolbar group after which this one
578 * should be added or `0` if this group should be the first one.
579 * @param {String} [subgroupOf] The name of the parent group.
580 * @member CKEDITOR.ui
581 */
582 CKEDITOR.ui.prototype.addToolbarGroup = function( name, previous, subgroupOf ) {
583 // The toolbarGroups from the privates is the one we gonna use for automatic toolbar creation.
584 var toolbarGroups = getPrivateToolbarGroups( this.editor ),
585 atStart = previous === 0,
586 newGroup = { name: name };
587
588 if ( subgroupOf ) {
589 // Transform the subgroupOf name in the real subgroup object.
590 subgroupOf = CKEDITOR.tools.search( toolbarGroups, function( group ) {
591 return group.name == subgroupOf;
592 } );
593
594 if ( subgroupOf ) {
595 !subgroupOf.groups && ( subgroupOf.groups = [] ) ;
596
597 if ( previous ) {
598 // Search the "previous" item and add the new one after it.
599 previous = CKEDITOR.tools.indexOf( subgroupOf.groups, previous );
600 if ( previous >= 0 ) {
601 subgroupOf.groups.splice( previous + 1, 0, name );
602 return;
603 }
604 }
605
606 // If no previous found.
607
608 if ( atStart )
609 subgroupOf.groups.splice( 0, 0, name );
610 else
611 subgroupOf.groups.push( name );
612 return;
613 } else {
614 // Ignore "previous" if subgroupOf has not been found.
615 previous = null;
616 }
617 }
618
619 if ( previous ) {
620 // Transform the "previous" name into its index.
621 previous = CKEDITOR.tools.indexOf( toolbarGroups, function( group ) {
622 return group.name == previous;
623 } );
624 }
625
626 if ( atStart )
627 toolbarGroups.splice( 0, 0, name );
628 else if ( typeof previous == 'number' )
629 toolbarGroups.splice( previous + 1, 0, newGroup );
630 else
631 toolbarGroups.push( name );
632 };
633
634 function getPrivateToolbarGroups( editor ) {
635 return editor._.toolbarGroups || ( editor._.toolbarGroups = [
636 { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
637 { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
638 { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
639 { name: 'forms' },
640 '/',
641 { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
642 { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
643 { name: 'links' },
644 { name: 'insert' },
645 '/',
646 { name: 'styles' },
647 { name: 'colors' },
648 { name: 'tools' },
649 { name: 'others' },
650 { name: 'about' }
651 ] );
652 }
653} )();
654
655/**
656 * Separator UI element.
657 *
658 * @readonly
659 * @property {String} [='separator']
660 * @member CKEDITOR
661 */
662CKEDITOR.UI_SEPARATOR = 'separator';
663
664/**
665 * The part of the user interface where the toolbar will be rendered. For the default
666 * editor implementation, the recommended options are `'top'` and `'bottom'`.
667 *
668 * Please note that this option is only applicable to [classic](#!/guide/dev_framed)
669 * (`iframe`-based) editor. In case of [inline](#!/guide/dev_inline) editor the toolbar
670 * position is set dynamically depending on the position of the editable element on the screen.
671 *
672 * Read more in the [documentation](#!/guide/dev_toolbarlocation)
673 * and see the [SDK sample](http://sdk.ckeditor.com/samples/toolbarlocation.html).
674 *
675 * config.toolbarLocation = 'bottom';
676 *
677 * @cfg
678 * @member CKEDITOR.config
679 */
680CKEDITOR.config.toolbarLocation = 'top';
681
682/**
683 * The toolbox (alias toolbar) definition. It is a toolbar name or an array of
684 * toolbars (strips), each one being also an array, containing a list of UI items.
685 *
686 * If set to `null`, the toolbar will be generated automatically using all available buttons
687 * and {@link #toolbarGroups} as a toolbar groups layout.
688 *
689 * In CKEditor 4.5+ you can generate your toolbar customization code by using the [visual
690 * toolbar configurator](http://docs.ckeditor.com/#!/guide/dev_toolbar).
691 *
692 * // Defines a toolbar with only one strip containing the "Source" button, a
693 * // separator, and the "Bold" and "Italic" buttons.
694 * config.toolbar = [
695 * [ 'Source', '-', 'Bold', 'Italic' ]
696 * ];
697 *
698 * // Similar to the example above, defines a "Basic" toolbar with only one strip containing three buttons.
699 * // Note that this setting is composed by "toolbar_" added to the toolbar name, which in this case is called "Basic".
700 * // This second part of the setting name can be anything. You must use this name in the CKEDITOR.config.toolbar setting
701 * // in order to instruct the editor which `toolbar_(name)` setting should be used.
702 * config.toolbar_Basic = [
703 * [ 'Source', '-', 'Bold', 'Italic' ]
704 * ];
705 * // Load toolbar_Name where Name = Basic.
706 * config.toolbar = 'Basic';
707 *
708 * @cfg {Array/String} [toolbar=null]
709 * @member CKEDITOR.config
710 */
711
712/**
713 * The toolbar groups definition.
714 *
715 * If the toolbar layout is not explicitly defined by the {@link #toolbar} setting, then
716 * this setting is used to group all defined buttons (see {@link CKEDITOR.ui#addButton}).
717 * Buttons are associated with toolbar groups by the `toolbar` property in their definition objects.
718 *
719 * New groups may be dynamically added during the editor and plugin initialization by
720 * {@link CKEDITOR.ui#addToolbarGroup}. This is only possible if the default setting was used.
721 *
722 * // Default setting.
723 * config.toolbarGroups = [
724 * { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
725 * { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
726 * { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
727 * { name: 'forms' },
728 * '/',
729 * { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
730 * { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
731 * { name: 'links' },
732 * { name: 'insert' },
733 * '/',
734 * { name: 'styles' },
735 * { name: 'colors' },
736 * { name: 'tools' },
737 * { name: 'others' },
738 * { name: 'about' }
739 * ];
740 *
741 * @cfg {Array} [toolbarGroups=see example]
742 * @member CKEDITOR.config
743 */
744
745/**
746 * Whether the toolbar can be collapsed by the user. If disabled, the Collapse Toolbar
747 * button will not be displayed.
748 *
749 * config.toolbarCanCollapse = true;
750 *
751 * @cfg {Boolean} [toolbarCanCollapse=false]
752 * @member CKEDITOR.config
753 */
754
755/**
756 * Whether the toolbar must start expanded when the editor is loaded.
757 *
758 * Setting this option to `false` will affect the toolbar only when
759 * {@link #toolbarCanCollapse} is set to `true`:
760 *
761 * config.toolbarCanCollapse = true;
762 * config.toolbarStartupExpanded = false;
763 *
764 * @cfg {Boolean} [toolbarStartupExpanded=true]
765 * @member CKEDITOR.config
766 */
767
768/**
769 * When enabled, causes the *Arrow* keys navigation to cycle within the current
770 * toolbar group. Otherwise the *Arrow* keys will move through all items available in
771 * the toolbar. The *Tab* key will still be used to quickly jump among the
772 * toolbar groups.
773 *
774 * config.toolbarGroupCycling = false;
775 *
776 * @since 3.6
777 * @cfg {Boolean} [toolbarGroupCycling=true]
778 * @member CKEDITOR.config
779 */
780
781/**
782 * List of toolbar button names that must not be rendered. This will also work
783 * for non-button toolbar items, like the Font drop-down list.
784 *
785 * config.removeButtons = 'Underline,JustifyCenter';
786 *
787 * This configuration option should not be overused. The recommended way is to use the
788 * {@link CKEDITOR.config#removePlugins} setting to remove features from the editor
789 * or even better, [create a custom editor build](http://ckeditor.com/builder) with
790 * just the features that you will use.
791 * In some cases though, a single plugin may define a set of toolbar buttons and
792 * `removeButtons` may be useful when just a few of them are to be removed.
793 *
794 * @cfg {String} [removeButtons]
795 * @member CKEDITOR.config
796 */
797
798/**
799 * The toolbar definition used by the editor. It is created from the
800 * {@link CKEDITOR.config#toolbar} option if it is set or automatically
801 * based on {@link CKEDITOR.config#toolbarGroups}.
802 *
803 * @readonly
804 * @property {Object} toolbar
805 * @member CKEDITOR.editor
806 */
diff --git a/sources/plugins/toolbar/samples/toolbar.html b/sources/plugins/toolbar/samples/toolbar.html
new file mode 100644
index 0000000..e40d2a1
--- /dev/null
+++ b/sources/plugins/toolbar/samples/toolbar.html
@@ -0,0 +1,235 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Toolbar Configuration &mdash; CKEditor Sample</title>
10 <meta name="ckeditor-sample-name" content="Toolbar Configurations">
11 <meta name="ckeditor-sample-group" content="Advanced Samples">
12 <meta name="ckeditor-sample-description" content="Configuring CKEditor to display full or custom toolbar layout.">
13 <script src="../../../ckeditor.js"></script>
14 <link href="../../../samples/old/sample.css" rel="stylesheet">
15</head>
16<body>
17 <h1 class="samples">
18 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Toolbar Configuration
19 </h1>
20 <div class="warning deprecated">
21 This sample is not maintained anymore. Check out the <a href="../../../samples/toolbarconfigurator/index.html#basic">brand new CKEditor Toolbar Configurator</a>.
22 </div>
23 <div class="description">
24 <p>
25 This sample page demonstrates editor with loaded <a href="#fullToolbar">full toolbar</a> (all registered buttons) and, if
26 current editor's configuration modifies default settings, also editor with <a href="#currentToolbar">modified toolbar</a>.
27 </p>
28
29 <p>Since CKEditor 4 there are two ways to configure toolbar buttons.</p>
30
31 <h2 class="samples">By <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-toolbar">config.toolbar</a></h2>
32
33 <p>
34 You can explicitly define which buttons are displayed in which groups and in which order.
35 This is the more precise setting, but less flexible. If newly added plugin adds its
36 own button you'll have to add it manually to your <code>config.toolbar</code> setting as well.
37 </p>
38
39 <p>To add a CKEditor instance with custom toolbar setting, insert the following JavaScript call to your code:</p>
40
41 <pre class="samples">
42CKEDITOR.replace( <em>'textarea_id'</em>, {
43 <strong>toolbar:</strong> [
44 { name: 'document', items: [ 'Source', '-', 'NewPage', 'Preview', '-', 'Templates' ] }, // Defines toolbar group with name (used to create voice label) and items in 3 subgroups.
45 [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ], // Defines toolbar group without name.
46 '/', // Line break - next group will be placed in new line.
47 { name: 'basicstyles', items: [ 'Bold', 'Italic' ] }
48 ]
49});</pre>
50
51 <h2 class="samples">By <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-toolbarGroups">config.toolbarGroups</a></h2>
52
53 <p>
54 You can define which groups of buttons (like e.g. <code>basicstyles</code>, <code>clipboard</code>
55 and <code>forms</code>) are displayed and in which order. Registered buttons are associated
56 with toolbar groups by <code>toolbar</code> property in their definition.
57 This setting's advantage is that you don't have to modify toolbar configuration
58 when adding/removing plugins which register their own buttons.
59 </p>
60
61 <p>To add a CKEditor instance with custom toolbar groups setting, insert the following JavaScript call to your code:</p>
62
63 <pre class="samples">
64CKEDITOR.replace( <em>'textarea_id'</em>, {
65 <strong>toolbarGroups:</strong> [
66 { name: 'document', groups: [ 'mode', 'document' ] }, // Displays document group with its two subgroups.
67 { name: 'clipboard', groups: [ 'clipboard', 'undo' ] }, // Group's name will be used to create voice label.
68 '/', // Line break - next group will be placed in new line.
69 { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
70 { name: 'links' }
71 ]
72
73 // NOTE: Remember to leave 'toolbar' property with the default value (null).
74});</pre>
75 </div>
76
77 <div id="currentToolbar" style="display: none">
78 <h2 class="samples">Current toolbar configuration</h2>
79 <p>Below you can see editor with current toolbar definition.</p>
80 <textarea cols="80" id="editorCurrent" name="editorCurrent" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
81 <pre id="editorCurrentCfg" class="samples"></pre>
82 </div>
83
84 <div id="fullToolbar">
85 <h2 class="samples">Full toolbar configuration</h2>
86 <p>Below you can see editor with full toolbar, generated automatically by the editor.</p>
87 <p>
88 <strong>Note</strong>: To create editor instance with full toolbar you don't have to set anything.
89 Just leave <code>toolbar</code> and <code>toolbarGroups</code> with the default, <code>null</code> values.
90 </p>
91 <textarea cols="80" id="editorFull" name="editorFull" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
92 <pre id="editorFullCfg" class="samples"></pre>
93 </div>
94
95 <script>
96
97(function() {
98 'use strict';
99
100 var buttonsNames;
101
102 CKEDITOR.config.extraPlugins = 'toolbar';
103
104 CKEDITOR.on( 'instanceReady', function( evt ) {
105 var editor = evt.editor,
106 editorCurrent = editor.name == 'editorCurrent',
107 defaultToolbar = !( editor.config.toolbar || editor.config.toolbarGroups || editor.config.removeButtons ),
108 pre = CKEDITOR.document.getById( editor.name + 'Cfg' ),
109 output = '';
110
111 if ( editorCurrent ) {
112 // If default toolbar configuration has been modified, show "current toolbar" section.
113 if ( !defaultToolbar )
114 CKEDITOR.document.getById( 'currentToolbar' ).show();
115 else
116 return;
117 }
118
119 if ( !buttonsNames )
120 buttonsNames = createButtonsNamesHash( editor.ui.items );
121
122 // Toolbar isn't set explicitly, so it was created automatically from toolbarGroups.
123 if ( !editor.config.toolbar ) {
124 output +=
125 '// Toolbar configuration generated automatically by the editor based on config.toolbarGroups.\n' +
126 dumpToolbarConfiguration( editor ) +
127 '\n\n' +
128 '// Toolbar groups configuration.\n' +
129 dumpToolbarConfiguration( editor, true )
130 }
131 // Toolbar groups doesn't count in this case - print only toolbar.
132 else {
133 output += '// Toolbar configuration.\n' +
134 dumpToolbarConfiguration( editor );
135 }
136
137 // Recreate to avoid old IE from loosing whitespaces on filling <pre> content.
138 var preOutput = pre.getOuterHtml().replace( /(?=<\/)/, output );
139 CKEDITOR.dom.element.createFromHtml( preOutput ).replace( pre );
140 } );
141
142 CKEDITOR.replace( 'editorCurrent', { height: 100 } );
143 CKEDITOR.replace( 'editorFull', {
144 // Reset toolbar settings, so full toolbar will be generated automatically.
145 toolbar: null,
146 toolbarGroups: null,
147 removeButtons: null,
148 height: 100
149 } );
150
151 function dumpToolbarConfiguration( editor, printGroups ) {
152 var output = [],
153 toolbar = editor.toolbar;
154
155 for ( var i = 0; i < toolbar.length; ++i ) {
156 var group = dumpToolbarGroup( toolbar[ i ], printGroups );
157 if ( group )
158 output.push( group );
159 }
160
161 return 'config.toolbar' + ( printGroups ? 'Groups' : '' ) + ' = [\n\t' + output.join( ',\n\t' ) + '\n];';
162 }
163
164 function dumpToolbarGroup( group, printGroups ) {
165 var output = [];
166
167 if ( typeof group == 'string' )
168 return '\'' + group + '\'';
169 if ( CKEDITOR.tools.isArray( group ) )
170 return dumpToolbarItems( group );
171 // Skip group when printing entire toolbar configuration and there are no items in this group.
172 if ( !printGroups && !group.items )
173 return;
174
175 if ( group.name )
176 output.push( 'name: \'' + group.name + '\'' );
177
178 if ( group.groups )
179 output.push( 'groups: ' + dumpToolbarItems( group.groups ) );
180
181 if ( !printGroups )
182 output.push( 'items: ' + dumpToolbarItems( group.items ) );
183
184 return '{ ' + output.join( ', ' ) + ' }';
185 }
186
187 function dumpToolbarItems( items ) {
188 if ( typeof items == 'string' )
189 return '\'' + items + '\'';
190
191 var names = [],
192 i, item;
193
194 for ( var i = 0; i < items.length; ++i ) {
195 item = items[ i ];
196 if ( typeof item == 'string' )
197 names.push( item );
198 else {
199 if ( item.type == CKEDITOR.UI_SEPARATOR )
200 names.push( '-' );
201 else
202 names.push( buttonsNames[ item.name ] );
203 }
204 }
205
206 return '[ \'' + names.join( '\', \'' ) + '\' ]';
207 }
208
209 // Creates { 'lowercased': 'LowerCased' } buttons names hash.
210 function createButtonsNamesHash( items ) {
211 var hash = {},
212 name;
213
214 for ( name in items ) {
215 hash[ items[ name ].name ] = name;
216 }
217
218 return hash;
219 }
220
221})();
222 </script>
223
224 <div id="footer">
225 <hr>
226 <p>
227 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
228 </p>
229 <p id="copy">
230 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
231 Knabben. All rights reserved.
232 </p>
233 </div>
234</body>
235</html>
diff --git a/sources/plugins/widget/dev/assets/contents.css b/sources/plugins/widget/dev/assets/contents.css
new file mode 100644
index 0000000..2cff316
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/contents.css
@@ -0,0 +1,23 @@
1.mediumBorder {
2 border-width: 2px;
3}
4.thickBorder {
5 border-width: 5px;
6}
7img.thickBorder, img.mediumBorder {
8 border-style: solid;
9 border-color: #CCC;
10}
11.important.soMuch {
12 margin: 25px;
13 padding: 25px;
14 background: red;
15 border: none;
16}
17
18span.redMarker {
19 background-color: red;
20}
21.invisible {
22 opacity: 0.1;
23}
diff --git a/sources/plugins/widget/dev/assets/sample.jpg b/sources/plugins/widget/dev/assets/sample.jpg
new file mode 100644
index 0000000..a4a77fa
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/sample.jpg
Binary files differ
diff --git a/sources/plugins/widget/dev/assets/simplebox/contents.css b/sources/plugins/widget/dev/assets/simplebox/contents.css
new file mode 100644
index 0000000..ddf3675
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/simplebox/contents.css
@@ -0,0 +1,36 @@
1.simplebox {
2 padding: 8px;
3 margin: 10px;
4 background: #eee;
5 border-radius: 8px;
6 border: 1px solid #ddd;
7 box-shadow: 0 1px 1px #fff inset, 0 -1px 0px #ccc inset;
8}
9.simplebox-title, .simplebox-content {
10 box-shadow: 0 1px 1px #ddd inset;
11 border: 1px solid #cccccc;
12 border-radius: 5px;
13 background: #fff;
14}
15.simplebox-title {
16 margin: 0 0 8px;
17 padding: 5px 8px;
18}
19.simplebox-content {
20 padding: 0 8px;
21}
22.simplebox-content::after {
23 content: '';
24 display: block;
25 clear: both;
26}
27.simplebox.align-right {
28 float: right;
29}
30.simplebox.align-left {
31 float: left;
32}
33.simplebox.align-center {
34 margin-left: auto;
35 margin-right: auto;
36}
diff --git a/sources/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js b/sources/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js
new file mode 100644
index 0000000..45a150c
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js
@@ -0,0 +1,51 @@
1// Note: This automatic widget to dialog window binding (the fact that every field is set up from the widget
2// and is committed to the widget) is only possible when the dialog is opened by the Widgets System
3// (i.e. the widgetDef.dialog property is set).
4// When you are opening the dialog window by yourself, you need to take care of this by yourself too.
5
6CKEDITOR.dialog.add( 'simplebox', function( editor ) {
7 return {
8 title: 'Edit Simple Box',
9 minWidth: 200,
10 minHeight: 100,
11 contents: [
12 {
13 id: 'info',
14 elements: [
15 {
16 id: 'align',
17 type: 'select',
18 label: 'Align',
19 items: [
20 [ editor.lang.common.notSet, '' ],
21 [ editor.lang.common.alignLeft, 'left' ],
22 [ editor.lang.common.alignRight, 'right' ],
23 [ editor.lang.common.alignCenter, 'center' ]
24 ],
25 // When setting up this field, set its value to the "align" value from widget data.
26 // Note: Align values used in the widget need to be the same as those defined in the "items" array above.
27 setup: function( widget ) {
28 this.setValue( widget.data.align );
29 },
30 // When committing (saving) this field, set its value to the widget data.
31 commit: function( widget ) {
32 widget.setData( 'align', this.getValue() );
33 }
34 },
35 {
36 id: 'width',
37 type: 'text',
38 label: 'Width',
39 width: '50px',
40 setup: function( widget ) {
41 this.setValue( widget.data.width );
42 },
43 commit: function( widget ) {
44 widget.setData( 'width', this.getValue() );
45 }
46 }
47 ]
48 }
49 ]
50 };
51} );
diff --git a/sources/plugins/widget/dev/assets/simplebox/icons/simplebox.png b/sources/plugins/widget/dev/assets/simplebox/icons/simplebox.png
new file mode 100644
index 0000000..6a5e313
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/simplebox/icons/simplebox.png
Binary files differ
diff --git a/sources/plugins/widget/dev/assets/simplebox/plugin.js b/sources/plugins/widget/dev/assets/simplebox/plugin.js
new file mode 100644
index 0000000..43dbad5
--- /dev/null
+++ b/sources/plugins/widget/dev/assets/simplebox/plugin.js
@@ -0,0 +1,114 @@
1'use strict';
2
3// Register the plugin within the editor.
4CKEDITOR.plugins.add( 'simplebox', {
5 // This plugin requires the Widgets System defined in the 'widget' plugin.
6 requires: 'widget',
7
8 // Register the icon used for the toolbar button. It must be the same
9 // as the name of the widget.
10 icons: 'simplebox',
11
12 // The plugin initialization logic goes inside this method.
13 init: function( editor ) {
14 // Register the editing dialog.
15 CKEDITOR.dialog.add( 'simplebox', this.path + 'dialogs/simplebox.js' );
16
17 // Register the simplebox widget.
18 editor.widgets.add( 'simplebox', {
19 // Allow all HTML elements, classes, and styles that this widget requires.
20 // Read more about the Advanced Content Filter here:
21 // * http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
22 // * http://docs.ckeditor.com/#!/guide/plugin_sdk_integration_with_acf
23 allowedContent:
24 'div(!simplebox,align-left,align-right,align-center){width};' +
25 'div(!simplebox-content); h2(!simplebox-title)',
26
27 // Minimum HTML which is required by this widget to work.
28 requiredContent: 'div(simplebox)',
29
30 // Define two nested editable areas.
31 editables: {
32 title: {
33 // Define CSS selector used for finding the element inside widget element.
34 selector: '.simplebox-title',
35 // Define content allowed in this nested editable. Its content will be
36 // filtered accordingly and the toolbar will be adjusted when this editable
37 // is focused.
38 allowedContent: 'br strong em'
39 },
40 content: {
41 selector: '.simplebox-content'
42 }
43 },
44
45 // Define the template of a new Simple Box widget.
46 // The template will be used when creating new instances of the Simple Box widget.
47 template:
48 '<div class="simplebox">' +
49 '<h2 class="simplebox-title">Title</h2>' +
50 '<div class="simplebox-content"><p>Content...</p></div>' +
51 '</div>',
52
53 // Define the label for a widget toolbar button which will be automatically
54 // created by the Widgets System. This button will insert a new widget instance
55 // created from the template defined above, or will edit selected widget
56 // (see second part of this tutorial to learn about editing widgets).
57 //
58 // Note: In order to be able to translate your widget you should use the
59 // editor.lang.simplebox.* property. A string was used directly here to simplify this tutorial.
60 button: 'Create a simple box',
61
62 // Set the widget dialog window name. This enables the automatic widget-dialog binding.
63 // This dialog window will be opened when creating a new widget or editing an existing one.
64 dialog: 'simplebox',
65
66 // Check the elements that need to be converted to widgets.
67 //
68 // Note: The "element" argument is an instance of http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.element
69 // so it is not a real DOM element yet. This is caused by the fact that upcasting is performed
70 // during data processing which is done on DOM represented by JavaScript objects.
71 upcast: function( element ) {
72 // Return "true" (that element needs to converted to a Simple Box widget)
73 // for all <div> elements with a "simplebox" class.
74 return element.name == 'div' && element.hasClass( 'simplebox' );
75 },
76
77 // When a widget is being initialized, we need to read the data ("align" and "width")
78 // from DOM and set it by using the widget.setData() method.
79 // More code which needs to be executed when DOM is available may go here.
80 init: function() {
81 var width = this.element.getStyle( 'width' );
82 if ( width )
83 this.setData( 'width', width );
84
85 if ( this.element.hasClass( 'align-left' ) )
86 this.setData( 'align', 'left' );
87 if ( this.element.hasClass( 'align-right' ) )
88 this.setData( 'align', 'right' );
89 if ( this.element.hasClass( 'align-center' ) )
90 this.setData( 'align', 'center' );
91 },
92
93 // Listen on the widget#data event which is fired every time the widget data changes
94 // and updates the widget's view.
95 // Data may be changed by using the widget.setData() method, which we use in the
96 // Simple Box dialog window.
97 data: function() {
98 // Check whether "width" widget data is set and remove or set "width" CSS style.
99 // The style is set on widget main element (div.simplebox).
100 if ( !this.data.width )
101 this.element.removeStyle( 'width' );
102 else
103 this.element.setStyle( 'width', this.data.width );
104
105 // Brutally remove all align classes and set a new one if "align" widget data is set.
106 this.element.removeClass( 'align-left' );
107 this.element.removeClass( 'align-right' );
108 this.element.removeClass( 'align-center' );
109 if ( this.data.align )
110 this.element.addClass( 'align-' + this.data.align );
111 }
112 } );
113 }
114} );
diff --git a/sources/plugins/widget/dev/console.js b/sources/plugins/widget/dev/console.js
new file mode 100644
index 0000000..78db0d0
--- /dev/null
+++ b/sources/plugins/widget/dev/console.js
@@ -0,0 +1,131 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/* global CKCONSOLE */
7
8'use strict';
9
10( function() {
11
12 CKCONSOLE.add( 'widget', {
13 panels: [
14 {
15 type: 'box',
16 content: '<ul class="ckconsole_list ckconsole_value" data-value="instances"></ul>',
17
18 refresh: function( editor ) {
19 var instances = obj2Array( editor.widgets.instances );
20
21 return {
22 header: 'Instances (' + instances.length + ')',
23 instances: generateInstancesList( instances )
24 };
25 },
26
27 refreshOn: function( editor, refresh ) {
28 editor.widgets.on( 'instanceCreated', function( evt ) {
29 refresh();
30
31 evt.data.on( 'data', refresh );
32 } );
33
34 editor.widgets.on( 'instanceDestroyed', refresh );
35 }
36 },
37
38 {
39 type: 'box',
40 content:
41 '<ul class="ckconsole_list">' +
42 '<li>focused: <span class="ckconsole_value" data-value="focused"></span></li>' +
43 '<li>selected: <span class="ckconsole_value" data-value="selected"></span></li>' +
44 '</ul>',
45
46 refresh: function( editor ) {
47 var focused = editor.widgets.focused,
48 selected = editor.widgets.selected,
49 selectedIds = [];
50
51 for ( var i = 0; i < selected.length; ++i )
52 selectedIds.push( selected[ i ].id );
53
54 return {
55 header: 'Focus &amp; selection',
56 focused: focused ? 'id: ' + focused.id : '-',
57 selected: selectedIds.length ? 'id: ' + selectedIds.join( ', id: ' ) : '-'
58 };
59 },
60
61 refreshOn: function( editor, refresh ) {
62 editor.on( 'selectionCheck', refresh, null, null, 999 );
63 }
64 },
65
66 {
67 type: 'log',
68
69 on: function( editor, log, logFn ) {
70 // Add all listeners with high priorities to log
71 // messages in the correct order when one event depends on another.
72 // E.g. selectionChange triggers widget selection - if this listener
73 // for selectionChange will be executed later than that one, then order
74 // will be incorrect.
75
76 editor.on( 'selectionChange', function( evt ) {
77 var msg = 'selection change',
78 sel = evt.data.selection,
79 el = sel.getSelectedElement(),
80 widget;
81
82 if ( el && ( widget = editor.widgets.getByElement( el, true ) ) )
83 msg += ' (id: ' + widget.id + ')';
84
85 log( msg );
86 }, null, null, 1 );
87
88 editor.widgets.on( 'instanceDestroyed', function( evt ) {
89 log( 'instance destroyed (id: ' + evt.data.id + ')' );
90 }, null, null, 1 );
91
92 editor.widgets.on( 'instanceCreated', function( evt ) {
93 log( 'instance created (id: ' + evt.data.id + ')' );
94 }, null, null, 1 );
95
96 editor.widgets.on( 'widgetFocused', function( evt ) {
97 log( 'widget focused (id: ' + evt.data.widget.id + ')' );
98 }, null, null, 1 );
99
100 editor.widgets.on( 'widgetBlurred', function( evt ) {
101 log( 'widget blurred (id: ' + evt.data.widget.id + ')' );
102 }, null, null, 1 );
103
104 editor.widgets.on( 'checkWidgets', logFn( 'checking widgets' ), null, null, 1 );
105 editor.widgets.on( 'checkSelection', logFn( 'checking selection' ), null, null, 1 );
106 }
107 }
108 ]
109 } );
110
111 function generateInstancesList( instances ) {
112 var html = '',
113 instance;
114
115 for ( var i = 0; i < instances.length; ++i ) {
116 instance = instances[ i ];
117 html += itemTpl.output( { id: instance.id, name: instance.name, data: JSON.stringify( instance.data ) } );
118 }
119 return html;
120 }
121
122 function obj2Array( obj ) {
123 var arr = [];
124 for ( var id in obj )
125 arr.push( obj[ id ] );
126
127 return arr;
128 }
129
130 var itemTpl = new CKEDITOR.template( '<li>id: <code>{id}</code>, name: <code>{name}</code>, data: <code>{data}</code></li>' );
131} )();
diff --git a/sources/plugins/widget/dev/nestedwidgets.html b/sources/plugins/widget/dev/nestedwidgets.html
new file mode 100644
index 0000000..0686d2c
--- /dev/null
+++ b/sources/plugins/widget/dev/nestedwidgets.html
@@ -0,0 +1,134 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Nested widgets &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../dev/console/console.js"></script>
12 <script src="../../../dev/console/focusconsole.js"></script>
13 <script src="console.js"></script>
14 <link rel="stylesheet" href="../../../samples/old/sample.css">
15 <link rel="stylesheet" href="../../../contents.css">
16 <link rel="stylesheet" href="assets/simplebox/contents.css">
17</head>
18<body>
19 <h1 class="samples">Nested widgets</h1>
20
21 <h2>Classic (iframe-based) Sample</h2>
22 <textarea cols="80" id="editor1" name="editor1" rows="10">
23 <h1>Simple Box Sample</h1>
24
25 <div class="simplebox align-right" style="width: 60%">
26 <h2 class="simplebox-title">Title</h2>
27 <div class="simplebox-content">
28 <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
29
30 <figure class="image" style="float: right">
31 <img alt="The Eagle" src="assets/sample.jpg" width="150" />
32 <figcaption>The Eagle in lunar orbit</figcaption>
33 </figure>
34
35 <ul>
36 <li>Foo!</li>
37 <li>Bar!</li>
38 </ul>
39
40 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
41 </div>
42 </div>
43
44 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
45
46 <p>Pellentesque vitae eleifend nisl, non accumsan tellus. Maecenas nec libero non tellus tincidunt mollis porttitor sed arcu. Donec ultricies nulla vitae eros lacinia, vel congue sem auctor. Vivamus convallis, urna ac tincidunt malesuada, lectus erat convallis metus, a hendrerit massa augue accumsan magna. Nulla mattis tellus elit, nec congue magna scelerisque eget. Aliquam posuere nisi augue, posuere sodales nisi iaculis eu. Donec fermentum urna id nibh sagittis fermentum sit amet sed enim. Aliquam neque elit, pretium elementum nunc a, faucibus accumsan lorem. Etiam pulvinar odio et hendrerit tincidunt. Suspendisse tempus eros lacus, in convallis velit mollis ut. Aenean congue, justo eleifend ultricies malesuada, nunc nunc molestie mauris, eget placerat libero eros vel nisi. Quisque diam arcu, mollis ac laoreet vitae, varius et sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis in vehicula sapien. Nunc feugiat porta elit nec volutpat.</p>
47
48 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
49
50 <div class="simplebox align-center" style="width: 750px">
51 <h2 class="simplebox-title">Title</h2>
52 <div class="simplebox-content">
53 <p><img alt="The Eagle" src="assets/sample.jpg" width="150" style="float: left" /><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
54
55 <ul>
56 <li>Foo!</li>
57 <li>Bar!</li>
58 </ul>
59 </div>
60 </div>
61
62 <p>Ut eget ipsum a sapien porta ultrices. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus mi lacus, pharetra eu bibendum blandit, tristique sit amet leo. Integer eu nulla nec magna vulputate blandit. Praesent mattis quis ante eget adipiscing. Nulla vel tempus risus, in placerat velit. Mauris sed nibh at elit posuere laoreet. Morbi non sapien sed nunc fringilla imperdiet.</p>
63 </textarea>
64
65 <h2>Inline Sample</h2>
66 <div id="editor2" contenteditable="true">
67 <h1>Simple Box Sample</h1>
68
69 <div class="simplebox align-right" style="width: 60%">
70 <h2 class="simplebox-title">Title</h2>
71 <div class="simplebox-content">
72 <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
73
74 <figure class="image" style="float: right">
75 <img alt="The Eagle" src="assets/sample.jpg" width="150" />
76 <figcaption>The Eagle in lunar orbit</figcaption>
77 </figure>
78
79 <ul>
80 <li>Foo!</li>
81 <li>Bar!</li>
82 </ul>
83
84 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
85 </div>
86 </div>
87
88 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
89
90 <p>Pellentesque vitae eleifend nisl, non accumsan tellus. Maecenas nec libero non tellus tincidunt mollis porttitor sed arcu. Donec ultricies nulla vitae eros lacinia, vel congue sem auctor. Vivamus convallis, urna ac tincidunt malesuada, lectus erat convallis metus, a hendrerit massa augue accumsan magna. Nulla mattis tellus elit, nec congue magna scelerisque eget. Aliquam posuere nisi augue, posuere sodales nisi iaculis eu. Donec fermentum urna id nibh sagittis fermentum sit amet sed enim. Aliquam neque elit, pretium elementum nunc a, faucibus accumsan lorem. Etiam pulvinar odio et hendrerit tincidunt. Suspendisse tempus eros lacus, in convallis velit mollis ut. Aenean congue, justo eleifend ultricies malesuada, nunc nunc molestie mauris, eget placerat libero eros vel nisi. Quisque diam arcu, mollis ac laoreet vitae, varius et sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis in vehicula sapien. Nunc feugiat porta elit nec volutpat.</p>
91
92 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p>
93
94 <div class="simplebox align-center" style="width: 750px">
95 <h2 class="simplebox-title">Title</h2>
96 <div class="simplebox-content">
97 <p><img alt="The Eagle" src="assets/sample.jpg" width="150" style="float: left" /><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
98
99 <ul>
100 <li>Foo!</li>
101 <li>Bar!</li>
102 </ul>
103 </div>
104 </div>
105
106 <p>Ut eget ipsum a sapien porta ultrices. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus mi lacus, pharetra eu bibendum blandit, tristique sit amet leo. Integer eu nulla nec magna vulputate blandit. Praesent mattis quis ante eget adipiscing. Nulla vel tempus risus, in placerat velit. Mauris sed nibh at elit posuere laoreet. Morbi non sapien sed nunc fringilla imperdiet.</p>
107 </div>
108
109 <script>
110 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
111 CKEDITOR.tools.enableHtml5Elements( document );
112
113 CKEDITOR.plugins.addExternal( 'simplebox', 'plugins/widget/dev/assets/simplebox/' );
114
115 CKEDITOR.replace( 'editor1', {
116 extraPlugins: 'simplebox,placeholder,image2',
117 removePlugins: 'forms,bidi',
118 contentsCss: [ '../../../contents.css', 'assets/simplebox/contents.css' ],
119 height: 500
120 } );
121
122 CKEDITOR.inline( 'editor2', {
123 extraPlugins: 'simplebox,placeholder,image2',
124 removePlugins: 'forms,bidi'
125 } );
126
127 CKCONSOLE.create( 'widget', { editor: 'editor1' } );
128 CKCONSOLE.create( 'focus', { editor: 'editor1' } );
129 CKCONSOLE.create( 'widget', { editor: 'editor2', folded: true } );
130 CKCONSOLE.create( 'focus', { editor: 'editor2', folded: true } );
131
132 </script>
133</body>
134</html>
diff --git a/sources/plugins/widget/dev/widgetstyles.html b/sources/plugins/widget/dev/widgetstyles.html
new file mode 100644
index 0000000..8e54b8d
--- /dev/null
+++ b/sources/plugins/widget/dev/widgetstyles.html
@@ -0,0 +1,144 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Applying styles to widgets &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link rel="stylesheet" href="../../../samples/old/sample.css">
12 <link rel="stylesheet" href="../../../contents.css">
13 <link rel="stylesheet" href="assets/contents.css">
14</head>
15<body>
16 <h1 class="samples">Applying styles to widgets</h1>
17
18 <h2>Classic (iframe-based) Sample</h2>
19 <textarea cols="80" id="editor1" name="editor1" rows="10">
20 <h1>Apollo 11</h1>
21
22 <figure class="image" style="float: right">
23 <img alt="Saturn V" src="../../../samples/assets/sample.jpg" width="150" />
24 <figcaption>Roll out of Saturn V on launch pad</figcaption>
25 </figure>
26
27 <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
28
29 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
30
31 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
32
33 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
34
35 <blockquote>
36 <p>One small step for [a] man, one giant leap for mankind.</p>
37 </blockquote>
38
39 <p><span class="math-tex">\( \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \)</span></p>
40
41 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
42
43 <blockquote>
44 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
45 </blockquote>
46
47 <figure class="image" style="float: right">
48 <img alt="The Eagle" src="../../../samples/assets/sample.jpg" width="150" />
49 <figcaption>The Eagle in lunar orbit</figcaption>
50 </figure>
51
52 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
53
54 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
55
56 <ol>
57 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
58 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
59 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
60 </ol>
61
62 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
63 </textarea>
64
65 <h2>Inline Sample</h2>
66 <div id="editor2" contenteditable="true">
67 <h1>Apollo 11</h1>
68
69 <figure class="image" style="float: right">
70 <img alt="Saturn V" src="../../../samples/assets/sample.jpg" width="150" />
71 <figcaption>Roll out of Saturn V on launch pad</figcaption>
72 </figure>
73
74 <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p>
75
76 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
77
78 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
79
80 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
81
82 <blockquote>
83 <p>One small step for [a] man, one giant leap for mankind.</p>
84 </blockquote>
85
86 <p><span class="math-tex">\( \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \)</span></p>
87
88 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
89
90 <blockquote>
91 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
92 </blockquote>
93
94 <figure class="image" style="float: right">
95 <img alt="The Eagle" src="../../../samples/assets/sample.jpg" width="150" />
96 <figcaption>The Eagle in lunar orbit</figcaption>
97 </figure>
98
99 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
100
101 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
102
103 <ol>
104 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
105 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
106 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
107 </ol>
108
109 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
110 </div>
111
112 <script>
113 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
114 CKEDITOR.tools.enableHtml5Elements( document );
115
116 CKEDITOR.disableAutoInline = true;
117
118 var stylesSet = [
119 { name: 'Medium border', type: 'widget', widget: 'image', attributes: { 'class': 'mediumBorder' } },
120 { name: 'Thick border', type: 'widget', widget: 'image', attributes: { 'class': 'thickBorder' } },
121 { name: 'So important', type: 'widget', widget: 'image', attributes: { 'class': 'important soMuch' } },
122
123 { name: 'Red marker', type: 'widget', widget: 'placeholder', attributes: { 'class': 'redMarker' } },
124 { name: 'Invisible Placeholder', type: 'widget', widget: 'placeholder', attributes: { 'class': 'invisible' } },
125
126 { name: 'Invisible Mathjax', type: 'widget', widget: 'mathjax', attributes: { 'class': 'invisible' } }
127 ];
128
129 CKEDITOR.replace( 'editor1', {
130 extraPlugins: 'placeholder,image2,mathjax',
131 contentsCss: [ '../../../contents.css', 'assets/contents.css' ],
132 stylesSet: stylesSet,
133 height: 300
134 } );
135
136 CKEDITOR.inline( 'editor2', {
137 extraPlugins: 'placeholder,image2,mathjax',
138 stylesSet: stylesSet,
139 height: 300
140 } );
141
142 </script>
143</body>
144</html>
diff --git a/sources/plugins/widget/images/handle.png b/sources/plugins/widget/images/handle.png
new file mode 100644
index 0000000..ba8cda5
--- /dev/null
+++ b/sources/plugins/widget/images/handle.png
Binary files differ
diff --git a/sources/plugins/widget/lang/af.js b/sources/plugins/widget/lang/af.js
new file mode 100644
index 0000000..e37c598
--- /dev/null
+++ b/sources/plugins/widget/lang/af.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'af', {
6 'move': 'Klik en trek on te beweeg',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ar.js b/sources/plugins/widget/lang/ar.js
new file mode 100644
index 0000000..0a4f8eb
--- /dev/null
+++ b/sources/plugins/widget/lang/ar.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ar', {
6 'move': 'إضغط و إسحب للتحريك',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/az.js b/sources/plugins/widget/lang/az.js
new file mode 100644
index 0000000..24ddaf3
--- /dev/null
+++ b/sources/plugins/widget/lang/az.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'az', {
6 'move': 'Tıklayın və aparın',
7 'label': '%1 vidjet'
8} );
diff --git a/sources/plugins/widget/lang/bg.js b/sources/plugins/widget/lang/bg.js
new file mode 100644
index 0000000..9b51458
--- /dev/null
+++ b/sources/plugins/widget/lang/bg.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'bg', {
6 'move': 'Кликни и влачи, за да преместиш',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ca.js b/sources/plugins/widget/lang/ca.js
new file mode 100644
index 0000000..f46a4f8
--- /dev/null
+++ b/sources/plugins/widget/lang/ca.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ca', {
6 'move': 'Clicar i arrossegar per moure',
7 'label': '%1 widget'
8} );
diff --git a/sources/plugins/widget/lang/cs.js b/sources/plugins/widget/lang/cs.js
new file mode 100644
index 0000000..5d9590b
--- /dev/null
+++ b/sources/plugins/widget/lang/cs.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'cs', {
6 'move': 'Klepněte a táhněte pro přesunutí',
7 'label': 'Ovládací prvek %1'
8} );
diff --git a/sources/plugins/widget/lang/cy.js b/sources/plugins/widget/lang/cy.js
new file mode 100644
index 0000000..29dc110
--- /dev/null
+++ b/sources/plugins/widget/lang/cy.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'cy', {
6 'move': 'Clcio a llusgo i symud',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/da.js b/sources/plugins/widget/lang/da.js
new file mode 100644
index 0000000..8dfe785
--- /dev/null
+++ b/sources/plugins/widget/lang/da.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'da', {
6 'move': 'Klik og træk for at flytte',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/de-ch.js b/sources/plugins/widget/lang/de-ch.js
new file mode 100644
index 0000000..a95febb
--- /dev/null
+++ b/sources/plugins/widget/lang/de-ch.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'de-ch', {
6 'move': 'Zum Verschieben anwählen und ziehen',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/de.js b/sources/plugins/widget/lang/de.js
new file mode 100644
index 0000000..838ad89
--- /dev/null
+++ b/sources/plugins/widget/lang/de.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'de', {
6 'move': 'Zum Verschieben anwählen und ziehen',
7 'label': '%1 Steuerelement'
8} );
diff --git a/sources/plugins/widget/lang/el.js b/sources/plugins/widget/lang/el.js
new file mode 100644
index 0000000..863604a
--- /dev/null
+++ b/sources/plugins/widget/lang/el.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'el', {
6 'move': 'Κάνετε κλικ και σύρετε το ποντίκι για να μετακινήστε',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/en-gb.js b/sources/plugins/widget/lang/en-gb.js
new file mode 100644
index 0000000..ed09606
--- /dev/null
+++ b/sources/plugins/widget/lang/en-gb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'en-gb', {
6 'move': 'Click and drag to move',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/en.js b/sources/plugins/widget/lang/en.js
new file mode 100644
index 0000000..5967f4d
--- /dev/null
+++ b/sources/plugins/widget/lang/en.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'en', {
6 'move': 'Click and drag to move',
7 'label': '%1 widget'
8} );
diff --git a/sources/plugins/widget/lang/eo.js b/sources/plugins/widget/lang/eo.js
new file mode 100644
index 0000000..f4979ac
--- /dev/null
+++ b/sources/plugins/widget/lang/eo.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'eo', {
6 'move': 'klaki kaj treni por movi',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/es.js b/sources/plugins/widget/lang/es.js
new file mode 100644
index 0000000..d8deb2c
--- /dev/null
+++ b/sources/plugins/widget/lang/es.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'es', {
6 'move': 'Dar clic y arrastrar para mover',
7 'label': 'reproductor %1'
8} );
diff --git a/sources/plugins/widget/lang/eu.js b/sources/plugins/widget/lang/eu.js
new file mode 100644
index 0000000..e128dfe
--- /dev/null
+++ b/sources/plugins/widget/lang/eu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'eu', {
6 'move': 'Klikatu eta arrastatu lekuz aldatzeko',
7 'label': '%1 widget'
8} );
diff --git a/sources/plugins/widget/lang/fa.js b/sources/plugins/widget/lang/fa.js
new file mode 100644
index 0000000..57ea31f
--- /dev/null
+++ b/sources/plugins/widget/lang/fa.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'fa', {
6 'move': 'کلیک و کشیدن برای جابجایی',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/fi.js b/sources/plugins/widget/lang/fi.js
new file mode 100644
index 0000000..759b2cf
--- /dev/null
+++ b/sources/plugins/widget/lang/fi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'fi', {
6 'move': 'Siirrä klikkaamalla ja raahaamalla',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/fr.js b/sources/plugins/widget/lang/fr.js
new file mode 100644
index 0000000..9decbf6
--- /dev/null
+++ b/sources/plugins/widget/lang/fr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'fr', {
6 'move': 'Cliquer et glisser pour déplacer',
7 'label': 'Élément %1'
8} );
diff --git a/sources/plugins/widget/lang/gl.js b/sources/plugins/widget/lang/gl.js
new file mode 100644
index 0000000..ef070b6
--- /dev/null
+++ b/sources/plugins/widget/lang/gl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'gl', {
6 'move': 'Prema e arrastre para mover',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/he.js b/sources/plugins/widget/lang/he.js
new file mode 100644
index 0000000..b8dd2cb
--- /dev/null
+++ b/sources/plugins/widget/lang/he.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'he', {
6 'move': 'לחץ וגרור להזזה',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/hr.js b/sources/plugins/widget/lang/hr.js
new file mode 100644
index 0000000..952d800
--- /dev/null
+++ b/sources/plugins/widget/lang/hr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'hr', {
6 'move': 'Klikni i povuci da pomakneš',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/hu.js b/sources/plugins/widget/lang/hu.js
new file mode 100644
index 0000000..4721305
--- /dev/null
+++ b/sources/plugins/widget/lang/hu.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'hu', {
6 'move': 'Kattints és húzd a mozgatáshoz',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/id.js b/sources/plugins/widget/lang/id.js
new file mode 100644
index 0000000..ef19392
--- /dev/null
+++ b/sources/plugins/widget/lang/id.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'id', {
6 'move': 'Tekan dan geser untuk memindahkan',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/it.js b/sources/plugins/widget/lang/it.js
new file mode 100644
index 0000000..59b43f6
--- /dev/null
+++ b/sources/plugins/widget/lang/it.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'it', {
6 'move': 'Fare clic e trascinare per spostare',
7 'label': 'Widget %1'
8} );
diff --git a/sources/plugins/widget/lang/ja.js b/sources/plugins/widget/lang/ja.js
new file mode 100644
index 0000000..a742718
--- /dev/null
+++ b/sources/plugins/widget/lang/ja.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ja', {
6 'move': 'ドラッグして移動',
7 'label': '%1 ウィジェット'
8} );
diff --git a/sources/plugins/widget/lang/km.js b/sources/plugins/widget/lang/km.js
new file mode 100644
index 0000000..6c61c73
--- /dev/null
+++ b/sources/plugins/widget/lang/km.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'km', {
6 'move': 'ចុច​ហើយ​ទាញ​ដើម្បី​ផ្លាស់​ទី',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ko.js b/sources/plugins/widget/lang/ko.js
new file mode 100644
index 0000000..0107a13
--- /dev/null
+++ b/sources/plugins/widget/lang/ko.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ko', {
6 'move': '움직이려면 클릭 후 드래그 하세요',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ku.js b/sources/plugins/widget/lang/ku.js
new file mode 100644
index 0000000..2af50cb
--- /dev/null
+++ b/sources/plugins/widget/lang/ku.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ku', {
6 'move': 'کرتەبکە و ڕایبکێشە بۆ جوڵاندن',
7 'label': '%1 ویجێت'
8} );
diff --git a/sources/plugins/widget/lang/lv.js b/sources/plugins/widget/lang/lv.js
new file mode 100644
index 0000000..e5fc3ac
--- /dev/null
+++ b/sources/plugins/widget/lang/lv.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'lv', {
6 'move': 'Klikšķina un velc, lai pārvietotu',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/nb.js b/sources/plugins/widget/lang/nb.js
new file mode 100644
index 0000000..af46bc9
--- /dev/null
+++ b/sources/plugins/widget/lang/nb.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'nb', {
6 'move': 'Klikk og dra for å flytte',
7 'label': 'Widget %1'
8} );
diff --git a/sources/plugins/widget/lang/nl.js b/sources/plugins/widget/lang/nl.js
new file mode 100644
index 0000000..56b182c
--- /dev/null
+++ b/sources/plugins/widget/lang/nl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'nl', {
6 'move': 'Klik en sleep om te verplaatsen',
7 'label': '%1 widget'
8} );
diff --git a/sources/plugins/widget/lang/no.js b/sources/plugins/widget/lang/no.js
new file mode 100644
index 0000000..b86bd7b
--- /dev/null
+++ b/sources/plugins/widget/lang/no.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'no', {
6 'move': 'Klikk og dra for å flytte',
7 'label': 'Widget %1'
8} );
diff --git a/sources/plugins/widget/lang/oc.js b/sources/plugins/widget/lang/oc.js
new file mode 100644
index 0000000..10ff842
--- /dev/null
+++ b/sources/plugins/widget/lang/oc.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'oc', {
6 'move': 'Clicar e lisar per desplaçar',
7 'label': 'Element %1'
8} );
diff --git a/sources/plugins/widget/lang/pl.js b/sources/plugins/widget/lang/pl.js
new file mode 100644
index 0000000..2d90df8
--- /dev/null
+++ b/sources/plugins/widget/lang/pl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'pl', {
6 'move': 'Kliknij i przeciągnij, by przenieść.',
7 'label': 'Widget %1'
8} );
diff --git a/sources/plugins/widget/lang/pt-br.js b/sources/plugins/widget/lang/pt-br.js
new file mode 100644
index 0000000..9ce9be4
--- /dev/null
+++ b/sources/plugins/widget/lang/pt-br.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'pt-br', {
6 'move': 'Click e arraste para mover',
7 'label': '%1 widget'
8} );
diff --git a/sources/plugins/widget/lang/pt.js b/sources/plugins/widget/lang/pt.js
new file mode 100644
index 0000000..422ef93
--- /dev/null
+++ b/sources/plugins/widget/lang/pt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'pt', {
6 'move': 'Clique e arraste para mover',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ru.js b/sources/plugins/widget/lang/ru.js
new file mode 100644
index 0000000..d6f36f5
--- /dev/null
+++ b/sources/plugins/widget/lang/ru.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ru', {
6 'move': 'Нажмите и перетащите, чтобы переместить',
7 'label': '%1 виджет'
8} );
diff --git a/sources/plugins/widget/lang/sk.js b/sources/plugins/widget/lang/sk.js
new file mode 100644
index 0000000..05acac4
--- /dev/null
+++ b/sources/plugins/widget/lang/sk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'sk', {
6 'move': 'Kliknite a potiahnite pre presunutie',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/sl.js b/sources/plugins/widget/lang/sl.js
new file mode 100644
index 0000000..96ffd1e
--- /dev/null
+++ b/sources/plugins/widget/lang/sl.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'sl', {
6 'move': 'Kliknite in povlecite, da premaknete',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/sq.js b/sources/plugins/widget/lang/sq.js
new file mode 100644
index 0000000..ad46c7d
--- /dev/null
+++ b/sources/plugins/widget/lang/sq.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'sq', {
6 'move': 'Kliko dhe tërhiqe për ta lëvizur',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/sv.js b/sources/plugins/widget/lang/sv.js
new file mode 100644
index 0000000..7faff37
--- /dev/null
+++ b/sources/plugins/widget/lang/sv.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'sv', {
6 'move': 'Klicka och drag för att flytta',
7 'label': '%1-widget'
8} );
diff --git a/sources/plugins/widget/lang/tr.js b/sources/plugins/widget/lang/tr.js
new file mode 100644
index 0000000..92fa952
--- /dev/null
+++ b/sources/plugins/widget/lang/tr.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'tr', {
6 'move': 'Taşımak için, tıklayın ve sürükleyin',
7 'label': '%1 Grafik Beleşeni'
8} );
diff --git a/sources/plugins/widget/lang/tt.js b/sources/plugins/widget/lang/tt.js
new file mode 100644
index 0000000..30fb31a
--- /dev/null
+++ b/sources/plugins/widget/lang/tt.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'tt', {
6 'move': 'Күчереп куер өчен басып шудырыгыз',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/ug.js b/sources/plugins/widget/lang/ug.js
new file mode 100644
index 0000000..fc216c4
--- /dev/null
+++ b/sources/plugins/widget/lang/ug.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'ug', {
6 'move': 'يۆتكەشتە چېكىپ سۆرەڭ',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/uk.js b/sources/plugins/widget/lang/uk.js
new file mode 100644
index 0000000..fab6d5d
--- /dev/null
+++ b/sources/plugins/widget/lang/uk.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'uk', {
6 'move': 'Клікніть і потягніть для переміщення',
7 'label': '%1 віджет'
8} );
diff --git a/sources/plugins/widget/lang/vi.js b/sources/plugins/widget/lang/vi.js
new file mode 100644
index 0000000..2bbe246
--- /dev/null
+++ b/sources/plugins/widget/lang/vi.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'vi', {
6 'move': 'Nhấp chuột và kéo để di chuyển',
7 'label': '%1 widget' // MISSING
8} );
diff --git a/sources/plugins/widget/lang/zh-cn.js b/sources/plugins/widget/lang/zh-cn.js
new file mode 100644
index 0000000..2381407
--- /dev/null
+++ b/sources/plugins/widget/lang/zh-cn.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'zh-cn', {
6 'move': '点击并拖拽以移动',
7 'label': '%1 小部件'
8} );
diff --git a/sources/plugins/widget/lang/zh.js b/sources/plugins/widget/lang/zh.js
new file mode 100644
index 0000000..b6e945b
--- /dev/null
+++ b/sources/plugins/widget/lang/zh.js
@@ -0,0 +1,8 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5CKEDITOR.plugins.setLang( 'widget', 'zh', {
6 'move': '拖曳以移動',
7 'label': '%1 小工具'
8} );
diff --git a/sources/plugins/widget/plugin.js b/sources/plugins/widget/plugin.js
new file mode 100644
index 0000000..37374ab
--- /dev/null
+++ b/sources/plugins/widget/plugin.js
@@ -0,0 +1,4126 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview [Widget](http://ckeditor.com/addon/widget) plugin.
8 */
9
10'use strict';
11
12( function() {
13 var DRAG_HANDLER_SIZE = 15;
14
15 CKEDITOR.plugins.add( 'widget', {
16 // jscs:disable maximumLineLength
17 lang: 'af,ar,az,bg,ca,cs,cy,da,de,de-ch,el,en,en-gb,eo,es,eu,fa,fi,fr,gl,he,hr,hu,id,it,ja,km,ko,ku,lv,nb,nl,no,oc,pl,pt,pt-br,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
18 // jscs:enable maximumLineLength
19 requires: 'lineutils,clipboard,widgetselection',
20 onLoad: function() {
21 CKEDITOR.addCss(
22 '.cke_widget_wrapper{' +
23 'position:relative;' +
24 'outline:none' +
25 '}' +
26 '.cke_widget_inline{' +
27 'display:inline-block' +
28 '}' +
29 '.cke_widget_wrapper:hover>.cke_widget_element{' +
30 'outline:2px solid yellow;' +
31 'cursor:default' +
32 '}' +
33 '.cke_widget_wrapper:hover .cke_widget_editable{' +
34 'outline:2px solid yellow' +
35 '}' +
36 '.cke_widget_wrapper.cke_widget_focused>.cke_widget_element,' +
37 // We need higher specificity than hover style.
38 '.cke_widget_wrapper .cke_widget_editable.cke_widget_editable_focused{' +
39 'outline:2px solid #ace' +
40 '}' +
41 '.cke_widget_editable{' +
42 'cursor:text' +
43 '}' +
44 '.cke_widget_drag_handler_container{' +
45 'position:absolute;' +
46 'width:' + DRAG_HANDLER_SIZE + 'px;' +
47 'height:0;' +
48 // Initially drag handler should not be visible, until its position will be
49 // calculated (#11177).
50 // We need to hide unpositined handlers, so they don't extend
51 // widget's outline far to the left (#12024).
52 'display:none;' +
53 'opacity:0.75;' +
54 'transition:height 0s 0.2s;' + // Delay hiding drag handler.
55 // Prevent drag handler from being misplaced (#11198).
56 'line-height:0' +
57 '}' +
58 '.cke_widget_wrapper:hover>.cke_widget_drag_handler_container{' +
59 'height:' + DRAG_HANDLER_SIZE + 'px;' +
60 'transition:none' +
61 '}' +
62 '.cke_widget_drag_handler_container:hover{' +
63 'opacity:1' +
64 '}' +
65 'img.cke_widget_drag_handler{' +
66 'cursor:move;' +
67 'width:' + DRAG_HANDLER_SIZE + 'px;' +
68 'height:' + DRAG_HANDLER_SIZE + 'px;' +
69 'display:inline-block' +
70 '}' +
71 '.cke_widget_mask{' +
72 'position:absolute;' +
73 'top:0;' +
74 'left:0;' +
75 'width:100%;' +
76 'height:100%;' +
77 'display:block' +
78 '}' +
79 '.cke_editable.cke_widget_dragging, .cke_editable.cke_widget_dragging *{' +
80 'cursor:move !important' +
81 '}'
82 );
83 },
84
85 beforeInit: function( editor ) {
86 /**
87 * An instance of widget repository. It contains all
88 * {@link CKEDITOR.plugins.widget.repository#registered registered widget definitions} and
89 * {@link CKEDITOR.plugins.widget.repository#instances initialized instances}.
90 *
91 * editor.widgets.add( 'someName', {
92 * // Widget definition...
93 * } );
94 *
95 * editor.widgets.registered.someName; // -> Widget definition
96 *
97 * @since 4.3
98 * @readonly
99 * @property {CKEDITOR.plugins.widget.repository} widgets
100 * @member CKEDITOR.editor
101 */
102 editor.widgets = new Repository( editor );
103 },
104
105 afterInit: function( editor ) {
106 addWidgetButtons( editor );
107 setupContextMenu( editor );
108 }
109 } );
110
111 /**
112 * Widget repository. It keeps track of all {@link #registered registered widget definitions} and
113 * {@link #instances initialized instances}. An instance of the repository is available under
114 * the {@link CKEDITOR.editor#widgets} property.
115 *
116 * @class CKEDITOR.plugins.widget.repository
117 * @mixins CKEDITOR.event
118 * @constructor Creates a widget repository instance. Note that the widget plugin automatically
119 * creates a repository instance which is available under the {@link CKEDITOR.editor#widgets} property.
120 * @param {CKEDITOR.editor} editor The editor instance for which the repository will be created.
121 */
122 function Repository( editor ) {
123 /**
124 * The editor instance for which this repository was created.
125 *
126 * @readonly
127 * @property {CKEDITOR.editor} editor
128 */
129 this.editor = editor;
130
131 /**
132 * A hash of registered widget definitions (definition name => {@link CKEDITOR.plugins.widget.definition}).
133 *
134 * To register a definition use the {@link #add} method.
135 *
136 * @readonly
137 */
138 this.registered = {};
139
140 /**
141 * An object containing initialized widget instances (widget id => {@link CKEDITOR.plugins.widget}).
142 *
143 * @readonly
144 */
145 this.instances = {};
146
147 /**
148 * An array of selected widget instances.
149 *
150 * @readonly
151 * @property {CKEDITOR.plugins.widget[]} selected
152 */
153 this.selected = [];
154
155 /**
156 * The focused widget instance. See also {@link CKEDITOR.plugins.widget#event-focus}
157 * and {@link CKEDITOR.plugins.widget#event-blur} events.
158 *
159 * editor.on( 'selectionChange', function() {
160 * if ( editor.widgets.focused ) {
161 * // Do something when a widget is focused...
162 * }
163 * } );
164 *
165 * @readonly
166 * @property {CKEDITOR.plugins.widget} focused
167 */
168 this.focused = null;
169
170 /**
171 * The widget instance that contains the nested editable which is currently focused.
172 *
173 * @readonly
174 * @property {CKEDITOR.plugins.widget} widgetHoldingFocusedEditable
175 */
176 this.widgetHoldingFocusedEditable = null;
177
178 this._ = {
179 nextId: 0,
180 upcasts: [],
181 upcastCallbacks: [],
182 filters: {}
183 };
184
185 setupWidgetsLifecycle( this );
186 setupSelectionObserver( this );
187 setupMouseObserver( this );
188 setupKeyboardObserver( this );
189 setupDragAndDrop( this );
190 setupNativeCutAndCopy( this );
191 }
192
193 Repository.prototype = {
194 /**
195 * Minimum interval between selection checks.
196 *
197 * @private
198 */
199 MIN_SELECTION_CHECK_INTERVAL: 500,
200
201 /**
202 * Adds a widget definition to the repository. Fires the {@link CKEDITOR.editor#widgetDefinition} event
203 * which allows to modify the widget definition which is going to be registered.
204 *
205 * @param {String} name The name of the widget definition.
206 * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget definition.
207 * @returns {CKEDITOR.plugins.widget.definition}
208 */
209 add: function( name, widgetDef ) {
210 // Create prototyped copy of original widget definition, so we won't modify it.
211 widgetDef = CKEDITOR.tools.prototypedCopy( widgetDef );
212 widgetDef.name = name;
213
214 widgetDef._ = widgetDef._ || {};
215
216 this.editor.fire( 'widgetDefinition', widgetDef );
217
218 if ( widgetDef.template )
219 widgetDef.template = new CKEDITOR.template( widgetDef.template );
220
221 addWidgetCommand( this.editor, widgetDef );
222 addWidgetProcessors( this, widgetDef );
223
224 this.registered[ name ] = widgetDef;
225
226 return widgetDef;
227 },
228
229 /**
230 * Adds a callback for element upcasting. Each callback will be executed
231 * for every element which is later tested by upcast methods. If a callback
232 * returns `false`, the element will not be upcasted.
233 *
234 * // Images with the "banner" class will not be upcasted (e.g. to the image widget).
235 * editor.widgets.addUpcastCallback( function( element ) {
236 * if ( element.name == 'img' && element.hasClass( 'banner' ) )
237 * return false;
238 * } );
239 *
240 * @param {Function} callback
241 * @param {CKEDITOR.htmlParser.element} callback.element
242 */
243 addUpcastCallback: function( callback ) {
244 this._.upcastCallbacks.push( callback );
245 },
246
247 /**
248 * Checks the selection to update widget states (selection and focus).
249 *
250 * This method is triggered by the {@link #event-checkSelection} event.
251 */
252 checkSelection: function() {
253 var sel = this.editor.getSelection(),
254 selectedElement = sel.getSelectedElement(),
255 updater = stateUpdater( this ),
256 widget;
257
258 // Widget is focused so commit and finish checking.
259 if ( selectedElement && ( widget = this.getByElement( selectedElement, true ) ) )
260 return updater.focus( widget ).select( widget ).commit();
261
262 var range = sel.getRanges()[ 0 ];
263
264 // No ranges or collapsed range mean that nothing is selected, so commit and finish checking.
265 if ( !range || range.collapsed )
266 return updater.commit();
267
268 // Range is not empty, so create walker checking for wrappers.
269 var walker = new CKEDITOR.dom.walker( range ),
270 wrapper;
271
272 walker.evaluator = Widget.isDomWidgetWrapper;
273
274 while ( ( wrapper = walker.next() ) )
275 updater.select( this.getByElement( wrapper ) );
276
277 updater.commit();
278 },
279
280 /**
281 * Checks if all widget instances are still present in the DOM.
282 * Destroys those instances that are not present.
283 * Reinitializes widgets on widget wrappers for which widget instances
284 * cannot be found. Takes nested widgets into account, too.
285 *
286 * This method triggers the {@link #event-checkWidgets} event whose listeners
287 * can cancel the method's execution or modify its options.
288 *
289 * @param [options] The options object.
290 * @param {Boolean} [options.initOnlyNew] Initializes widgets only on newly wrapped
291 * widget elements (those which still have the `cke_widget_new` class). When this option is
292 * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)
293 * will not be reinitialized. This makes the check faster.
294 * @param {Boolean} [options.focusInited] If only one widget is initialized by
295 * the method, it will be focused.
296 */
297 checkWidgets: function( options ) {
298 this.fire( 'checkWidgets', CKEDITOR.tools.copy( options || {} ) );
299 },
300
301 /**
302 * Removes the widget from the editor and moves the selection to the closest
303 * editable position if the widget was focused before.
304 *
305 * @param {CKEDITOR.plugins.widget} widget The widget instance to be deleted.
306 */
307 del: function( widget ) {
308 if ( this.focused === widget ) {
309 var editor = widget.editor,
310 range = editor.createRange(),
311 found;
312
313 // If haven't found place for caret on the default side,
314 // try to find it on the other side.
315 if ( !( found = range.moveToClosestEditablePosition( widget.wrapper, true ) ) )
316 found = range.moveToClosestEditablePosition( widget.wrapper, false );
317
318 if ( found )
319 editor.getSelection().selectRanges( [ range ] );
320 }
321
322 widget.wrapper.remove();
323 this.destroy( widget, true );
324 },
325
326 /**
327 * Destroys the widget instance and all its nested widgets (widgets inside its nested editables).
328 *
329 * @param {CKEDITOR.plugins.widget} widget The widget instance to be destroyed.
330 * @param {Boolean} [offline] Whether the widget is offline (detached from the DOM tree) &mdash;
331 * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
332 */
333 destroy: function( widget, offline ) {
334 if ( this.widgetHoldingFocusedEditable === widget )
335 setFocusedEditable( this, widget, null, offline );
336
337 widget.destroy( offline );
338 delete this.instances[ widget.id ];
339 this.fire( 'instanceDestroyed', widget );
340 },
341
342 /**
343 * Destroys all widget instances.
344 *
345 * @param {Boolean} [offline] Whether the widgets are offline (detached from the DOM tree) &mdash;
346 * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
347 * @param {CKEDITOR.dom.element} [container] The container within widgets will be destroyed.
348 * This option will be ignored if the `offline` flag was set to `true`, because in such case
349 * it is not possible to find widgets within the passed block.
350 */
351 destroyAll: function( offline, container ) {
352 var widget,
353 id,
354 instances = this.instances;
355
356 if ( container && !offline ) {
357 var wrappers = container.find( '.cke_widget_wrapper' ),
358 l = wrappers.count(),
359 i = 0;
360
361 // Length is constant, because this is not a live node list.
362 // Note: since querySelectorAll returns nodes in document order,
363 // outer widgets are always placed before their nested widgets and therefore
364 // are destroyed before them.
365 for ( ; i < l; ++i ) {
366 widget = this.getByElement( wrappers.getItem( i ), true );
367 // Widget might not be found, because it could be a nested widget,
368 // which would be destroyed when destroying its parent.
369 if ( widget )
370 this.destroy( widget );
371 }
372
373 return;
374 }
375
376 for ( id in instances ) {
377 widget = instances[ id ];
378 this.destroy( widget, offline );
379 }
380 },
381
382 /**
383 * Finalizes a process of widget creation. This includes:
384 *
385 * * inserting widget element into editor,
386 * * marking widget instance as ready (see {@link CKEDITOR.plugins.widget#event-ready}),
387 * * focusing widget instance.
388 *
389 * This method is used by the default widget's command and is called
390 * after widget's dialog (if set) is closed. It may also be used in a
391 * customized process of widget creation and insertion.
392 *
393 * widget.once( 'edit', function() {
394 * // Finalize creation only of not ready widgets.
395 * if ( widget.isReady() )
396 * return;
397 *
398 * // Cancel edit event to prevent automatic widget insertion.
399 * evt.cancel();
400 *
401 * CustomDialog.open( widget.data, function saveCallback( savedData ) {
402 * // Cache the container, because widget may be destroyed while saving data,
403 * // if this process will require some deep transformations.
404 * var container = widget.wrapper.getParent();
405 *
406 * widget.setData( savedData );
407 *
408 * // Widget will be retrieved from container and inserted into editor.
409 * editor.widgets.finalizeCreation( container );
410 * } );
411 * } );
412 *
413 * @param {CKEDITOR.dom.element/CKEDITOR.dom.documentFragment} container The element
414 * or document fragment which contains widget wrapper. The container is used, so before
415 * finalizing creation the widget can be freely transformed (even destroyed and reinitialized).
416 */
417 finalizeCreation: function( container ) {
418 var wrapper = container.getFirst();
419 if ( wrapper && Widget.isDomWidgetWrapper( wrapper ) ) {
420 this.editor.insertElement( wrapper );
421
422 var widget = this.getByElement( wrapper );
423 // Fire postponed #ready event.
424 widget.ready = true;
425 widget.fire( 'ready' );
426 widget.focus();
427 }
428 },
429
430 /**
431 * Finds a widget instance which contains a given element. The element will be the {@link CKEDITOR.plugins.widget#wrapper wrapper}
432 * of the returned widget or a descendant of this {@link CKEDITOR.plugins.widget#wrapper wrapper}.
433 *
434 * editor.widgets.getByElement( someWidget.wrapper ); // -> someWidget
435 * editor.widgets.getByElement( someWidget.parts.caption ); // -> someWidget
436 *
437 * // Check wrapper only:
438 * editor.widgets.getByElement( someWidget.wrapper, true ); // -> someWidget
439 * editor.widgets.getByElement( someWidget.parts.caption, true ); // -> null
440 *
441 * @param {CKEDITOR.dom.element} element The element to be checked.
442 * @param {Boolean} [checkWrapperOnly] If set to `true`, the method will not check wrappers' descendants.
443 * @returns {CKEDITOR.plugins.widget} The widget instance or `null`.
444 */
445 getByElement: ( function() {
446 var validWrapperElements = { div: 1, span: 1 };
447 function getWidgetId( element ) {
448 return element.is( validWrapperElements ) && element.data( 'cke-widget-id' );
449 }
450
451 return function( element, checkWrapperOnly ) {
452 if ( !element )
453 return null;
454
455 var id = getWidgetId( element );
456
457 // There's no need to check element parents if element is a wrapper.
458 if ( !checkWrapperOnly && !id ) {
459 var limit = this.editor.editable();
460
461 // Try to find a closest ascendant which is a widget wrapper.
462 do {
463 element = element.getParent();
464 } while ( element && !element.equals( limit ) && !( id = getWidgetId( element ) ) );
465 }
466
467 return this.instances[ id ] || null;
468 };
469 } )(),
470
471 /**
472 * Initializes a widget on a given element if the widget has not been initialized on it yet.
473 *
474 * @param {CKEDITOR.dom.element} element The future widget element.
475 * @param {String/CKEDITOR.plugins.widget.definition} [widgetDef] Name of a widget or a widget definition.
476 * The widget definition should be previously registered by using the
477 * {@link CKEDITOR.plugins.widget.repository#add} method.
478 * @param [startupData] Widget startup data (has precedence over default one).
479 * @returns {CKEDITOR.plugins.widget} The widget instance or `null` if a widget could not be initialized on
480 * a given element.
481 */
482 initOn: function( element, widgetDef, startupData ) {
483 if ( !widgetDef )
484 widgetDef = this.registered[ element.data( 'widget' ) ];
485 else if ( typeof widgetDef == 'string' )
486 widgetDef = this.registered[ widgetDef ];
487
488 if ( !widgetDef )
489 return null;
490
491 // Wrap element if still wasn't wrapped (was added during runtime by method that skips dataProcessor).
492 var wrapper = this.wrapElement( element, widgetDef.name );
493
494 if ( wrapper ) {
495 // Check if widget wrapper is new (widget hasn't been initialized on it yet).
496 // This class will be removed by widget constructor to avoid locking snapshot twice.
497 if ( wrapper.hasClass( 'cke_widget_new' ) ) {
498 var widget = new Widget( this, this._.nextId++, element, widgetDef, startupData );
499
500 // Widget could be destroyed when initializing it.
501 if ( widget.isInited() ) {
502 this.instances[ widget.id ] = widget;
503
504 return widget;
505 } else {
506 return null;
507 }
508 }
509
510 // Widget already has been initialized, so try to get widget by element.
511 // Note - it may happen that other instance will returned than the one created above,
512 // if for example widget was destroyed and reinitialized.
513 return this.getByElement( element );
514 }
515
516 // No wrapper means that there's no widget for this element.
517 return null;
518 },
519
520 /**
521 * Initializes widgets on all elements which were wrapped by {@link #wrapElement} and
522 * have not been initialized yet.
523 *
524 * @param {CKEDITOR.dom.element} [container=editor.editable()] The container which will be checked for not
525 * initialized widgets. Defaults to editor's {@link CKEDITOR.editor#editable editable} element.
526 * @returns {CKEDITOR.plugins.widget[]} Array of widget instances which have been initialized.
527 * Note: Only first-level widgets are returned &mdash; without nested widgets.
528 */
529 initOnAll: function( container ) {
530 var newWidgets = ( container || this.editor.editable() ).find( '.cke_widget_new' ),
531 newInstances = [],
532 instance;
533
534 for ( var i = newWidgets.count(); i--; ) {
535 instance = this.initOn( newWidgets.getItem( i ).getFirst( Widget.isDomWidgetElement ) );
536 if ( instance )
537 newInstances.push( instance );
538 }
539
540 return newInstances;
541 },
542
543 /**
544 * Allows to listen to events on specific types of widgets, even if they are not created yet.
545 *
546 * Please note that this method inherits parameters from the {@link CKEDITOR.event#method-on} method with one
547 * extra parameter at the beginning which is the widget name.
548 *
549 * editor.widgets.onWidget( 'image', 'action', function( evt ) {
550 * // Event `action` occurs on `image` widget.
551 * } );
552 *
553 * @since 4.5
554 * @param {String} widgetName
555 * @param {String} eventName
556 * @param {Function} listenerFunction
557 * @param {Object} [scopeObj]
558 * @param {Object} [listenerData]
559 * @param {Number} [priority=10]
560 */
561 onWidget: function( widgetName ) {
562 var args = Array.prototype.slice.call( arguments );
563
564 args.shift();
565
566 for ( var i in this.instances ) {
567 var instance = this.instances[ i ];
568
569 if ( instance.name == widgetName ) {
570 instance.on.apply( instance, args );
571 }
572 }
573
574 this.on( 'instanceCreated', function( evt ) {
575 var widget = evt.data;
576
577 if ( widget.name == widgetName ) {
578 widget.on.apply( widget, args );
579 }
580 } );
581 },
582
583 /**
584 * Parses element classes string and returns an object
585 * whose keys contain class names. Skips all `cke_*` classes.
586 *
587 * This method is used by the {@link CKEDITOR.plugins.widget#getClasses} method and
588 * may be used when overriding that method.
589 *
590 * @since 4.4
591 * @param {String} classes String (value of `class` attribute).
592 * @returns {Object} Object containing classes or `null` if no classes found.
593 */
594 parseElementClasses: function( classes ) {
595 if ( !classes )
596 return null;
597
598 classes = CKEDITOR.tools.trim( classes ).split( /\s+/ );
599
600 var cl,
601 obj = {},
602 hasClasses = 0;
603
604 while ( ( cl = classes.pop() ) ) {
605 if ( cl.indexOf( 'cke_' ) == -1 )
606 obj[ cl ] = hasClasses = 1;
607 }
608
609 return hasClasses ? obj : null;
610 },
611
612 /**
613 * Wraps an element with a widget's non-editable container.
614 *
615 * If this method is called on an {@link CKEDITOR.htmlParser.element}, then it will
616 * also take care of fixing the DOM after wrapping (the wrapper may not be allowed in element's parent).
617 *
618 * @param {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} element The widget element to be wrapped.
619 * @param {String} [widgetName] The name of the widget definition. Defaults to element's `data-widget`
620 * attribute value.
621 * @returns {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} The wrapper element or `null` if
622 * the widget definition of this name is not registered.
623 */
624 wrapElement: function( element, widgetName ) {
625 var wrapper = null,
626 widgetDef,
627 isInline;
628
629 if ( element instanceof CKEDITOR.dom.element ) {
630 widgetName = widgetName || element.data( 'widget' );
631 widgetDef = this.registered[ widgetName ];
632
633 if ( !widgetDef )
634 return null;
635
636 // Do not wrap already wrapped element.
637 wrapper = element.getParent();
638 if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.data( 'cke-widget-wrapper' ) )
639 return wrapper;
640
641 // If attribute isn't already set (e.g. for pasted widget), set it.
642 if ( !element.hasAttribute( 'data-cke-widget-keep-attr' ) )
643 element.data( 'cke-widget-keep-attr', element.data( 'widget' ) ? 1 : 0 );
644
645 element.data( 'widget', widgetName );
646
647 isInline = isWidgetInline( widgetDef, element.getName() );
648
649 wrapper = new CKEDITOR.dom.element( isInline ? 'span' : 'div' );
650 wrapper.setAttributes( getWrapperAttributes( isInline, widgetName ) );
651
652 wrapper.data( 'cke-display-name', widgetDef.pathName ? widgetDef.pathName : element.getName() );
653
654 // Replace element unless it is a detached one.
655 if ( element.getParent( true ) )
656 wrapper.replace( element );
657 element.appendTo( wrapper );
658 }
659 else if ( element instanceof CKEDITOR.htmlParser.element ) {
660 widgetName = widgetName || element.attributes[ 'data-widget' ];
661 widgetDef = this.registered[ widgetName ];
662
663 if ( !widgetDef )
664 return null;
665
666 wrapper = element.parent;
667 if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.attributes[ 'data-cke-widget-wrapper' ] )
668 return wrapper;
669
670 // If attribute isn't already set (e.g. for pasted widget), set it.
671 if ( !( 'data-cke-widget-keep-attr' in element.attributes ) )
672 element.attributes[ 'data-cke-widget-keep-attr' ] = element.attributes[ 'data-widget' ] ? 1 : 0;
673 if ( widgetName )
674 element.attributes[ 'data-widget' ] = widgetName;
675
676 isInline = isWidgetInline( widgetDef, element.name );
677
678 wrapper = new CKEDITOR.htmlParser.element( isInline ? 'span' : 'div', getWrapperAttributes( isInline, widgetName ) );
679 wrapper.attributes[ 'data-cke-display-name' ] = widgetDef.pathName ? widgetDef.pathName : element.name;
680
681 var parent = element.parent,
682 index;
683
684 // Don't detach already detached element.
685 if ( parent ) {
686 index = element.getIndex();
687 element.remove();
688 }
689
690 wrapper.add( element );
691
692 // Insert wrapper fixing DOM (splitting parents if wrapper is not allowed inside them).
693 parent && insertElement( parent, index, wrapper );
694 }
695
696 return wrapper;
697 },
698
699 // Expose for tests.
700 _tests_createEditableFilter: createEditableFilter
701 };
702
703 CKEDITOR.event.implementOn( Repository.prototype );
704
705 /**
706 * An event fired when a widget instance is created, but before it is fully initialized.
707 *
708 * @event instanceCreated
709 * @param {CKEDITOR.plugins.widget} data The widget instance.
710 */
711
712 /**
713 * An event fired when a widget instance was destroyed.
714 *
715 * See also {@link CKEDITOR.plugins.widget#event-destroy}.
716 *
717 * @event instanceDestroyed
718 * @param {CKEDITOR.plugins.widget} data The widget instance.
719 */
720
721 /**
722 * An event fired to trigger the selection check.
723 *
724 * See the {@link #method-checkSelection} method.
725 *
726 * @event checkSelection
727 */
728
729 /**
730 * An event fired by the the {@link #method-checkWidgets} method.
731 *
732 * It can be canceled in order to stop the {@link #method-checkWidgets}
733 * method execution or the event listener can modify the method's options.
734 *
735 * @event checkWidgets
736 * @param [data]
737 * @param {Boolean} [data.initOnlyNew] Initialize widgets only on newly wrapped
738 * widget elements (those which still have the `cke_widget_new` class). When this option is
739 * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)
740 * will not be reinitialized. This makes the check faster.
741 * @param {Boolean} [data.focusInited] If only one widget is initialized by
742 * the method, it will be focused.
743 */
744
745
746 /**
747 * An instance of a widget. Together with {@link CKEDITOR.plugins.widget.repository} these
748 * two classes constitute the core of the Widget System.
749 *
750 * Note that neither the repository nor the widget instances can be created by using their constructors.
751 * A repository instance is automatically set up by the Widget plugin and is accessible under
752 * {@link CKEDITOR.editor#widgets}, while widget instances are created and destroyed by the repository.
753 *
754 * To create a widget, first you need to {@link CKEDITOR.plugins.widget.repository#add register} its
755 * {@link CKEDITOR.plugins.widget.definition definition}:
756 *
757 * editor.widgets.add( 'simplebox', {
758 * upcast: function( element ) {
759 * // Defines which elements will become widgets.
760 * if ( element.hasClass( 'simplebox' ) )
761 * return true;
762 * },
763 * init: function() {
764 * // ...
765 * }
766 * } );
767 *
768 * Once the widget definition is registered, widgets will be automatically
769 * created when loading data:
770 *
771 * editor.setData( '<div class="simplebox">foo</div>', function() {
772 * console.log( editor.widgets.instances ); // -> An object containing one instance.
773 * } );
774 *
775 * It is also possible to create instances during runtime by using a command
776 * (if a {@link CKEDITOR.plugins.widget.definition#template} property was defined):
777 *
778 * // You can execute an automatically defined command to
779 * // insert a new simplebox widget or edit the one currently focused.
780 * editor.execCommand( 'simplebox' );
781 *
782 * Note: Since CKEditor 4.5 widget's `startupData` can be passed as the command argument:
783 *
784 * editor.execCommand( 'simplebox', {
785 * startupData: {
786 * align: 'left'
787 * }
788 * } );
789 *
790 * A widget can also be created in a completely custom way:
791 *
792 * var element = editor.document.createElement( 'div' );
793 * editor.insertElement( element );
794 * var widget = editor.widgets.initOn( element, 'simplebox' );
795 *
796 * @since 4.3
797 * @class CKEDITOR.plugins.widget
798 * @mixins CKEDITOR.event
799 * @extends CKEDITOR.plugins.widget.definition
800 * @constructor Creates an instance of the widget class. Do not use it directly, but instead initialize widgets
801 * by using the {@link CKEDITOR.plugins.widget.repository#initOn} method or by the upcasting system.
802 * @param {CKEDITOR.plugins.widget.repository} widgetsRepo
803 * @param {Number} id Unique ID of this widget instance.
804 * @param {CKEDITOR.dom.element} element The widget element.
805 * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget's registered definition.
806 * @param [startupData] Initial widget data. This data object will overwrite the default data and
807 * the data loaded from the DOM.
808 */
809 function Widget( widgetsRepo, id, element, widgetDef, startupData ) {
810 var editor = widgetsRepo.editor;
811
812 // Extend this widget with widgetDef-specific methods and properties.
813 CKEDITOR.tools.extend( this, widgetDef, {
814 /**
815 * The editor instance.
816 *
817 * @readonly
818 * @property {CKEDITOR.editor}
819 */
820 editor: editor,
821
822 /**
823 * This widget's unique (per editor instance) ID.
824 *
825 * @readonly
826 * @property {Number}
827 */
828 id: id,
829
830 /**
831 * Whether this widget is an inline widget (based on an inline element unless
832 * forced otherwise by {@link CKEDITOR.plugins.widget.definition#inline}).
833 *
834 * **Note:** This option does not allow to turn a block element into an inline widget.
835 * However, it makes it possible to turn an inline element into a block widget or to
836 * force a correct type in case when automatic recognition fails.
837 *
838 * @readonly
839 * @property {Boolean}
840 */
841 inline: element.getParent().getName() == 'span',
842
843 /**
844 * The widget element &mdash; the element on which the widget was initialized.
845 *
846 * @readonly
847 * @property {CKEDITOR.dom.element} element
848 */
849 element: element,
850
851 /**
852 * Widget's data object.
853 *
854 * The data can only be set by using the {@link #setData} method.
855 * Changes made to the data fire the {@link #event-data} event.
856 *
857 * @readonly
858 */
859 data: CKEDITOR.tools.extend( {}, typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults ),
860
861 /**
862 * Indicates if a widget is data-ready. Set to `true` when data from all sources
863 * ({@link CKEDITOR.plugins.widget.definition#defaults}, set in the
864 * {@link #init} method, loaded from the widget's element and startup data coming from the constructor)
865 * are finally loaded. This is immediately followed by the first {@link #event-data}.
866 *
867 * @readonly
868 */
869 dataReady: false,
870
871 /**
872 * Whether a widget instance was initialized. This means that:
873 *
874 * * An instance was created,
875 * * Its properties were set,
876 * * The `init` method was executed.
877 *
878 * **Note**: The first {@link #event-data} event could not be fired yet which
879 * means that the widget's DOM has not been set up yet. Wait for the {@link #event-ready}
880 * event to be notified when a widget is fully initialized and ready.
881 *
882 * **Note**: Use the {@link #isInited} method to check whether a widget is initialized and
883 * has not been destroyed.
884 *
885 * @readonly
886 */
887 inited: false,
888
889 /**
890 * Whether a widget instance is ready. This means that the widget is {@link #inited} and
891 * that its DOM was finally set up.
892 *
893 * **Note:** Use the {@link #isReady} method to check whether a widget is ready and
894 * has not been destroyed.
895 *
896 * @readonly
897 */
898 ready: false,
899
900 // Revert what widgetDef could override (automatic #edit listener).
901 edit: Widget.prototype.edit,
902
903 /**
904 * The nested editable element which is currently focused.
905 *
906 * @readonly
907 * @property {CKEDITOR.plugins.widget.nestedEditable}
908 */
909 focusedEditable: null,
910
911 /**
912 * The widget definition from which this instance was created.
913 *
914 * @readonly
915 * @property {CKEDITOR.plugins.widget.definition} definition
916 */
917 definition: widgetDef,
918
919 /**
920 * Link to the widget repository which created this instance.
921 *
922 * @readonly
923 * @property {CKEDITOR.plugins.widget.repository} repository
924 */
925 repository: widgetsRepo,
926
927 draggable: widgetDef.draggable !== false,
928
929 // WAAARNING: Overwrite widgetDef's priv object, because otherwise violent unicorn's gonna visit you.
930 _: {
931 downcastFn: ( widgetDef.downcast && typeof widgetDef.downcast == 'string' ) ?
932 widgetDef.downcasts[ widgetDef.downcast ] : widgetDef.downcast
933 }
934 }, true );
935
936 /**
937 * An object of widget component elements.
938 *
939 * For every `partName => selector` pair in {@link CKEDITOR.plugins.widget.definition#parts},
940 * one `partName => element` pair is added to this object during the widget initialization.
941 *
942 * @readonly
943 * @property {Object} parts
944 */
945
946 /**
947 * The template which will be used to create a new widget element (when the widget's command is executed).
948 * It will be populated with {@link #defaults default values}.
949 *
950 * @readonly
951 * @property {CKEDITOR.template} template
952 */
953
954 /**
955 * The widget wrapper &mdash; a non-editable `div` or `span` element (depending on {@link #inline})
956 * which is a parent of the {@link #element} and widget compontents like the drag handler and the {@link #mask}.
957 * It is the outermost widget element.
958 *
959 * @readonly
960 * @property {CKEDITOR.dom.element} wrapper
961 */
962
963 widgetsRepo.fire( 'instanceCreated', this );
964
965 setupWidget( this, widgetDef );
966
967 this.init && this.init();
968
969 // Finally mark widget as inited.
970 this.inited = true;
971
972 setupWidgetData( this, startupData );
973
974 // If at some point (e.g. in #data listener) widget hasn't been destroyed
975 // and widget is already attached to document then fire #ready.
976 if ( this.isInited() && editor.editable().contains( this.wrapper ) ) {
977 this.ready = true;
978 this.fire( 'ready' );
979 }
980 }
981
982 Widget.prototype = {
983 /**
984 * Adds a class to the widget element. This method is used by
985 * the {@link #applyStyle} method and should be overridden by widgets
986 * which should handle classes differently (e.g. add them to other elements).
987 *
988 * Since 4.6.0 this method also adds a corresponding class prefixed with {@link #WRAPPER_CLASS_PREFIX}
989 * to the widget wrapper element.
990 *
991 * **Note**: This method should not be used directly. Use the {@link #setData} method to
992 * set the `classes` property. Read more in the {@link #setData} documentation.
993 *
994 * See also: {@link #removeClass}, {@link #hasClass}, {@link #getClasses}.
995 *
996 * @since 4.4
997 * @param {String} className The class name to be added.
998 */
999 addClass: function( className ) {
1000 this.element.addClass( className );
1001 this.wrapper.addClass( Widget.WRAPPER_CLASS_PREFIX + className );
1002 },
1003
1004 /**
1005 * Applies the specified style to the widget. It is highly recommended to use the
1006 * {@link CKEDITOR.editor#applyStyle} or {@link CKEDITOR.style#apply} methods instead of
1007 * using this method directly, because unlike editor's and style's methods, this one
1008 * does not perform any checks.
1009 *
1010 * By default this method handles only classes defined in the style. It clones existing
1011 * classes which are stored in the {@link #property-data widget data}'s `classes` property,
1012 * adds new classes, and calls the {@link #setData} method if at least one new class was added.
1013 * Then, using the {@link #event-data} event listener widget applies modifications passing
1014 * new classes to the {@link #addClass} method.
1015 *
1016 * If you need to handle classes differently than in the default way, you can override the
1017 * {@link #addClass} and related methods. You can also handle other style properties than `classes`
1018 * by overriding this method.
1019 *
1020 * See also: {@link #checkStyleActive}, {@link #removeStyle}.
1021 *
1022 * @since 4.4
1023 * @param {CKEDITOR.style} style The custom widget style to be applied.
1024 */
1025 applyStyle: function( style ) {
1026 applyRemoveStyle( this, style, 1 );
1027 },
1028
1029 /**
1030 * Checks if the specified style is applied to this widget. It is highly recommended to use the
1031 * {@link CKEDITOR.style#checkActive} method instead of using this method directly,
1032 * because unlike style's method, this one does not perform any checks.
1033 *
1034 * By default this method handles only classes defined in the style and passes
1035 * them to the {@link #hasClass} method. You can override these methods to handle classes
1036 * differently or to handle more of the style properties.
1037 *
1038 * See also: {@link #applyStyle}, {@link #removeStyle}.
1039 *
1040 * @since 4.4
1041 * @param {CKEDITOR.style} style The custom widget style to be checked.
1042 * @returns {Boolean} Whether the style is applied to this widget.
1043 */
1044 checkStyleActive: function( style ) {
1045 var classes = getStyleClasses( style ),
1046 cl;
1047
1048 if ( !classes )
1049 return false;
1050
1051 while ( ( cl = classes.pop() ) ) {
1052 if ( !this.hasClass( cl ) )
1053 return false;
1054 }
1055 return true;
1056 },
1057
1058 /**
1059 * Destroys this widget instance.
1060 *
1061 * Use {@link CKEDITOR.plugins.widget.repository#destroy} when possible instead of this method.
1062 *
1063 * This method fires the {#event-destroy} event.
1064 *
1065 * @param {Boolean} [offline] Whether a widget is offline (detached from the DOM tree) &mdash;
1066 * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
1067 */
1068 destroy: function( offline ) {
1069 this.fire( 'destroy' );
1070
1071 if ( this.editables ) {
1072 for ( var name in this.editables )
1073 this.destroyEditable( name, offline );
1074 }
1075
1076 if ( !offline ) {
1077 if ( this.element.data( 'cke-widget-keep-attr' ) == '0' )
1078 this.element.removeAttribute( 'data-widget' );
1079 this.element.removeAttributes( [ 'data-cke-widget-data', 'data-cke-widget-keep-attr' ] );
1080 this.element.removeClass( 'cke_widget_element' );
1081 this.element.replace( this.wrapper );
1082 }
1083
1084 this.wrapper = null;
1085 },
1086
1087 /**
1088 * Destroys a nested editable and all nested widgets.
1089 *
1090 * @param {String} editableName Nested editable name.
1091 * @param {Boolean} [offline] See {@link #method-destroy} method.
1092 */
1093 destroyEditable: function( editableName, offline ) {
1094 var editable = this.editables[ editableName ];
1095
1096 editable.removeListener( 'focus', onEditableFocus );
1097 editable.removeListener( 'blur', onEditableBlur );
1098 this.editor.focusManager.remove( editable );
1099
1100 if ( !offline ) {
1101 this.repository.destroyAll( false, editable );
1102 editable.removeClass( 'cke_widget_editable' );
1103 editable.removeClass( 'cke_widget_editable_focused' );
1104 editable.removeAttributes( [ 'contenteditable', 'data-cke-widget-editable', 'data-cke-enter-mode' ] );
1105 }
1106
1107 delete this.editables[ editableName ];
1108 },
1109
1110 /**
1111 * Starts widget editing.
1112 *
1113 * This method fires the {@link CKEDITOR.plugins.widget#event-edit} event
1114 * which may be canceled in order to prevent it from opening a dialog window.
1115 *
1116 * The dialog window name is obtained from the event's data `dialog` property or
1117 * from {@link CKEDITOR.plugins.widget.definition#dialog}.
1118 *
1119 * @returns {Boolean} Returns `true` if a dialog window was opened.
1120 */
1121 edit: function() {
1122 var evtData = { dialog: this.dialog },
1123 that = this;
1124
1125 // Edit event was blocked or there's no dialog to be automatically opened.
1126 if ( this.fire( 'edit', evtData ) === false || !evtData.dialog )
1127 return false;
1128
1129 this.editor.openDialog( evtData.dialog, function( dialog ) {
1130 var showListener,
1131 okListener;
1132
1133 // Allow to add a custom dialog handler.
1134 if ( that.fire( 'dialog', dialog ) === false )
1135 return;
1136
1137 showListener = dialog.on( 'show', function() {
1138 dialog.setupContent( that );
1139 } );
1140
1141 okListener = dialog.on( 'ok', function() {
1142 // Commit dialog's fields, but prevent from
1143 // firing data event for every field. Fire only one,
1144 // bulk event at the end.
1145 var dataChanged,
1146 dataListener = that.on( 'data', function( evt ) {
1147 dataChanged = 1;
1148 evt.cancel();
1149 }, null, null, 0 );
1150
1151 // Create snapshot preceeding snapshot with changed widget...
1152 // TODO it should not be required, but it is and I found similar
1153 // code in dialog#ok listener in dialog/plugin.js.
1154 that.editor.fire( 'saveSnapshot' );
1155 dialog.commitContent( that );
1156
1157 dataListener.removeListener();
1158 if ( dataChanged ) {
1159 that.fire( 'data', that.data );
1160 that.editor.fire( 'saveSnapshot' );
1161 }
1162 } );
1163
1164 dialog.once( 'hide', function() {
1165 showListener.removeListener();
1166 okListener.removeListener();
1167 } );
1168 } );
1169
1170 return true;
1171 },
1172
1173 /**
1174 * Returns widget element classes parsed to an object. This method
1175 * is used to populate the `classes` property of widget's {@link #property-data}.
1176 *
1177 * This method reuses {@link CKEDITOR.plugins.widget.repository#parseElementClasses}.
1178 * It should be overriden if a widget should handle classes differently (e.g. on other elements).
1179 *
1180 * See also: {@link #removeClass}, {@link #addClass}, {@link #hasClass}.
1181 *
1182 * @since 4.4
1183 * @returns {Object}
1184 */
1185 getClasses: function() {
1186 return this.repository.parseElementClasses( this.element.getAttribute( 'class' ) );
1187 },
1188
1189 /**
1190 * Checks if the widget element has specified class. This method is used by
1191 * the {@link #checkStyleActive} method and should be overriden by widgets
1192 * which should handle classes differently (e.g. on other elements).
1193 *
1194 * See also: {@link #removeClass}, {@link #addClass}, {@link #getClasses}.
1195 *
1196 * @since 4.4
1197 * @param {String} className The class to be checked.
1198 * @param {Boolean} Whether a widget has specified class.
1199 */
1200 hasClass: function( className ) {
1201 return this.element.hasClass( className );
1202 },
1203
1204 /**
1205 * Initializes a nested editable.
1206 *
1207 * **Note**: Only elements from {@link CKEDITOR.dtd#$editable} may become editables.
1208 *
1209 * @param {String} editableName The nested editable name.
1210 * @param {CKEDITOR.plugins.widget.nestedEditable.definition} definition The definition of the nested editable.
1211 * @returns {Boolean} Whether an editable was successfully initialized.
1212 */
1213 initEditable: function( editableName, definition ) {
1214 // Don't fetch just first element which matched selector but look for a correct one. (#13334)
1215 var editable = this._findOneNotNested( definition.selector );
1216
1217 if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) {
1218 editable = new NestedEditable( this.editor, editable, {
1219 filter: createEditableFilter.call( this.repository, this.name, editableName, definition )
1220 } );
1221 this.editables[ editableName ] = editable;
1222
1223 editable.setAttributes( {
1224 contenteditable: 'true',
1225 'data-cke-widget-editable': editableName,
1226 'data-cke-enter-mode': editable.enterMode
1227 } );
1228
1229 if ( editable.filter )
1230 editable.data( 'cke-filter', editable.filter.id );
1231
1232 editable.addClass( 'cke_widget_editable' );
1233 // This class may be left when d&ding widget which
1234 // had focused editable. Clean this class here, not in
1235 // cleanUpWidgetElement for performance and code size reasons.
1236 editable.removeClass( 'cke_widget_editable_focused' );
1237
1238 if ( definition.pathName )
1239 editable.data( 'cke-display-name', definition.pathName );
1240
1241 this.editor.focusManager.add( editable );
1242 editable.on( 'focus', onEditableFocus, this );
1243 CKEDITOR.env.ie && editable.on( 'blur', onEditableBlur, this );
1244
1245 // Finally, process editable's data. This data wasn't processed when loading
1246 // editor's data, becuase they need to be processed separately, with its own filters and settings.
1247 editable._.initialSetData = true;
1248 editable.setData( editable.getHtml() );
1249
1250 return true;
1251 }
1252
1253 return false;
1254 },
1255
1256 /**
1257 * Looks inside wrapper element to find a node that
1258 * matches given selector and is not nested in other widget. (#13334)
1259 *
1260 * @since 4.5
1261 * @private
1262 * @param {String} selector Selector to match.
1263 * @returns {CKEDITOR.dom.element} Matched element or `null` if a node has not been found.
1264 */
1265 _findOneNotNested: function( selector ) {
1266 var matchedElements = this.wrapper.find( selector ),
1267 match,
1268 closestWrapper;
1269
1270 for ( var i = 0; i < matchedElements.count(); i++ ) {
1271 match = matchedElements.getItem( i );
1272 closestWrapper = match.getAscendant( Widget.isDomWidgetWrapper );
1273
1274 // The closest ascendant-wrapper of this match defines to which widget
1275 // this match belongs. If the ascendant is this widget's wrapper
1276 // it means that the match is not nested in other widget.
1277 if ( this.wrapper.equals( closestWrapper ) ) {
1278 return match;
1279 }
1280 }
1281
1282 return null;
1283 },
1284
1285 /**
1286 * Checks if a widget has already been initialized and has not been destroyed yet.
1287 *
1288 * See {@link #inited} for more details.
1289 *
1290 * @returns {Boolean}
1291 */
1292 isInited: function() {
1293 return !!( this.wrapper && this.inited );
1294 },
1295
1296 /**
1297 * Checks if a widget is ready and has not been destroyed yet.
1298 *
1299 * See {@link #property-ready} for more details.
1300 *
1301 * @returns {Boolean}
1302 */
1303 isReady: function() {
1304 return this.isInited() && this.ready;
1305 },
1306
1307 /**
1308 * Focuses a widget by selecting it.
1309 */
1310 focus: function() {
1311 var sel = this.editor.getSelection();
1312
1313 // Fake the selection before focusing editor, to avoid unpreventable viewports scrolling
1314 // on Webkit/Blink/IE which is done because there's no selection or selection was somewhere else than widget.
1315 if ( sel ) {
1316 var isDirty = this.editor.checkDirty();
1317
1318 sel.fake( this.wrapper );
1319
1320 !isDirty && this.editor.resetDirty();
1321 }
1322
1323 // Always focus editor (not only when focusManger.hasFocus is false) (because of #10483).
1324 this.editor.focus();
1325 },
1326
1327 /**
1328 * Removes a class from the widget element. This method is used by
1329 * the {@link #removeStyle} method and should be overriden by widgets
1330 * which should handle classes differently (e.g. on other elements).
1331 *
1332 * **Note**: This method should not be used directly. Use the {@link #setData} method to
1333 * set the `classes` property. Read more in the {@link #setData} documentation.
1334 *
1335 * See also: {@link #hasClass}, {@link #addClass}.
1336 *
1337 * @since 4.4
1338 * @param {String} className The class to be removed.
1339 */
1340 removeClass: function( className ) {
1341 this.element.removeClass( className );
1342 this.wrapper.removeClass( Widget.WRAPPER_CLASS_PREFIX + className );
1343 },
1344
1345 /**
1346 * Removes the specified style from the widget. It is highly recommended to use the
1347 * {@link CKEDITOR.editor#removeStyle} or {@link CKEDITOR.style#remove} methods instead of
1348 * using this method directly, because unlike editor's and style's methods, this one
1349 * does not perform any checks.
1350 *
1351 * Read more about how applying/removing styles works in the {@link #applyStyle} method documentation.
1352 *
1353 * See also {@link #checkStyleActive}, {@link #applyStyle}, {@link #getClasses}.
1354 *
1355 * @since 4.4
1356 * @param {CKEDITOR.style} style The custom widget style to be removed.
1357 */
1358 removeStyle: function( style ) {
1359 applyRemoveStyle( this, style, 0 );
1360 },
1361
1362 /**
1363 * Sets widget value(s) in the {@link #property-data} object.
1364 * If the given value(s) modifies current ones, the {@link #event-data} event is fired.
1365 *
1366 * this.setData( 'align', 'left' );
1367 * this.data.align; // -> 'left'
1368 *
1369 * this.setData( { align: 'right', opened: false } );
1370 * this.data.align; // -> 'right'
1371 * this.data.opened; // -> false
1372 *
1373 * Set values are stored in {@link #element}'s attribute (`data-cke-widget-data`),
1374 * in a JSON string, therefore {@link #property-data} should contain
1375 * only serializable data.
1376 *
1377 * **Note:** A special data property, `classes`, exists. It contains an object with
1378 * classes which were returned by the {@link #getClasses} method during the widget initialization.
1379 * This property is then used by the {@link #applyStyle} and {@link #removeStyle} methods.
1380 * When it is changed (the reference to object must be changed!), the widget updates its classes by
1381 * using the {@link #addClass} and {@link #removeClass} methods.
1382 *
1383 * // Adding a new class.
1384 * var classes = CKEDITOR.tools.clone( widget.data.classes );
1385 * classes.newClass = 1;
1386 * widget.setData( 'classes', classes );
1387 *
1388 * // Removing a class.
1389 * var classes = CKEDITOR.tools.clone( widget.data.classes );
1390 * delete classes.newClass;
1391 * widget.setData( 'classes', classes );
1392 *
1393 * @param {String/Object} keyOrData
1394 * @param {Object} value
1395 * @chainable
1396 */
1397 setData: function( key, value ) {
1398 var data = this.data,
1399 modified = 0;
1400
1401 if ( typeof key == 'string' ) {
1402 if ( data[ key ] !== value ) {
1403 data[ key ] = value;
1404 modified = 1;
1405 }
1406 }
1407 else {
1408 var newData = key;
1409
1410 for ( key in newData ) {
1411 if ( data[ key ] !== newData[ key ] ) {
1412 modified = 1;
1413 data[ key ] = newData[ key ];
1414 }
1415 }
1416 }
1417
1418 // Block firing data event and overwriting data element before setupWidgetData is executed.
1419 if ( modified && this.dataReady ) {
1420 writeDataToElement( this );
1421 this.fire( 'data', data );
1422 }
1423
1424 return this;
1425 },
1426
1427 /**
1428 * Changes the widget's focus state. This method is executed automatically after
1429 * a widget was focused by the {@link #method-focus} method or the selection was moved
1430 * out of the widget.
1431 *
1432 * This is a low-level method which is not integrated with e.g. the undo manager.
1433 * Use the {@link #method-focus} method instead.
1434 *
1435 * @param {Boolean} selected Whether to select or deselect this widget.
1436 * @chainable
1437 */
1438 setFocused: function( focused ) {
1439 this.wrapper[ focused ? 'addClass' : 'removeClass' ]( 'cke_widget_focused' );
1440 this.fire( focused ? 'focus' : 'blur' );
1441 return this;
1442 },
1443
1444 /**
1445 * Changes the widget's select state. This method is executed automatically after
1446 * a widget was selected by the {@link #method-focus} method or the selection
1447 * was moved out of the widget.
1448 *
1449 * This is a low-level method which is not integrated with e.g. the undo manager.
1450 * Use the {@link #method-focus} method instead or simply change the selection.
1451 *
1452 * @param {Boolean} selected Whether to select or deselect this widget.
1453 * @chainable
1454 */
1455 setSelected: function( selected ) {
1456 this.wrapper[ selected ? 'addClass' : 'removeClass' ]( 'cke_widget_selected' );
1457 this.fire( selected ? 'select' : 'deselect' );
1458 return this;
1459 },
1460
1461 /**
1462 * Repositions drag handler according to the widget's element position. Should be called from events, like mouseover.
1463 */
1464 updateDragHandlerPosition: function() {
1465 var editor = this.editor,
1466 domElement = this.element.$,
1467 oldPos = this._.dragHandlerOffset,
1468 newPos = {
1469 x: domElement.offsetLeft,
1470 y: domElement.offsetTop - DRAG_HANDLER_SIZE
1471 };
1472
1473 if ( oldPos && newPos.x == oldPos.x && newPos.y == oldPos.y )
1474 return;
1475
1476 // We need to make sure that dirty state is not changed (#11487).
1477 var initialDirty = editor.checkDirty();
1478
1479 editor.fire( 'lockSnapshot' );
1480 this.dragHandlerContainer.setStyles( {
1481 top: newPos.y + 'px',
1482 left: newPos.x + 'px',
1483 display: 'block'
1484 } );
1485 editor.fire( 'unlockSnapshot' );
1486 !initialDirty && editor.resetDirty();
1487
1488 this._.dragHandlerOffset = newPos;
1489 }
1490 };
1491
1492 CKEDITOR.event.implementOn( Widget.prototype );
1493
1494 /**
1495 * Gets the {@link #isDomNestedEditable nested editable}
1496 * (returned as a {@link CKEDITOR.dom.element}, not as a {@link CKEDITOR.plugins.widget.nestedEditable})
1497 * closest to the `node` or the `node` if it is a nested editable itself.
1498 *
1499 * @since 4.5
1500 * @static
1501 * @param {CKEDITOR.dom.element} guard Stop ancestor search on this node (usually editor's editable).
1502 * @param {CKEDITOR.dom.node} node Start the search from this node.
1503 * @returns {CKEDITOR.dom.element/null} Element or `null` if not found.
1504 */
1505 Widget.getNestedEditable = function( guard, node ) {
1506 if ( !node || node.equals( guard ) )
1507 return null;
1508
1509 if ( Widget.isDomNestedEditable( node ) )
1510 return node;
1511
1512 return Widget.getNestedEditable( guard, node.getParent() );
1513 };
1514
1515 /**
1516 * Checks whether the `node` is a widget's drag handle element.
1517 *
1518 * @since 4.5
1519 * @static
1520 * @param {CKEDITOR.dom.node} node
1521 * @returns {Boolean}
1522 */
1523 Widget.isDomDragHandler = function( node ) {
1524 return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-drag-handler' );
1525 };
1526
1527 /**
1528 * Checks whether the `node` is a container of the widget's drag handle element.
1529 *
1530 * @since 4.5
1531 * @static
1532 * @param {CKEDITOR.dom.node} node
1533 * @returns {Boolean}
1534 */
1535 Widget.isDomDragHandlerContainer = function( node ) {
1536 return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_widget_drag_handler_container' );
1537 };
1538
1539 /**
1540 * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#editables nested editable}.
1541 * Note that this function only checks whether it is the right element, not whether
1542 * the passed `node` is an instance of {@link CKEDITOR.plugins.widget.nestedEditable}.
1543 *
1544 * @since 4.5
1545 * @static
1546 * @param {CKEDITOR.dom.node} node
1547 * @returns {Boolean}
1548 */
1549 Widget.isDomNestedEditable = function( node ) {
1550 return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-editable' );
1551 };
1552
1553 /**
1554 * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}.
1555 *
1556 * @since 4.5
1557 * @static
1558 * @param {CKEDITOR.dom.node} node
1559 * @returns {Boolean}
1560 */
1561 Widget.isDomWidgetElement = function( node ) {
1562 return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-widget' );
1563 };
1564
1565 /**
1566 * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}.
1567 *
1568 * @since 4.5
1569 * @static
1570 * @param {CKEDITOR.dom.element} node
1571 * @returns {Boolean}
1572 */
1573 Widget.isDomWidgetWrapper = function( node ) {
1574 return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-wrapper' );
1575 };
1576
1577 /**
1578 * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}.
1579 *
1580 * @since 4.5
1581 * @static
1582 * @param {CKEDITOR.htmlParser.node} node
1583 * @returns {Boolean}
1584 */
1585 Widget.isParserWidgetElement = function( node ) {
1586 return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-widget' ];
1587 };
1588
1589 /**
1590 * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}.
1591 *
1592 * @since 4.5
1593 * @static
1594 * @param {CKEDITOR.htmlParser.element} node
1595 * @returns {Boolean}
1596 */
1597 Widget.isParserWidgetWrapper = function( node ) {
1598 return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-cke-widget-wrapper' ];
1599 };
1600
1601 /**
1602 * Prefix added to wrapper classes. Each class added to the widget element by the {@link #addClass}
1603 * method will also be added to the wrapper prefixed with it.
1604 *
1605 * @since 4.6.0
1606 * @static
1607 * @readonly
1608 * @property {String} [='cke_widget_wrapper_']
1609 */
1610 Widget.WRAPPER_CLASS_PREFIX = 'cke_widget_wrapper_';
1611
1612 /**
1613 * An event fired when a widget is ready (fully initialized). This event is fired after:
1614 *
1615 * * {@link #init} is called,
1616 * * The first {@link #event-data} event is fired,
1617 * * A widget is attached to the document.
1618 *
1619 * Therefore, in case of widget creation with a command which opens a dialog window, this event
1620 * will be delayed after the dialog window is closed and the widget is finally inserted into the document.
1621 *
1622 * **Note**: If your widget does not use automatic dialog window binding (i.e. you open the dialog window manually)
1623 * or another situation in which the widget wrapper is not attached to document at the time when it is
1624 * initialized occurs, you need to take care of firing {@link #event-ready} yourself.
1625 *
1626 * See also {@link #property-ready} and {@link #property-inited} properties, and
1627 * {@link #isReady} and {@link #isInited} methods.
1628 *
1629 * @event ready
1630 */
1631
1632 /**
1633 * An event fired when a widget is about to be destroyed, but before it is
1634 * fully torn down.
1635 *
1636 * @event destroy
1637 */
1638
1639 /**
1640 * An event fired when a widget is focused.
1641 *
1642 * Widget can be focused by executing {@link #method-focus}.
1643 *
1644 * @event focus
1645 */
1646
1647 /**
1648 * An event fired when a widget is blurred.
1649 *
1650 * @event blur
1651 */
1652
1653 /**
1654 * An event fired when a widget is selected.
1655 *
1656 * @event select
1657 */
1658
1659 /**
1660 * An event fired when a widget is deselected.
1661 *
1662 * @event deselect
1663 */
1664
1665 /**
1666 * An event fired by the {@link #method-edit} method. It can be canceled
1667 * in order to stop the default action (opening a dialog window and/or
1668 * {@link CKEDITOR.plugins.widget.repository#finalizeCreation finalizing widget creation}).
1669 *
1670 * @event edit
1671 * @param data
1672 * @param {String} data.dialog Defaults to {@link CKEDITOR.plugins.widget.definition#dialog}
1673 * and can be changed or set by the listener.
1674 */
1675
1676 /**
1677 * An event fired when a dialog window for widget editing is opened.
1678 * This event can be canceled in order to handle the editing dialog in a custom manner.
1679 *
1680 * @event dialog
1681 * @param {CKEDITOR.dialog} data The opened dialog window instance.
1682 */
1683
1684 /**
1685 * An event fired when a key is pressed on a focused widget.
1686 * This event is forwarded from the {@link CKEDITOR.editor#key} event and
1687 * has the ability to block editor keystrokes if it is canceled.
1688 *
1689 * @event key
1690 * @param data
1691 * @param {Number} data.keyCode A number representing the key code (or combination).
1692 */
1693
1694 /**
1695 * An event fired when a widget is double clicked.
1696 *
1697 * **Note:** If a default editing action is executed on double click (i.e. a widget has a
1698 * {@link CKEDITOR.plugins.widget.definition#dialog dialog} defined and the {@link #event-doubleclick} event was not
1699 * canceled), this event will be automatically canceled, so a listener added with the default priority (10)
1700 * will not be executed. Use a listener with low priority (e.g. 5) to be sure that it will be executed.
1701 *
1702 * widget.on( 'doubleclick', function( evt ) {
1703 * console.log( 'widget#doubleclick' );
1704 * }, null, null, 5 );
1705 *
1706 * If your widget handles double click in a special way (so the default editing action is not executed),
1707 * make sure you cancel this event, because otherwise it will be propagated to {@link CKEDITOR.editor#doubleclick}
1708 * and another feature may step in (e.g. a Link dialog window may be opened if your widget was inside a link).
1709 *
1710 * @event doubleclick
1711 * @param data
1712 * @param {CKEDITOR.dom.element} data.element The double-clicked element.
1713 */
1714
1715 /**
1716 * An event fired when the context menu is opened for a widget.
1717 *
1718 * @event contextMenu
1719 * @param data The object containing context menu options to be added
1720 * for this widget. See {@link CKEDITOR.plugins.contextMenu#addListener}.
1721 */
1722
1723 /**
1724 * An event fired when the widget data changed. See the {@link #setData} method and the {@link #property-data} property.
1725 *
1726 * @event data
1727 */
1728
1729
1730
1731 /**
1732 * The wrapper class for editable elements inside widgets.
1733 *
1734 * Do not use directly. Use {@link CKEDITOR.plugins.widget.definition#editables} or
1735 * {@link CKEDITOR.plugins.widget#initEditable}.
1736 *
1737 * @class CKEDITOR.plugins.widget.nestedEditable
1738 * @extends CKEDITOR.dom.element
1739 * @constructor
1740 * @param {CKEDITOR.editor} editor
1741 * @param {CKEDITOR.dom.element} element
1742 * @param config
1743 * @param {CKEDITOR.filter} [config.filter]
1744 */
1745 function NestedEditable( editor, element, config ) {
1746 // Call the base constructor.
1747 CKEDITOR.dom.element.call( this, element.$ );
1748 this.editor = editor;
1749 this._ = {};
1750 var filter = this.filter = config.filter;
1751
1752 // If blockless editable - always use BR mode.
1753 if ( !CKEDITOR.dtd[ this.getName() ].p )
1754 this.enterMode = this.shiftEnterMode = CKEDITOR.ENTER_BR;
1755 else {
1756 this.enterMode = filter ? filter.getAllowedEnterMode( editor.enterMode ) : editor.enterMode;
1757 this.shiftEnterMode = filter ? filter.getAllowedEnterMode( editor.shiftEnterMode, true ) : editor.shiftEnterMode;
1758 }
1759 }
1760
1761 NestedEditable.prototype = CKEDITOR.tools.extend( CKEDITOR.tools.prototypedCopy( CKEDITOR.dom.element.prototype ), {
1762 /**
1763 * Sets the editable data. The data will be passed through the {@link CKEDITOR.editor#dataProcessor}
1764 * and the {@link CKEDITOR.editor#filter}. This ensures that the data was filtered and prepared to be
1765 * edited like the {@link CKEDITOR.editor#method-setData editor data}.
1766 *
1767 * Before content is changed, all nested widgets are destroyed. Afterwards, after new content is loaded,
1768 * all nested widgets are initialized.
1769 *
1770 * @param {String} data
1771 */
1772 setData: function( data ) {
1773 // For performance reasons don't call destroyAll when initializing a nested editable,
1774 // because there are no widgets inside.
1775 if ( !this._.initialSetData ) {
1776 // Destroy all nested widgets before setting data.
1777 this.editor.widgets.destroyAll( false, this );
1778 }
1779 this._.initialSetData = false;
1780
1781 data = this.editor.dataProcessor.toHtml( data, {
1782 context: this.getName(),
1783 filter: this.filter,
1784 enterMode: this.enterMode
1785 } );
1786 this.setHtml( data );
1787
1788 this.editor.widgets.initOnAll( this );
1789 },
1790
1791 /**
1792 * Gets the editable data. Like {@link #setData}, this method will process and filter the data.
1793 *
1794 * @returns {String}
1795 */
1796 getData: function() {
1797 return this.editor.dataProcessor.toDataFormat( this.getHtml(), {
1798 context: this.getName(),
1799 filter: this.filter,
1800 enterMode: this.enterMode
1801 } );
1802 }
1803 } );
1804
1805 /**
1806 * The editor instance.
1807 *
1808 * @readonly
1809 * @property {CKEDITOR.editor} editor
1810 */
1811
1812 /**
1813 * The filter instance if allowed content rules were defined.
1814 *
1815 * @readonly
1816 * @property {CKEDITOR.filter} filter
1817 */
1818
1819 /**
1820 * The enter mode active in this editable.
1821 * It is determined from editable's name (whether it is a blockless editable),
1822 * its allowed content rules (if defined) and the default editor's mode.
1823 *
1824 * @readonly
1825 * @property {Number} enterMode
1826 */
1827
1828 /**
1829 * The shift enter move active in this editable.
1830 *
1831 * @readonly
1832 * @property {Number} shiftEnterMode
1833 */
1834
1835
1836 //
1837 // REPOSITORY helpers -----------------------------------------------------
1838 //
1839
1840 function addWidgetButtons( editor ) {
1841 var widgets = editor.widgets.registered,
1842 widget,
1843 widgetName,
1844 widgetButton;
1845
1846 for ( widgetName in widgets ) {
1847 widget = widgets[ widgetName ];
1848
1849 // Create button if defined.
1850 widgetButton = widget.button;
1851 if ( widgetButton && editor.ui.addButton ) {
1852 editor.ui.addButton( CKEDITOR.tools.capitalize( widget.name, true ), {
1853 label: widgetButton,
1854 command: widget.name,
1855 toolbar: 'insert,10'
1856 } );
1857 }
1858 }
1859 }
1860
1861 // Create a command creating and editing widget.
1862 //
1863 // @param editor
1864 // @param {CKEDITOR.plugins.widget.definition} widgetDef
1865 function addWidgetCommand( editor, widgetDef ) {
1866 editor.addCommand( widgetDef.name, {
1867 exec: function( editor, commandData ) {
1868 var focused = editor.widgets.focused;
1869 // If a widget of the same type is focused, start editing.
1870 if ( focused && focused.name == widgetDef.name )
1871 focused.edit();
1872 // Otherwise...
1873 // ... use insert method is was defined.
1874 else if ( widgetDef.insert )
1875 widgetDef.insert();
1876 // ... or create a brand-new widget from template.
1877 else if ( widgetDef.template ) {
1878 var defaults = typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults,
1879 element = CKEDITOR.dom.element.createFromHtml( widgetDef.template.output( defaults ) ),
1880 instance,
1881 wrapper = editor.widgets.wrapElement( element, widgetDef.name ),
1882 temp = new CKEDITOR.dom.documentFragment( wrapper.getDocument() );
1883
1884 // Append wrapper to a temporary document. This will unify the environment
1885 // in which #data listeners work when creating and editing widget.
1886 temp.append( wrapper );
1887 instance = editor.widgets.initOn( element, widgetDef, commandData && commandData.startupData );
1888
1889 // Instance could be destroyed during initialization.
1890 // In this case finalize creation if some new widget
1891 // was left in temporary document fragment.
1892 if ( !instance ) {
1893 finalizeCreation();
1894 return;
1895 }
1896
1897 // Listen on edit to finalize widget insertion.
1898 //
1899 // * If dialog was set, then insert widget after dialog was successfully saved or destroy this
1900 // temporary instance.
1901 // * If dialog wasn't set and edit wasn't canceled, insert widget.
1902 var editListener = instance.once( 'edit', function( evt ) {
1903 if ( evt.data.dialog ) {
1904 instance.once( 'dialog', function( evt ) {
1905 var dialog = evt.data,
1906 okListener,
1907 cancelListener;
1908
1909 // Finalize creation AFTER (20) new data was set.
1910 okListener = dialog.once( 'ok', finalizeCreation, null, null, 20 );
1911
1912 cancelListener = dialog.once( 'cancel', function( evt ) {
1913 if ( !( evt.data && evt.data.hide === false ) ) {
1914 editor.widgets.destroy( instance, true );
1915 }
1916 } );
1917
1918 dialog.once( 'hide', function() {
1919 okListener.removeListener();
1920 cancelListener.removeListener();
1921 } );
1922 } );
1923 } else {
1924 // Dialog hasn't been set, so insert widget now.
1925 finalizeCreation();
1926 }
1927 }, null, null, 999 );
1928
1929 instance.edit();
1930
1931 // Remove listener in case someone canceled it before this
1932 // listener was executed.
1933 editListener.removeListener();
1934 }
1935
1936 function finalizeCreation() {
1937 editor.widgets.finalizeCreation( temp );
1938 }
1939 },
1940
1941 allowedContent: widgetDef.allowedContent,
1942 requiredContent: widgetDef.requiredContent,
1943 contentForms: widgetDef.contentForms,
1944 contentTransformations: widgetDef.contentTransformations
1945 } );
1946 }
1947
1948 function addWidgetProcessors( widgetsRepo, widgetDef ) {
1949 var upcast = widgetDef.upcast,
1950 upcasts,
1951 priority = widgetDef.upcastPriority || 10;
1952
1953 if ( !upcast )
1954 return;
1955
1956 // Multiple upcasts defined in string.
1957 if ( typeof upcast == 'string' ) {
1958 upcasts = upcast.split( ',' );
1959 while ( upcasts.length ) {
1960 addUpcast( widgetDef.upcasts[ upcasts.pop() ], widgetDef.name, priority );
1961 }
1962 }
1963 // Single rule which is automatically activated.
1964 else {
1965 addUpcast( upcast, widgetDef.name, priority );
1966 }
1967
1968 function addUpcast( upcast, name, priority ) {
1969 // Find index of the first higher (in terms of value) priority upcast.
1970 var index = CKEDITOR.tools.getIndex( widgetsRepo._.upcasts, function( element ) {
1971 return element[ 2 ] > priority;
1972 } );
1973 // Add at the end if it is the highest priority so far.
1974 if ( index < 0 ) {
1975 index = widgetsRepo._.upcasts.length;
1976 }
1977
1978 widgetsRepo._.upcasts.splice( index, 0, [ upcast, name, priority ] );
1979 }
1980 }
1981
1982 function blurWidget( widgetsRepo, widget ) {
1983 widgetsRepo.focused = null;
1984
1985 if ( widget.isInited() ) {
1986 var isDirty = widget.editor.checkDirty();
1987
1988 // Widget could be destroyed in the meantime - e.g. data could be set.
1989 widgetsRepo.fire( 'widgetBlurred', { widget: widget } );
1990 widget.setFocused( false );
1991
1992 !isDirty && widget.editor.resetDirty();
1993 }
1994 }
1995
1996 function checkWidgets( evt ) {
1997 var options = evt.data;
1998
1999 if ( this.editor.mode != 'wysiwyg' )
2000 return;
2001
2002 var editable = this.editor.editable(),
2003 instances = this.instances,
2004 newInstances, i, count, wrapper, notYetInitialized;
2005
2006 if ( !editable )
2007 return;
2008
2009 // Remove widgets which have no corresponding elements in DOM.
2010 for ( i in instances ) {
2011 // #13410 Remove widgets that are ready. This prevents from destroying widgets that are during loading process.
2012 if ( instances[ i ].isReady() && !editable.contains( instances[ i ].wrapper ) )
2013 this.destroy( instances[ i ], true );
2014 }
2015
2016 // Init on all (new) if initOnlyNew option was passed.
2017 if ( options && options.initOnlyNew )
2018 newInstances = this.initOnAll();
2019 else {
2020 var wrappers = editable.find( '.cke_widget_wrapper' );
2021 newInstances = [];
2022
2023 // Create widgets on existing wrappers if they do not exists.
2024 for ( i = 0, count = wrappers.count(); i < count; i++ ) {
2025 wrapper = wrappers.getItem( i );
2026 notYetInitialized = !this.getByElement( wrapper, true );
2027
2028 // Check if:
2029 // * there's no instance for this widget
2030 // * wrapper is not inside some temporary element like copybin (#11088)
2031 // * it was a nested widget's wrapper which has been detached from DOM,
2032 // when nested editable has been initialized (it overwrites its innerHTML
2033 // and initializes nested widgets).
2034 if ( notYetInitialized && !findParent( wrapper, isDomTemp ) && editable.contains( wrapper ) ) {
2035 // Add cke_widget_new class because otherwise
2036 // widget will not be created on such wrapper.
2037 wrapper.addClass( 'cke_widget_new' );
2038 newInstances.push( this.initOn( wrapper.getFirst( Widget.isDomWidgetElement ) ) );
2039 }
2040 }
2041 }
2042
2043 // If only single widget was initialized and focusInited was passed, focus it.
2044 if ( options && options.focusInited && newInstances.length == 1 )
2045 newInstances[ 0 ].focus();
2046 }
2047
2048 // Unwraps widget element and clean up element.
2049 //
2050 // This function is used to clean up pasted widgets.
2051 // It should have similar result to widget#destroy plus
2052 // some additional adjustments, specific for pasting.
2053 //
2054 // @param {CKEDITOR.htmlParser.element} el
2055 function cleanUpWidgetElement( el ) {
2056 var parent = el.parent;
2057 if ( parent.type == CKEDITOR.NODE_ELEMENT && parent.attributes[ 'data-cke-widget-wrapper' ] )
2058 parent.replaceWith( el );
2059 }
2060
2061 // Similar to cleanUpWidgetElement, but works on DOM and finds
2062 // widget elements by its own.
2063 //
2064 // Unlike cleanUpWidgetElement it will wrap element back.
2065 //
2066 // @param {CKEDITOR.dom.element} container
2067 function cleanUpAllWidgetElements( widgetsRepo, container ) {
2068 var wrappers = container.find( '.cke_widget_wrapper' ),
2069 wrapper, element,
2070 i = 0,
2071 l = wrappers.count();
2072
2073 for ( ; i < l; ++i ) {
2074 wrapper = wrappers.getItem( i );
2075 element = wrapper.getFirst( Widget.isDomWidgetElement );
2076 // If wrapper contains widget element - unwrap it and wrap again.
2077 if ( element.type == CKEDITOR.NODE_ELEMENT && element.data( 'widget' ) ) {
2078 element.replace( wrapper );
2079 widgetsRepo.wrapElement( element );
2080 } else {
2081 // Otherwise - something is wrong... clean this up.
2082 wrapper.remove();
2083 }
2084 }
2085 }
2086
2087 // Creates {@link CKEDITOR.filter} instance for given widget, editable and rules.
2088 //
2089 // Once filter for widget-editable pair is created it is cached, so the same instance
2090 // will be returned when method is executed again.
2091 //
2092 // @param {String} widgetName
2093 // @param {String} editableName
2094 // @param {CKEDITOR.plugins.widget.nestedEditableDefinition} editableDefinition The nested editable definition.
2095 // @returns {CKEDITOR.filter} Filter instance or `null` if rules are not defined.
2096 // @context CKEDITOR.plugins.widget.repository
2097 function createEditableFilter( widgetName, editableName, editableDefinition ) {
2098 if ( !editableDefinition.allowedContent )
2099 return null;
2100
2101 var editables = this._.filters[ widgetName ];
2102
2103 if ( !editables )
2104 this._.filters[ widgetName ] = editables = {};
2105
2106 var filter = editables[ editableName ];
2107
2108 if ( !filter )
2109 editables[ editableName ] = filter = new CKEDITOR.filter( editableDefinition.allowedContent );
2110
2111 return filter;
2112 }
2113
2114 // Creates an iterator function which when executed on all
2115 // elements in DOM tree will gather elements that should be wrapped
2116 // and initialized as widgets.
2117 function createUpcastIterator( widgetsRepo ) {
2118 var toBeWrapped = [],
2119 upcasts = widgetsRepo._.upcasts,
2120 upcastCallbacks = widgetsRepo._.upcastCallbacks;
2121
2122 return {
2123 toBeWrapped: toBeWrapped,
2124
2125 iterator: function( element ) {
2126 var upcast, upcasted,
2127 data,
2128 i,
2129 upcastsLength,
2130 upcastCallbacksLength;
2131
2132 // Wrapper found - find widget element, add it to be
2133 // cleaned up (unwrapped) and wrapped and stop iterating in this branch.
2134 if ( 'data-cke-widget-wrapper' in element.attributes ) {
2135 element = element.getFirst( Widget.isParserWidgetElement );
2136
2137 if ( element )
2138 toBeWrapped.push( [ element ] );
2139
2140 // Do not iterate over descendants.
2141 return false;
2142 }
2143 // Widget element found - add it to be cleaned up (just in case)
2144 // and wrapped and stop iterating in this branch.
2145 else if ( 'data-widget' in element.attributes ) {
2146 toBeWrapped.push( [ element ] );
2147
2148 // Do not iterate over descendants.
2149 return false;
2150 }
2151 else if ( ( upcastsLength = upcasts.length ) ) {
2152 // Ignore elements with data-cke-widget-upcasted to avoid multiple upcasts (#11533).
2153 // Do not iterate over descendants.
2154 if ( element.attributes[ 'data-cke-widget-upcasted' ] )
2155 return false;
2156
2157 // Check element with upcast callbacks first.
2158 // If any of them return false abort upcasting.
2159 for ( i = 0, upcastCallbacksLength = upcastCallbacks.length; i < upcastCallbacksLength; ++i ) {
2160 if ( upcastCallbacks[ i ]( element ) === false )
2161 return;
2162 // Return nothing in order to continue iterating over ascendants.
2163 // See http://dev.ckeditor.com/ticket/11186#comment:6
2164 }
2165
2166 for ( i = 0; i < upcastsLength; ++i ) {
2167 upcast = upcasts[ i ];
2168 data = {};
2169
2170 if ( ( upcasted = upcast[ 0 ]( element, data ) ) ) {
2171 // If upcast function returned element, upcast this one.
2172 // It can be e.g. a new element wrapping the original one.
2173 if ( upcasted instanceof CKEDITOR.htmlParser.element )
2174 element = upcasted;
2175
2176 // Set initial data attr with data from upcast method.
2177 element.attributes[ 'data-cke-widget-data' ] = encodeURIComponent( JSON.stringify( data ) );
2178 element.attributes[ 'data-cke-widget-upcasted' ] = 1;
2179
2180 toBeWrapped.push( [ element, upcast[ 1 ] ] );
2181
2182 // Do not iterate over descendants.
2183 return false;
2184 }
2185 }
2186 }
2187 }
2188 };
2189 }
2190
2191 // Finds a first parent that matches query.
2192 //
2193 // @param {CKEDITOR.dom.element} element
2194 // @param {Function} query
2195 function findParent( element, query ) {
2196 var parent = element;
2197
2198 while ( ( parent = parent.getParent() ) ) {
2199 if ( query( parent ) )
2200 return true;
2201 }
2202 return false;
2203 }
2204
2205 function getWrapperAttributes( inlineWidget, name ) {
2206 return {
2207 // tabindex="-1" means that it can receive focus by code.
2208 tabindex: -1,
2209 contenteditable: 'false',
2210 'data-cke-widget-wrapper': 1,
2211 'data-cke-filter': 'off',
2212 // Class cke_widget_new marks widgets which haven't been initialized yet.
2213 'class': 'cke_widget_wrapper cke_widget_new cke_widget_' +
2214 ( inlineWidget ? 'inline' : 'block' ) +
2215 ( name ? ' cke_widget_' + name : '' )
2216 };
2217 }
2218
2219 // Inserts element at given index.
2220 // It will check DTD and split ancestor elements up to the first
2221 // that can contain this element.
2222 //
2223 // @param {CKEDITOR.htmlParser.element} parent
2224 // @param {Number} index
2225 // @param {CKEDITOR.htmlParser.element} element
2226 function insertElement( parent, index, element ) {
2227 // Do not split doc fragment...
2228 if ( parent.type == CKEDITOR.NODE_ELEMENT ) {
2229 var parentAllows = CKEDITOR.dtd[ parent.name ];
2230 // Parent element is known (included in DTD) and cannot contain
2231 // this element.
2232 if ( parentAllows && !parentAllows[ element.name ] ) {
2233 var parent2 = parent.split( index ),
2234 parentParent = parent.parent;
2235
2236 // Element will now be inserted at right parent's index.
2237 index = parent2.getIndex();
2238
2239 // If left part of split is empty - remove it.
2240 if ( !parent.children.length ) {
2241 index -= 1;
2242 parent.remove();
2243 }
2244
2245 // If right part of split is empty - remove it.
2246 if ( !parent2.children.length )
2247 parent2.remove();
2248
2249 // Try inserting as grandpas' children.
2250 return insertElement( parentParent, index, element );
2251 }
2252 }
2253
2254 // Finally we can add this element.
2255 parent.add( element, index );
2256 }
2257
2258 // Checks whether for the given widget definition and element widget should be created in inline or block mode.
2259 //
2260 // See also: {@link CKEDITOR.plugins.widget.definition#inline} and {@link CKEDITOR.plugins.widget#element}.
2261 //
2262 // @param {CKEDITOR.plugins.widget.definition} widgetDef The widget definition.
2263 // @param {String} elementName The name of the widget element.
2264 // @returns {Boolean}
2265 function isWidgetInline( widgetDef, elementName ) {
2266 return typeof widgetDef.inline == 'boolean' ? widgetDef.inline : !!CKEDITOR.dtd.$inline[ elementName ];
2267 }
2268
2269 // @param {CKEDITOR.dom.element}
2270 // @returns {Boolean}
2271 function isDomTemp( element ) {
2272 return element.hasAttribute( 'data-cke-temp' );
2273 }
2274
2275 function onEditableKey( widget, keyCode ) {
2276 var focusedEditable = widget.focusedEditable,
2277 range;
2278
2279 // CTRL+A.
2280 if ( keyCode == CKEDITOR.CTRL + 65 ) {
2281 var bogus = focusedEditable.getBogus();
2282
2283 range = widget.editor.createRange();
2284 range.selectNodeContents( focusedEditable );
2285 // Exclude bogus if exists.
2286 if ( bogus )
2287 range.setEndAt( bogus, CKEDITOR.POSITION_BEFORE_START );
2288
2289 range.select();
2290 // Cancel event - block default.
2291 return false;
2292 }
2293 // DEL or BACKSPACE.
2294 else if ( keyCode == 8 || keyCode == 46 ) {
2295 var ranges = widget.editor.getSelection().getRanges();
2296
2297 range = ranges[ 0 ];
2298
2299 // Block del or backspace if at editable's boundary.
2300 return !( ranges.length == 1 && range.collapsed &&
2301 range.checkBoundaryOfElement( focusedEditable, CKEDITOR[ keyCode == 8 ? 'START' : 'END' ] ) );
2302 }
2303 }
2304
2305 function setFocusedEditable( widgetsRepo, widget, editableElement, offline ) {
2306 var editor = widgetsRepo.editor;
2307
2308 editor.fire( 'lockSnapshot' );
2309
2310 if ( editableElement ) {
2311 var editableName = editableElement.data( 'cke-widget-editable' ),
2312 editableInstance = widget.editables[ editableName ];
2313
2314 widgetsRepo.widgetHoldingFocusedEditable = widget;
2315 widget.focusedEditable = editableInstance;
2316 editableElement.addClass( 'cke_widget_editable_focused' );
2317
2318 if ( editableInstance.filter )
2319 editor.setActiveFilter( editableInstance.filter );
2320 editor.setActiveEnterMode( editableInstance.enterMode, editableInstance.shiftEnterMode );
2321 } else {
2322 if ( !offline )
2323 widget.focusedEditable.removeClass( 'cke_widget_editable_focused' );
2324
2325 widget.focusedEditable = null;
2326 widgetsRepo.widgetHoldingFocusedEditable = null;
2327 editor.setActiveFilter( null );
2328 editor.setActiveEnterMode( null, null );
2329 }
2330
2331 editor.fire( 'unlockSnapshot' );
2332 }
2333
2334 function setupContextMenu( editor ) {
2335 if ( !editor.contextMenu )
2336 return;
2337
2338 editor.contextMenu.addListener( function( element ) {
2339 var widget = editor.widgets.getByElement( element, true );
2340
2341 if ( widget )
2342 return widget.fire( 'contextMenu', {} );
2343 } );
2344 }
2345
2346 // And now we've got two problems - original problem and RegExp.
2347 // Some softeners:
2348 // * FF tends to copy all blocks up to the copybin container.
2349 // * IE tends to copy only the copybin, without its container.
2350 // * We use spans on IE and blockless editors, but divs in other cases.
2351 var pasteReplaceRegex = new RegExp(
2352 '^' +
2353 '(?:<(?:div|span)(?: data-cke-temp="1")?(?: id="cke_copybin")?(?: data-cke-temp="1")?>)?' +
2354 '(?:<(?:div|span)(?: style="[^"]+")?>)?' +
2355 '<span [^>]*data-cke-copybin-start="1"[^>]*>.?</span>([\\s\\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?</span>' +
2356 '(?:</(?:div|span)>)?' +
2357 '(?:</(?:div|span)>)?' +
2358 '$',
2359 // IE8 prefers uppercase when browsers stick to lowercase HTML (#13460).
2360 'i'
2361 );
2362
2363 function pasteReplaceFn( match, wrapperHtml ) {
2364 // Avoid polluting pasted data with any whitspaces,
2365 // what's going to break check whether only one widget was pasted.
2366 return CKEDITOR.tools.trim( wrapperHtml );
2367 }
2368
2369 function setupDragAndDrop( widgetsRepo ) {
2370 var editor = widgetsRepo.editor,
2371 lineutils = CKEDITOR.plugins.lineutils;
2372
2373 // These listeners handle inline and block widgets drag and drop.
2374 // The only thing we need to do to make block widgets custom drag and drop functionality
2375 // is to fire those events with the right properties (like the target which must be the drag handle).
2376 editor.on( 'dragstart', function( evt ) {
2377 var target = evt.data.target;
2378
2379 if ( Widget.isDomDragHandler( target ) ) {
2380 var widget = widgetsRepo.getByElement( target );
2381
2382 evt.data.dataTransfer.setData( 'cke/widget-id', widget.id );
2383
2384 // IE needs focus.
2385 editor.focus();
2386
2387 // and widget need to be focused on drag start (#12172#comment:10).
2388 widget.focus();
2389 }
2390 } );
2391
2392 editor.on( 'drop', function( evt ) {
2393 var dataTransfer = evt.data.dataTransfer,
2394 id = dataTransfer.getData( 'cke/widget-id' ),
2395 transferType = dataTransfer.getTransferType( editor ),
2396 dragRange = editor.createRange(),
2397 sourceWidget;
2398
2399 // Disable cross-editor drag & drop for widgets - #13599.
2400 if ( id !== '' && transferType === CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) {
2401 evt.cancel();
2402 return;
2403 }
2404
2405 if ( id === '' || transferType != CKEDITOR.DATA_TRANSFER_INTERNAL ) {
2406 return;
2407 }
2408
2409 sourceWidget = widgetsRepo.instances[ id ];
2410 if ( !sourceWidget ) {
2411 return;
2412 }
2413
2414 dragRange.setStartBefore( sourceWidget.wrapper );
2415 dragRange.setEndAfter( sourceWidget.wrapper );
2416 evt.data.dragRange = dragRange;
2417
2418 // [IE8-9] Reset state of the clipboard#fixSplitNodesAfterDrop fix because by setting evt.data.dragRange
2419 // (see above) after drop happened we do not need it. That fix is needed only if dragRange was created
2420 // before drop (before text node was split).
2421 delete CKEDITOR.plugins.clipboard.dragStartContainerChildCount;
2422 delete CKEDITOR.plugins.clipboard.dragEndContainerChildCount;
2423
2424 evt.data.dataTransfer.setData( 'text/html', editor.editable().getHtmlFromRange( dragRange ).getHtml() );
2425 editor.widgets.destroy( sourceWidget, true );
2426 } );
2427
2428 editor.on( 'contentDom', function() {
2429 var editable = editor.editable();
2430
2431 // Register Lineutils's utilities as properties of repo.
2432 CKEDITOR.tools.extend( widgetsRepo, {
2433 finder: new lineutils.finder( editor, {
2434 lookups: {
2435 // Element is block but not list item and not in nested editable.
2436 'default': function( el ) {
2437 if ( el.is( CKEDITOR.dtd.$listItem ) )
2438 return;
2439
2440 if ( !el.is( CKEDITOR.dtd.$block ) )
2441 return;
2442
2443 // Allow drop line inside, but never before or after nested editable (#12006).
2444 if ( Widget.isDomNestedEditable( el ) )
2445 return;
2446
2447 // Do not allow droping inside the widget being dragged (#13397).
2448 if ( widgetsRepo._.draggedWidget.wrapper.contains( el ) ) {
2449 return;
2450 }
2451
2452 // If element is nested editable, make sure widget can be dropped there (#12006).
2453 var nestedEditable = Widget.getNestedEditable( editable, el );
2454 if ( nestedEditable ) {
2455 var draggedWidget = widgetsRepo._.draggedWidget;
2456
2457 // Don't let the widget to be dropped into its own nested editable.
2458 if ( widgetsRepo.getByElement( nestedEditable ) == draggedWidget )
2459 return;
2460
2461 var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ],
2462 draggedRequiredContent = draggedWidget.requiredContent;
2463
2464 // There will be no relation if the filter of nested editable does not allow
2465 // requiredContent of dragged widget.
2466 if ( filter && draggedRequiredContent && !filter.check( draggedRequiredContent ) )
2467 return;
2468 }
2469
2470 return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER;
2471 }
2472 }
2473 } ),
2474 locator: new lineutils.locator( editor ),
2475 liner: new lineutils.liner( editor, {
2476 lineStyle: {
2477 cursor: 'move !important',
2478 'border-top-color': '#666'
2479 },
2480 tipLeftStyle: {
2481 'border-left-color': '#666'
2482 },
2483 tipRightStyle: {
2484 'border-right-color': '#666'
2485 }
2486 } )
2487 }, true );
2488 } );
2489 }
2490
2491 // Setup mouse observer which will trigger:
2492 // * widget focus on widget click,
2493 // * widget#doubleclick forwarded from editor#doubleclick.
2494 function setupMouseObserver( widgetsRepo ) {
2495 var editor = widgetsRepo.editor;
2496
2497 editor.on( 'contentDom', function() {
2498 var editable = editor.editable(),
2499 evtRoot = editable.isInline() ? editable : editor.document,
2500 widget,
2501 mouseDownOnDragHandler;
2502
2503 editable.attachListener( evtRoot, 'mousedown', function( evt ) {
2504 var target = evt.data.getTarget();
2505
2506 // #10887 Clicking scrollbar in IE8 will invoke event with empty target object.
2507 if ( !target.type )
2508 return false;
2509
2510 widget = widgetsRepo.getByElement( target );
2511 mouseDownOnDragHandler = 0; // Reset.
2512
2513 // Widget was clicked, but not editable nested in it.
2514 if ( widget ) {
2515 // Ignore mousedown on drag and drop handler if the widget is inline.
2516 // Block widgets are handled by Lineutils.
2517 if ( widget.inline && target.type == CKEDITOR.NODE_ELEMENT && target.hasAttribute( 'data-cke-widget-drag-handler' ) ) {
2518 mouseDownOnDragHandler = 1;
2519
2520 // When drag handler is pressed we have to clear current selection if it wasn't already on this widget.
2521 // Otherwise, the selection may be in a fillingChar, which prevents dragging a widget. (#13284, see comment 8 and 9.)
2522 if ( widgetsRepo.focused != widget )
2523 editor.getSelection().removeAllRanges();
2524
2525 return;
2526 }
2527
2528 if ( !Widget.getNestedEditable( widget.wrapper, target ) ) {
2529 evt.data.preventDefault();
2530 if ( !CKEDITOR.env.ie )
2531 widget.focus();
2532 } else {
2533 // Reset widget so mouseup listener is not confused.
2534 widget = null;
2535 }
2536 }
2537 } );
2538
2539 // Focus widget on mouseup if mousedown was fired on drag handler.
2540 // Note: mouseup won't be fired at all if widget was dragged and dropped, so
2541 // this code will be executed only when drag handler was clicked.
2542 editable.attachListener( evtRoot, 'mouseup', function() {
2543 // Check if widget is not destroyed (if widget is destroyed the wrapper will be null).
2544 if ( mouseDownOnDragHandler && widget && widget.wrapper ) {
2545 mouseDownOnDragHandler = 0;
2546 widget.focus();
2547 }
2548 } );
2549
2550 // On IE it is not enough to block mousedown. If widget wrapper (element with
2551 // contenteditable=false attribute) is clicked directly (it is a target),
2552 // then after mouseup/click IE will select that element.
2553 // It is not possible to prevent that default action,
2554 // so we force fake selection after everything happened.
2555 if ( CKEDITOR.env.ie ) {
2556 editable.attachListener( evtRoot, 'mouseup', function() {
2557 setTimeout( function() {
2558 // Check if widget is not destroyed (if widget is destroyed the wrapper will be null) and
2559 // in editable contains widget (it could be dragged and removed).
2560 if ( widget && widget.wrapper && editable.contains( widget.wrapper ) ) {
2561 widget.focus();
2562 widget = null;
2563 }
2564 } );
2565 } );
2566 }
2567 } );
2568
2569 editor.on( 'doubleclick', function( evt ) {
2570 var widget = widgetsRepo.getByElement( evt.data.element );
2571
2572 // Not in widget or in nested editable.
2573 if ( !widget || Widget.getNestedEditable( widget.wrapper, evt.data.element ) )
2574 return;
2575
2576 return widget.fire( 'doubleclick', { element: evt.data.element } );
2577 }, null, null, 1 );
2578 }
2579
2580 // Setup editor#key observer which will forward it
2581 // to focused widget.
2582 function setupKeyboardObserver( widgetsRepo ) {
2583 var editor = widgetsRepo.editor;
2584
2585 editor.on( 'key', function( evt ) {
2586 var focused = widgetsRepo.focused,
2587 widgetHoldingFocusedEditable = widgetsRepo.widgetHoldingFocusedEditable,
2588 ret;
2589
2590 if ( focused )
2591 ret = focused.fire( 'key', { keyCode: evt.data.keyCode } );
2592 else if ( widgetHoldingFocusedEditable )
2593 ret = onEditableKey( widgetHoldingFocusedEditable, evt.data.keyCode );
2594
2595 return ret;
2596 }, null, null, 1 );
2597 }
2598
2599 // Setup copybin on native copy and cut events in order to handle copy and cut commands
2600 // if user accepted security alert on IEs.
2601 // Note: when copying or cutting using keystroke, copySingleWidget will be first executed
2602 // by the keydown listener. Conflict between two calls will be resolved by copy_bin existence check.
2603 function setupNativeCutAndCopy( widgetsRepo ) {
2604 var editor = widgetsRepo.editor;
2605
2606 editor.on( 'contentDom', function() {
2607 var editable = editor.editable();
2608
2609 editable.attachListener( editable, 'copy', eventListener );
2610 editable.attachListener( editable, 'cut', eventListener );
2611 } );
2612
2613 function eventListener( evt ) {
2614 if ( widgetsRepo.focused )
2615 copySingleWidget( widgetsRepo.focused, evt.name == 'cut' );
2616 }
2617 }
2618
2619 // Setup selection observer which will trigger:
2620 // * widget select & focus on selection change,
2621 // * nested editable focus (related properites and classes) on selection change,
2622 // * deselecting and blurring all widgets on data,
2623 // * blurring widget on editor blur.
2624 function setupSelectionObserver( widgetsRepo ) {
2625 var editor = widgetsRepo.editor;
2626
2627 editor.on( 'selectionCheck', function() {
2628 widgetsRepo.fire( 'checkSelection' );
2629 } );
2630
2631 widgetsRepo.on( 'checkSelection', widgetsRepo.checkSelection, widgetsRepo );
2632
2633 editor.on( 'selectionChange', function( evt ) {
2634 var nestedEditable = Widget.getNestedEditable( editor.editable(), evt.data.selection.getStartElement() ),
2635 newWidget = nestedEditable && widgetsRepo.getByElement( nestedEditable ),
2636 oldWidget = widgetsRepo.widgetHoldingFocusedEditable;
2637
2638 if ( oldWidget ) {
2639 if ( oldWidget !== newWidget || !oldWidget.focusedEditable.equals( nestedEditable ) ) {
2640 setFocusedEditable( widgetsRepo, oldWidget, null );
2641
2642 if ( newWidget && nestedEditable )
2643 setFocusedEditable( widgetsRepo, newWidget, nestedEditable );
2644 }
2645 }
2646 // It may happen that there's no widget even if editable was found -
2647 // e.g. if selection was automatically set in editable although widget wasn't initialized yet.
2648 else if ( newWidget && nestedEditable ) {
2649 setFocusedEditable( widgetsRepo, newWidget, nestedEditable );
2650 }
2651 } );
2652
2653 // Invalidate old widgets early - immediately on dataReady.
2654 editor.on( 'dataReady', function() {
2655 // Deselect and blur all widgets.
2656 stateUpdater( widgetsRepo ).commit();
2657 } );
2658
2659 editor.on( 'blur', function() {
2660 var widget;
2661
2662 if ( ( widget = widgetsRepo.focused ) )
2663 blurWidget( widgetsRepo, widget );
2664
2665 if ( ( widget = widgetsRepo.widgetHoldingFocusedEditable ) )
2666 setFocusedEditable( widgetsRepo, widget, null );
2667 } );
2668 }
2669
2670 // Set up actions like:
2671 // * processing in toHtml/toDataFormat,
2672 // * pasting handling,
2673 // * insertion handling,
2674 // * editable reload handling (setData, mode switch, undo/redo),
2675 // * DOM invalidation handling,
2676 // * widgets checks.
2677 function setupWidgetsLifecycle( widgetsRepo ) {
2678 setupWidgetsLifecycleStart( widgetsRepo );
2679 setupWidgetsLifecycleEnd( widgetsRepo );
2680
2681 widgetsRepo.on( 'checkWidgets', checkWidgets );
2682 widgetsRepo.editor.on( 'contentDomInvalidated', widgetsRepo.checkWidgets, widgetsRepo );
2683 }
2684
2685 function setupWidgetsLifecycleEnd( widgetsRepo ) {
2686 var editor = widgetsRepo.editor,
2687 downcastingSessions = {};
2688
2689 // Listen before htmlDP#htmlFilter is applied to cache all widgets, because we'll
2690 // loose data-cke-* attributes.
2691 editor.on( 'toDataFormat', function( evt ) {
2692 // To avoid conflicts between htmlDP#toDF calls done at the same time
2693 // (e.g. nestedEditable#getData called during downcasting some widget)
2694 // mark every toDataFormat event chain with the downcasting session id.
2695 var id = CKEDITOR.tools.getNextNumber(),
2696 toBeDowncasted = [];
2697 evt.data.downcastingSessionId = id;
2698 downcastingSessions[ id ] = toBeDowncasted;
2699
2700 evt.data.dataValue.forEach( function( element ) {
2701 var attrs = element.attributes,
2702 widget, widgetElement;
2703
2704 // Wrapper.
2705 // Perform first part of downcasting (cleanup) and cache widgets,
2706 // because after applying DP's filter all data-cke-* attributes will be gone.
2707 if ( 'data-cke-widget-id' in attrs ) {
2708 widget = widgetsRepo.instances[ attrs[ 'data-cke-widget-id' ] ];
2709 if ( widget ) {
2710 widgetElement = element.getFirst( Widget.isParserWidgetElement );
2711 toBeDowncasted.push( {
2712 wrapper: element,
2713 element: widgetElement,
2714 widget: widget,
2715 editables: {}
2716 } );
2717
2718 // If widget did not have data-cke-widget attribute before upcasting remove it.
2719 if ( widgetElement.attributes[ 'data-cke-widget-keep-attr' ] != '1' )
2720 delete widgetElement.attributes[ 'data-widget' ];
2721 }
2722 }
2723 // Nested editable.
2724 else if ( 'data-cke-widget-editable' in attrs ) {
2725 // Save the reference to this nested editable in the closest widget to be downcasted.
2726 // Nested editables are downcasted in the successive toDataFormat to create an opportunity
2727 // for dataFilter's "excludeNestedEditable" option to do its job (that option relies on
2728 // contenteditable="true" attribute) (#11372).
2729 toBeDowncasted[ toBeDowncasted.length - 1 ].editables[ attrs[ 'data-cke-widget-editable' ] ] = element;
2730
2731 // Don't check children - there won't be next wrapper or nested editable which we
2732 // should process in this session.
2733 return false;
2734 }
2735 }, CKEDITOR.NODE_ELEMENT, true );
2736 }, null, null, 8 );
2737
2738 // Listen after dataProcessor.htmlFilter and ACF were applied
2739 // so wrappers securing widgets' contents are removed after all filtering was done.
2740 editor.on( 'toDataFormat', function( evt ) {
2741 // Ignore some unmarked sessions.
2742 if ( !evt.data.downcastingSessionId )
2743 return;
2744
2745 var toBeDowncasted = downcastingSessions[ evt.data.downcastingSessionId ],
2746 toBe, widget, widgetElement, retElement, editableElement, e;
2747
2748 while ( ( toBe = toBeDowncasted.shift() ) ) {
2749 widget = toBe.widget;
2750 widgetElement = toBe.element;
2751 retElement = widget._.downcastFn && widget._.downcastFn.call( widget, widgetElement );
2752
2753 // Replace nested editables' content with their output data.
2754 for ( e in toBe.editables ) {
2755 editableElement = toBe.editables[ e ];
2756
2757 delete editableElement.attributes.contenteditable;
2758 editableElement.setHtml( widget.editables[ e ].getData() );
2759 }
2760
2761 // Returned element always defaults to widgetElement.
2762 if ( !retElement )
2763 retElement = widgetElement;
2764
2765 toBe.wrapper.replaceWith( retElement );
2766 }
2767 }, null, null, 13 );
2768
2769
2770 editor.on( 'contentDomUnload', function() {
2771 widgetsRepo.destroyAll( true );
2772 } );
2773 }
2774
2775 function setupWidgetsLifecycleStart( widgetsRepo ) {
2776 var editor = widgetsRepo.editor,
2777 processedWidgetOnly,
2778 snapshotLoaded;
2779
2780 // Listen after ACF (so data are filtered),
2781 // but before dataProcessor.dataFilter was applied (so we can secure widgets' internals).
2782 editor.on( 'toHtml', function( evt ) {
2783 var upcastIterator = createUpcastIterator( widgetsRepo ),
2784 toBeWrapped;
2785
2786 evt.data.dataValue.forEach( upcastIterator.iterator, CKEDITOR.NODE_ELEMENT, true );
2787
2788 // Clean up and wrap all queued elements.
2789 while ( ( toBeWrapped = upcastIterator.toBeWrapped.pop() ) ) {
2790 cleanUpWidgetElement( toBeWrapped[ 0 ] );
2791 widgetsRepo.wrapElement( toBeWrapped[ 0 ], toBeWrapped[ 1 ] );
2792 }
2793
2794 // Used to determine whether only widget was pasted.
2795 if ( evt.data.protectedWhitespaces ) {
2796 // Whitespaces are protected by wrapping content with spans. Take the middle node only.
2797 processedWidgetOnly = evt.data.dataValue.children.length == 3 &&
2798 Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 1 ] );
2799 } else {
2800 processedWidgetOnly = evt.data.dataValue.children.length == 1 &&
2801 Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] );
2802 }
2803 }, null, null, 8 );
2804
2805 editor.on( 'dataReady', function() {
2806 // Clean up all widgets loaded from snapshot.
2807 if ( snapshotLoaded )
2808 cleanUpAllWidgetElements( widgetsRepo, editor.editable() );
2809 snapshotLoaded = 0;
2810
2811 // Some widgets were destroyed on contentDomUnload,
2812 // some on loadSnapshot, but that does not include
2813 // e.g. setHtml on inline editor or widgets removed just
2814 // before setting data.
2815 widgetsRepo.destroyAll( true );
2816 widgetsRepo.initOnAll();
2817 } );
2818
2819 // Set flag so dataReady will know that additional
2820 // cleanup is needed, because snapshot containing widgets was loaded.
2821 editor.on( 'loadSnapshot', function( evt ) {
2822 // Primitive but sufficient check which will prevent from executing
2823 // heavier cleanUpAllWidgetElements if not needed.
2824 if ( ( /data-cke-widget/ ).test( evt.data ) )
2825 snapshotLoaded = 1;
2826
2827 widgetsRepo.destroyAll( true );
2828 }, null, null, 9 );
2829
2830 // Handle pasted single widget.
2831 editor.on( 'paste', function( evt ) {
2832 var data = evt.data;
2833
2834 data.dataValue = data.dataValue.replace( pasteReplaceRegex, pasteReplaceFn );
2835
2836 // If drag'n'drop kind of paste into nested editable (data.range), selection is set AFTER
2837 // data is pasted, which means editor has no chance to change activeFilter's context.
2838 // As a result, pasted data is filtered with default editor's filter instead of NE's and
2839 // funny things get inserted. Changing the filter by analysis of the paste range below (#13186).
2840 if ( data.range ) {
2841 // Check if pasting into nested editable.
2842 var nestedEditable = Widget.getNestedEditable( editor.editable(), data.range.startContainer );
2843
2844 if ( nestedEditable ) {
2845 // Retrieve the filter from NE's data and set it active before editor.insertHtml is done
2846 // in clipboard plugin.
2847 var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ];
2848
2849 if ( filter ) {
2850 editor.setActiveFilter( filter );
2851 }
2852 }
2853 }
2854 } );
2855
2856 // Listen with high priority to check widgets after data was inserted.
2857 editor.on( 'afterInsertHtml', function( evt ) {
2858 if ( evt.data.intoRange ) {
2859 widgetsRepo.checkWidgets( { initOnlyNew: true } );
2860 } else {
2861 editor.fire( 'lockSnapshot' );
2862 // Init only new for performance reason.
2863 // Focus inited if only widget was processed.
2864 widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } );
2865
2866 editor.fire( 'unlockSnapshot' );
2867 }
2868 } );
2869 }
2870
2871 // Helper for coordinating which widgets should be
2872 // selected/deselected and which one should be focused/blurred.
2873 function stateUpdater( widgetsRepo ) {
2874 var currentlySelected = widgetsRepo.selected,
2875 toBeSelected = [],
2876 toBeDeselected = currentlySelected.slice( 0 ),
2877 focused = null;
2878
2879 return {
2880 select: function( widget ) {
2881 if ( CKEDITOR.tools.indexOf( currentlySelected, widget ) < 0 )
2882 toBeSelected.push( widget );
2883
2884 var index = CKEDITOR.tools.indexOf( toBeDeselected, widget );
2885 if ( index >= 0 )
2886 toBeDeselected.splice( index, 1 );
2887
2888 return this;
2889 },
2890
2891 focus: function( widget ) {
2892 focused = widget;
2893 return this;
2894 },
2895
2896 commit: function() {
2897 var focusedChanged = widgetsRepo.focused !== focused,
2898 widget, isDirty;
2899
2900 widgetsRepo.editor.fire( 'lockSnapshot' );
2901
2902 if ( focusedChanged && ( widget = widgetsRepo.focused ) )
2903 blurWidget( widgetsRepo, widget );
2904
2905 while ( ( widget = toBeDeselected.pop() ) ) {
2906 currentlySelected.splice( CKEDITOR.tools.indexOf( currentlySelected, widget ), 1 );
2907 // Widget could be destroyed in the meantime - e.g. data could be set.
2908 if ( widget.isInited() ) {
2909 isDirty = widget.editor.checkDirty();
2910
2911 widget.setSelected( false );
2912
2913 !isDirty && widget.editor.resetDirty();
2914 }
2915 }
2916
2917 if ( focusedChanged && focused ) {
2918 isDirty = widgetsRepo.editor.checkDirty();
2919
2920 widgetsRepo.focused = focused;
2921 widgetsRepo.fire( 'widgetFocused', { widget: focused } );
2922 focused.setFocused( true );
2923
2924 !isDirty && widgetsRepo.editor.resetDirty();
2925 }
2926
2927 while ( ( widget = toBeSelected.pop() ) ) {
2928 currentlySelected.push( widget );
2929 widget.setSelected( true );
2930 }
2931
2932 widgetsRepo.editor.fire( 'unlockSnapshot' );
2933 }
2934 };
2935 }
2936
2937
2938 //
2939 // WIDGET helpers ---------------------------------------------------------
2940 //
2941
2942 // LEFT, RIGHT, UP, DOWN, DEL, BACKSPACE - unblock default fake sel handlers.
2943 var keystrokesNotBlockedByWidget = { 37: 1, 38: 1, 39: 1, 40: 1, 8: 1, 46: 1 };
2944
2945 // Applies or removes style's classes from widget.
2946 // @param {CKEDITOR.style} style Custom widget style.
2947 // @param {Boolean} apply Whether to apply or remove style.
2948 function applyRemoveStyle( widget, style, apply ) {
2949 var changed = 0,
2950 classes = getStyleClasses( style ),
2951 updatedClasses = widget.data.classes || {},
2952 cl;
2953
2954 // Ee... Something is wrong with this style.
2955 if ( !classes )
2956 return;
2957
2958 // Clone, because we need to break reference.
2959 updatedClasses = CKEDITOR.tools.clone( updatedClasses );
2960
2961 while ( ( cl = classes.pop() ) ) {
2962 if ( apply ) {
2963 if ( !updatedClasses[ cl ] )
2964 changed = updatedClasses[ cl ] = 1;
2965 } else {
2966 if ( updatedClasses[ cl ] ) {
2967 delete updatedClasses[ cl ];
2968 changed = 1;
2969 }
2970 }
2971 }
2972 if ( changed )
2973 widget.setData( 'classes', updatedClasses );
2974 }
2975
2976 function cancel( evt ) {
2977 evt.cancel();
2978 }
2979
2980 function copySingleWidget( widget, isCut ) {
2981 var editor = widget.editor,
2982 doc = editor.document;
2983
2984 // We're still handling previous copy/cut.
2985 // When keystroke is used to copy/cut this will also prevent
2986 // conflict with copySingleWidget called again for native copy/cut event.
2987 if ( doc.getById( 'cke_copybin' ) )
2988 return;
2989
2990 // [IE] Use span for copybin and its container to avoid bug with expanding editable height by
2991 // absolutely positioned element.
2992 var copybinName = ( editor.blockless || CKEDITOR.env.ie ) ? 'span' : 'div',
2993 copybin = doc.createElement( copybinName ),
2994 copybinContainer = doc.createElement( copybinName ),
2995 // IE8 always jumps to the end of document.
2996 needsScrollHack = CKEDITOR.env.ie && CKEDITOR.env.version < 9;
2997
2998 copybinContainer.setAttributes( {
2999 id: 'cke_copybin',
3000 'data-cke-temp': '1'
3001 } );
3002
3003 // Position copybin element outside current viewport.
3004 copybin.setStyles( {
3005 position: 'absolute',
3006 width: '1px',
3007 height: '1px',
3008 overflow: 'hidden'
3009 } );
3010
3011 copybin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-5000px' );
3012
3013 var range = editor.createRange();
3014 range.setStartBefore( widget.wrapper );
3015 range.setEndAfter( widget.wrapper );
3016
3017 copybin.setHtml(
3018 '<span data-cke-copybin-start="1">\u200b</span>' +
3019 editor.editable().getHtmlFromRange( range ).getHtml() +
3020 '<span data-cke-copybin-end="1">\u200b</span>' );
3021
3022 // Save snapshot with the current state.
3023 editor.fire( 'saveSnapshot' );
3024
3025 // Ignore copybin.
3026 editor.fire( 'lockSnapshot' );
3027
3028 copybinContainer.append( copybin );
3029 editor.editable().append( copybinContainer );
3030
3031 var listener1 = editor.on( 'selectionChange', cancel, null, null, 0 ),
3032 listener2 = widget.repository.on( 'checkSelection', cancel, null, null, 0 );
3033
3034 if ( needsScrollHack ) {
3035 var docElement = doc.getDocumentElement().$,
3036 scrollTop = docElement.scrollTop;
3037 }
3038
3039 // Once the clone of the widget is inside of copybin, select
3040 // the entire contents. This selection will be copied by the
3041 // native browser's clipboard system.
3042 range = editor.createRange();
3043 range.selectNodeContents( copybin );
3044 range.select();
3045
3046 if ( needsScrollHack )
3047 docElement.scrollTop = scrollTop;
3048
3049 setTimeout( function() {
3050 // [IE] Focus widget before removing copybin to avoid scroll jump.
3051 if ( !isCut )
3052 widget.focus();
3053
3054 copybinContainer.remove();
3055
3056 listener1.removeListener();
3057 listener2.removeListener();
3058
3059 editor.fire( 'unlockSnapshot' );
3060
3061 if ( isCut ) {
3062 widget.repository.del( widget );
3063 editor.fire( 'saveSnapshot' );
3064 }
3065 }, 100 ); // Use 100ms, so Chrome (@Mac) will be able to grab the content.
3066 }
3067
3068 // Extracts classes array from style instance.
3069 function getStyleClasses( style ) {
3070 var attrs = style.getDefinition().attributes,
3071 classes = attrs && attrs[ 'class' ];
3072
3073 return classes ? classes.split( /\s+/ ) : null;
3074 }
3075
3076 // [IE] Force keeping focus because IE sometimes forgets to fire focus on main editable
3077 // when blurring nested editable.
3078 // @context widget
3079 function onEditableBlur() {
3080 var active = CKEDITOR.document.getActive(),
3081 editor = this.editor,
3082 editable = editor.editable();
3083
3084 // If focus stays within editor override blur and set currentActive because it should be
3085 // automatically changed to editable on editable#focus but it is not fired.
3086 if ( ( editable.isInline() ? editable : editor.document.getWindow().getFrame() ).equals( active ) )
3087 editor.focusManager.focus( editable );
3088 }
3089
3090 // Force selectionChange when editable was focused.
3091 // Similar to hack in selection.js#~620.
3092 // @context widget
3093 function onEditableFocus() {
3094 // Gecko does not support 'DOMFocusIn' event on which we unlock selection
3095 // in selection.js to prevent selection locking when entering nested editables.
3096 if ( CKEDITOR.env.gecko )
3097 this.editor.unlockSelection();
3098
3099 // We don't need to force selectionCheck on Webkit, because on Webkit
3100 // we do that on DOMFocusIn in selection.js.
3101 if ( !CKEDITOR.env.webkit ) {
3102 this.editor.forceNextSelectionCheck();
3103 this.editor.selectionChange( 1 );
3104 }
3105 }
3106
3107 // Setup listener on widget#data which will update (remove/add) classes
3108 // by comparing newly set classes with the old ones.
3109 function setupDataClassesListener( widget ) {
3110 // Note: previousClasses and newClasses may be null!
3111 // Tip: for ( cl in null ) is correct.
3112 var previousClasses = null;
3113
3114 widget.on( 'data', function() {
3115 var newClasses = this.data.classes,
3116 cl;
3117
3118 // When setting new classes one need to remember
3119 // that he must break reference.
3120 if ( previousClasses == newClasses )
3121 return;
3122
3123 for ( cl in previousClasses ) {
3124 // Avoid removing and adding classes again.
3125 if ( !( newClasses && newClasses[ cl ] ) )
3126 this.removeClass( cl );
3127 }
3128 for ( cl in newClasses )
3129 this.addClass( cl );
3130
3131 previousClasses = newClasses;
3132 } );
3133 }
3134
3135 // Add a listener to data event that will set/change widget's label (#14539).
3136 function setupA11yListener( widget ) {
3137 // Note, the function gets executed in a context of widget instance.
3138 function getLabelDefault() {
3139 return this.editor.lang.widget.label.replace( /%1/, this.pathName || this.element.getName() );
3140 }
3141
3142 // Setting a listener on data is enough, there's no need to perform it on widget initialization, as
3143 // setupWidgetData fires this event anyway.
3144 widget.on( 'data', function() {
3145 // In some cases widget might get destroyed in an earlier data listener. For instance, image2 plugin, does
3146 // so when changing its internal state.
3147 if ( !widget.wrapper ) {
3148 return;
3149 }
3150
3151 var label = this.getLabel ? this.getLabel() : getLabelDefault.call( this );
3152
3153 widget.wrapper.setAttribute( 'role', 'region' );
3154 widget.wrapper.setAttribute( 'aria-label', label );
3155 }, null, null, 9999 );
3156 }
3157
3158 function setupDragHandler( widget ) {
3159 if ( !widget.draggable )
3160 return;
3161
3162 var editor = widget.editor,
3163 // Use getLast to find wrapper's direct descendant (#12022).
3164 container = widget.wrapper.getLast( Widget.isDomDragHandlerContainer ),
3165 img;
3166
3167 // Reuse drag handler if already exists (#11281).
3168 if ( container )
3169 img = container.findOne( 'img' );
3170 else {
3171 container = new CKEDITOR.dom.element( 'span', editor.document );
3172 container.setAttributes( {
3173 'class': 'cke_reset cke_widget_drag_handler_container',
3174 // Split background and background-image for IE8 which will break on rgba().
3175 style: 'background:rgba(220,220,220,0.5);background-image:url(' + editor.plugins.widget.path + 'images/handle.png)'
3176 } );
3177
3178 img = new CKEDITOR.dom.element( 'img', editor.document );
3179 img.setAttributes( {
3180 'class': 'cke_reset cke_widget_drag_handler',
3181 'data-cke-widget-drag-handler': '1',
3182 src: CKEDITOR.tools.transparentImageData,
3183 width: DRAG_HANDLER_SIZE,
3184 title: editor.lang.widget.move,
3185 height: DRAG_HANDLER_SIZE,
3186 role: 'presentation'
3187 } );
3188 widget.inline && img.setAttribute( 'draggable', 'true' );
3189
3190 container.append( img );
3191 widget.wrapper.append( container );
3192 }
3193
3194 // Preventing page reload when dropped content on widget wrapper (#13015).
3195 // Widget is not editable so by default drop on it isn't allowed what means that
3196 // browser handles it (there's no editable#drop event). If there's no drop event we cannot block
3197 // the drop, so page is reloaded. This listener enables drop on widget wrappers.
3198 widget.wrapper.on( 'dragover', function( evt ) {
3199 evt.data.preventDefault();
3200 } );
3201
3202 widget.wrapper.on( 'mouseenter', widget.updateDragHandlerPosition, widget );
3203 setTimeout( function() {
3204 widget.on( 'data', widget.updateDragHandlerPosition, widget );
3205 }, 50 );
3206
3207 if ( !widget.inline ) {
3208 img.on( 'mousedown', onBlockWidgetDrag, widget );
3209
3210 // On IE8 'dragstart' is propagated to editable, so editor#dragstart is fired twice on block widgets.
3211 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
3212 img.on( 'dragstart', function( evt ) {
3213 evt.data.preventDefault( true );
3214 } );
3215 }
3216 }
3217
3218 widget.dragHandlerContainer = container;
3219 }
3220
3221 function onBlockWidgetDrag( evt ) {
3222 var finder = this.repository.finder,
3223 locator = this.repository.locator,
3224 liner = this.repository.liner,
3225 editor = this.editor,
3226 editable = editor.editable(),
3227 listeners = [],
3228 sorted = [],
3229 locations,
3230 y;
3231
3232 // Mark dragged widget for repository#finder.
3233 this.repository._.draggedWidget = this;
3234
3235 // Harvest all possible relations and display some closest.
3236 var relations = finder.greedySearch(),
3237
3238 buffer = CKEDITOR.tools.eventsBuffer( 50, function() {
3239 locations = locator.locate( relations );
3240
3241 // There's only a single line displayed for D&D.
3242 sorted = locator.sort( y, 1 );
3243
3244 if ( sorted.length ) {
3245 liner.prepare( relations, locations );
3246 liner.placeLine( sorted[ 0 ] );
3247 liner.cleanup();
3248 }
3249 } );
3250
3251 // Let's have the "dragging cursor" over entire editable.
3252 editable.addClass( 'cke_widget_dragging' );
3253
3254 // Cache mouse position so it is re-used in events buffer.
3255 listeners.push( editable.on( 'mousemove', function( evt ) {
3256 y = evt.data.$.clientY;
3257 buffer.input();
3258 } ) );
3259
3260 // Fire drag start as it happens during the native D&D.
3261 editor.fire( 'dragstart', { target: evt.sender } );
3262
3263 function onMouseUp() {
3264 var l;
3265
3266 buffer.reset();
3267
3268 // Stop observing events.
3269 while ( ( l = listeners.pop() ) )
3270 l.removeListener();
3271
3272 onBlockWidgetDrop.call( this, sorted, evt.sender );
3273 }
3274
3275 // Mouseup means "drop". This is when the widget is being detached
3276 // from DOM and placed at range determined by the line (location).
3277 listeners.push( editor.document.once( 'mouseup', onMouseUp, this ) );
3278
3279 // Prevent calling 'onBlockWidgetDrop' twice in the inline editor.
3280 // `removeListener` does not work if it is called at the same time event is fired.
3281 if ( !editable.isInline() ) {
3282 // Mouseup may occur when user hovers the line, which belongs to
3283 // the outer document. This is, of course, a valid listener too.
3284 listeners.push( CKEDITOR.document.once( 'mouseup', onMouseUp, this ) );
3285 }
3286 }
3287
3288 function onBlockWidgetDrop( sorted, dragTarget ) {
3289 var finder = this.repository.finder,
3290 liner = this.repository.liner,
3291 editor = this.editor,
3292 editable = this.editor.editable();
3293
3294 if ( !CKEDITOR.tools.isEmpty( liner.visible ) ) {
3295 // Retrieve range for the closest location.
3296 var dropRange = finder.getRange( sorted[ 0 ] );
3297
3298 // Focus widget (it could lost focus after mousedown+mouseup)
3299 // and save this state as the one where we want to be taken back when undoing.
3300 this.focus();
3301
3302 // Drag range will be set in the drop listener.
3303 editor.fire( 'drop', {
3304 dropRange: dropRange,
3305 target: dropRange.startContainer
3306 } );
3307 }
3308
3309 // Clean-up custom cursor for editable.
3310 editable.removeClass( 'cke_widget_dragging' );
3311
3312 // Clean-up all remaining lines.
3313 liner.hideVisible();
3314
3315 // Clean-up drag & drop.
3316 editor.fire( 'dragend', { target: dragTarget } );
3317 }
3318
3319 function setupEditables( widget ) {
3320 var editableName,
3321 editableDef,
3322 definedEditables = widget.editables;
3323
3324 widget.editables = {};
3325
3326 if ( !widget.editables )
3327 return;
3328
3329 for ( editableName in definedEditables ) {
3330 editableDef = definedEditables[ editableName ];
3331 widget.initEditable( editableName, typeof editableDef == 'string' ? { selector: editableDef } : editableDef );
3332 }
3333 }
3334
3335 function setupMask( widget ) {
3336 if ( !widget.mask )
3337 return;
3338
3339 // Reuse mask if already exists (#11281).
3340 var img = widget.wrapper.findOne( '.cke_widget_mask' );
3341
3342 if ( !img ) {
3343 img = new CKEDITOR.dom.element( 'img', widget.editor.document );
3344 img.setAttributes( {
3345 src: CKEDITOR.tools.transparentImageData,
3346 'class': 'cke_reset cke_widget_mask'
3347 } );
3348 widget.wrapper.append( img );
3349 }
3350
3351 widget.mask = img;
3352 }
3353
3354 // Replace parts object containing:
3355 // partName => selector pairs
3356 // with:
3357 // partName => element pairs
3358 function setupParts( widget ) {
3359 if ( widget.parts ) {
3360 var parts = {},
3361 el, partName;
3362
3363 for ( partName in widget.parts ) {
3364 el = widget.wrapper.findOne( widget.parts[ partName ] );
3365 parts[ partName ] = el;
3366 }
3367 widget.parts = parts;
3368 }
3369 }
3370
3371 function setupWidget( widget, widgetDef ) {
3372 setupWrapper( widget );
3373 setupParts( widget );
3374 setupEditables( widget );
3375 setupMask( widget );
3376 setupDragHandler( widget );
3377 setupDataClassesListener( widget );
3378 setupA11yListener( widget );
3379
3380 // #11145: [IE8] Non-editable content of widget is draggable.
3381 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
3382 widget.wrapper.on( 'dragstart', function( evt ) {
3383 var target = evt.data.getTarget();
3384
3385 // Allow text dragging inside nested editables or dragging inline widget's drag handler.
3386 if ( !Widget.getNestedEditable( widget, target ) && !( widget.inline && Widget.isDomDragHandler( target ) ) )
3387 evt.data.preventDefault();
3388 } );
3389 }
3390
3391 widget.wrapper.removeClass( 'cke_widget_new' );
3392 widget.element.addClass( 'cke_widget_element' );
3393
3394 widget.on( 'key', function( evt ) {
3395 var keyCode = evt.data.keyCode;
3396
3397 // ENTER.
3398 if ( keyCode == 13 ) {
3399 widget.edit();
3400 // CTRL+C or CTRL+X.
3401 } else if ( keyCode == CKEDITOR.CTRL + 67 || keyCode == CKEDITOR.CTRL + 88 ) {
3402 copySingleWidget( widget, keyCode == CKEDITOR.CTRL + 88 );
3403 return; // Do not preventDefault.
3404 } else if ( keyCode in keystrokesNotBlockedByWidget || ( CKEDITOR.CTRL & keyCode ) || ( CKEDITOR.ALT & keyCode ) ) {
3405 // Pass chosen keystrokes to other plugins or default fake sel handlers.
3406 // Pass all CTRL/ALT keystrokes.
3407 return;
3408 }
3409
3410 return false;
3411 }, null, null, 999 );
3412 // Listen with high priority so it's possible
3413 // to overwrite this callback.
3414
3415 widget.on( 'doubleclick', function( evt ) {
3416 if ( widget.edit() ) {
3417 // We have to cancel event if edit method opens a dialog, otherwise
3418 // link plugin may open extra dialog (#12140).
3419 evt.cancel();
3420 }
3421 } );
3422
3423 if ( widgetDef.data )
3424 widget.on( 'data', widgetDef.data );
3425
3426 if ( widgetDef.edit )
3427 widget.on( 'edit', widgetDef.edit );
3428 }
3429
3430 function setupWidgetData( widget, startupData ) {
3431 var widgetDataAttr = widget.element.data( 'cke-widget-data' );
3432
3433 if ( widgetDataAttr )
3434 widget.setData( JSON.parse( decodeURIComponent( widgetDataAttr ) ) );
3435 if ( startupData )
3436 widget.setData( startupData );
3437
3438 // Populate classes if they are not preset.
3439 if ( !widget.data.classes )
3440 widget.setData( 'classes', widget.getClasses() );
3441
3442 // Unblock data and...
3443 widget.dataReady = true;
3444
3445 // Write data to element because this was blocked when data wasn't ready.
3446 writeDataToElement( widget );
3447
3448 // Fire data event first time, because this was blocked when data wasn't ready.
3449 widget.fire( 'data', widget.data );
3450 }
3451
3452 function setupWrapper( widget ) {
3453 // Retrieve widget wrapper. Assign an id to it.
3454 var wrapper = widget.wrapper = widget.element.getParent();
3455 wrapper.setAttribute( 'data-cke-widget-id', widget.id );
3456 }
3457
3458 function writeDataToElement( widget ) {
3459 widget.element.data( 'cke-widget-data', encodeURIComponent( JSON.stringify( widget.data ) ) );
3460 }
3461
3462 //
3463 // WIDGET STYLE HANDLER ---------------------------------------------------
3464 //
3465
3466 ( function() {
3467 // Styles categorized by group. It is used to prevent applying styles for the same group being used together.
3468 var styleGroups = {};
3469
3470 /**
3471 * The class representing a widget style. It is an {@link CKEDITOR#STYLE_OBJECT object} like
3472 * the styles handler for widgets.
3473 *
3474 * **Note:** This custom style handler does not support all methods of the {@link CKEDITOR.style} class.
3475 * Not supported methods: {@link #applyToRange}, {@link #removeFromRange}, {@link #applyToObject}.
3476 *
3477 * @since 4.4
3478 * @class CKEDITOR.style.customHandlers.widget
3479 * @extends CKEDITOR.style
3480 */
3481 CKEDITOR.style.addCustomHandler( {
3482 type: 'widget',
3483
3484 setup: function( styleDefinition ) {
3485 /**
3486 * The name of widget to which this style can be applied.
3487 * It is extracted from style definition's `widget` property.
3488 *
3489 * @property {String} widget
3490 */
3491 this.widget = styleDefinition.widget;
3492
3493 /**
3494 * An array of groups that this style belongs to.
3495 * Styles assigned to the same group cannot be combined.
3496 *
3497 * @since 4.6.2
3498 * @property {Array} group
3499 */
3500 this.group = typeof styleDefinition.group == 'string' ? [ styleDefinition.group ] : styleDefinition.group;
3501
3502 // Store style categorized by its group.
3503 // It is used to prevent enabling two styles from same group.
3504 if ( this.group ) {
3505 saveStyleGroup( this );
3506 }
3507 },
3508
3509 apply: function( editor ) {
3510 var widget;
3511
3512 // Before CKEditor 4.4 wasn't a required argument, so we need to
3513 // handle a case when it wasn't provided.
3514 if ( !( editor instanceof CKEDITOR.editor ) )
3515 return;
3516
3517 // Theoretically we could bypass checkApplicable, get widget from
3518 // widgets.focused and check its name, what would be faster, but then
3519 // this custom style would work differently than the default style
3520 // which checks if it's applicable before applying or removing itself.
3521 if ( this.checkApplicable( editor.elementPath(), editor ) ) {
3522 widget = editor.widgets.focused;
3523
3524 // Remove other styles from the same group.
3525 if ( this.group ) {
3526 this.removeStylesFromSameGroup( editor );
3527 }
3528
3529 widget.applyStyle( this );
3530 }
3531 },
3532
3533 remove: function( editor ) {
3534 // Before CKEditor 4.4 wasn't a required argument, so we need to
3535 // handle a case when it wasn't provided.
3536 if ( !( editor instanceof CKEDITOR.editor ) )
3537 return;
3538
3539 if ( this.checkApplicable( editor.elementPath(), editor ) )
3540 editor.widgets.focused.removeStyle( this );
3541 },
3542
3543 /**
3544 * Removes all styles that belong to the same group as this style. This method will neither add nor remove
3545 * the current style.
3546 * Returns `true` if any style was removed, otherwise returns `false`.
3547 *
3548 * @since 4.6.2
3549 * @param {CKEDITOR.editor} editor
3550 * @returns {Boolean}
3551 */
3552 removeStylesFromSameGroup: function( editor ) {
3553 var stylesFromSameGroup,
3554 path,
3555 removed = false;
3556
3557 // Before CKEditor 4.4 wasn't a required argument, so we need to
3558 // handle a case when it wasn't provided.
3559 if ( !( editor instanceof CKEDITOR.editor ) )
3560 return false;
3561
3562 path = editor.elementPath();
3563 if ( this.checkApplicable( path, editor ) ) {
3564 // Iterate over each group.
3565 for ( var i = 0, l = this.group.length; i < l; i++ ) {
3566 stylesFromSameGroup = styleGroups[ this.widget ][ this.group[ i ] ];
3567 // Iterate over each style from group.
3568 for ( var j = 0; j < stylesFromSameGroup.length; j++ ) {
3569 if ( stylesFromSameGroup[ j ] !== this && stylesFromSameGroup[ j ].checkActive( path, editor ) ) {
3570 editor.widgets.focused.removeStyle( stylesFromSameGroup[ j ] );
3571 removed = true;
3572 }
3573 }
3574 }
3575 }
3576
3577 return removed;
3578 },
3579
3580 checkActive: function( elementPath, editor ) {
3581 return this.checkElementMatch( elementPath.lastElement, 0, editor );
3582 },
3583
3584 checkApplicable: function( elementPath, editor ) {
3585 // Before CKEditor 4.4 wasn't a required argument, so we need to
3586 // handle a case when it wasn't provided.
3587 if ( !( editor instanceof CKEDITOR.editor ) )
3588 return false;
3589
3590 return this.checkElement( elementPath.lastElement );
3591 },
3592
3593 checkElementMatch: checkElementMatch,
3594
3595 checkElementRemovable: checkElementMatch,
3596
3597 /**
3598 * Checks if an element is a {@link CKEDITOR.plugins.widget#wrapper wrapper} of a
3599 * widget whose name matches the {@link #widget widget name} specified in the style definition.
3600 *
3601 * @param {CKEDITOR.dom.element} element
3602 * @returns {Boolean}
3603 */
3604 checkElement: function( element ) {
3605 if ( !Widget.isDomWidgetWrapper( element ) )
3606 return false;
3607
3608 var widgetElement = element.getFirst( Widget.isDomWidgetElement );
3609 return widgetElement && widgetElement.data( 'widget' ) == this.widget;
3610 },
3611
3612 buildPreview: function( label ) {
3613 return label || this._.definition.name;
3614 },
3615
3616 /**
3617 * Returns allowed content rules which should be registered for this style.
3618 * Uses widget's {@link CKEDITOR.plugins.widget.definition#styleableElements} to make a rule
3619 * allowing classes on specified elements or use widget's
3620 * {@link CKEDITOR.plugins.widget.definition#styleToAllowedContentRules} method to transform a style
3621 * into allowed content rules.
3622 *
3623 * @param {CKEDITOR.editor} The editor instance.
3624 * @returns {CKEDITOR.filter.allowedContentRules}
3625 */
3626 toAllowedContentRules: function( editor ) {
3627 if ( !editor )
3628 return null;
3629
3630 var widgetDef = editor.widgets.registered[ this.widget ],
3631 classes,
3632 rule = {};
3633
3634 if ( !widgetDef )
3635 return null;
3636
3637 if ( widgetDef.styleableElements ) {
3638 classes = this.getClassesArray();
3639 if ( !classes )
3640 return null;
3641
3642 rule[ widgetDef.styleableElements ] = {
3643 classes: classes,
3644 propertiesOnly: true
3645 };
3646 return rule;
3647 }
3648 if ( widgetDef.styleToAllowedContentRules )
3649 return widgetDef.styleToAllowedContentRules( this );
3650 return null;
3651 },
3652
3653 /**
3654 * Returns classes defined in the style in form of an array.
3655 *
3656 * @returns {String[]}
3657 */
3658 getClassesArray: function() {
3659 var classes = this._.definition.attributes && this._.definition.attributes[ 'class' ];
3660
3661 return classes ? CKEDITOR.tools.trim( classes ).split( /\s+/ ) : null;
3662 },
3663
3664 /**
3665 * Not implemented.
3666 *
3667 * @method applyToRange
3668 */
3669 applyToRange: notImplemented,
3670
3671 /**
3672 * Not implemented.
3673 *
3674 * @method removeFromRange
3675 */
3676 removeFromRange: notImplemented,
3677
3678 /**
3679 * Not implemented.
3680 *
3681 * @method applyToObject
3682 */
3683 applyToObject: notImplemented
3684 } );
3685
3686 function notImplemented() {}
3687
3688 // @context style
3689 function checkElementMatch( element, fullMatch, editor ) {
3690 // Before CKEditor 4.4 wasn't a required argument, so we need to
3691 // handle a case when it wasn't provided.
3692 if ( !editor )
3693 return false;
3694
3695 if ( !this.checkElement( element ) )
3696 return false;
3697
3698 var widget = editor.widgets.getByElement( element, true );
3699 return widget && widget.checkStyleActive( this );
3700 }
3701
3702 // Save and categorize style by its group.
3703 function saveStyleGroup( style ) {
3704 var widgetName = style.widget,
3705 group;
3706
3707 if ( !styleGroups[ widgetName ] ) {
3708 styleGroups[ widgetName ] = {};
3709 }
3710
3711 for ( var i = 0, l = style.group.length; i < l; i++ ) {
3712 group = style.group[ i ];
3713 if ( !styleGroups[ widgetName ][ group ] ) {
3714 styleGroups[ widgetName ][ group ] = [];
3715 }
3716
3717 styleGroups[ widgetName ][ group ].push( style );
3718 }
3719 }
3720
3721 } )();
3722
3723 //
3724 // EXPOSE PUBLIC API ------------------------------------------------------
3725 //
3726
3727 CKEDITOR.plugins.widget = Widget;
3728 Widget.repository = Repository;
3729 Widget.nestedEditable = NestedEditable;
3730} )();
3731
3732/**
3733 * An event fired when a widget definition is registered by the {@link CKEDITOR.plugins.widget.repository#add} method.
3734 * It is possible to modify the definition being registered.
3735 *
3736 * @event widgetDefinition
3737 * @member CKEDITOR.editor
3738 * @param {CKEDITOR.plugins.widget.definition} data Widget definition.
3739 */
3740
3741/**
3742 * This is an abstract class that describes the definition of a widget.
3743 * It is a type of {@link CKEDITOR.plugins.widget.repository#add} method's second argument.
3744 *
3745 * Widget instances inherit from registered widget definitions, although not in a prototypal way.
3746 * They are simply extended with corresponding widget definitions. Note that not all properties of
3747 * the widget definition become properties of a widget. Some, like {@link #data} or {@link #edit}, become
3748 * widget's events listeners.
3749 *
3750 * @class CKEDITOR.plugins.widget.definition
3751 * @abstract
3752 * @mixins CKEDITOR.feature
3753 */
3754
3755/**
3756 * Widget definition name. It is automatically set when the definition is
3757 * {@link CKEDITOR.plugins.widget.repository#add registered}.
3758 *
3759 * @property {String} name
3760 */
3761
3762/**
3763 * The method executed while initializing a widget, after a widget instance
3764 * is created, but before it is ready. It is executed before the first
3765 * {@link CKEDITOR.plugins.widget#event-data} is fired so it is common to
3766 * use the `init` method to populate widget data with information loaded from
3767 * the DOM, like for exmaple:
3768 *
3769 * init: function() {
3770 * this.setData( 'width', this.element.getStyle( 'width' ) );
3771 *
3772 * if ( this.parts.caption.getStyle( 'display' ) != 'none' )
3773 * this.setData( 'showCaption', true );
3774 * }
3775 *
3776 * @property {Function} init
3777 */
3778
3779/**
3780 * The function to be used to upcast an element to this widget or a
3781 * comma-separated list of upcast methods from the {@link #upcasts} object.
3782 *
3783 * The upcast function **is not** executed in the widget context (because the widget
3784 * does not exist yet) and two arguments are passed:
3785 *
3786 * * `element` ({@link CKEDITOR.htmlParser.element}) &ndash; The element to be checked.
3787 * * `data` (`Object`) &ndash; The object which can be extended with data which will then be passed to the widget.
3788 *
3789 * An element will be upcasted if a function returned `true` or an instance of
3790 * a {@link CKEDITOR.htmlParser.element} if upcasting meant DOM structure changes
3791 * (in this case the widget will be initialized on the returned element).
3792 *
3793 * @property {String/Function} upcast
3794 */
3795
3796/**
3797 * The object containing functions which can be used to upcast this widget.
3798 * Only those pointed by the {@link #upcast} property will be used.
3799 *
3800 * In most cases it is appropriate to use {@link #upcast} directly,
3801 * because majority of widgets need just one method.
3802 * However, in some cases the widget author may want to expose more than one variant
3803 * and then this property may be used.
3804 *
3805 * upcasts: {
3806 * // This function may upcast only figure elements.
3807 * figure: function() {
3808 * // ...
3809 * },
3810 * // This function may upcast only image elements.
3811 * image: function() {
3812 * // ...
3813 * },
3814 * // More variants...
3815 * }
3816 *
3817 * // Then, widget user may choose which upcast methods will be enabled.
3818 * editor.on( 'widgetDefinition', function( evt ) {
3819 * if ( evt.data.name == 'image' )
3820 * evt.data.upcast = 'figure,image'; // Use both methods.
3821 * } );
3822 *
3823 * @property {Object} upcasts
3824 */
3825
3826/**
3827 * The {@link #upcast} method(s) priority. The upcast with a lower priority number will be called before
3828 * the one with a higher number. The default priority is `10`.
3829 *
3830 * @since 4.5
3831 * @property {Number} [upcastPriority=10]
3832 */
3833
3834/**
3835 * The function to be used to downcast this widget or
3836 * a name of the downcast option from the {@link #downcasts} object.
3837 *
3838 * The downcast funciton will be executed in the {@link CKEDITOR.plugins.widget} context
3839 * and with `widgetElement` ({@link CKEDITOR.htmlParser.element}) argument which is
3840 * the widget's main element.
3841 *
3842 * The function may return an instance of the {@link CKEDITOR.htmlParser.node} class if the widget
3843 * needs to be downcasted to a different node than the widget's main element.
3844 *
3845 * @property {String/Function} downcast
3846 */
3847
3848/**
3849 * The object containing functions which can be used to downcast this widget.
3850 * Only the one pointed by the {@link #downcast} property will be used.
3851 *
3852 * In most cases it is appropriate to use {@link #downcast} directly,
3853 * because majority of widgets have just one variant of downcasting (or none at all).
3854 * However, in some cases the widget author may want to expose more than one variant
3855 * and then this property may be used.
3856 *
3857 * downcasts: {
3858 * // This downcast may transform the widget into the figure element.
3859 * figure: function() {
3860 * // ...
3861 * },
3862 * // This downcast may transform the widget into the image element with data-* attributes.
3863 * image: function() {
3864 * // ...
3865 * }
3866 * }
3867 *
3868 * // Then, the widget user may choose one of the downcast options when setting up his editor.
3869 * editor.on( 'widgetDefinition', function( evt ) {
3870 * if ( evt.data.name == 'image' )
3871 * evt.data.downcast = 'figure';
3872 * } );
3873 *
3874 * @property downcasts
3875 */
3876
3877/**
3878 * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-edit} event listener.
3879 * This means that it will be executed when a widget is being edited.
3880 * See the {@link CKEDITOR.plugins.widget#method-edit} method.
3881 *
3882 * @property {Function} edit
3883 */
3884
3885/**
3886 * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-data} event listener.
3887 * This means that it will be executed every time the {@link CKEDITOR.plugins.widget#property-data widget data} changes.
3888 *
3889 * @property {Function} data
3890 */
3891
3892/**
3893 * The method to be executed when the widget's command is executed in order to insert a new widget
3894 * (widget of this type is not focused). If not defined, then the default action will be
3895 * performed which means that:
3896 *
3897 * * An instance of the widget will be created in a detached {@link CKEDITOR.dom.documentFragment document fragment},
3898 * * The {@link CKEDITOR.plugins.widget#method-edit} method will be called to trigger widget editing,
3899 * * The widget element will be inserted into DOM.
3900 *
3901 * @property {Function} insert
3902 */
3903
3904/**
3905 * The name of a dialog window which will be opened on {@link CKEDITOR.plugins.widget#method-edit}.
3906 * If not defined, then the {@link CKEDITOR.plugins.widget#method-edit} method will not perform any action and
3907 * widget's command will insert a new widget without opening a dialog window first.
3908 *
3909 * @property {String} dialog
3910 */
3911
3912/**
3913 * The template which will be used to create a new widget element (when the widget's command is executed).
3914 * This string is populated with {@link #defaults default values} by using the {@link CKEDITOR.template} format.
3915 * Therefore it has to be a valid {@link CKEDITOR.template} argument.
3916 *
3917 * @property {String} template
3918 */
3919
3920/**
3921 * The data object which will be used to populate the data of a newly created widget.
3922 * See {@link CKEDITOR.plugins.widget#property-data}.
3923 *
3924 * defaults: {
3925 * showCaption: true,
3926 * align: 'none'
3927 * }
3928 *
3929 * @property defaults
3930 */
3931
3932/**
3933 * An object containing definitions of widget components (part name => CSS selector).
3934 *
3935 * parts: {
3936 * image: 'img',
3937 * caption: 'div.caption'
3938 * }
3939 *
3940 * @property parts
3941 */
3942
3943/**
3944 * An object containing definitions of nested editables (editable name => {@link CKEDITOR.plugins.widget.nestedEditable.definition}).
3945 * Note that editables *have to* be defined in the same order as they are in DOM / {@link CKEDITOR.plugins.widget.definition#template template}.
3946 * Otherwise errors will occur when nesting widgets inside each other.
3947 *
3948 * editables: {
3949 * header: 'h1',
3950 * content: {
3951 * selector: 'div.content',
3952 * allowedContent: 'p strong em; a[!href]'
3953 * }
3954 * }
3955 *
3956 * @property editables
3957 */
3958
3959/**
3960 * The function used to obtain an accessibility label for the widget. It might be used to make
3961 * the widget labels as precise as possible, since it has access to the widget instance.
3962 *
3963 * If not specified, the default implementation will use the {@link #pathName} or the main
3964 * {@link CKEDITOR.plugins.widget#element element} tag name.
3965 *
3966 * @property {Function} getLabel
3967 */
3968
3969/**
3970 * The widget name displayed in the elements path.
3971 *
3972 * @property {String} pathName
3973 */
3974
3975/**
3976 * If set to `true`, the widget's element will be covered with a transparent mask.
3977 * This will prevent its content from being clickable, which matters in case
3978 * of special elements like embedded Flash or iframes that generate a separate "context".
3979 *
3980 * @property {Boolean} mask
3981 */
3982
3983/**
3984 * If set to `true/false`, it will force the widget to be either an inline or a block widget.
3985 * If not set, the widget type will be determined from the widget element.
3986 *
3987 * Widget type influences whether a block (`div`) or an inline (`span`) element is used
3988 * for the wrapper.
3989 *
3990 * @property {Boolean} inline
3991 */
3992
3993/**
3994 * The label for the widget toolbar button.
3995 *
3996 * editor.widgets.add( 'simplebox', {
3997 * button: 'Create a simple box'
3998 * } );
3999 *
4000 * editor.widgets.add( 'simplebox', {
4001 * button: editor.lang.simplebox.title
4002 * } );
4003 *
4004 * @property {String} button
4005 */
4006
4007/**
4008 * Whether widget should be draggable. Defaults to `true`.
4009 * If set to `false` drag handler will not be displayed when hovering widget.
4010 *
4011 * @property {Boolean} draggable
4012 */
4013
4014/**
4015 * Names of element(s) (separated by spaces) for which the {@link CKEDITOR.filter} should allow classes
4016 * defined in the widget styles. For example if your widget is upcasted from a simple `<div>`
4017 * element, then in order to make it styleable you can set:
4018 *
4019 * editor.widgets.add( 'customWidget', {
4020 * upcast: function( element ) {
4021 * return element.name == 'div';
4022 * },
4023 *
4024 * // ...
4025 *
4026 * styleableElements: 'div'
4027 * } );
4028 *
4029 * Then, when the following style is defined:
4030 *
4031 * {
4032 * name: 'Thick border', type: 'widget', widget: 'customWidget',
4033 * attributes: { 'class': 'thickBorder' }
4034 * }
4035 *
4036 * a rule allowing the `thickBorder` class for `div` elements will be registered in the {@link CKEDITOR.filter}.
4037 *
4038 * If you need to have more freedom when transforming widget style to allowed content rules,
4039 * you can use the {@link #styleToAllowedContentRules} callback.
4040 *
4041 * @since 4.4
4042 * @property {String} styleableElements
4043 */
4044
4045/**
4046 * Function transforming custom widget's {@link CKEDITOR.style} instance into
4047 * {@link CKEDITOR.filter.allowedContentRules}. It may be used when a static
4048 * {@link #styleableElements} property is not enough to inform the {@link CKEDITOR.filter}
4049 * what HTML features should be enabled when allowing the given style.
4050 *
4051 * In most cases, when style's classes just have to be added to element name(s) used by
4052 * the widget element, it is recommended to use simpler {@link #styleableElements} property.
4053 *
4054 * In order to get parsed classes from the style definition you can use
4055 * {@link CKEDITOR.style.customHandlers.widget#getClassesArray}.
4056 *
4057 * For example, if you want to use the [object format of allowed content rules](#!/guide/dev_allowed_content_rules-section-object-format),
4058 * to specify `match` validator, your implementation could look like this:
4059 *
4060 * editor.widgets.add( 'customWidget', {
4061 * // ...
4062 *
4063 * styleToAllowedContentRules: funciton( style ) {
4064 * // Retrieve classes defined in the style.
4065 * var classes = style.getClassesArray();
4066 *
4067 * // Do something crazy - for example return allowed content rules in object format,
4068 * // with custom match property and propertiesOnly flag.
4069 * return {
4070 * h1: {
4071 * match: isWidgetElement,
4072 * propertiesOnly: true,
4073 * classes: classes
4074 * }
4075 * };
4076 * }
4077 * } );
4078 *
4079 * @since 4.4
4080 * @property {Function} styleToAllowedContentRules
4081 * @param {CKEDITOR.style.customHandlers.widget} style The style to be transformed.
4082 * @returns {CKEDITOR.filter.allowedContentRules}
4083 */
4084
4085/**
4086 * This is an abstract class that describes the definition of a widget's nested editable.
4087 * It is a type of values in the {@link CKEDITOR.plugins.widget.definition#editables} object.
4088 *
4089 * In the simplest case the definition is a string which is a CSS selector used to
4090 * find an element that will become a nested editable inside the widget. Note that
4091 * the widget element can be a nested editable, too.
4092 *
4093 * In the more advanced case a definition is an object with a required `selector` property.
4094 *
4095 * editables: {
4096 * header: 'h1',
4097 * content: {
4098 * selector: 'div.content',
4099 * allowedContent: 'p strong em; a[!href]'
4100 * }
4101 * }
4102 *
4103 * @class CKEDITOR.plugins.widget.nestedEditable.definition
4104 * @abstract
4105 */
4106
4107/**
4108 * The CSS selector used to find an element which will become a nested editable.
4109 *
4110 * @property {String} selector
4111 */
4112
4113/**
4114 * The [Advanced Content Filter](#!/guide/dev_advanced_content_filter) rules
4115 * which will be used to limit the content allowed in this nested editable.
4116 * This option is similar to {@link CKEDITOR.config#allowedContent} and one can
4117 * use it to limit the editor features available in the nested editable.
4118 *
4119 * @property {CKEDITOR.filter.allowedContentRules} allowedContent
4120 */
4121
4122/**
4123 * Nested editable name displayed in elements path.
4124 *
4125 * @property {String} pathName
4126 */
diff --git a/sources/plugins/widgetselection/plugin.js b/sources/plugins/widgetselection/plugin.js
new file mode 100644
index 0000000..b7aa6a0
--- /dev/null
+++ b/sources/plugins/widgetselection/plugin.js
@@ -0,0 +1,366 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview A plugin created to handle ticket #11064. While the issue is caused by native WebKit/Blink behaviour,
8 * this plugin can be easily detached or modified when the issue is fixed in the browsers without changing the core.
9 * When Ctrl/Cmd + A is pressed to select all content it does not work due to a bug in
10 * Webkit/Blink if a non-editable element is at the beginning or the end of the content.
11 */
12
13( function() {
14 'use strict';
15
16 CKEDITOR.plugins.add( 'widgetselection', {
17
18 init: function( editor ) {
19 if ( CKEDITOR.env.webkit ) {
20 var widgetselection = CKEDITOR.plugins.widgetselection;
21
22 editor.on( 'contentDom', function( evt ) {
23
24 var editor = evt.editor,
25 doc = editor.document,
26 editable = editor.editable();
27
28 editable.attachListener( doc, 'keydown', function( evt ) {
29 var data = evt.data.$;
30
31 // Ctrl/Cmd + A
32 if ( evt.data.getKey() == 65 && ( CKEDITOR.env.mac && data.metaKey || !CKEDITOR.env.mac && data.ctrlKey ) ) {
33
34 // Defer the call so the selection is already changed by the pressed keys.
35 CKEDITOR.tools.setTimeout( function() {
36
37 // Manage filler elements on keydown. If there is no need
38 // to add fillers, we need to check and clean previously used once.
39 if ( !widgetselection.addFillers( editable ) ) {
40 widgetselection.removeFillers( editable );
41 }
42 }, 0 );
43 }
44 }, null, null, -1 );
45
46 // Check and clean previously used fillers.
47 editor.on( 'selectionCheck', function( evt ) {
48 widgetselection.removeFillers( evt.editor.editable() );
49 } );
50
51 // Remove fillers on paste before data gets inserted into editor.
52 editor.on( 'paste', function( evt ) {
53 evt.data.dataValue = widgetselection.cleanPasteData( evt.data.dataValue );
54 } );
55
56 if ( 'selectall' in editor.plugins ) {
57 widgetselection.addSelectAllIntegration( editor );
58 }
59 } );
60 }
61 }
62 } );
63
64 /**
65 * A set of helper methods for the Widget Selection plugin.
66 *
67 * @property widgetselection
68 * @member CKEDITOR.plugins
69 * @since 4.6.1
70 */
71 CKEDITOR.plugins.widgetselection = {
72
73 /**
74 * The start filler element reference.
75 *
76 * @property {CKEDITOR.dom.element}
77 * @member CKEDITOR.plugins.widgetselection
78 * @private
79 */
80 startFiller: null,
81
82 /**
83 * The end filler element reference.
84 *
85 * @property {CKEDITOR.dom.element}
86 * @member CKEDITOR.plugins.widgetselection
87 * @private
88 */
89 endFiller: null,
90
91 /**
92 * An attribute which identifies the filler element.
93 *
94 * @property {String}
95 * @member CKEDITOR.plugins.widgetselection
96 * @private
97 */
98 fillerAttribute: 'data-cke-filler-webkit',
99
100 /**
101 * The default content of the filler element. Note: The filler needs to have `visible` content.
102 * Unprintable elements or empty content do not help as a workaround.
103 *
104 * @property {String}
105 * @member CKEDITOR.plugins.widgetselection
106 * @private
107 */
108 fillerContent: '&nbsp;',
109
110 /**
111 * Tag name which is used to create fillers.
112 *
113 * @property {String}
114 * @member CKEDITOR.plugins.widgetselection
115 * @private
116 */
117 fillerTagName: 'div',
118
119 /**
120 * Adds a filler before or after a non-editable element at the beginning or the end of the `editable`.
121 *
122 * @param {CKEDITOR.editable} editable
123 * @returns {Boolean}
124 * @member CKEDITOR.plugins.widgetselection
125 */
126 addFillers: function( editable ) {
127 var editor = editable.editor;
128
129 // Whole content should be selected, if not fix the selection manually.
130 if ( !this.isWholeContentSelected( editable ) && editable.getChildCount() > 0 ) {
131
132 var firstChild = editable.getFirst( filterTempElements ),
133 lastChild = editable.getLast( filterTempElements );
134
135 // Check if first element is editable. If not prepend with filler.
136 if ( firstChild && firstChild.type == CKEDITOR.NODE_ELEMENT && !firstChild.isEditable() ) {
137 this.startFiller = this.createFiller();
138 editable.append( this.startFiller, 1 );
139 }
140
141 // Check if last element is editable. If not append filler.
142 if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && !lastChild.isEditable() ) {
143 this.endFiller = this.createFiller( true );
144 editable.append( this.endFiller, 0 );
145 }
146
147 // Reselect whole content after any filler was added.
148 if ( this.hasFiller( editable ) ) {
149 var rangeAll = editor.createRange();
150 rangeAll.selectNodeContents( editable );
151 rangeAll.select();
152 return true;
153 }
154 }
155 return false;
156 },
157
158 /**
159 * Removes filler elements or updates their references.
160 *
161 * It will **not remove** filler elements if the whole content is selected, as it would break the
162 * selection.
163 *
164 * @param {CKEDITOR.editable} editable
165 * @member CKEDITOR.plugins.widgetselection
166 */
167 removeFillers: function( editable ) {
168 // If startFiller or endFiller exists and not entire content is selected it means the selection
169 // just changed from selected all. We need to remove fillers and set proper selection/content.
170 if ( this.hasFiller( editable ) && !this.isWholeContentSelected( editable ) ) {
171
172 var startFillerContent = editable.findOne( this.fillerTagName + '[' + this.fillerAttribute + '=start]' ),
173 endFillerContent = editable.findOne( this.fillerTagName + '[' + this.fillerAttribute + '=end]' );
174
175 if ( this.startFiller && startFillerContent && this.startFiller.equals( startFillerContent ) ) {
176 this.removeFiller( this.startFiller, editable );
177 } else {
178 // The start filler is still present but it is a different element than previous one. It means the
179 // undo recreating entirely selected content was performed. We need to update filler reference.
180 this.startFiller = startFillerContent;
181 }
182
183 if ( this.endFiller && endFillerContent && this.endFiller.equals( endFillerContent ) ) {
184 this.removeFiller( this.endFiller, editable );
185 } else {
186 // Same as with start filler.
187 this.endFiller = endFillerContent;
188 }
189 }
190 },
191
192 /**
193 * Removes fillers from the paste data.
194 *
195 * @param {String} data
196 * @returns {String}
197 * @member CKEDITOR.plugins.widgetselection
198 * @private
199 */
200 cleanPasteData: function( data ) {
201 if ( data && data.length ) {
202 data = data
203 .replace( this.createFillerRegex(), '' )
204 .replace( this.createFillerRegex( true ), '' );
205 }
206 return data;
207 },
208
209 /**
210 * Checks if the entire content of the given editable is selected.
211 *
212 * @param {CKEDITOR.editable} editable
213 * @returns {Boolean}
214 * @member CKEDITOR.plugins.widgetselection
215 * @private
216 */
217 isWholeContentSelected: function( editable ) {
218
219 var range = editable.editor.getSelection().getRanges()[ 0 ];
220 if ( range ) {
221
222 if ( range && range.collapsed ) {
223 return false;
224
225 } else {
226 var rangeClone = range.clone();
227 rangeClone.enlarge( CKEDITOR.ENLARGE_ELEMENT );
228
229 return !!( rangeClone && editable && rangeClone.startContainer && rangeClone.endContainer &&
230 rangeClone.startOffset === 0 && rangeClone.endOffset === editable.getChildCount() &&
231 rangeClone.startContainer.equals( editable ) && rangeClone.endContainer.equals( editable ) );
232 }
233 }
234 return false;
235 },
236
237 /**
238 * Checks if there is any filler element in the given editable.
239 *
240 * @param {CKEDITOR.editable} editable
241 * @returns {Boolean}
242 * @member CKEDITOR.plugins.widgetselection
243 * @private
244 */
245 hasFiller: function( editable ) {
246 return editable.find( this.fillerTagName + '[' + this.fillerAttribute + ']' ).count() > 0;
247 },
248
249 /**
250 * Creates a filler element.
251 *
252 * @param {Boolean} [onEnd] If filler will be placed on end or beginning of the content.
253 * @returns {CKEDITOR.dom.element}
254 * @member CKEDITOR.plugins.widgetselection
255 * @private
256 */
257 createFiller: function( onEnd ) {
258 var filler = new CKEDITOR.dom.element( this.fillerTagName );
259 filler.setHtml( this.fillerContent );
260 filler.setAttribute( this.fillerAttribute, onEnd ? 'end' : 'start' );
261 filler.setAttribute( 'data-cke-temp', 1 );
262 filler.setStyles( {
263 display: 'block',
264 width: 0,
265 height: 0,
266 padding: 0,
267 border: 0,
268 margin: 0,
269 position: 'absolute',
270 top: 0,
271 left: '-9999px',
272 opacity: 0,
273 overflow: 'hidden'
274 } );
275
276 return filler;
277 },
278
279 /**
280 * Removes the specific filler element from the given editable. If the filler contains any content (typed or pasted),
281 * it replaces the current editable content. If not, the caret is placed before the first or after the last editable
282 * element (depends if the filler was at the beginning or the end).
283 *
284 * @param {CKEDITOR.dom.element} filler
285 * @param {CKEDITOR.editable} editable
286 * @member CKEDITOR.plugins.widgetselection
287 * @private
288 */
289 removeFiller: function( filler, editable ) {
290 if ( filler ) {
291 var editor = editable.editor,
292 currentRange = editable.editor.getSelection().getRanges()[ 0 ],
293 currentPath = currentRange.startPath(),
294 range = editor.createRange(),
295 insertedHtml,
296 fillerOnStart,
297 manuallyHandleCaret;
298
299 if ( currentPath.contains( filler ) ) {
300 insertedHtml = filler.getHtml();
301 manuallyHandleCaret = true;
302 }
303
304 fillerOnStart = filler.getAttribute( this.fillerAttribute ) == 'start';
305 filler.remove();
306 filler = null;
307
308 if ( insertedHtml && insertedHtml.length > 0 && insertedHtml != this.fillerContent ) {
309 editable.insertHtmlIntoRange( insertedHtml, editor.getSelection().getRanges()[ 0 ] );
310 range.setStartAt( editable.getChild( editable.getChildCount() - 1 ), CKEDITOR.POSITION_BEFORE_END );
311 editor.getSelection().selectRanges( [ range ] );
312
313 } else if ( manuallyHandleCaret ) {
314 if ( fillerOnStart ) {
315 range.setStartAt( editable.getFirst().getNext(), CKEDITOR.POSITION_AFTER_START );
316 } else {
317 range.setEndAt( editable.getLast().getPrevious(), CKEDITOR.POSITION_BEFORE_END );
318 }
319 editable.editor.getSelection().selectRanges( [ range ] );
320 }
321 }
322 },
323
324 /**
325 * Creates a regular expression which will match the filler HTML in the text.
326 *
327 * @param {Boolean} [onEnd] Whether a regular expression should be created for the filler at the beginning or
328 * the end of the content.
329 * @returns {RegExp}
330 * @member CKEDITOR.plugins.widgetselection
331 * @private
332 */
333 createFillerRegex: function( onEnd ) {
334 var matcher = this.createFiller( onEnd ).getOuterHtml()
335 .replace( /style="[^"]*"/gi, 'style="[^"]*"' )
336 .replace( />[^<]*</gi, '>[^<]*<' );
337
338 return new RegExp( ( !onEnd ? '^' : '' ) + matcher + ( onEnd ? '$' : '' ) );
339 },
340
341 /**
342 * Adds an integration for the [Select All](http://ckeditor.com/addon/selectall) plugin to the given `editor`.
343 *
344 * @private
345 * @param {CKEDITOR.editor} editor
346 * @member CKEDITOR.plugins.widgetselection
347 */
348 addSelectAllIntegration: function( editor ) {
349 var widgetselection = this;
350
351 editor.editable().attachListener( editor, 'beforeCommandExec', function( evt ) {
352 var editable = editor.editable();
353
354 if ( evt.data.name == 'selectAll' && editable ) {
355 widgetselection.addFillers( editable );
356 }
357 }, null, null, 9999 );
358 }
359 };
360
361
362 function filterTempElements( el ) {
363 return el.getName && !el.hasAttribute( 'data-cke-temp' );
364 }
365
366} )();
diff --git a/sources/plugins/wysiwygarea/plugin.js b/sources/plugins/wysiwygarea/plugin.js
new file mode 100644
index 0000000..962f31e
--- /dev/null
+++ b/sources/plugins/wysiwygarea/plugin.js
@@ -0,0 +1,713 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @fileOverview The WYSIWYG Area plugin. It registers the "wysiwyg" editing
8 * mode, which handles the main editing area space.
9 */
10
11( function() {
12 var framedWysiwyg;
13
14 CKEDITOR.plugins.add( 'wysiwygarea', {
15 init: function( editor ) {
16 if ( editor.config.fullPage ) {
17 editor.addFeature( {
18 allowedContent: 'html head title; style [media,type]; body (*)[id]; meta link [*]',
19 requiredContent: 'body'
20 } );
21 }
22
23 editor.addMode( 'wysiwyg', function( callback ) {
24 var src = 'document.open();' +
25 // In IE, the document domain must be set any time we call document.open().
26 ( CKEDITOR.env.ie ? '(' + CKEDITOR.tools.fixDomain + ')();' : '' ) +
27 'document.close();';
28
29 // With IE, the custom domain has to be taken care at first,
30 // for other browers, the 'src' attribute should be left empty to
31 // trigger iframe's 'load' event.
32 // Microsoft Edge throws "Permission Denied" if treated like an IE (#13441).
33 if ( CKEDITOR.env.air ) {
34 src = 'javascript:void(0)'; // jshint ignore:line
35 } else if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
36 src = 'javascript:void(function(){' + encodeURIComponent( src ) + '}())'; // jshint ignore:line
37 } else {
38 src = '';
39 }
40
41 var iframe = CKEDITOR.dom.element.createFromHtml( '<iframe src="' + src + '" frameBorder="0"></iframe>' );
42 iframe.setStyles( { width: '100%', height: '100%' } );
43 iframe.addClass( 'cke_wysiwyg_frame' ).addClass( 'cke_reset' );
44
45 var contentSpace = editor.ui.space( 'contents' );
46 contentSpace.append( iframe );
47
48
49 // Asynchronous iframe loading is only required in IE>8 and Gecko (other reasons probably).
50 // Do not use it on WebKit as it'll break the browser-back navigation.
51 var useOnloadEvent = ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) || CKEDITOR.env.gecko;
52 if ( useOnloadEvent )
53 iframe.on( 'load', onLoad );
54
55 var frameLabel = editor.title,
56 helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label;
57
58 if ( frameLabel ) {
59 if ( CKEDITOR.env.ie && helpLabel )
60 frameLabel += ', ' + helpLabel;
61
62 iframe.setAttribute( 'title', frameLabel );
63 }
64
65 if ( helpLabel ) {
66 var labelId = CKEDITOR.tools.getNextId(),
67 desc = CKEDITOR.dom.element.createFromHtml( '<span id="' + labelId + '" class="cke_voice_label">' + helpLabel + '</span>' );
68
69 contentSpace.append( desc, 1 );
70 iframe.setAttribute( 'aria-describedby', labelId );
71 }
72
73 // Remove the ARIA description.
74 editor.on( 'beforeModeUnload', function( evt ) {
75 evt.removeListener();
76 if ( desc )
77 desc.remove();
78 } );
79
80 iframe.setAttributes( {
81 tabIndex: editor.tabIndex,
82 allowTransparency: 'true'
83 } );
84
85 // Execute onLoad manually for all non IE||Gecko browsers.
86 !useOnloadEvent && onLoad();
87
88 editor.fire( 'ariaWidget', iframe );
89
90 function onLoad( evt ) {
91 evt && evt.removeListener();
92 editor.editable( new framedWysiwyg( editor, iframe.$.contentWindow.document.body ) );
93 editor.setData( editor.getData( 1 ), callback );
94 }
95 } );
96 }
97 } );
98
99 /**
100 * Adds the path to a stylesheet file to the exisiting {@link CKEDITOR.config#contentsCss} value.
101 *
102 * **Note:** This method is available only with the `wysiwygarea` plugin and only affects
103 * classic editors based on it (so it does not affect inline editors).
104 *
105 * editor.addContentsCss( 'assets/contents.css' );
106 *
107 * @since 4.4
108 * @param {String} cssPath The path to the stylesheet file which should be added.
109 * @member CKEDITOR.editor
110 */
111 CKEDITOR.editor.prototype.addContentsCss = function( cssPath ) {
112 var cfg = this.config,
113 curContentsCss = cfg.contentsCss;
114
115 // Convert current value into array.
116 if ( !CKEDITOR.tools.isArray( curContentsCss ) )
117 cfg.contentsCss = curContentsCss ? [ curContentsCss ] : [];
118
119 cfg.contentsCss.push( cssPath );
120 };
121
122 function onDomReady( win ) {
123 var editor = this.editor,
124 doc = win.document,
125 body = doc.body;
126
127 // Remove helper scripts from the DOM.
128 var script = doc.getElementById( 'cke_actscrpt' );
129 script && script.parentNode.removeChild( script );
130 script = doc.getElementById( 'cke_shimscrpt' );
131 script && script.parentNode.removeChild( script );
132 script = doc.getElementById( 'cke_basetagscrpt' );
133 script && script.parentNode.removeChild( script );
134
135 body.contentEditable = true;
136
137 if ( CKEDITOR.env.ie ) {
138 // Don't display the focus border.
139 body.hideFocus = true;
140
141 // Disable and re-enable the body to avoid IE from
142 // taking the editing focus at startup. (#141 / #523)
143 body.disabled = true;
144 body.removeAttribute( 'disabled' );
145 }
146
147 delete this._.isLoadingData;
148
149 // Play the magic to alter element reference to the reloaded one.
150 this.$ = body;
151
152 doc = new CKEDITOR.dom.document( doc );
153
154 this.setup();
155 this.fixInitialSelection();
156
157 var editable = this;
158
159 // Without it IE8 has problem with removing selection in nested editable. (#13785)
160 if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
161 doc.getDocumentElement().addClass( doc.$.compatMode );
162 }
163
164 // Prevent IE/Edge from leaving a new paragraph/div after deleting all contents in body. (#6966, #13142)
165 if ( CKEDITOR.env.ie && !CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_P ) {
166 removeSuperfluousElement( 'p' );
167 } else if ( CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_DIV ) {
168 removeSuperfluousElement( 'div' );
169 }
170
171 // Fix problem with cursor not appearing in Webkit and IE11+ when clicking below the body (#10945, #10906).
172 // Fix for older IEs (8-10 and QM) is placed inside selection.js.
173 if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version > 10 ) ) {
174 doc.getDocumentElement().on( 'mousedown', function( evt ) {
175 if ( evt.data.getTarget().is( 'html' ) ) {
176 // IE needs this timeout. Webkit does not, but it does not cause problems too.
177 setTimeout( function() {
178 editor.editable().focus();
179 } );
180 }
181 } );
182 }
183
184 // Config props: disableObjectResizing and disableNativeTableHandles handler.
185 objectResizeDisabler( editor );
186
187 // Enable dragging of position:absolute elements in IE.
188 try {
189 editor.document.$.execCommand( '2D-position', false, true );
190 } catch ( e ) {}
191
192 if ( CKEDITOR.env.gecko || CKEDITOR.env.ie && editor.document.$.compatMode == 'CSS1Compat' ) {
193 this.attachListener( this, 'keydown', function( evt ) {
194 var keyCode = evt.data.getKeystroke();
195
196 // PageUp OR PageDown
197 if ( keyCode == 33 || keyCode == 34 ) {
198 // PageUp/PageDown scrolling is broken in document
199 // with standard doctype, manually fix it. (#4736)
200 if ( CKEDITOR.env.ie ) {
201 setTimeout( function() {
202 editor.getSelection().scrollIntoView();
203 }, 0 );
204 }
205 // Page up/down cause editor selection to leak
206 // outside of editable thus we try to intercept
207 // the behavior, while it affects only happen
208 // when editor contents are not overflowed. (#7955)
209 else if ( editor.window.$.innerHeight > this.$.offsetHeight ) {
210 var range = editor.createRange();
211 range[ keyCode == 33 ? 'moveToElementEditStart' : 'moveToElementEditEnd' ]( this );
212 range.select();
213 evt.data.preventDefault();
214 }
215 }
216 } );
217 }
218
219 if ( CKEDITOR.env.ie ) {
220 // [IE] Iframe will still keep the selection when blurred, if
221 // focus is moved onto a non-editing host, e.g. link or button, but
222 // it becomes a problem for the object type selection, since the resizer
223 // handler attached on it will mark other part of the UI, especially
224 // for the dialog. (#8157)
225 // [IE<8 & Opera] Even worse For old IEs, the cursor will not vanish even if
226 // the selection has been moved to another text input in some cases. (#4716)
227 //
228 // Now the range restore is disabled, so we simply force IE to clean
229 // up the selection before blur.
230 this.attachListener( doc, 'blur', function() {
231 // Error proof when the editor is not visible. (#6375)
232 try {
233 doc.$.selection.empty();
234 } catch ( er ) {}
235 } );
236 }
237
238 if ( CKEDITOR.env.iOS ) {
239 // [iOS] If touch is bound to any parent of the iframe blur happens on any touch
240 // event and body becomes the focused element (#10714).
241 this.attachListener( doc, 'touchend', function() {
242 win.focus();
243 } );
244 }
245
246 var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );
247 // document.title is malfunctioning on Chrome, so get value from the element (#12402).
248 title.data( 'cke-title', title.getText() );
249
250 // [IE] JAWS will not recognize the aria label we used on the iframe
251 // unless the frame window title string is used as the voice label,
252 // backup the original one and restore it on output.
253 if ( CKEDITOR.env.ie )
254 editor.document.$.title = this._.docTitle;
255
256 CKEDITOR.tools.setTimeout( function() {
257 // Editable is ready after first setData.
258 if ( this.status == 'unloaded' )
259 this.status = 'ready';
260
261 editor.fire( 'contentDom' );
262
263 if ( this._.isPendingFocus ) {
264 editor.focus();
265 this._.isPendingFocus = false;
266 }
267
268 setTimeout( function() {
269 editor.fire( 'dataReady' );
270 }, 0 );
271 }, 0, this );
272
273 function removeSuperfluousElement( tagName ) {
274 var lockRetain = false;
275
276 // Superfluous elements appear after keydown
277 // and before keyup, so the procedure is as follows:
278 // 1. On first keydown mark all elements with
279 // a specified tag name as non-superfluous.
280 editable.attachListener( editable, 'keydown', function() {
281 var body = doc.getBody(),
282 retained = body.getElementsByTag( tagName );
283
284 if ( !lockRetain ) {
285 for ( var i = 0; i < retained.count(); i++ ) {
286 retained.getItem( i ).setCustomData( 'retain', true );
287 }
288 lockRetain = true;
289 }
290 }, null, null, 1 );
291
292 // 2. On keyup remove all elements that were not marked
293 // as non-superfluous (which means they must have had appeared in the meantime).
294 // Also we should preserve all temporary elements inserted by editor – otherwise we'd likely
295 // leak fake selection's content into editable due to removing hidden selection container (#14831).
296 editable.attachListener( editable, 'keyup', function() {
297 var elements = doc.getElementsByTag( tagName );
298 if ( lockRetain ) {
299 if ( elements.count() == 1 && !elements.getItem( 0 ).getCustomData( 'retain' ) &&
300 !elements.getItem( 0 ).hasAttribute( 'data-cke-temp' ) ) {
301 elements.getItem( 0 ).remove( 1 );
302 }
303 lockRetain = false;
304 }
305 } );
306 }
307 }
308
309 framedWysiwyg = CKEDITOR.tools.createClass( {
310 $: function() {
311 this.base.apply( this, arguments );
312
313 this._.frameLoadedHandler = CKEDITOR.tools.addFunction( function( win ) {
314 // Avoid opening design mode in a frame window thread,
315 // which will cause host page scrolling.(#4397)
316 CKEDITOR.tools.setTimeout( onDomReady, 0, this, win );
317 }, this );
318
319 this._.docTitle = this.getWindow().getFrame().getAttribute( 'title' );
320 },
321
322 base: CKEDITOR.editable,
323
324 proto: {
325 setData: function( data, isSnapshot ) {
326 var editor = this.editor;
327
328 if ( isSnapshot ) {
329 this.setHtml( data );
330 this.fixInitialSelection();
331
332 // Fire dataReady for the consistency with inline editors
333 // and because it makes sense. (#10370)
334 editor.fire( 'dataReady' );
335 }
336 else {
337 this._.isLoadingData = true;
338 editor._.dataStore = { id: 1 };
339
340 var config = editor.config,
341 fullPage = config.fullPage,
342 docType = config.docType;
343
344 // Build the additional stuff to be included into <head>.
345 var headExtra = CKEDITOR.tools.buildStyleHtml( iframeCssFixes() ).replace( /<style>/, '<style data-cke-temp="1">' );
346
347 if ( !fullPage )
348 headExtra += CKEDITOR.tools.buildStyleHtml( editor.config.contentsCss );
349
350 var baseTag = config.baseHref ? '<base href="' + config.baseHref + '" data-cke-temp="1" />' : '';
351
352 if ( fullPage ) {
353 // Search and sweep out the doctype declaration.
354 data = data.replace( /<!DOCTYPE[^>]*>/i, function( match ) {
355 editor.docType = docType = match;
356 return '';
357 } ).replace( /<\?xml\s[^\?]*\?>/i, function( match ) {
358 editor.xmlDeclaration = match;
359 return '';
360 } );
361 }
362
363 // Get the HTML version of the data.
364 data = editor.dataProcessor.toHtml( data );
365
366 if ( fullPage ) {
367 // Check if the <body> tag is available.
368 if ( !( /<body[\s|>]/ ).test( data ) )
369 data = '<body>' + data;
370
371 // Check if the <html> tag is available.
372 if ( !( /<html[\s|>]/ ).test( data ) )
373 data = '<html>' + data + '</html>';
374
375 // Check if the <head> tag is available.
376 if ( !( /<head[\s|>]/ ).test( data ) )
377 data = data.replace( /<html[^>]*>/, '$&<head><title></title></head>' );
378 else if ( !( /<title[\s|>]/ ).test( data ) )
379 data = data.replace( /<head[^>]*>/, '$&<title></title>' );
380
381 // The base must be the first tag in the HEAD, e.g. to get relative
382 // links on styles.
383 baseTag && ( data = data.replace( /<head[^>]*?>/, '$&' + baseTag ) );
384
385 // Inject the extra stuff into <head>.
386 // Attention: do not change it before testing it well. (V2)
387 // This is tricky... if the head ends with <meta ... content type>,
388 // Firefox will break. But, it works if we place our extra stuff as
389 // the last elements in the HEAD.
390 data = data.replace( /<\/head\s*>/, headExtra + '$&' );
391
392 // Add the DOCTYPE back to it.
393 data = docType + data;
394 } else {
395 data = config.docType +
396 '<html dir="' + config.contentsLangDirection + '"' +
397 ' lang="' + ( config.contentsLanguage || editor.langCode ) + '">' +
398 '<head>' +
399 '<title>' + this._.docTitle + '</title>' +
400 baseTag +
401 headExtra +
402 '</head>' +
403 '<body' + ( config.bodyId ? ' id="' + config.bodyId + '"' : '' ) +
404 ( config.bodyClass ? ' class="' + config.bodyClass + '"' : '' ) +
405 '>' +
406 data +
407 '</body>' +
408 '</html>';
409 }
410
411 if ( CKEDITOR.env.gecko ) {
412 // Hack to make Fx put cursor at the start of doc on fresh focus.
413 data = data.replace( /<body/, '<body contenteditable="true" ' );
414
415 // Another hack which is used by onDomReady to remove a leading
416 // <br> which is inserted by Firefox 3.6 when document.write is called.
417 // This additional <br> is present because of contenteditable="true"
418 if ( CKEDITOR.env.version < 20000 )
419 data = data.replace( /<body[^>]*>/, '$&<!-- cke-content-start -->' );
420 }
421
422 // The script that launches the bootstrap logic on 'domReady', so the document
423 // is fully editable even before the editing iframe is fully loaded (#4455).
424 var bootstrapCode =
425 '<script id="cke_actscrpt" type="text/javascript"' + ( CKEDITOR.env.ie ? ' defer="defer" ' : '' ) + '>' +
426 'var wasLoaded=0;' + // It must be always set to 0 as it remains as a window property.
427 'function onload(){' +
428 'if(!wasLoaded)' + // FF3.6 calls onload twice when editor.setData. Stop that.
429 'window.parent.CKEDITOR.tools.callFunction(' + this._.frameLoadedHandler + ',window);' +
430 'wasLoaded=1;' +
431 '}' +
432 ( CKEDITOR.env.ie ? 'onload();' : 'document.addEventListener("DOMContentLoaded", onload, false );' ) +
433 '</script>';
434
435 // For IE<9 add support for HTML5's elements.
436 // Note: this code must not be deferred.
437 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {
438 bootstrapCode +=
439 '<script id="cke_shimscrpt">' +
440 'window.parent.CKEDITOR.tools.enableHtml5Elements(document)' +
441 '</script>';
442 }
443
444 // IE<10 needs this hack to properly enable <base href="...">.
445 // See: http://stackoverflow.com/a/13373180/1485219 (#11910).
446 if ( baseTag && CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
447 bootstrapCode +=
448 '<script id="cke_basetagscrpt">' +
449 'var baseTag = document.querySelector( "base" );' +
450 'baseTag.href = baseTag.href;' +
451 '</script>';
452 }
453
454 data = data.replace( /(?=\s*<\/(:?head)>)/, bootstrapCode );
455
456 // Current DOM will be deconstructed by document.write, cleanup required.
457 this.clearCustomData();
458 this.clearListeners();
459
460 editor.fire( 'contentDomUnload' );
461
462 var doc = this.getDocument();
463
464 // Work around Firefox bug - error prune when called from XUL (#320),
465 // defer it thanks to the async nature of this method.
466 try {
467 doc.write( data );
468 } catch ( e ) {
469 setTimeout( function() {
470 doc.write( data );
471 }, 0 );
472 }
473 }
474 },
475
476 getData: function( isSnapshot ) {
477 if ( isSnapshot )
478 return this.getHtml();
479 else {
480 var editor = this.editor,
481 config = editor.config,
482 fullPage = config.fullPage,
483 docType = fullPage && editor.docType,
484 xmlDeclaration = fullPage && editor.xmlDeclaration,
485 doc = this.getDocument();
486
487 var data = fullPage ? doc.getDocumentElement().getOuterHtml() : doc.getBody().getHtml();
488
489 // BR at the end of document is bogus node for Mozilla. (#5293).
490 // Prevent BRs from disappearing from the end of the content
491 // while enterMode is ENTER_BR (#10146).
492 if ( CKEDITOR.env.gecko && config.enterMode != CKEDITOR.ENTER_BR )
493 data = data.replace( /<br>(?=\s*(:?$|<\/body>))/, '' );
494
495 data = editor.dataProcessor.toDataFormat( data );
496
497 if ( xmlDeclaration )
498 data = xmlDeclaration + '\n' + data;
499 if ( docType )
500 data = docType + '\n' + data;
501
502 return data;
503 }
504 },
505
506 focus: function() {
507 if ( this._.isLoadingData )
508 this._.isPendingFocus = true;
509 else
510 framedWysiwyg.baseProto.focus.call( this );
511 },
512
513 detach: function() {
514 var editor = this.editor,
515 doc = editor.document,
516 iframe,
517 onResize;
518
519 // Trying to access window's frameElement property on Edge throws an exception
520 // when frame was already removed from DOM. (#13850, #13790)
521 try {
522 iframe = editor.window.getFrame();
523 } catch ( e ) {}
524
525 framedWysiwyg.baseProto.detach.call( this );
526
527 // Memory leak proof.
528 this.clearCustomData();
529 doc.getDocumentElement().clearCustomData();
530 CKEDITOR.tools.removeFunction( this._.frameLoadedHandler );
531
532 // On IE, iframe is returned even after remove() method is called on it.
533 // Checking if parent is present fixes this issue. (#13850)
534 if ( iframe && iframe.getParent() ) {
535 iframe.clearCustomData();
536 onResize = iframe.removeCustomData( 'onResize' );
537 onResize && onResize.removeListener();
538
539 // IE BUG: When destroying editor DOM with the selection remains inside
540 // editing area would break IE7/8's selection system, we have to put the editing
541 // iframe offline first. (#3812 and #5441)
542 iframe.remove();
543 } else {
544 CKEDITOR.warn( 'editor-destroy-iframe' );
545 }
546 }
547 }
548 } );
549
550 function objectResizeDisabler( editor ) {
551 if ( CKEDITOR.env.gecko ) {
552 // FF allows to change resizing preferences by calling execCommand.
553 try {
554 var doc = editor.document.$;
555 doc.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing );
556 doc.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles );
557 } catch ( e ) {}
558 } else if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 && editor.config.disableObjectResizing ) {
559 // It's possible to prevent resizing up to IE10.
560 blockResizeStart( editor );
561 }
562
563 // Disables resizing by preventing default action on resizestart event.
564 function blockResizeStart() {
565 var lastListeningElement;
566
567 // We'll attach only one listener at a time, instead of adding it to every img, input, hr etc.
568 // Listener will be attached upon selectionChange, we'll also check if there was any element that
569 // got listener before (lastListeningElement) - if so we need to remove previous listener.
570 editor.editable().attachListener( editor, 'selectionChange', function() {
571 var selectedElement = editor.getSelection().getSelectedElement();
572
573 if ( selectedElement ) {
574 if ( lastListeningElement ) {
575 lastListeningElement.detachEvent( 'onresizestart', resizeStartListener );
576 lastListeningElement = null;
577 }
578
579 // IE requires using attachEvent, because it does not work using W3C compilant addEventListener,
580 // tested with IE10.
581 selectedElement.$.attachEvent( 'onresizestart', resizeStartListener );
582 lastListeningElement = selectedElement.$;
583 }
584 } );
585 }
586
587 function resizeStartListener( evt ) {
588 evt.returnValue = false;
589 }
590 }
591
592 function iframeCssFixes() {
593 var css = [];
594
595 // IE>=8 stricts mode doesn't have 'contentEditable' in effect
596 // on element unless it has layout. (#5562)
597 if ( CKEDITOR.document.$.documentMode >= 8 ) {
598 css.push( 'html.CSS1Compat [contenteditable=false]{min-height:0 !important}' );
599
600 var selectors = [];
601
602 for ( var tag in CKEDITOR.dtd.$removeEmpty )
603 selectors.push( 'html.CSS1Compat ' + tag + '[contenteditable=false]' );
604
605 css.push( selectors.join( ',' ) + '{display:inline-block}' );
606 }
607 // Set the HTML style to 100% to have the text cursor in affect (#6341)
608 else if ( CKEDITOR.env.gecko ) {
609 css.push( 'html{height:100% !important}' );
610 css.push( 'img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}' );
611 }
612
613 // #6341: The text cursor must be set on the editor area.
614 // #6632: Avoid having "text" shape of cursor in IE7 scrollbars.
615 css.push( 'html{cursor:text;*cursor:auto}' );
616
617 // Use correct cursor for these elements
618 css.push( 'img,input,textarea{cursor:default}' );
619
620 return css.join( '\n' );
621 }
622} )();
623
624/**
625 * Disables the ability to resize objects (images and tables) in the editing area.
626 *
627 * config.disableObjectResizing = true;
628 *
629 * **Note:** Because of incomplete implementation of editing features in browsers
630 * this option does not work for inline editors (see ticket [#10197](http://dev.ckeditor.com/ticket/10197)),
631 * does not work in Internet Explorer 11+ (see [#9317](http://dev.ckeditor.com/ticket/9317#comment:16) and
632 * [IE11+ issue](https://connect.microsoft.com/IE/feedback/details/742593/please-respect-execcommand-enableobjectresizing-in-contenteditable-elements)).
633 * In Internet Explorer 8-10 this option only blocks resizing, but it is unable to hide the resize handles.
634 *
635 * @cfg
636 * @member CKEDITOR.config
637 */
638CKEDITOR.config.disableObjectResizing = false;
639
640/**
641 * Disables the "table tools" offered natively by the browser (currently
642 * Firefox only) to perform quick table editing operations, like adding or
643 * deleting rows and columns.
644 *
645 * config.disableNativeTableHandles = false;
646 *
647 * @cfg
648 * @member CKEDITOR.config
649 */
650CKEDITOR.config.disableNativeTableHandles = true;
651
652/**
653 * Disables the built-in spell checker if the browser provides one.
654 *
655 * **Note:** Although word suggestions provided natively by the browsers will
656 * not appear in CKEditor's default context menu,
657 * users can always reach the native context menu by holding the
658 * *Ctrl* key when right-clicking if {@link #browserContextMenuOnCtrl}
659 * is enabled or you are simply not using the
660 * [context menu](http://ckeditor.com/addon/contextmenu) plugin.
661 *
662 * config.disableNativeSpellChecker = false;
663 *
664 * @cfg
665 * @member CKEDITOR.config
666 */
667CKEDITOR.config.disableNativeSpellChecker = true;
668
669/**
670 * Language code of the writing language which is used to author the editor
671 * content. This option accepts one single entry value in the format defined in the
672 * [Tags for Identifying Languages (BCP47)](http://www.ietf.org/rfc/bcp/bcp47.txt)
673 * IETF document and is used in the `lang` attribute.
674 *
675 * config.contentsLanguage = 'fr';
676 *
677 * @cfg {String} [contentsLanguage=same value with editor's UI language]
678 * @member CKEDITOR.config
679 */
680
681/**
682 * The base href URL used to resolve relative and absolute URLs in the
683 * editor content.
684 *
685 * config.baseHref = 'http://www.example.com/path/';
686 *
687 * @cfg {String} [baseHref='']
688 * @member CKEDITOR.config
689 */
690
691/**
692 * Whether to automatically create wrapping blocks around inline content inside the document body.
693 * This helps to ensure the integrity of the block *Enter* mode.
694 *
695 * **Note:** This option is deprecated. Changing the default value might introduce unpredictable usability issues and is
696 * highly unrecommended.
697 *
698 * config.autoParagraph = false;
699 *
700 * @deprecated
701 * @since 3.6
702 * @cfg {Boolean} [autoParagraph=true]
703 * @member CKEDITOR.config
704 */
705
706/**
707 * Fired when some elements are added to the document.
708 *
709 * @event ariaWidget
710 * @member CKEDITOR.editor
711 * @param {CKEDITOR.editor} editor This editor instance.
712 * @param {CKEDITOR.dom.element} data The element being added.
713 */
diff --git a/sources/plugins/wysiwygarea/samples/fullpage.html b/sources/plugins/wysiwygarea/samples/fullpage.html
new file mode 100644
index 0000000..bb3193a
--- /dev/null
+++ b/sources/plugins/wysiwygarea/samples/fullpage.html
@@ -0,0 +1,80 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Full Page Editing &mdash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../samples/old/sample.js"></script>
12 <link rel="stylesheet" href="../../../samples/old/sample.css">
13 <meta name="ckeditor-sample-required-plugins" content="sourcearea">
14 <meta name="ckeditor-sample-name" content="Full page support">
15 <meta name="ckeditor-sample-group" content="Plugins">
16 <meta name="ckeditor-sample-description" content="CKEditor inserted with a JavaScript call and used to edit the whole page from &lt;html&gt; to &lt;/html&gt;.">
17</head>
18<body>
19 <h1 class="samples">
20 <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Full Page Editing
21 </h1>
22 <div class="warning deprecated">
23 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/fullpage.html">brand new version in CKEditor SDK</a>.
24 </div>
25 <div class="description">
26 <p>
27 This sample shows how to configure CKEditor to edit entire HTML pages, from the
28 <code>&lt;html&gt;</code> tag to the <code>&lt;/html&gt;</code> tag.
29 </p>
30 <p>
31 The CKEditor instance below is inserted with a JavaScript call using the following code:
32 </p>
33<pre class="samples">
34CKEDITOR.replace( '<em>textarea_id</em>', {
35 <strong>fullPage: true</strong>,
36 <strong>allowedContent: true</strong>
37});
38</pre>
39 <p>
40 Note that <code><em>textarea_id</em></code> in the code above is the <code>id</code> attribute of
41 the <code>&lt;textarea&gt;</code> element to be replaced.
42 </p>
43 <p>
44 The <code><em>allowedContent</em></code> in the code above is set to <code>true</code> to disable content filtering.
45 Setting this option is not obligatory, but in full page mode there is a strong chance that one may want be able to freely enter any HTML content in source mode without any limitations.
46 </p>
47 </div>
48 <form action="../../../samples/sample_posteddata.php" method="post">
49 <label for="editor1">
50 CKEditor output the entire page including content outside of
51 <code>&lt;body&gt;</code> element, so content like meta and title can be changed:
52 </label>
53 <textarea cols="80" id="editor1" name="editor1" rows="10">
54 &lt;h1&gt;&lt;img align=&quot;right&quot; alt=&quot;Saturn V carrying Apollo 11&quot; src=&quot;../../../samples/old/assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
55 </textarea>
56 <script>
57
58 CKEDITOR.replace( 'editor1', {
59 fullPage: true,
60 allowedContent: true,
61 extraPlugins: 'wysiwygarea'
62 });
63
64 </script>
65 <p>
66 <input type="submit" value="Submit">
67 </p>
68 </form>
69 <div id="footer">
70 <hr>
71 <p>
72 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
73 </p>
74 <p id="copy">
75 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
76 Knabben. All rights reserved.
77 </p>
78 </div>
79</body>
80</html>
diff --git a/sources/samples/css/samples.css b/sources/samples/css/samples.css
new file mode 100644
index 0000000..455b152
--- /dev/null
+++ b/sources/samples/css/samples.css
@@ -0,0 +1,1632 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5@media (max-width: 900px) {
6 .global-is-mobile-hidden {
7 display: none !important;
8 }
9}
10article,
11aside,
12details,
13figcaption,
14figure,
15footer,
16header,
17hgroup,
18main,
19menu,
20nav,
21section {
22 display: block;
23}
24body,
25html {
26 margin: 0;
27 padding: 0;
28 font: 16px / 1.8 Arial, 'Helvetica Neue', Helvetica, sans-serif;
29 font-weight: 300;
30 color: #575757;
31}
32.grid-width-10 {
33 width: 10%;
34}
35.grid-width-20 {
36 width: 20%;
37}
38.grid-width-30 {
39 width: 30%;
40}
41.grid-width-40 {
42 width: 40%;
43}
44.grid-width-50 {
45 width: 50%;
46}
47.grid-width-60 {
48 width: 60%;
49}
50.grid-width-70 {
51 width: 70%;
52}
53.grid-width-80 {
54 width: 80%;
55}
56.grid-width-90 {
57 width: 90%;
58}
59.grid-width-100 {
60 width: 100%;
61}
62@media (max-width: 900px) {
63 .grid-width-10,
64 .grid-width-20,
65 .grid-width-30,
66 .grid-width-40,
67 .grid-width-50,
68 .grid-width-60,
69 .grid-width-70,
70 .grid-width-80,
71 .grid-width-90,
72 .grid-width-100 {
73 width: 100%;
74 }
75}
76*[class*="grid-width"] {
77 -webkit-box-sizing: border-box;
78 -moz-box-sizing: border-box;
79 box-sizing: border-box;
80 padding-left: 4%;
81 padding-right: 4%;
82 float: left;
83}
84*[class*="grid-width"]:after,
85.grid-container:after,
86*[class*="grid-width"]:before,
87.grid-container:before {
88 content: '';
89 display: block;
90 overflow: hidden;
91 visibility: hidden;
92 font-size: 0;
93 line-height: 0;
94 width: 0;
95 height: 0;
96}
97*[class*="grid-width"]:after,
98.grid-container:after {
99 clear: both;
100}
101.grid-container {
102 -webkit-box-sizing: border-box;
103 -moz-box-sizing: border-box;
104 box-sizing: border-box;
105 margin-left: auto;
106 margin-right: auto;
107}
108.grid-container-nested *[class*="grid-width"]:first-child {
109 padding-left: 0;
110}
111.grid-container-nested *[class*="grid-width"]:last-child {
112 padding-right: 0;
113}
114@media (max-width: 900px) {
115 .grid-container-nested *[class*="grid-width"]:first-child {
116 padding-left: 4%;
117 }
118 .grid-container-nested *[class*="grid-width"]:last-child {
119 padding-right: 4%;
120 }
121}
122.header-a {
123 min-height: 140px;
124 overflow: hidden;
125}
126.header-a .header-a-logo {
127 margin: 40px 0 0;
128}
129@media (max-width: 900px) {
130 .header-a .header-a-logo {
131 text-align: center;
132 }
133}
134.header-a .header-a-logo img {
135 border: transparent;
136}
137.navigation-a {
138 height: 30px;
139 background: #3D3D3D;
140 position: absolute;
141 left: 0;
142 right: 0;
143 top: 0;
144 padding: 0;
145 overflow: hidden;
146}
147@media (max-width: 900px) {
148 .navigation-a {
149 text-align: center;
150 }
151}
152.navigation-a ul {
153 list-style: none;
154 margin: 0;
155 overflow: hidden;
156}
157.navigation-a ul li,
158.navigation-a ul li a {
159 display: inline-block;
160}
161@media (max-width: 900px) {
162 .navigation-a ul {
163 width: auto;
164 text-overflow: ellipsis;
165 white-space: nowrap;
166 display: inline-block;
167 float: none;
168 }
169 .navigation-a ul:before,
170 .navigation-a ul:after {
171 display: none;
172 }
173}
174.navigation-a ul.navigation-a-left {
175 text-align: left;
176}
177@media (max-width: 900px) {
178 .navigation-a ul.navigation-a-left {
179 padding-right: 0;
180 }
181}
182.navigation-a ul.navigation-a-right {
183 text-align: right;
184}
185@media (max-width: 900px) {
186 .navigation-a ul.navigation-a-right {
187 padding-left: 23px;
188 }
189}
190.navigation-a ul li + li {
191 margin-left: 23px;
192}
193.navigation-a ul li a {
194 font-size: 10px;
195 font-size: 0.625rem;
196 line-height: 18px;
197 line-height: 1.13rem;
198 line-height: 30px;
199 float: left;
200 color: #ddd;
201 font-weight: bold;
202 text-decoration: none;
203 text-transform: uppercase;
204}
205.navigation-a ul li a:hover {
206 cursor: pointer;
207 color: #fff;
208}
209.icon-navigation-a-github:before,
210.icon-navigation-a-github:after {
211 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAAXNSR0IArs4c6QAAAa9JREFUOBGNlM8rRGEUht0pDGosjKYZpUSIkuwsiCaxUEqK2VOUBcrWv2BjxUJho6wsLLDzY2fhD5iR5NeOcJvIjOfM3O927m3mmlPPnPec835nZprvjlVVJvL5fCOjMWiDCLzCLVxZlpUj/x8saYV9+IZS8UJzFWoCt2GYgk+oJG4wJUouZDANv5VsUZ47dNSzkEYHfIDEHixDWgoiB/rTHlPPwBNInPmXHRb7hdeUDFG10AN1Th1Fd5mD6BMwMVnoUyVA3t3EkjkQlDFfmwPkc7NsQTXf0bGgJWaGb16dk18+EmLYawzkC+6Q3KdK4kiZqtGdskx/kmdlCJS86RuGrDLFZJmtGi1KB0q+VhOGsDLZsiyjGsOY4qoOkrO+YUauwCDoOKWo9xk9JfM+MPdSzqZdA8UlyDO3AvKLPsIG9LsmBHUKduEHdCy6PrpJZyKXdwKMOemaissOHJ9O9xTeh57GluMYIsehWy8STW/d8ZhkI0b9PjFasA1fsAOb0KCN1PLXYyKLGNdzj2YYArnZDyDRrA3Ua4UuDzd5QM/KaoxhmAO5Om5Qt8OI2/CJP6MVa1dvltQ5AAAAAElFTkSuQmCC");
212}
213.navigation-b {
214 text-align: right;
215 margin: 52px 0 0;
216 overflow: visible;
217}
218@media (max-width: 900px) {
219 .navigation-b {
220 text-align: center;
221 margin-top: 20px;
222 padding: 0;
223 }
224}
225.navigation-b ul {
226 padding: 0;
227 list-style: none;
228 margin: 0;
229 overflow: visible;
230}
231.navigation-b ul li,
232.navigation-b ul li a {
233 display: inline-block;
234}
235@media (max-width: 900px) {
236 .navigation-b ul {
237 display: table;
238 width: 100%;
239 padding-bottom: 1.5em;
240 }
241}
242@media (max-width: 900px) {
243 .navigation-b ul li {
244 display: table-row;
245 }
246}
247.navigation-b ul li + li {
248 margin-left: 20px;
249}
250@media (max-width: 900px) {
251 .navigation-b ul li + li {
252 margin-left: 0;
253 }
254}
255.navigation-b ul li a {
256 -webkit-box-sizing: border-box;
257 -moz-box-sizing: border-box;
258 box-sizing: border-box;
259 text-transform: uppercase;
260 text-decoration: none;
261 outline: none;
262}
263@media (max-width: 900px) {
264 .navigation-b ul li a {
265 width: 100%;
266 -webkit-border-radius: 0;
267 -webkit-background-clip: padding-box;
268 -moz-border-radius: 0;
269 -moz-background-clip: padding;
270 border-radius: 0;
271 background-clip: padding-box;
272 }
273}
274.footer-a {
275 font-size: 13px;
276 font-size: 0.8125rem;
277 line-height: 23.4px;
278 line-height: 1.46rem;
279 padding-top: 2.25em;
280 padding-bottom: 2.25em;
281 overflow: hidden;
282 color: #8a8a8a;
283}
284.footer-a a {
285 color: #27C0D8;
286 text-decoration: none;
287 border-bottom: 1px dotted #27C0D8;
288}
289.footer-a a:hover {
290 color: #23adc2;
291}
292.footer-a p {
293 margin: 0;
294 display: inline-block;
295 text-align: center;
296}
297.content {
298 font-size: 14px;
299 font-size: 0.875rem;
300 line-height: 25.2px;
301 line-height: 1.57rem;
302 overflow: hidden;
303 padding-top: 1.5em;
304 padding-bottom: 1.5em;
305}
306.content p {
307 margin: 0.75em 0;
308}
309.content ul,
310.content ol,
311.content pre,
312.content blockquote,
313.content textarea:not([class^="cke"]),
314.content .cke {
315 margin: 1.875em 0;
316}
317.content code,
318.content kbd {
319 -webkit-border-radius: 3px;
320 -webkit-background-clip: padding-box;
321 -moz-border-radius: 3px;
322 -moz-background-clip: padding;
323 border-radius: 3px;
324 background-clip: padding-box;
325 padding: 3px 4px;
326}
327.content pre,
328.content code,
329.content kbd,
330.content blockquote {
331 background: #f5f5f5;
332}
333.content blockquote,
334.content pre {
335 background: none;
336 border-left: 4px solid #27C0D8;
337 padding: 1.5em 2.25em;
338}
339.content p a,
340.content ul a,
341.content ol a,
342.content blockquote a,
343.content h1 a,
344.content h2 a,
345.content h3 a,
346.content h4 a,
347.content h5 a {
348 color: #27C0D8;
349 text-decoration: none;
350 border-bottom: 1px dotted #27C0D8;
351}
352.content p a:hover,
353.content ul a:hover,
354.content ol a:hover,
355.content blockquote a:hover,
356.content h1 a:hover,
357.content h2 a:hover,
358.content h3 a:hover,
359.content h4 a:hover,
360.content h5 a:hover {
361 color: #23adc2;
362}
363.content h1,
364.content h2,
365.content h3,
366.content h4,
367.content h5 {
368 color: #000;
369 font-weight: 100;
370}
371.content h1 code,
372.content h2 code,
373.content h3 code,
374.content h4 code,
375.content h5 code,
376.content h1 kbd,
377.content h2 kbd,
378.content h3 kbd,
379.content h4 kbd,
380.content h5 kbd {
381 font-size: inherit;
382}
383.content h1 a.content-heading-anchor,
384.content h2 a.content-heading-anchor,
385.content h3 a.content-heading-anchor,
386.content h4 a.content-heading-anchor,
387.content h5 a.content-heading-anchor {
388 font-weight: 100;
389 vertical-align: middle;
390 opacity: 0;
391 border: 0;
392}
393.content h1:hover a.content-heading-anchor,
394.content h2:hover a.content-heading-anchor,
395.content h3:hover a.content-heading-anchor,
396.content h4:hover a.content-heading-anchor,
397.content h5:hover a.content-heading-anchor {
398 opacity: 1;
399}
400.content h1:target a,
401.content h2:target a,
402.content h3:target a,
403.content h4:target a,
404.content h5:target a {
405 -webkit-animation: targetLinkOpacity 0.5s linear alternate;
406 -moz-animation: targetLinkOpacity 0.5s linear alternate;
407 -o-animation: targetLinkOpacity 0.5s linear alternate;
408 animation: targetLinkOpacity 0.5s linear alternate;
409 opacity: 1;
410}
411.content input,
412.content select,
413.content textarea:not([class^="cke"]) {
414 -webkit-border-radius: 3px;
415 -webkit-background-clip: padding-box;
416 -moz-border-radius: 3px;
417 -moz-background-clip: padding;
418 border-radius: 3px;
419 background-clip: padding-box;
420 -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08);
421 -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08);
422 box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08);
423 font: inherit;
424 color: inherit;
425 border: 1px solid #D9D9D9;
426 padding: .2em .5em;
427}
428.content input:focus,
429.content select:focus,
430.content textarea:not([class^="cke"]):focus {
431 border-color: #66afe9;
432 outline: 0;
433 -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08), 0 0 8px #93c6ef;
434 -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08), 0 0 8px #93c6ef;
435 box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.08), 0 0 8px #93c6ef;
436}
437.content abbr {
438 border-bottom: 1px dotted #666;
439 cursor: pointer;
440}
441.content blockquote {
442 font-style: italic;
443 font-family: Georgia, Times, "Times New Roman", serif;
444 font-size: 16px;
445 font-size: 1rem;
446 line-height: 28.8px;
447 line-height: 1.8rem;
448}
449.content em {
450 font-style: italic;
451}
452.content h1 {
453 font-size: 36px;
454 font-size: 2.25rem;
455 line-height: 64.8px;
456 line-height: 4.05rem;
457 margin: 1.125em 0 0;
458}
459.content h2 {
460 font-size: 27.2px;
461 font-size: 1.7rem;
462 line-height: 48.96px;
463 line-height: 3.06rem;
464 margin: 0.9em 0 0;
465}
466.content h3 {
467 font-size: 24px;
468 font-size: 1.5rem;
469 line-height: 43.2px;
470 line-height: 2.7rem;
471 font-weight: 500;
472 margin: 0.75em 0 0;
473}
474.content h4 {
475 font-size: 19.2px;
476 font-size: 1.2rem;
477 line-height: 34.56px;
478 line-height: 2.16rem;
479 font-weight: 500;
480 margin: 0.75em 0 0;
481}
482.content h5 {
483 font-size: 17.6px;
484 font-size: 1.1rem;
485 line-height: 31.68px;
486 line-height: 1.98rem;
487 font-weight: 500;
488 margin: 0.75em 0 0;
489}
490.content hr {
491 border: 0;
492 border-top: 4px solid #D9D9D9;
493 margin: 1.5em 0;
494}
495.content input[type="text"] {
496 height: 1.8em;
497 line-height: 1.8em;
498}
499.content input[type="button"] {
500 -webkit-appearance: button;
501 -moz-appearance: button;
502 appearance: button;
503}
504.content kbd {
505 font-size: 12px;
506 font-size: 0.75rem;
507 line-height: 21.6px;
508 line-height: 1.35rem;
509 font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
510 padding: 2px 6px;
511 -webkit-box-shadow: 0 0 4px #fff inset, 0 2px 0 #D9D9D9;
512 -moz-box-shadow: 0 0 4px #fff inset, 0 2px 0 #D9D9D9;
513 box-shadow: 0 0 4px #fff inset, 0 2px 0 #D9D9D9;
514}
515.content p img {
516 vertical-align: middle;
517}
518.content p pre {
519 padding: 1.5em;
520}
521.content pre {
522 padding: 0;
523 border: 0;
524 tab-size: 4;
525 -o-tab-size: 4;
526 -moz-tab-size: 4;
527}
528.content pre,
529.content code {
530 font-size: 11.89px;
531 font-size: 0.743rem;
532 line-height: 21.4px;
533 line-height: 1.34rem;
534 font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
535}
536.content pre a,
537.content code a {
538 border: 0;
539}
540.content pre code {
541 padding: 0.75em;
542 display: block;
543}
544.content strong {
545 color: #000;
546}
547.content ul ul,
548.content ol ul,
549.content ul ol,
550.content ol ol {
551 margin: 0.75em 0;
552}
553.content ul li,
554.content ol li {
555 font-size: 14px;
556 font-size: 0.875rem;
557 line-height: 30.24px;
558 line-height: 1.89rem;
559}
560.content textarea:not([class^="cke"]) {
561 width: 100%;
562}
563.content div.todo {
564 border: 2px dotted #444;
565 padding: 10px;
566 margin: 60px 0 10px 0;
567 /* Remove me some day */
568}
569.content div.todo:before {
570 content: "TODO";
571 font-weight: bold;
572}
573body a.button-a,
574body button.button-a,
575body input.button-a {
576 -webkit-border-radius: 3px;
577 -webkit-background-clip: padding-box;
578 -moz-border-radius: 3px;
579 -moz-background-clip: padding;
580 border-radius: 3px;
581 background-clip: padding-box;
582 font-size: 14px;
583 font-size: 0.875rem;
584 line-height: 25.2px;
585 line-height: 1.57rem;
586 height: 36px;
587 line-height: 36px;
588 padding: 0 1.1em;
589 font-weight: 700;
590 color: #3e3e3e;
591 white-space: nowrap;
592 text-decoration: none;
593 display: inline-block;
594 cursor: pointer;
595 border: 0;
596 vertical-align: middle;
597 margin: 1px 0;
598 background: transparent;
599}
600body a.button-a.icon-pos-left,
601body button.button-a.icon-pos-left,
602body input.button-a.icon-pos-left {
603 padding-left: .8em;
604}
605body a.button-a.icon-pos-right,
606body button.button-a.icon-pos-right,
607body input.button-a.icon-pos-right {
608 padding-right: .8em;
609}
610body a.button-a.button-a-no-text,
611body button.button-a.button-a-no-text,
612body input.button-a.button-a-no-text {
613 -webkit-border-radius: 100px;
614 -webkit-background-clip: padding-box;
615 -moz-border-radius: 100px;
616 -moz-background-clip: padding;
617 border-radius: 100px;
618 background-clip: padding-box;
619 width: 36px;
620 padding: 0;
621 text-indent: -999px;
622 overflow: hidden;
623 position: relative;
624 text-align: center;
625}
626body a.button-a.button-a-no-text:before,
627body button.button-a.button-a-no-text:before,
628body input.button-a.button-a-no-text:before {
629 position: absolute;
630 left: 50%;
631 top: 50%;
632 margin: -9px 0 0 -9px;
633}
634@media (max-width: 900px) {
635 body a.button-a.button-a-mobile-collapsed,
636 body button.button-a.button-a-mobile-collapsed,
637 body input.button-a.button-a-mobile-collapsed {
638 -webkit-border-radius: 100px;
639 -webkit-background-clip: padding-box;
640 -moz-border-radius: 100px;
641 -moz-background-clip: padding;
642 border-radius: 100px;
643 background-clip: padding-box;
644 width: 36px;
645 padding: 0;
646 text-indent: -999px;
647 overflow: hidden;
648 position: relative;
649 text-align: center;
650 }
651 body a.button-a.button-a-mobile-collapsed:before,
652 body button.button-a.button-a-mobile-collapsed:before,
653 body input.button-a.button-a-mobile-collapsed:before {
654 position: absolute;
655 left: 50%;
656 top: 50%;
657 margin: -9px 0 0 -9px;
658 }
659 body a.button-a.button-a-mobile-collapsed:before,
660 body button.button-a.button-a-mobile-collapsed:before,
661 body input.button-a.button-a-mobile-collapsed:before {
662 position: absolute;
663 left: 50%;
664 top: 50%;
665 margin: -9px 0 0 -9px;
666 }
667}
668body a.button-a:active,
669body button.button-a:active,
670body input.button-a:active,
671body a.button-a:hover,
672body button.button-a:hover,
673body input.button-a:hover {
674 color: #fff;
675 background: #23adc2;
676}
677body a.button-a:focus,
678body button.button-a:focus,
679body input.button-a:focus {
680 border-color: #66afe9;
681 outline: 0;
682 -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px #93c6ef;
683 -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px #93c6ef;
684 box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px #93c6ef;
685}
686body a.button-a-soft,
687body button.button-a-soft,
688body input.button-a-soft {
689 background: #e7e7e7;
690}
691body a.button-a-soft:active,
692body button.button-a-soft:active,
693body input.button-a-soft:active,
694body a.button-a-soft:hover,
695body button.button-a-soft:hover,
696body input.button-a-soft:hover {
697 color: #3e3e3e;
698 background: #cecece;
699}
700body a.button-a-background,
701body button.button-a-background,
702body input.button-a-background,
703body a.navigation-b ul li a:hover,
704body button.navigation-b ul li a:hover,
705body input.navigation-b ul li a:hover {
706 color: #fff;
707 background: #27C0D8;
708}
709body a.button-a-background:active,
710body button.button-a-background:active,
711body input.button-a-background:active,
712body a.button-a-background:hover,
713body button.button-a-background:hover,
714body input.button-a-background:hover,
715body a.navigation-b ul li a:hover:active,
716body button.navigation-b ul li a:hover:active,
717body input.navigation-b ul li a:hover:active,
718body a.navigation-b ul li a:hover:hover,
719body button.navigation-b ul li a:hover:hover,
720body input.navigation-b ul li a:hover:hover {
721 color: #fff;
722 background: #23adc2;
723}
724.balloon-a {
725 font-size: 12px;
726 font-size: 0.75rem;
727 line-height: 21.6px;
728 line-height: 1.35rem;
729 -webkit-border-radius: 3px;
730 -webkit-background-clip: padding-box;
731 -moz-border-radius: 3px;
732 -moz-background-clip: padding;
733 border-radius: 3px;
734 background-clip: padding-box;
735 border-bottom: 3px solid #d4d4d4;
736 background: #ebebeb;
737 display: inline-block;
738 white-space: nowrap;
739 padding: .4em 1.2em .2em;
740 font-weight: 700;
741 position: relative;
742 z-index: 1000;
743 text-transform: none;
744 color: #575757;
745}
746.balloon-a:hover {
747 color: #575757;
748}
749.balloon-a:before {
750 content: '';
751 width: 0;
752 height: 0;
753 border-style: solid;
754 position: absolute;
755}
756.balloon-a-ne:before,
757.balloon-a-nw:before {
758 top: -13px;
759 border-width: 0 9px 15.6px 9px;
760 border-color: transparent transparent #ebebeb transparent;
761}
762.balloon-a-se:before,
763.balloon-a-sw:before {
764 bottom: -13px;
765 border-width: 15.6px 9px 0 9px;
766 border-color: #ebebeb transparent transparent transparent;
767}
768.balloon-a-nw:before,
769.balloon-a-sw:before {
770 left: 20px;
771}
772.balloon-a-ne:before,
773.balloon-a-se:before {
774 right: 20px;
775}
776.icon-pos-left:before,
777.icon-pos-right:after {
778 content: '';
779 display: inline-block;
780 width: 18px;
781 height: 18px;
782 vertical-align: middle;
783 background-repeat: no-repeat;
784}
785.icon-pos-left:before {
786 margin-right: 10px;
787}
788.icon-pos-right:after {
789 margin-left: 10px;
790}
791.icon-download:before,
792.icon-download:after {
793 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAQFJREFUOBGtVDESgjAQBGfobHwE/AIa/AN/8EEWfMWGZ+gDaG2ws8BdyY13SRgGcGducre3WQ5NSJIIxnGsES3ijhhcMCdXR7ZYCqIc0SGWQE1ud7sKjRLxXHJQfWpLYwaCk6wxET/u+U2GIngd8yRViINau28bBH/YAGqvSQPhRNQHqBqj3FY0NKq27TW7qhSTDaCOhkaRAj7Hmm8S4V+c6C+gUa+crsizuWmoc70MKbWCnqPy2GvcUJxE4a/sIajRaGkU+/sf4IuISQGePR/T/QMbHEhwPLVnMWPuOCwGnWg41dwVeaN3ccHch70idIRi/6WV0WC2/zMiZm661R+2DxyEdjTuST3mAAAAAElFTkSuQmCC");
794}
795.icon-question-mark:before,
796.icon-question-mark:after {
797 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAUhJREFUOBGllLFOAkEQhjk0WthT2JFA7Czsqc7OxFLewEeAZ/AVbO0tTLTSBKhstTBUNkYLEoVAbD2//zILe5e9uwCT/JnZmX/+m83ebq0WsCRJYnANxmBhUKxcHGjJpiC1wQBUmTjtbLetKHTAT5WCVxe3kxEjoUmKRL6pvYEZyJt6VpOxCG3nmfyx+yJxBM7BFPg2SDlkTv2sxZqi4YnUvfgswI9FuHAkzz9EUTTRmqYeTifXsvoj/s9i57oi6ljz9kviFdyBCbgHe+rCn4C8jVXQ18rshuKOiTSIXwLkRZWQTurARJrE7wERpea7kD7BkcgB+yB3CFGlPmgqCNiXhEagSGif2qU1Ln8FW/tupK3pXhXZrWNDuCoikY/rHPMT5KFr2MAPTSM90rIrUjJIeq1WV0RTwN7+0rrtILb9M+LEbLq1H7Z/Ea3+RvBddl0AAAAASUVORK5CYII=");
798}
799.icon-close:before,
800.icon-close:after {
801 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAUlJREFUOBGllDFuwzAMRe3Cd+jYKUCzd/XkDtm9dsoVOuUqBnqBoodwgBwiW8ZsXTIWqPu+Iia0LMAoTOBbJEV+UZTkosjIMAwN6MARXCKky9dkUsYuglagB3OimNU4O1pM1OB7jsHNK7YekeFQJZ5kj/0LcnLA+RMnlHOvDMNv5wO7BFuQkn3hq0ALjKwPVeF4BSaqpLRy0T1ZIHFz75bE2BR8dBImqmBrwRplg09QmR/9GZyBSadAHauXCZkRROKURLlHEemepJIlIyhHotzLg1/N6erTxtmmvqA8muHGIbc1rTBqrEuwnqWnGbbmmz0hwaHtvM2QhWbrXZnosvnTWWPrdCY9w7cDJtf3h9VHjy5Zq9UZ08beyJh7Aicg6W/VYvgnIjJdNn9PMIOITJWcgnV9VvcnEitY/mitNFZZ/hsxsljdv39sfybRQ4R/kU0MAAAAAElFTkSuQmCC");
802}
803.ie8 .switch > * {
804 vertical-align: middle;
805}
806.ie8 .switch input[type="radio"] {
807 margin: 0 0.25em;
808 display: inline-block;
809}
810.ie8 .switch label {
811 margin-left: 0 !important;
812 margin-right: 0 !important;
813}
814.ie8 .switch label[data-for="1"] {
815 float: left;
816}
817.ie8 .switch label[data-for="2"] {
818 float: right;
819}
820.ie8 .switch .switch-inner {
821 display: none;
822}
823.switch {
824 font-size: 14px;
825 font-size: 0.875rem;
826 line-height: 25.2px;
827 line-height: 1.57rem;
828 font-weight: bold;
829 background-color: #27C0D8;
830 overflow: hidden;
831 display: inline-block;
832 padding: 0.75em 0.25em;
833 color: #fff;
834 -webkit-border-radius: 3px;
835 -webkit-background-clip: padding-box;
836 -moz-border-radius: 3px;
837 -moz-background-clip: padding;
838 border-radius: 3px;
839 background-clip: padding-box;
840 position: relative;
841}
842.switch input[type="radio"] {
843 display: none;
844}
845.switch label {
846 position: relative;
847 z-index: 2;
848 float: left;
849 cursor: pointer;
850 padding: 0 0.75em;
851}
852.switch label:hover {
853 text-decoration: underline;
854}
855.switch .switch-inner {
856 float: left;
857 background-color: #FFF;
858 height: 1.5em;
859 width: 4.125em;
860 padding: 2px;
861 margin: 0 0.25em;
862 -webkit-border-radius: 5.5px;
863 -webkit-background-clip: padding-box;
864 -moz-border-radius: 5.5px;
865 -moz-background-clip: padding;
866 border-radius: 5.5px;
867 background-clip: padding-box;
868}
869.switch .switch-inner .handler {
870 overflow: hidden;
871 position: relative;
872 display: block;
873 height: 1.5em;
874 width: 1.5em;
875 background: #25b4cb;
876 -webkit-border-radius: 4.5px;
877 -webkit-background-clip: padding-box;
878 -moz-border-radius: 4.5px;
879 -moz-background-clip: padding;
880 border-radius: 4.5px;
881 background-clip: padding-box;
882}
883.switch .switch-inner .handler:before {
884 content: '';
885 display: block;
886 position: absolute;
887 top: 0;
888 right: 0;
889 bottom: 3px;
890 left: 0;
891 background-color: #34c4da;
892 -webkit-border-bottom-left-radius: 4.5px;
893 -moz-border-radius-bottomleft: 4.5px;
894 border-bottom-left-radius: 4.5px;
895 -webkit-border-bottom-right-radius: 4.5px;
896 -webkit-background-clip: padding-box;
897 -moz-border-radius-bottomright: 4.5px;
898 -moz-background-clip: padding;
899 border-bottom-right-radius: 4.5px;
900 background-clip: padding-box;
901}
902.switch:hover .switch-inner .handler:before {
903 background: #45c9dd;
904}
905.switch input[data-num="2"]:checked ~ .switch-inner > .handler {
906 margin-left: auto;
907}
908.switch input[data-num="2"]:checked ~ label[data-for="1"] {
909 padding-right: 5.125em;
910 margin-right: -4.375em;
911}
912.switch input[data-num="1"]:checked ~ label[data-for="2"] {
913 padding-left: 5.125em;
914 margin-left: -4.375em;
915}
916.toggler {
917 -webkit-user-select: none;
918 -moz-user-select: none;
919 -ms-user-select: none;
920 user-select: none;
921}
922.toggler label {
923 cursor: pointer;
924}
925.toggler [data-collapse] {
926 display: inherit;
927}
928.toggler [data-expand] {
929 display: none;
930}
931.toggler.collapsed [data-collapse] {
932 display: none;
933}
934.toggler.collapsed [data-expand] {
935 display: inherit;
936}
937.toggler-container {
938 overflow: hidden;
939}
940.toggler-container.collapsed {
941 height: 0;
942}
943.icon-toggler-expanded:before,
944.icon-toggler-collapsed:before,
945.icon-toggler-expanded:after,
946.icon-toggler-collapsed:after {
947 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAByCAYAAABeOoENAAAAAXNSR0IArs4c6QAAAbxJREFUaAXtmT1KBEEQhRdFQdBEMfQEBoaGopl3MfECXsFERLyBh/AUIuwJDEUQM//eB11Dz1A1uzotGFTBY2rr58306+kNpmazP7Z98V8Kj8JrAT4xcgttXRVXwofwFYAcNdS6RuJegOBTuBUOhc0CfGLkqKHWJeMuFDwJJ0Jk5Kihlp6esW4embuNkVgTNdTS09MMEbkDj76sUUsPvZ2xIwTRATsQuBuxGsTIYdSSo7cztpggwprdyKlJ8ImZUUuM3s48ol1lXwQjwydm5hINl2bF53KMCL82d2mR2GvqnBfg1+aKPbb9p+oGtYXbT1GTFxKiZkfEyHgy7x0y0clR454zSGpDMzaA3fzV30hNln4qkAqkAqlAKpAKpAKpQCqQCqQCqUAqkAqkAqlAKpAKpAKpQCrw3xWY/GGcz++TP9U3Gx40GWdEAxabXA33NBywRCOfdzFcCztDJv12Rz7REMpmIc9qPBNWK0J3COWNxegxIrs+KHZcyHpjsZUSXPaypcLtseJFS3tT84WwUZG4S4vEZkl3wl5FYK4rdrT9R9Y1uIbbT12TFxKiZkfEyCYfWojMJv+NGNGPr99GI9DP7P9TCgAAAABJRU5ErkJggg==");
948}
949.icon-toggler-expanded.icon-light:before,
950.icon-toggler-collapsed.icon-light:before,
951.icon-toggler-expanded.icon-light:after,
952.icon-toggler-collapsed.icon-light:after {
953 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAByCAYAAABeOoENAAAAAXNSR0IArs4c6QAAAcVJREFUaAXtmT9KA1EQxhMlASE2SkpPkCJlStHOu3gGwRPYBAm5gYfwFBKwtrARRAh26vr7ljfx7TrLChtBcAa+zOSbPy/7vcTC6fV+04qimIArsALrBMXiJq1nUzQEc/AOmkw51QzdgUqAWyD7AEswA6MExeKUk6n2+zBInSJ7BKfuaZDKpRpcMa/UQUgTfWSd1jjEmlSTatXzpRlvJKJsacVtXrVlB72bWgjdiGwmEj8FOq1u4qapRprJVvkgXbFsZCTxomSqL4ssr0uQrY3TJ/AGjeFfVJlM8diaiCuDdlLiIfmNcP1+/wnu0hoVJ84oq7XeUhNXbE4dgPuEgU2Qh3PFbrx+Gs6E2hD/+tMJ3b+QadB2fiLZsG4/2poG3f6M5MMiDgVCgVAgFAgFQoFQIBQIBUKBUCAUCAVCgVAgFAgFQoFQIBQIBf66AiwLuv1jnAH/Zb/Go5abq/qdwvsLFhJNK583ctfg0Bnmrnwq+zVrYoDZM8E52M1yP9uvqcGmZP6O+CTl3LWYHdTm9yk4aCzilLZHe6XmAuzZEGL30ZrEpr64AUc2wDycK7a7X6P42BpzD+9fv4pIxn4tWznnwm0r/gQpiG1tFshTowAAAABJRU5ErkJggg==");
954}
955.icon-toggler-expanded:before,
956.icon-toggler-expanded:after {
957 background-position: top left;
958}
959.icon-toggler-collapsed:before,
960.icon-toggler-collapsed:after {
961 background-position: bottom left;
962}
963.modal {
964 padding: 20px;
965 border-radius: 3px;
966 background-color: white;
967 max-width: 700px;
968 -webkit-box-sizing: border-box;
969 -moz-box-sizing: border-box;
970 box-sizing: border-box;
971 width: 80% !important;
972 top: 50% !important;
973 -webkit-transform: translate(-50%, -50%) !important;
974 -moz-transform: translate(-50%, -50%) !important;
975 -o-transform: translate(-50%, -50%) !important;
976 -ms-transform: translate(-50%, -50%) !important;
977 transform: translate(-50%, -50%) !important;
978}
979.modal-close {
980 -webkit-border-radius: 100px;
981 -webkit-background-clip: padding-box;
982 -moz-border-radius: 100px;
983 -moz-background-clip: padding;
984 border-radius: 100px;
985 background-clip: padding-box;
986 cursor: pointer;
987 height: 18px;
988 width: 18px;
989 position: absolute;
990 top: 10px;
991 right: 10px;
992 font-size: 17px;
993 text-align: center;
994 line-height: 19px;
995 background: #cccccc;
996}
997main .grid-container,
998header .grid-container,
999.navigation-a > div,
1000footer > div {
1001 max-width: 968px;
1002}
1003.header-a {
1004 margin-top: 30px;
1005}
1006.footer-a {
1007 border-top: 1px solid #D9D9D9;
1008}
1009.adjoined-top {
1010 background-color: #27C0D8;
1011 color: #fff;
1012}
1013.adjoined-top .content h1,
1014.adjoined-top .content h2,
1015.adjoined-top .content h3,
1016.adjoined-top .content h4,
1017.adjoined-top .content h5 {
1018 color: #fff;
1019}
1020.adjoined-top .content p {
1021 font-size: 18px;
1022 font-size: 1.125rem;
1023 line-height: 32.4px;
1024 line-height: 2.02rem;
1025 font-weight: 100;
1026}
1027.adjoined-top .content p a {
1028 text-decoration: none;
1029 border-bottom: 1px dotted #fff;
1030 color: inherit;
1031}
1032.adjoined-top .content p a:hover {
1033 color: #e6e6e6;
1034}
1035.adjoined-top .content button {
1036 color: #fff;
1037}
1038.adjoined-top .content strong {
1039 color: #fff;
1040}
1041.adjoined-top .content code {
1042 font-size: inherit;
1043 color: #27C0D8;
1044}
1045.adjoined-bottom {
1046 position: relative;
1047}
1048.adjoined-bottom:before {
1049 z-index: -1;
1050 content: '';
1051 background: #27C0D8;
1052 position: absolute;
1053 top: 0;
1054 left: 0;
1055 right: 0;
1056 height: 50%;
1057}
1058main .grid-container,
1059header .grid-container,
1060.navigation-a > div,
1061footer > div {
1062 max-width: 1052px;
1063}
1064main .grid-container.freed-width {
1065 max-width: none;
1066}
1067.switch {
1068 background: #25b4cb;
1069 float: right;
1070 overflow: visible;
1071}
1072.switch .balloon-a {
1073 position: absolute;
1074 top: -40px;
1075 right: 50%;
1076 margin-right: -15px;
1077 background: #FFEFC1;
1078 border-bottom-color: #DCDCA4;
1079}
1080.switch .balloon-a:before {
1081 border-color: #FFEFC1 transparent transparent transparent;
1082}
1083#toolbar .editors-container {
1084 overflow: hidden;
1085 height: 0;
1086 transition: height 200ms;
1087}
1088#toolbar .editors-container.active {
1089 height: auto;
1090}
1091#main #editor {
1092 background: #FFF;
1093 padding: 2% 4%;
1094 border: dashed 5px #27C0D8;
1095}
1096#main .adjoined-top:before {
1097 height: 335px;
1098}
1099#toolbar .adjoined-top:before {
1100 height: 219px;
1101}
1102#toolbar .adjoined-top .grid-container-nested {
1103 height: 147px;
1104}
1105.content .grid-switch-magic {
1106 margin: 3.5em 0 0;
1107}
1108#info-box {
1109 padding-bottom: 0;
1110}
1111#info-box > div {
1112 width: 100%;
1113 text-align: right;
1114}
1115#info-box > div .toggler {
1116 padding-right: 0;
1117}
1118#info-box > div .toggler:hover {
1119 background: transparent;
1120 color: #000;
1121}
1122#info-box > div .toggler:hover > label {
1123 text-decoration: underline;
1124}
1125#info-box > div h2 {
1126 float: left;
1127 margin-top: 0;
1128}
1129#info-box > div#instructions-container {
1130 text-align: left;
1131}
1132#toolbarModifierWrapper {
1133 overflow: hidden;
1134 height: 0;
1135 opacity: 0;
1136 transition: height 200ms;
1137}
1138#toolbarModifierWrapper.active {
1139 height: auto;
1140 opacity: 1;
1141}
1142header {
1143 overflow: visible;
1144}
1145header div.grid-container {
1146 overflow: visible;
1147}
1148header .navigation-b {
1149 overflow: visible;
1150}
1151header .navigation-b ul {
1152 overflow: visible;
1153}
1154header .navigation-b a {
1155 position: relative;
1156}
1157header .balloon-a {
1158 position: absolute;
1159 top: 48px;
1160 left: 50%;
1161 margin-left: -35px;
1162}
1163@media (max-width: 1140px) {
1164 header .balloon-a {
1165 left: auto;
1166 margin-left: auto;
1167 right: 50%;
1168 margin-right: -35px;
1169 }
1170 header .balloon-a:before {
1171 left: auto;
1172 right: 22px;
1173 }
1174}
1175@media (max-width: 900px) {
1176 header .balloon-a {
1177 display: none;
1178 }
1179}
1180#toolbar .cke_toolbar {
1181 pointer-events: none;
1182 -webkit-user-select: none;
1183 -moz-user-select: none;
1184 -ms-user-select: none;
1185 user-select: none;
1186 cursor: default;
1187}
1188.some-toolbar-active .cke_toolbar {
1189 zoom: 1;
1190 filter: alpha(opacity=50);
1191 -webkit-opacity: 0.5;
1192 -moz-opacity: 0.5;
1193 opacity: 0.5;
1194}
1195.cke_toolbar.active {
1196 position: relative;
1197 zoom: 1;
1198 filter: alpha(opacity=100);
1199 -webkit-opacity: 1;
1200 -moz-opacity: 1;
1201 opacity: 1;
1202}
1203.cke_toolbar.active:after {
1204 content: '';
1205 display: block;
1206 position: absolute;
1207 top: 0;
1208 right: 6px;
1209 bottom: 5px;
1210 left: 0;
1211 -webkit-border-radius: 5px;
1212 -webkit-background-clip: padding-box;
1213 -moz-border-radius: 5px;
1214 -moz-background-clip: padding;
1215 border-radius: 5px;
1216 background-clip: padding-box;
1217 -webkit-box-shadow: 0px 0px 15px 3px #fff4b0;
1218 -moz-box-shadow: 0px 0px 15px 3px #fff4b0;
1219 box-shadow: 0px 0px 15px 3px #fff4b0;
1220}
1221.cke_toolbar.active .cke_toolgroup {
1222 -webkit-box-shadow: none;
1223 -moz-box-shadow: none;
1224 box-shadow: none;
1225 border-color: #e3c300;
1226}
1227.cke_toolbar.active .cke_combo,
1228.cke_toolbar.active .cke_toolgroup {
1229 position: relative;
1230 z-index: 2;
1231}
1232.cke_toolbar.active .cke_combo_button {
1233 -webkit-box-shadow: none;
1234 -moz-box-shadow: none;
1235 box-shadow: none;
1236}
1237.unselectable {
1238 -webkit-user-select: none;
1239 -moz-user-select: none;
1240 -ms-user-select: none;
1241 user-select: none;
1242}
1243.toolbar {
1244 padding: 5px 0;
1245 margin-bottom: 2.4em;
1246 overflow: hidden;
1247 background: #fff;
1248}
1249.toolbar button.button-a.cke_button {
1250 cursor: pointer;
1251 display: inline-block;
1252 padding: 4px 6px;
1253 outline: 0;
1254 border: 1px solid #a6a6a6;
1255}
1256.toolbar button.button-a.hidden {
1257 display: none;
1258}
1259.toolbar button.button-a.left {
1260 float: left;
1261 margin-right: 8px;
1262}
1263.toolbar button.button-a.right {
1264 float: right;
1265 margin-left: 8px;
1266}
1267.toolbar button.button-a .highlight {
1268 color: #ffefc1;
1269}
1270.configContainer.hidden,
1271.toolbarModifier.hidden,
1272.toolbarModifier-hints.hidden {
1273 display: none;
1274}
1275.toolbarModifier :focus,
1276.toolbar button:focus,
1277.configContainer textarea.configCode:focus {
1278 outline: none;
1279}
1280div.toolbarModifier {
1281 padding: 0;
1282 overflow: hidden;
1283 width: 100%;
1284 position: relative;
1285 display: table;
1286 border-collapse: collapse;
1287}
1288div.toolbarModifier ::-moz-focus-inner {
1289 border: 0;
1290}
1291div.toolbarModifier .empty {
1292 display: none;
1293}
1294div.toolbarModifier.empty-visible .empty {
1295 display: table-row;
1296 zoom: 1;
1297 filter: alpha(opacity=60);
1298 -webkit-opacity: 0.6;
1299 -moz-opacity: 0.6;
1300 opacity: 0.6;
1301}
1302div.toolbarModifier .empty > p {
1303 line-height: 31px;
1304}
1305div.toolbarModifier > ul {
1306 padding: 0;
1307 margin: 0;
1308 border-top: 1px solid #ccc;
1309 width: 100%;
1310}
1311div.toolbarModifier > ul[data-type="table-header"] {
1312 display: table-header-group;
1313}
1314div.toolbarModifier > ul[data-type="table-body"] {
1315 display: table-row-group;
1316}
1317div.toolbarModifier > ul p {
1318 padding: 0;
1319 margin: 0;
1320}
1321div.toolbarModifier > ul > li {
1322 display: table-row;
1323}
1324div.toolbarModifier > ul > li[data-type="header"] {
1325 font-weight: bold;
1326 user-select: none;
1327 cursor: default;
1328}
1329div.toolbarModifier > ul > li[data-type="group"],
1330div.toolbarModifier > ul > li[data-type="separator"] {
1331 border-bottom: 1px solid #ccc;
1332}
1333div.toolbarModifier > ul > li[data-type="subgroup"] {
1334 border-top: 1px solid #eee;
1335}
1336div.toolbarModifier > ul > li[data-type="subgroup"]:first-child {
1337 border-top: none;
1338}
1339div.toolbarModifier > ul > li[data-type="group"].active,
1340div.toolbarModifier > ul > li[data-type="group"]:hover,
1341div.toolbarModifier > ul > li[data-type="separator"].active,
1342div.toolbarModifier > ul > li[data-type="separator"]:hover {
1343 overflow: hidden;
1344 z-index: 2;
1345}
1346div.toolbarModifier > ul > li[data-type="group"].active,
1347div.toolbarModifier > ul > li[data-type="separator"].active,
1348div.toolbarModifier > ul > li[data-type="group"].active:hover,
1349div.toolbarModifier > ul > li[data-type="separator"].active:hover {
1350 background: #f0fafb;
1351}
1352div.toolbarModifier > ul > li[data-type="group"]:hover,
1353div.toolbarModifier > ul > li[data-type="separator"]:hover {
1354 background: #fffbe3;
1355}
1356div.toolbarModifier > ul > li[data-type="separator"] {
1357 background: #f5f5f5;
1358}
1359div.toolbarModifier > ul > li[data-type="separator"]:after {
1360 content: '';
1361 width: 100%;
1362}
1363div.toolbarModifier > ul > li[data-type="separator"] > p {
1364 padding: 2px 5px;
1365}
1366div.toolbarModifier > ul > li > p,
1367div.toolbarModifier > ul > li > ul {
1368 display: table-cell;
1369 vertical-align: middle;
1370}
1371div.toolbarModifier > ul > li p {
1372 padding-left: 5px;
1373 min-width: 200px;
1374}
1375div.toolbarModifier > ul > li p span {
1376 white-space: nowrap;
1377 cursor: default;
1378}
1379div.toolbarModifier > ul > li p span button {
1380 font-size: 12.666px;
1381 margin-right: 5px;
1382 cursor: pointer;
1383 background: #fff;
1384 -webkit-border-radius: 5px;
1385 -webkit-background-clip: padding-box;
1386 -moz-border-radius: 5px;
1387 -moz-background-clip: padding;
1388 border-radius: 5px;
1389 background-clip: padding-box;
1390 border: 1px solid #bbb;
1391 padding: 0 7px;
1392 line-height: 12px;
1393 height: 20px;
1394}
1395div.toolbarModifier > ul > li p span button:not(.disabled):hover,
1396div.toolbarModifier > ul > li p span button:not(.disabled):focus {
1397 color: #fff;
1398 background-color: #454545;
1399 border-color: transparent;
1400}
1401div.toolbarModifier > ul > li p span button.move.disabled {
1402 cursor: default;
1403 zoom: 1;
1404 filter: alpha(opacity=20);
1405 -webkit-opacity: 0.2;
1406 -moz-opacity: 0.2;
1407 opacity: 0.2;
1408}
1409div.toolbarModifier > ul > li ul {
1410 border-collapse: collapse;
1411 padding: 0;
1412 width: 100%;
1413}
1414div.toolbarModifier > ul > li ul li {
1415 display: table-row;
1416 list-style-type: none;
1417 line-height: 1;
1418}
1419div.toolbarModifier > ul > li ul li[data-type="subgroup"] {
1420 border-top: 1px solid #ddd;
1421}
1422div.toolbarModifier > ul > li ul li[data-type="subgroup"]:first-child {
1423 border-top: 0;
1424}
1425div.toolbarModifier > ul > li ul li[data-type="subgroup"] [data-type="button"] {
1426 -webkit-border-radius: 3px;
1427 -webkit-background-clip: padding-box;
1428 -moz-border-radius: 3px;
1429 -moz-background-clip: padding;
1430 border-radius: 3px;
1431 background-clip: padding-box;
1432 padding: 0 2px;
1433}
1434div.toolbarModifier > ul > li ul li[data-type="subgroup"] [data-type="button"]:focus {
1435 background: rgba(0, 0, 0, 0.04);
1436}
1437div.toolbarModifier > ul > li ul li[data-type="subgroup"] [data-type="button"] input {
1438 vertical-align: middle;
1439}
1440div.toolbarModifier > ul > li ul li > p,
1441div.toolbarModifier > ul > li ul li > ul {
1442 display: table-cell;
1443 vertical-align: middle;
1444}
1445div.toolbarModifier > ul > li ul li ul {
1446 padding: 0;
1447}
1448div.toolbarModifier > ul > li ul li ul li {
1449 padding: 0;
1450 display: inline-block;
1451 cursor: pointer;
1452 margin: 2px 5px 2px 0;
1453}
1454div.toolbarModifier > ul > li ul li ul li .cke_combo_text {
1455 cursor: pointer;
1456 white-space: nowrap;
1457}
1458div.toolbarModifier > ul > li ul li ul li .cke_toolgroup,
1459div.toolbarModifier > ul > li ul li ul li .cke_combo_button {
1460 cursor: pointer;
1461 margin: 0;
1462 vertical-align: middle;
1463 border: 1px solid #ddd;
1464 font-size: 11.41px;
1465 font-size: 0.713rem;
1466 line-height: 20.54px;
1467 line-height: 1.28rem;
1468}
1469div.toolbarModifier > .codemirror-wrapper {
1470 overflow-y: auto;
1471}
1472div.toolbarModifier-hints {
1473 float: right;
1474 width: 350px;
1475 min-width: 150px;
1476 overflow-y: auto;
1477 margin-left: 1.5em;
1478}
1479div.toolbarModifier-hints h3 {
1480 font-size: 18.08px;
1481 font-size: 1.13rem;
1482 line-height: 32.54px;
1483 line-height: 2.03rem;
1484 padding: 0.36em 1.5em;
1485 background: #f5f5f5;
1486 border-bottom: 1px solid #ddd;
1487 margin-top: 0;
1488 margin-bottom: 1.2em;
1489}
1490div.toolbarModifier-hints dl {
1491 margin-bottom: 1.2em;
1492 overflow: hidden;
1493}
1494div.toolbarModifier-hints dl .list-header {
1495 font-weight: bold;
1496 border: 0;
1497 padding-bottom: 0.6em;
1498}
1499div.toolbarModifier-hints dl > p {
1500 text-align: center;
1501}
1502div.toolbarModifier-hints dl dt {
1503 float: left;
1504 width: 9em;
1505 clear: both;
1506 text-align: right;
1507 border-top: 1px solid #ddd;
1508 padding-left: 1.5em;
1509 padding-right: .1em;
1510 -webkit-box-sizing: border-box;
1511 -moz-box-sizing: border-box;
1512 box-sizing: border-box;
1513}
1514div.toolbarModifier-hints dl dt code {
1515 background: none;
1516 border: none;
1517 vertical-align: middle;
1518}
1519div.toolbarModifier-hints dl dd {
1520 margin-left: 10em;
1521 clear: right;
1522 padding-right: 1.5em;
1523}
1524div.toolbarModifier-hints dl dd code {
1525 line-height: 2.2em;
1526}
1527div.toolbarModifier-hints dl dd:after {
1528 content: '\00a0';
1529 display: block;
1530 clear: left;
1531 float: right;
1532 height: 0;
1533 width: 0;
1534}
1535.toolbarModifier-hints,
1536.configContainer textarea.configCode,
1537.CodeMirror {
1538 -webkit-border-radius: 3px;
1539 -webkit-background-clip: padding-box;
1540 -moz-border-radius: 3px;
1541 -moz-background-clip: padding;
1542 border-radius: 3px;
1543 background-clip: padding-box;
1544 border: 1px solid #ccc;
1545 font-size: 13.01px;
1546 font-size: 0.813rem;
1547 line-height: 23.42px;
1548 line-height: 1.46rem;
1549}
1550.configContainer textarea.configCode,
1551.CodeMirror pre,
1552.CodeMirror-linenumber {
1553 font-size: 13.01px;
1554 font-size: 0.813rem;
1555 line-height: 23.42px;
1556 line-height: 1.46rem;
1557 font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
1558}
1559.CodeMirror pre {
1560 border: none;
1561 padding: 0;
1562 margin: 0;
1563}
1564.configContainer textarea.configCode {
1565 -webkit-box-sizing: border-box;
1566 -moz-box-sizing: border-box;
1567 box-sizing: border-box;
1568 color: #575757;
1569 padding: 10px;
1570 width: 100%;
1571 min-height: 500px;
1572 margin: 0;
1573 resize: none;
1574 outline: none;
1575 -moz-tab-size: 4;
1576 tab-size: 4;
1577 white-space: pre;
1578 word-wrap: normal;
1579 overflow: auto;
1580}
1581.CodeMirror-hints.toolbar-modifier {
1582 padding: 0;
1583 color: #575757;
1584 font-size: 14px;
1585 font-size: 0.875rem;
1586 line-height: 25.2px;
1587 line-height: 1.57rem;
1588 font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
1589}
1590.CodeMirror-hints.toolbar-modifier .CodeMirror-hint-active {
1591 color: #575757;
1592 background: #f0fafb;
1593}
1594.CodeMirror-hints.toolbar-modifier > li:hover {
1595 background: #fffbe3;
1596}
1597/* Text modifier */
1598#toolbarModifierWrapper {
1599 margin-bottom: 1.2em;
1600}
1601#toolbarModifierWrapper .invalid .CodeMirror {
1602 background: #fff8f8;
1603 border-color: red;
1604}
1605#toolbarModifierWrapper .CodeMirror {
1606 height: auto;
1607 padding: 0 0.6em;
1608}
1609.staticContainer {
1610 position: fixed;
1611 top: 0;
1612 width: 100%;
1613 z-index: 10;
1614}
1615.staticContainer > .grid-container {
1616 max-width: 1052px;
1617}
1618.staticContainer > .grid-container .inner {
1619 background: #fff;
1620}
1621.staticContainer > .grid-container .inner .toolbar {
1622 margin-bottom: 0;
1623}
1624#help {
1625 position: relative;
1626 top: -15px;
1627 left: -5px;
1628}
1629#help-content {
1630 display: none;
1631}
1632/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2dsb2JhbC9nbG9iYWwubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2NvcmUvY29yZS5sZXNzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2Nrc291cmNlLXNhbXBsZXMtZnJhbWV3b3JrL2NvbXBvbmVudHMvZ3JpZC9ncmlkLmxlc3MiLCIuLi8uLi9ub2RlX21vZHVsZXMvY2tzb3VyY2Utc2FtcGxlcy1mcmFtZXdvcmsvbm9kZV9tb2R1bGVzL2xlc3NoYXQvYnVpbGQvbGVzc2hhdC5sZXNzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2Nrc291cmNlLXNhbXBsZXMtZnJhbWV3b3JrL2NvbXBvbmVudHMvaGVhZGVyLWEvaGVhZGVyLWEubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL25hdmlnYXRpb24tYS9uYXZpZ2F0aW9uLWEubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL25hdmlnYXRpb24tYi9uYXZpZ2F0aW9uLWIubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2Zvb3Rlci1hL2Zvb3Rlci1hLmxlc3MiLCIuLi8uLi9ub2RlX21vZHVsZXMvY2tzb3VyY2Utc2FtcGxlcy1mcmFtZXdvcmsvY29tcG9uZW50cy9jb250ZW50L2NvbnRlbnQubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2J1dHRvbi1hL2J1dHRvbi1hLmxlc3MiLCIuLi8uLi9ub2RlX21vZHVsZXMvY2tzb3VyY2Utc2FtcGxlcy1mcmFtZXdvcmsvY29tcG9uZW50cy9iYWxsb29uLWEvYmFsbG9vbi1hLmxlc3MiLCIuLi8uLi9ub2RlX21vZHVsZXMvY2tzb3VyY2Utc2FtcGxlcy1mcmFtZXdvcmsvY29tcG9uZW50cy9pY29uL2ljb24ubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL3N3aXRjaC9zd2l0Y2gubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL3RvZ2dsZXIvdG9nZ2xlci5sZXNzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2Nrc291cmNlLXNhbXBsZXMtZnJhbWV3b3JrL2NvbXBvbmVudHMvbW9kYWwvbW9kYWwubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2Jhc2ljc2FtcGxlL2NvcmUubGVzcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9ja3NvdXJjZS1zYW1wbGVzLWZyYW1ld29yay9jb21wb25lbnRzL2Jhc2ljc2FtcGxlL2Fkam9pbmVkLmxlc3MiLCIuLi8uLi9zYW1wbGVzL2xlc3MvY3VzdG9tLmxlc3MiLCIuLi8uLi9zYW1wbGVzL3Rvb2xiYXJjb25maWd1cmF0b3IvbGVzcy90b29sYmFybW9kaWZpZXIubGVzcyIsIi4uLy4uL3NhbXBsZXMvdG9vbGJhcmNvbmZpZ3VyYXRvci9sZXNzL2Jhc2UubGVzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBc0RBLFFBSGlDO0VBeUNoQztJQUNDLHdCQUFBOzs7QUMxRkY7QUFBUztBQUFPO0FBQVM7QUFBWTtBQUFRO0FBQVE7QUFBUTtBQUFRO0FBQU07QUFBTTtBQUFLO0VBQ3JGLGNBQUE7O0FBR0Q7QUFBTTtFQUNMLFNBQUE7RUFDQSxVQUFBO0VBQ0Esd0JETitCLHVDQ00vQjtFQUNBLGdCQUFBO0VBQ0EsY0FBQTs7QUNIQSxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsVUFBQTs7QUFERCxZQUFZO0VBQ1gsV0FBQTs7QUY0Q0YsUUFIaUM7RUVqQ2hDO0VBS0MsWUFBWTtFQUFaLFlBQVk7RUFBWixZQUFZO0VBQVosWUFBWTtFQUFaLFlBQVk7RUFBWixZQUFZO0VBQVosWUFBWTtFQUFaLFlBQVk7RUFBWixZQUFZO0lBSlosV0FBQTs7O0FBYUYsQ0FBQztFQ3FSQyw4QkFBQTtFQUNBLDJCQUFBO0VBQ0Esc0JBQUE7RURyUkQsZ0JBQUE7RUFDQSxpQkFBQTtFQUNBLFdBQUE7O0FBSUEsQ0FEQSxxQkFDQztBQUFELGVBQUM7QUFBUSxDQURULHFCQUNVO0FBQUQsZUFBQztFQUNULFNBQVMsRUFBVDtFQUNBLGNBQUE7RUFDQSxnQkFBQTtFQUNBLGtCQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7RUFDQSxRQUFBO0VBQ0EsU0FBQTs7QUFLRCxDQURBLHFCQUNDO0FBQUQsZUFBQztFQUNBLFdBQUE7O0FBSUY7RUMyUEUsOEJBQUE7RUFDQSwyQkFBQTtFQUNBLHNCQUFBO0VEM1BELGlCQUFBO0VBQ0Esa0JBQUE7O0FBS0Msc0JBREQsRUFBQyxxQkFDQztFQUNBLGVBQUE7O0FBR0Qsc0JBTEQsRUFBQyxxQkFLQztFQUNBLGdCQUFBOztBRmpCSCxRQUhpQztFRTBCOUIsc0JBREQsRUFBQyxxQkFDQztJQUNBLGdCQUFBOztFQUdELHNCQUxELEVBQUMscUJBS0M7SUFDQSxpQkFBQTs7O0FFN0VKO0VBQ0MsaUJBQUE7RUFHQSxnQkFBQTs7QUFKRCxTQU1DO0VBQ0MsZ0JBQUE7O0FKMENGLFFBSGlDO0VBNkNqQyxTSXJGQztJQUlFLGtCQUFBOzs7QUFWSCxTQU1DLGVBT0M7RUFDQyxtQkFBQTs7QUNWSDtFQUNDLFlBQUE7RUFDQSxtQkFBQTtFQUNBLGtCQUFBO0VBQ0EsT0FBQTtFQUNBLFFBQUE7RUFDQSxNQUFBO0VBQ0EsVUFBQTtFQUNBLGdCQUFBOztBTHFDRCxRQUhpQztFQTZDakM7SUs1RUUsa0JBQUE7OztBQVhGLGFBY0M7RUFDQyxnQkFBQTtFQUNBLFNBQUE7RUFDQSxnQkFBQTs7QUFqQkYsYUFjQyxHQUtDO0FBbkJGLGFBY0MsR0FLSyxHQUFHO0VBQ04scUJBQUE7O0FMeUJILFFBSGlDO0VBNkNqQyxhS3pFQztJQVVFLFdBQUE7SUFDQSx1QkFBQTtJQUNBLG1CQUFBO0lBQ0EscUJBQUE7SUFDQSxXQUFBOztFQUVBLGFBaEJGLEdBZ0JHO0VBQVMsYUFoQlosR0FnQmE7SUFDVixhQUFBOzs7QUFLRCxhQXRCRixHQXFCRSxhQUNDO0VBQ0EsZ0JBQUE7O0FMUUosUUFIaUM7RUE2Q2pDLGFLekVDLEdBcUJFLGFBQ0M7SUFJQyxnQkFBQTs7O0FBSUYsYUE5QkYsR0FxQkUsYUFTQztFQUNBLGlCQUFBOztBTEFKLFFBSGlDO0VBNkNqQyxhS3pFQyxHQXFCRSxhQVNDO0lBSUMsa0JBQUE7OztBQU1GLGFBeENGLEdBdUNDLEdBQ0c7RUFDRCxpQkFBQTs7QUF2REosYUFjQyxHQXVDQyxHQUtDO0VMeENGLGVBQUE7RUFDQSxtQkFBQTtFQUNBLGlCQUFBO0VBQ0Esb0JBQUE7RUt1Q0csaUJBQUE7RUFDQSxXQUFBO0VBQ0EsV0FBQTtFQUNBLGlCQUFBO0VBQ0EscUJBQUE7RUFDQSx5QkFBQTs7QUFFQSxhQXJESCxHQXVDQyxHQUtDLEVBU0U7RUFDQSxlQUFBO0VBQ0EsV0FBQTs7QUFRSix5QkFBQztBQUFTLHlCQUFDO0VBQ1Ysc0JBQWtCLHFyQkFBbEI7O0FDcEZGO0VBQ0MsaUJBQUE7RUFDQSxnQkFBQTtFQUNBLGlCQUFBOztBTmdERCxRQUhpQztFQTZDakM7SU12RkUsa0JBQUE7SUFDQSxnQkFBQTtJQUdBLFVBQUE7OztBQVZGLGFBYUM7RUFDQyxVQUFBO0VBQ0EsZ0JBQUE7RUFDQSxTQUFBO0VBQ0EsaUJBQUE7O0FBakJGLGFBYUMsR0FNQztBQW5CRixhQWFDLEdBTUssR0FBRztFQUNOLHFCQUFBOztBTitCSCxRQUhpQztFQTZDakMsYU1oRkM7SUFXRSxjQUFBO0lBQ0EsV0FBQTtJQUNBLHFCQUFBOzs7QU55QkgsUUFIaUM7RUE2Q2pDLGFNaEZDLEdBZ0JDO0lBRUUsa0JBQUE7OztBQUdELGFBckJGLEdBZ0JDLEdBS0c7RUFDRCxpQkFBQTs7QU5nQkosUUFIaUM7RUE2Q2pDLGFNaEZDLEdBZ0JDLEdBS0c7SUFJQSxjQUFBOzs7QUF0Q0wsYUFhQyxHQWdCQyxHQWFDO0VId1FELDhCQUFBO0VBQ0EsMkJBQUE7RUFDQSxzQkFBQTtFR3hRRSx5QkFBQTtFQUNBLHFCQUFBO0VBQ0EsYUFBQTs7QU5LSixRQUhpQztFQTZDakMsYU1oRkMsR0FnQkMsR0FhQztJQU9FLFdBQUE7SUhxT0gsd0JBQUE7SUFBaUMsb0NBQUE7SUFDakMscUJBQUE7SUFBOEIsNkJBQUE7SUFDOUIsZ0JBQUE7SUFBeUIsNEJBQUE7OztBSXhSM0I7RVB3QkMsZUFBQTtFQUNBLG9CQUFBO0VBQ0EsbUJBQUE7RUFDQSxvQkFBQTtFT3hCQSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0EsZ0JBQUE7RUFDQSxjQUFBOztBQU5ELFNQNEVDO0VBQ0MsY0FBQTtFQUNBLHFCQUFBO0VBRUEsaUNBQUE7O0FBRUEsU0FORCxFQU1FO0VBQ0EsY0FBQTs7QU9uRkgsU0FRQztFQUNDLFNBQUE7RUFDQSxxQkFBQTtFQUNBLGtCQUFBOztBQ1hGO0VSd0JDLGVBQUE7RUFDQSxtQkFBQTtFQUNBLG1CQUFBO0VBQ0Esb0JBQUE7RVF6QkEsZ0JBQUE7RUFDQSxrQkFBQTtFQUNBLHFCQUFBOztBQUpELFFBU0M7RUFDQyxnQkFBQTs7QUFWRixRQWFDO0FBYkQsUUFhSztBQWJMLFFBYVM7QUFiVCxRQWFjO0FBYmQsUUFhMEIsU0FBUSxJQUFJO0FBYnRDLFFBYXdEO0VBQ3RELGlCQUFBOztBQWRGLFFBaUJDO0FBakJELFFBaUJPO0VMcVFMLDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VLclF6QixnQkFBQTs7QUFuQkYsUUFzQkM7QUF0QkQsUUFzQk07QUF0Qk4sUUFzQlk7QUF0QlosUUFzQmlCO0VBQ2YsbUJBQUE7O0FBdkJGLFFBMEJDO0FBMUJELFFBMEJhO0VBQ1gsZ0JBQUE7RUFDQSw4QkFBQTtFQUNBLHFCQUFBOztBQTdCRixRQW9DQyxFUndDQTtBUTVFRCxRQW9DSSxHUndDSDtBUTVFRCxRQW9DUSxHUndDUDtBUTVFRCxRQW9DWSxXUndDWDtBUTVFRCxRQW9Dd0IsR1J3Q3ZCO0FRNUVELFFBb0M0QixHUndDM0I7QVE1RUQsUUFvQ2dDLEdSd0MvQjtBUTVFRCxRQW9Db0MsR1J3Q25DO0FRNUVELFFBb0N3QyxHUndDdkM7RUFDQyxjQUFBO0VBQ0EscUJBQUE7RUFFQSxpQ0FBQTs7QUFFQSxRUTlDRCxFUndDQSxFQU1FO0FBQUQsUVE5Q0UsR1J3Q0gsRUFNRTtBQUFELFFROUNNLEdSd0NQLEVBTUU7QUFBRCxRUTlDVSxXUndDWCxFQU1FO0FBQUQsUVE5Q3NCLEdSd0N2QixFQU1FO0FBQUQsUVE5QzBCLEdSd0MzQixFQU1FO0FBQUQsUVE5QzhCLEdSd0MvQixFQU1FO0FBQUQsUVE5Q2tDLEdSd0NuQyxFQU1FO0FBQUQsUVE5Q3NDLEdSd0N2QyxFQU1FO0VBQ0EsY0FBQTs7QVFuRkgsUUF3Q0M7QUF4Q0QsUUF3Q0s7QUF4Q0wsUUF3Q1M7QUF4Q1QsUUF3Q2E7QUF4Q2IsUUF3Q2lCO0VBQ2YsV0FBQTtFQUNBLGdCQUFBOztBQTFDRixRQXdDQyxHQUtDO0FBN0NGLFFBd0NLLEdBS0g7QUE3Q0YsUUF3Q1MsR0FLUDtBQTdDRixRQXdDYSxHQUtYO0FBN0NGLFFBd0NpQixHQUtmO0FBN0NGLFFBd0NDLEdBS087QUE3Q1IsUUF3Q0ssR0FLRztBQTdDUixRQXdDUyxHQUtEO0FBN0NSLFFBd0NhLEdBS0w7QUE3Q1IsUUF3Q2lCLEdBS1Q7RUFDTCxrQkFBQTs7QUE5Q0gsUUF3Q0MsR0FVQyxFQUFDO0FBbERILFFBd0NLLEdBVUgsRUFBQztBQWxESCxRQXdDUyxHQVVQLEVBQUM7QUFsREgsUUF3Q2EsR0FVWCxFQUFDO0FBbERILFFBd0NpQixHQVVmLEVBQUM7RUFDQSxnQkFBQTtFQUNBLHNCQUFBO0VBQ0EsVUFBQTtFQUNBLFNBQUE7O0FBR0QsUUFqQkQsR0FpQkUsTUFDQSxFQUFDO0FBREYsUUFqQkcsR0FpQkYsTUFDQSxFQUFDO0FBREYsUUFqQk8sR0FpQk4sTUFDQSxFQUFDO0FBREYsUUFqQlcsR0FpQlYsTUFDQSxFQUFDO0FBREYsUUFqQmUsR0FpQmQsTUFDQSxFQUFDO0VBQ0EsVUFBQTs7QUFJRixRQXZCRCxHQXVCRSxPQUNBO0FBREQsUUF2QkcsR0F1QkYsT0FDQTtBQURELFFBdkJPLEdBdUJOLE9BQ0E7QUFERCxRQXZCVyxHQXVCVixPQUNBO0FBREQsUUF2QmUsR0F1QmQsT0FDQTtFTDhERCwwREFBQTtFQUNBLHVEQUFBO0VBQ0EscURBQUE7RUFDQSxrREFBQTtFSy9ERSxVQUFBOztBQWxFSixRQXVFQztBQXZFRCxRQXVFUTtBQXZFUixRQXVFZ0IsU0FBUSxJQUFJO0VMK00xQiwwQkFBQTtFQUFpQyxvQ0FBQTtFQUNqQyx1QkFBQTtFQUE4Qiw2QkFBQTtFQUM5QixrQkFBQTtFQUF5Qiw0QkFBQTtFQW1CekIsdURBQUE7RUFDQSxvREFBQTtFQUNBLCtDQUFBO0VLbE9BLGFBQUE7RUFDQSxjQUFBO0VBRUEseUJBQUE7RUFDQSxrQkFBQTs7QUFFQSxRQVZELE1BVUU7QUFBRCxRQVZNLE9BVUw7QUFBRCxRQVZjLFNBQVEsSUFBSSxnQkFVekI7RUFDQSxxQkFBQTtFQUNBLFVBQUE7RUx3TkQsd0VBQUE7RUFDQSxxRUFBQTtFQUNBLGdFQUFBOztBSzdTRixRQThGQztFQUNDLDhCQUFBO0VBQ0EsZUFBQTs7QUFoR0YsUUFtR0M7RUFDQyxrQkFBQTtFQUNBLDZCUm5HMkMsd0JRbUczQztFUjdFRCxlQUFBO0VBQ0EsZUFBQTtFQUNBLG1CQUFBO0VBQ0EsbUJBQUE7O0FRM0JELFFBeUdDO0VBQ0Msa0JBQUE7O0FBMUdGLFFBNkdDO0VSckZBLGVBQUE7RUFDQSxrQkFBQTtFQUNBLG1CQUFBO0VBQ0Esb0JBQUE7RVFvRkMsbUJBQUE7O0FBL0dGLFFBa0hDO0VSMUZBLGlCQUFBO0VBQ0EsaUJBQUE7RUFDQSxvQkFBQTtFQUNBLG9CQUFBO0VReUZDLGlCQUFBOztBQXBIRixRQXVIQztFUi9GQSxlQUFBO0VBQ0EsaUJBQUE7RUFDQSxtQkFBQTtFQUNBLG1CQUFBO0VROEZDLGdCQUFBO0VBQ0Esa0JBQUE7O0FBMUhGLFFBNkhDO0VSckdBLGlCQUFBO0VBQ0EsaUJBQUE7RUFDQSxvQkFBQTtFQUNBLG9CQUFBO0VRb0dDLGdCQUFBO0VBQ0Esa0JBQUE7O0FBaElGLFFBbUlDO0VSM0dBLGlCQUFBO0VBQ0EsaUJBQUE7RUFDQSxvQkFBQTtFQUNBLG9CQUFBO0VRMEdDLGdCQUFBO0VBQ0Esa0JBQUE7O0FBdElGLFFBeUlDO0VBQ0MsU0FBQTtFQUNBLDZCQUFBO0VBQ0EsZUFBQTs7QUFJQSxRQURELE1BQ0U7RUFDQSxhQUFBO0VBQ0Esa0JBQUE7O0FBR0QsUUFORCxNQU1FO0VMaURELDBCQUFBO0VBQ0EsdUJBQUE7RUFDQSxrQkFBQTs7QUt4TUYsUUE0SkM7RVJwSUEsZUFBQTtFQUNBLGtCQUFBO0VBQ0EsbUJBQUE7RUFDQSxvQkFBQTtFUW1JQyxvQlI3SjhCLHVDUTZKOUI7RUFDQSxnQkFBQTtFTDRJQSx1REFBQTtFQUNBLG9EQUFBO0VBQ0EsK0NBQUE7O0FLN1NGLFFBdUtDLEVBQ0M7RUFDQyxzQkFBQTs7QUF6S0gsUUF1S0MsRUFLQztFQUNDLGNBQUE7O0FBN0tILFFBaUxDO0VBQ0MsVUFBQTtFQUNBLFNBQUE7RUFFQSxXQUFBO0VBQ0EsY0FBQTtFQUNBLGdCQUFBOztBQXZMRixRQTBMQztBQTFMRCxRQTBMTTtFUmxLTCxrQkFBQTtFQUNBLG1CQUFBO0VBQ0EsbUJBQUE7RUFDQSxvQkFBQTtFUWtLQyxnSkFBQTs7QUE3TEYsUUEwTEMsSUFLQztBQS9MRixRQTBMTSxLQUtKO0VBQ0MsU0FBQTs7QUFoTUgsUUFxTUMsSUFBSTtFQUNILGVBQUE7RUFDQSxjQUFBOztBQXZNRixRQTBNQztFQUNDLFdBQUE7O0FBM01GLFFBOE1DLEdBRUM7QUFoTkYsUUE4TUssR0FFSDtBQWhORixRQThNQyxHQUVLO0FBaE5OLFFBOE1LLEdBRUM7RUFDSCxnQkFBQTs7QUFqTkgsUUE4TUMsR0FNQztBQXBORixRQThNSyxHQU1IO0VSNUxELGVBQUE7RUFDQSxtQkFBQTtFQUNBLG9CQUFBO0VBQ0Esb0JBQUE7O0FRM0JELFFBME5DLFNBQVEsSUFBSTtFQUNYLFdBQUE7O0FBM05GLFFBOE5DLElBQUc7RUFDRix1QkFBQTtFQUNBLGFBQUE7RUFDQSxxQkFBQTs7O0FBR0EsUUFORCxJQUFHLEtBTUQ7RUFDQSxTQUFTLE1BQVQ7RUFDQSxpQkFBQTs7QUNqT0QsSUFERCxFQUNFO0FBQUQsSUFERSxPQUNEO0FBQUQsSUFEVSxNQUNUO0VOaVJELDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VIaFExQixlQUFBO0VBQ0EsbUJBQUE7RUFDQSxtQkFBQTtFQUNBLG9CQUFBO0VTbkJFLFlBQUE7RUFDQSxpQkFBQTtFQUNBLGdCQUFBO0VBQ0EsZ0JBQUE7RUFDQSxjQUFBO0VBQ0EsbUJBQUE7RUFDQSxxQkFBQTtFQUNBLHFCQUFBO0VBQ0EsZUFBQTtFQUNBLFNBQUE7RUFDQSxzQkFBQTtFQUlBLGFBQUE7RUFHQSx1QkFBQTs7QUFFQSxJQXZCRixFQUNFLFNBc0JDO0FBQUQsSUF2QkMsT0FDRCxTQXNCQztBQUFELElBdkJTLE1BQ1QsU0FzQkM7RUFDQSxrQkFBQTs7QUFHRCxJQTNCRixFQUNFLFNBMEJDO0FBQUQsSUEzQkMsT0FDRCxTQTBCQztBQUFELElBM0JTLE1BQ1QsU0EwQkM7RUFDQSxtQkFBQTs7QUFvQkQsSUFoREYsRUFDRSxTQStDQztBQUFELElBaERDLE9BQ0QsU0ErQ0M7QUFBRCxJQWhEUyxNQUNULFNBK0NDO0VOa09GLDRCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHlCQUFBO0VBQThCLDZCQUFBO0VBQzlCLG9CQUFBO0VBQXlCLDRCQUFBO0VNblB2QixXQUFBO0VBQ0EsVUFBQTtFQUNBLG1CQUFBO0VBQ0EsZ0JBQUE7RUFDQSxrQkFBQTtFQUNBLGtCQUFBOztBQUVBLElBeENILEVBQ0UsU0ErQ0MsaUJBUkM7QUFBRCxJQXhDQSxPQUNELFNBK0NDLGlCQVJDO0FBQUQsSUF4Q1EsTUFDVCxTQStDQyxpQkFSQztFQUNBLGtCQUFBO0VBQ0EsU0FBQTtFQUNBLFFBQUE7RUFDQSxxQkFBQTs7QVRHTCxRQUhpQztFQTZDakMsSVN6RkMsRUFDRSxTQW1EQztFVHFDSixJU3pGSSxPQUNELFNBbURDO0VUcUNKLElTekZZLE1BQ1QsU0FtREM7SU44TkYsNEJBQUE7SUFBaUMsb0NBQUE7SUFDakMseUJBQUE7SUFBOEIsNkJBQUE7SUFDOUIsb0JBQUE7SUFBeUIsNEJBQUE7SU1uUHZCLFdBQUE7SUFDQSxVQUFBO0lBQ0EsbUJBQUE7SUFDQSxnQkFBQTtJQUNBLGtCQUFBO0lBQ0Esa0JBQUE7O0VBRUEsSUF4Q0gsRUFDRSxTQW1EQywwQkFaQztFQUFELElBeENBLE9BQ0QsU0FtREMsMEJBWkM7RUFBRCxJQXhDUSxNQUNULFNBbURDLDBCQVpDO0lBQ0Esa0JBQUE7SUFDQSxTQUFBO0lBQ0EsUUFBQTtJQUNBLHFCQUFBOztFQUpELElBeENILEVBQ0UsU0FtREMsMEJBWkM7RUFBRCxJQXhDQSxPQUNELFNBbURDLDBCQVpDO0VBQUQsSUF4Q1EsTUFDVCxTQW1EQywwQkFaQztJQUNBLGtCQUFBO0lBQ0EsU0FBQTtJQUNBLFFBQUE7SUFDQSxxQkFBQTs7O0FBY0YsSUExREYsRUFDRSxTQXlEQztBQUFELElBMURDLE9BQ0QsU0F5REM7QUFBRCxJQTFEUyxNQUNULFNBeURDO0FBQ0QsSUEzREYsRUFDRSxTQTBEQztBQUFELElBM0RDLE9BQ0QsU0EwREM7QUFBRCxJQTNEUyxNQUNULFNBMERDO0VBQ0EsV0FBQTtFQUNBLG1CQUFBOztBQUdELElBaEVGLEVBQ0UsU0ErREM7QUFBRCxJQWhFQyxPQUNELFNBK0RDO0FBQUQsSUFoRVMsTUFDVCxTQStEQztFQUNBLHFCQUFBO0VBQ0EsVUFBQTtFTnFPRix5RUFBQTtFQUNBLHNFQUFBO0VBQ0EsaUVBQUE7O0FNNU5BLElBN0VELEVBNkVFO0FBQUQsSUE3RUUsT0E2RUQ7QUFBRCxJQTdFVSxNQTZFVDtFQUNBLG1CQUFBOztBQUVBLElBaEZGLEVBNkVFLGNBR0M7QUFBRCxJQWhGQyxPQTZFRCxjQUdDO0FBQUQsSUFoRlMsTUE2RVQsY0FHQztBQUNELElBakZGLEVBNkVFLGNBSUM7QUFBRCxJQWpGQyxPQTZFRCxjQUlDO0FBQUQsSUFqRlMsTUE2RVQsY0FJQztFQUNBLGNBQUE7RUFDQSxtQkFBQTs7QUFJRixJQXZGRCxFQXVGRTtBQUFELElBdkZFLE9BdUZEO0FBQUQsSUF2RlUsTUF1RlQ7QUFBRCxJQXZGRCxFSGlERyxhQXhDSCxHQWdCQyxHQWFDLEVBV0U7QUdzQ0gsSUF2RkUsT0hpREEsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFO0FHc0NILElBdkZVLE1IaURSLGFBeENILEdBZ0JDLEdBYUMsRUFXRTtFR3VDRixXQUFBO0VBQ0EsbUJBQUE7O0FBRUEsSUEzRkYsRUF1RkUsb0JBSUM7QUFBRCxJQTNGQyxPQXVGRCxvQkFJQztBQUFELElBM0ZTLE1BdUZULG9CQUlDO0FBQ0QsSUE1RkYsRUF1RkUsb0JBS0M7QUFBRCxJQTVGQyxPQXVGRCxvQkFLQztBQUFELElBNUZTLE1BdUZULG9CQUtDO0FBREQsSUEzRkYsRUhpREcsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMENEO0FBQUQsSUEzRkMsT0hpREEsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMENEO0FBQUQsSUEzRlMsTUhpRFIsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMENEO0FBQ0QsSUE1RkYsRUhpREcsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMkNEO0FBQUQsSUE1RkMsT0hpREEsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMkNEO0FBQUQsSUE1RlMsTUhpRFIsYUF4Q0gsR0FnQkMsR0FhQyxFQVdFLE1HMkNEO0VBQ0EsV0FBQTtFQUNBLG1CQUFBOztBQ2hHSjtFVnNCQyxlQUFBO0VBQ0Esa0JBQUE7RUFDQSxtQkFBQTtFQUNBLG9CQUFBO0VHMlBDLDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VPblIxQixnQ0FBQTtFQUVBLG1CQUFBO0VBQ0EscUJBQUE7RUFDQSxtQkFBQTtFQUNBLHdCQUFBO0VBQ0EsZ0JBQUE7RUFDQSxrQkFBQTtFQUNBLGFBQUE7RUFDQSxvQkFBQTtFQUNBLGNBQUE7O0FBRUEsVUFBQztFQUNBLGNBQUE7O0FBR0QsVUFBQztFQUNBLFNBQVMsRUFBVDtFQUNBLFFBQUE7RUFDQSxTQUFBO0VBQ0EsbUJBQUE7RUFDQSxrQkFBQTs7QUFNRCxhQUFDO0FBQUQsYUFBQztFQUNBLFVBQUE7RUFDQSw4QkFBQTtFQUNBLHlEQUFBOztBQU1ELGFBQUM7QUFBRCxhQUFDO0VBQ0EsYUFBQTtFQUNBLDhCQUFBO0VBQ0EseURBQUE7O0FBTUQsYUFBQztBQUFELGFBQUM7RUFDQSxVQUFBOztBQU1ELGFBQUM7QUFBRCxhQUFDO0VBQ0EsV0FBQTs7QUN2REYsY0FBYztBQUNkLGVBQWU7RUFDZCxTQUFTLEVBQVQ7RUFDQSxxQkFBQTtFQUNBLFdBQUE7RUFDQSxZQUFBO0VBQ0Esc0JBQUE7RUFDQSw0QkFBQTs7QUFHRCxjQUFjO0VBQ2Isa0JBQUE7O0FBR0QsZUFBZTtFQUNkLGlCQUFBOztBQUlBLGNBQUM7QUFBUyxjQUFDO0VBQ1Ysc0JBQWtCLDZjQUFsQjs7QUFLRCxtQkFBQztBQUFTLG1CQUFDO0VBQ1Ysc0JBQWtCLDZpQkFBbEI7O0FBS0QsV0FBQztBQUFTLFdBQUM7RUFDVixzQkFBa0IsNmlCQUFsQjs7QUM1QkYsSUFBSyxRQUVKO0VBQ0Msc0JBQUE7O0FBSEYsSUFBSyxRQU1KLE1BQUs7RUFDSixnQkFBQTtFQUNBLHFCQUFBOztBQVJGLElBQUssUUFXSjtFQUNDLHlCQUFBO0VBQ0EsMEJBQUE7O0FBRUEsSUFmRyxRQVdKLE1BSUU7RUFDQSxXQUFBOztBQUdELElBbkJHLFFBV0osTUFRRTtFQUNBLFlBQUE7O0FBcEJILElBQUssUUF3Qko7RUFDQyxhQUFBOztBQUlGO0VaWkMsZUFBQTtFQUNBLG1CQUFBO0VBQ0EsbUJBQUE7RUFDQSxvQkFBQTtFWVdBLGlCQUFBO0VBQ0EseUJBQUE7RUFDQSxnQkFBQTtFQUNBLHFCQUFBO0VBQ0Esc0JBQUE7RUFDQSxXQUFBO0VUMk9DLDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VTM08xQixrQkFBQTs7QUFURCxPQVdDLE1BQUs7RUFDSixhQUFBOztBQVpGLE9BZUM7RUFDQyxrQkFBQTtFQUNBLFVBQUE7RUFDQSxXQUFBO0VBQ0EsZUFBQTtFQUNBLGlCQUFBOztBQUVBLE9BUEQsTUFPRTtFQUNBLDBCQUFBOztBQXZCSCxPQTJCQztFQUNDLFdBQUE7RUFDQSxzQkFBQTtFQUNBLGFBQUE7RUFDQSxjQUFBO0VBQ0EsWUFBQTtFQUNBLGdCQUFBO0VUaU5BLDRCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHlCQUFBO0VBQThCLDZCQUFBO0VBQzlCLG9CQUFBO0VBQXlCLDRCQUFBOztBU3BQM0IsT0EyQkMsY0FTQztFQUNDLGdCQUFBO0VBQ0Esa0JBQUE7RUFDQSxjQUFBO0VBQ0EsYUFBQTtFQUNBLFlBQUE7RUFDQSxtQkFBQTtFVHdNRCw0QkFBQTtFQUFpQyxvQ0FBQTtFQUNqQyx5QkFBQTtFQUE4Qiw2QkFBQTtFQUM5QixvQkFBQTtFQUF5Qiw0QkFBQTs7QVN2TXhCLE9BbEJGLGNBU0MsU0FTRTtFQUNBLFNBQVMsRUFBVDtFQUNBLGNBQUE7RUFDQSxrQkFBQTtFQUNBLE1BQUE7RUFDQSxRQUFBO0VBQ0EsV0FBQTtFQUNBLE9BQUE7RUFFQSx5QkFBQTtFVHNLRix3Q0FBQTtFQUNBLG9DQUFBO0VBQ0EsZ0NBQUE7RUFLQSx5Q0FBQTtFQUE4QyxvQ0FBQTtFQUM5QyxxQ0FBQTtFQUEwQyw2QkFBQTtFQUMxQyxpQ0FBQTtFQUFzQyw0QkFBQTs7QVN2S3ZDLE9BQUMsTUFDQSxjQUFjLFNBQVE7RUFDckIsbUJBQUE7O0FBaEVILE9Bb0VDLE1BQUssY0FBZ0IsUUFFcEIsZ0JBQWdCO0VBQ2YsaUJBQUE7O0FBdkVILE9Bb0VDLE1BQUssY0FBZ0IsUUFTcEIsUUFBTztFQUNOLHNCQUFBO0VBQ0Esc0JBQUE7O0FBL0VILE9BbUZDLE1BQUssY0FBZ0IsUUFBUyxRQUFPO0VBQ3BDLHFCQUFBO0VBQ0EscUJBQUE7O0FDekhGO0VWazNCRSx5QkFBQTtFQUNBLHNCQUFBO0VBQ0EscUJBQUE7RUFDQSxpQkFBQTs7QVVyM0JGLFFBR0M7RUFDQyxlQUFBOztBQUpGLFFBTUM7RUFDQyxnQkFBQTs7QUFQRixRQVVDO0VBQ0MsYUFBQTs7QUFHRCxRQUFDLFVBQ0E7RUFDQyxhQUFBOztBQUZGLFFBQUMsVUFLQTtFQUNDLGdCQUFBOztBQUtIO0VBQ0MsZ0JBQUE7O0FBRUEsa0JBQUM7RUFDQSxTQUFBOztBQU1ELHNCQUFDO0FBQUQsdUJBQUM7QUFBUyxzQkFBQztBQUFELHVCQUFDO0VBQ1Ysc0JBQWtCLHlzQkFBbEI7O0FBSUEsc0JBREEsV0FDQztBQUFELHVCQURBLFdBQ0M7QUFBUyxzQkFEVixXQUNXO0FBQUQsdUJBRFYsV0FDVztFQUNWLHNCQUFrQixxdEJBQWxCOztBQU1GLHNCQUFDO0FBQ0Qsc0JBQUM7RUFDQSw2QkFBQTs7QUFLRCx1QkFBQztBQUNELHVCQUFDO0VBQ0EsZ0NBQUE7O0FDdERGO0VBQ0MsYUFBQTtFQUNBLGtCQUFBO0VBQ0EsdUJBQUE7RUFDQSxnQkFBQTtFWDRTQyw4QkFBQTtFQUNBLDJCQUFBO0VBQ0Esc0JBQUE7RVd6U0QscUJBQUE7RUFDQSxtQkFBQTtFWGd2QkMsd0NBQUE7RUFDQSxxQ0FBQTtFQUNBLG1DQUFBO0VBQ0Esb0NBQUE7RUFDQSxnQ0FBQTs7QVdqdkJELE1BQUM7RVh1UUEsNEJBQUE7RUFBaUMsb0NBQUE7RUFDakMseUJBQUE7RUFBOEIsNkJBQUE7RUFDOUIsb0JBQUE7RUFBeUIsNEJBQUE7RVd2UXpCLGVBQUE7RUFDQSxZQUFBO0VBQ0EsV0FBQTtFQUNBLGtCQUFBO0VBQ0EsU0FBQTtFQUNBLFdBQUE7RUFDQSxlQUFBO0VBQ0Esa0JBQUE7RUFDQSxpQkFBQTtFQUNBLG1CQUFBOztBQ3pCRixJQUFLO0FBQ0wsTUFBTztBQUNQLGFBQWM7QUFDZCxNQUFPO0VBQ04sZ0JBQUE7O0FBSUQ7RUFDQyxnQkFBQTs7QUFHRDtFQUNDLDZCQUFBOztBQ1hBLFNBQUM7RUFDQSx5QkFBQTtFQUNBLFdBQUE7O0FBRkQsU0FBQyxJQUlBLFNBQ0M7QUFMRixTQUFDLElBSUEsU0FDSztBQUxOLFNBQUMsSUFJQSxTQUNTO0FBTFYsU0FBQyxJQUlBLFNBQ2E7QUFMZCxTQUFDLElBSUEsU0FDaUI7RUFDZixXQUFBOztBQU5ILFNBQUMsSUFJQSxTQUtDO0VoQllGLGVBQUE7RUFDQSxtQkFBQTtFQUNBLG1CQUFBO0VBQ0Esb0JBQUE7RWdCYkcsZ0JBQUE7O0FBWEgsU0FBQyxJQUlBLFNBS0MsRUFJQztFQUNDLHFCQUFBO0VBQ0EsOEJBQUE7RUFDQSxjQUFBOztBQUVBLFNBbEJILElBSUEsU0FLQyxFQUlDLEVBS0U7RUFDQSxjQUFBOztBQW5CTCxTQUFDLElBSUEsU0FvQkM7RUFDQyxXQUFBOztBQXpCSCxTQUFDLElBSUEsU0F3QkM7RUFDQyxXQUFBOztBQTdCSCxTQUFDLElBSUEsU0E0QkM7RUFDQyxrQkFBQTtFQUNBLGNBQUE7O0FBS0gsU0FBQztFQUNBLGtCQUFBOztBQUVBLFNBSEEsT0FHQztFQUNBLFdBQUE7RUFDQSxTQUFTLEVBQVQ7RUFDQSxtQkFBQTtFQUNBLGtCQUFBO0VBQ0EsTUFBQTtFQUNBLE9BQUE7RUFDQSxRQUFBO0VBQ0EsV0FBQTs7QUN4REgsSUFBSztBQUNMLE1BQU87QUFDUCxhQUFjO0FBQ2QsTUFBTztFQUNOLGlCQUFBOztBQUdELElBQUssZ0JBQWU7RUFDbkIsZUFBQTs7QUFHRDtFQUNDLG1CQUFBO0VBQ0EsWUFBQTtFQUNBLGlCQUFBOztBQUhELE9BTUM7RUFFQyxrQkFBQTtFQUNBLFVBQUE7RUFDQSxVQUFBO0VBQ0EsbUJBQUE7RUFHQSxtQkFBQTtFQUNBLDRCQUFBOztBQUVBLE9BWEQsV0FXRTtFQUNBLHlEQUFBOztBQUtILFFBQVM7RUFDUixnQkFBQTtFQUNBLFNBQUE7RUFDQSx3QkFBQTs7QUFFQSxRQUxRLG1CQUtQO0VBQ0EsWUFBQTs7QUFLRixLQUFNO0VBQ0wsZ0JBQUE7RUFDQSxjQUFBO0VBQ0EsMEJBQUE7O0FBR0QsS0FBTSxjQUFhO0VBQ2xCLGFBQUE7O0FBSUEsUUFEUSxjQUNQO0VBQ0EsYUFBQTs7QUFGRixRQUFTLGNBS1I7RUFDQyxhQUFBOztBQUlGLFFBQ0M7RUFDQyxpQkFBQTs7QUFJRjtFQUNDLGlCQUFBOztBQURELFNBR0M7RUFDQyxXQUFBO0VBQ0EsaUJBQUE7O0FBTEYsU0FHQyxNQUlDO0VBQ0MsZ0JBQUE7O0FBRUEsU0FQRixNQUlDLFNBR0U7RUFDQSx1QkFBQTtFQUNBLFdBQUE7O0FBRkQsU0FQRixNQUlDLFNBR0UsTUFJQTtFQUNDLDBCQUFBOztBQWZMLFNBR0MsTUFpQkM7RUFDQyxXQUFBO0VBQ0EsYUFBQTs7QUFHRCxTQXRCRCxNQXNCRTtFQUNBLGdCQUFBOztBQUtIO0VBQ0MsZ0JBQUE7RUFDQSxTQUFBO0VBQ0EsVUFBQTtFQUNBLHdCQUFBOztBQUVBLHVCQUFDO0VBQ0EsWUFBQTtFQUNBLFVBQUE7O0FBS0Y7RUFDQyxpQkFBQTs7QUFERCxNQUdDLElBQUc7RUFDRixpQkFBQTs7QUFKRixNQU9DO0VBQ0MsaUJBQUE7O0FBUkYsTUFPQyxjQUdDO0VBQ0MsaUJBQUE7O0FBWEgsTUFPQyxjQU9DO0VBRUMsa0JBQUE7O0FBaEJILE1Bb0JDO0VBQ0Msa0JBQUE7RUFDQSxTQUFBO0VBRUEsU0FBQTtFQUNBLGtCQUFBOztBakJ0RkYsUUFIaUM7RUE2Q2pDLE1pQnVDQztJQVVFLFVBQUE7SUFDQSxpQkFBQTtJQUVBLFVBQUE7SUFDQSxtQkFBQTs7RUFFQSxNQWhCRixXQWdCRztJQUNBLFVBQUE7SUFDQSxXQUFBOzs7QWpCbkdKLFFBSGlDO0VBNkNqQyxNaUJ1Q0M7SUF3QkUsYUFBQTs7O0FDOUlILFFBQVM7RUFDUixvQkFBQTtFZm0yQkMseUJBQUE7RUFDQSxzQkFBQTtFQUNBLHFCQUFBO0VBQ0EsaUJBQUE7RWVwMkJELGVBQUE7O0FBSUQsb0JBQXFCO0VmNmVsQixPQUFBO0VBQVMseUJBQUE7RUFDVixvQkFBQTtFQUNBLGlCQUFBO0VBQ0EsWUFBQTs7QWU1ZUYsWUFBWTtFQUNYLGtCQUFBO0Vmd2VFLE9BQUE7RUFBUywwQkFBQTtFQUNWLGtCQUFBO0VBQ0EsZUFBQTtFQUNBLFVBQUE7O0FldGVELFlBTlcsT0FNVjtFQUNBLFNBQVMsRUFBVDtFQUNBLGNBQUE7RUFDQSxrQkFBQTtFQUNBLE1BQUE7RUFDQSxVQUFBO0VBQ0EsV0FBQTtFQUNBLE9BQUE7RWZnUEEsMEJBQUE7RUFBaUMsb0NBQUE7RUFDakMsdUJBQUE7RUFBOEIsNkJBQUE7RUFDOUIsa0JBQUE7RUFBeUIsNEJBQUE7RUFtQnpCLDRDQUFBO0VBQ0EseUNBQUE7RUFDQSxvQ0FBQTs7QWVwUkYsWUFBWSxPQWtCWDtFZmdRQyx3QkFBQTtFQUNBLHFCQUFBO0VBQ0EsZ0JBQUE7RWVoUUEscUJBQUE7O0FBcEJGLFlBQVksT0F1Qlg7QUF2QkQsWUFBWSxPQXdCWDtFQUNDLGtCQUFBO0VBQ0EsVUFBQTs7QUExQkYsWUFBWSxPQTZCWDtFZnFQQyx3QkFBQTtFQUNBLHFCQUFBO0VBQ0EsZ0JBQUE7O0FlbFBGO0VmdXpCRSx5QkFBQTtFQUNBLHNCQUFBO0VBQ0EscUJBQUE7RUFDQSxpQkFBQTs7QWV2ekJGO0VBQ0MsY0FBQTtFQUNBLG9CQUFBO0VBQ0EsZ0JBQUE7RUFDQSxnQkFBQTs7QUFHQyxRQURELE9BQU0sU0FDSjtFQUNBLGVBQUE7RUFFQSxxQkFBQTtFQUNBLGdCQUFBO0VBQ0EsVUFBQTtFQUNBLHlCQUFBOztBQUdELFFBVkQsT0FBTSxTQVVKO0VBQ0EsYUFBQTs7QUFHRCxRQWRELE9BQU0sU0FjSjtFQUNBLFdBQUE7RUFDQSxpQkFBQTs7QUFHRCxRQW5CRCxPQUFNLFNBbUJKO0VBQ0EsWUFBQTtFQUNBLGdCQUFBOztBQTNCSCxRQU1DLE9BQU0sU0F3Qkw7RUFDQyxjQUFBOztBQU1ILGdCQUFnQjtBQUNoQixnQkFBZ0I7QUFDaEIsc0JBQXNCO0VBQ3JCLGFBQUE7O0FBR0QsZ0JBQWlCO0FBQ2pCLFFBQVMsT0FBTTtBQUNmLGdCQUFpQixTQUFRLFdBQVc7RUFDbkMsYUFBQTs7QUFHRCxHQUFHO0VBQ0YsVUFBQTtFQUNBLGdCQUFBO0VBQ0EsV0FBQTtFQUNBLGtCQUFBO0VBQ0EsY0FBQTtFQUNBLHlCQUFBOztBQU5ELEdBQUcsZ0JBUUY7RUFDQyxTQUFBOztBQVRGLEdBQUcsZ0JBWUY7RUFDQyxhQUFBOztBQUdELEdBaEJFLGdCQWdCRCxjQUFlO0VBQ2Ysa0JBQUE7RWZrWUMsT0FBQTtFQUFTLHlCQUFBO0VBQ1Ysb0JBQUE7RUFDQSxpQkFBQTtFQUNBLFlBQUE7O0FldFpGLEdBQUcsZ0JBdUJGLE9BQU87RUFDTixpQkFBQTs7QUFJRCxHQTVCRSxnQkE0QkE7RUFDRCxVQUFBO0VBQ0EsU0FBQTtFQUNBLDBCQUFBO0VBQ0EsV0FBQTs7QUFFQSxHQWxDQyxnQkE0QkEsS0FNQTtFQUNBLDJCQUFBOztBQUdELEdBdENDLGdCQTRCQSxLQVVBO0VBQ0Esd0JBQUE7O0FBWEYsR0E1QkUsZ0JBNEJBLEtBZUQ7RUFDQyxVQUFBO0VBQ0EsU0FBQTs7QUFJRCxHQWpEQyxnQkE0QkEsS0FxQkM7RUFDRCxrQkFBQTs7QUFFQSxHQXBEQSxnQkE0QkEsS0FxQkMsS0FHQTtFQUNBLGlCQUFBO0VBQ0EsaUJBQUE7RUFDQSxlQUFBOztBQUdELEdBMURBLGdCQTRCQSxLQXFCQyxLQVNBO0FBQ0QsR0EzREEsZ0JBNEJBLEtBcUJDLEtBVUE7RUFDQSw2QkFBQTs7QUFHRCxHQS9EQSxnQkE0QkEsS0FxQkMsS0FjQTtFQUNBLDBCQUFBOztBQUVBLEdBbEVELGdCQTRCQSxLQXFCQyxLQWNBLHNCQUdDO0VBQ0EsZ0JBQUE7O0FBSUYsR0F2RUEsZ0JBNEJBLEtBcUJDLEtBc0JBLG1CQUFtQjtBQUNwQixHQXhFQSxnQkE0QkEsS0FxQkMsS0F1QkEsbUJBQW1CO0FBQ3BCLEdBekVBLGdCQTRCQSxLQXFCQyxLQXdCQSx1QkFBdUI7QUFDeEIsR0ExRUEsZ0JBNEJBLEtBcUJDLEtBeUJBLHVCQUF1QjtFQUN2QixnQkFBQTtFQUNBLFVBQUE7O0FBR0QsR0EvRUEsZ0JBNEJBLEtBcUJDLEtBOEJBLG1CQUFtQjtBQUNwQixHQWhGQSxnQkE0QkEsS0FxQkMsS0ErQkEsdUJBQXVCO0FBQ3hCLEdBakZBLGdCQTRCQSxLQXFCQyxLQWdDQSxtQkFBbUIsT0FBTztBQUMzQixHQWxGQSxnQkE0QkEsS0FxQkMsS0FpQ0EsdUJBQXVCLE9BQU87RUFDOUIsbUJBQUE7O0FBR0QsR0F0RkEsZ0JBNEJBLEtBcUJDLEtBcUNBLG1CQUFtQjtBQUNwQixHQXZGQSxnQkE0QkEsS0FxQkMsS0FzQ0EsdUJBQXVCO0VBQ3ZCLG1CQUFBOztBQUdELEdBM0ZBLGdCQTRCQSxLQXFCQyxLQTBDQTtFQU1BLG1CQUFBOztBQUxBLEdBNUZELGdCQTRCQSxLQXFCQyxLQTBDQSx1QkFDQztFQUNBLFNBQVMsRUFBVDtFQUNBLFdBQUE7O0FBS0QsR0FuR0QsZ0JBNEJBLEtBcUJDLEtBMENBLHVCQVFFO0VBQ0QsZ0JBQUE7O0FBSUYsR0F4R0EsZ0JBNEJBLEtBcUJDLEtBdURDO0FBQUssR0F4R1AsZ0JBNEJBLEtBcUJDLEtBdURRO0VBQ1IsbUJBQUE7RUFDQSxzQkFBQTs7QUF6REYsR0FqREMsZ0JBNEJBLEtBcUJDLEtBNkREO0VBQ0MsaUJBQUE7RUFDQSxnQkFBQTs7QUEvREYsR0FqREMsZ0JBNEJBLEtBcUJDLEtBNkRELEVBSUM7RUFDQyxtQkFBQTtFQUNBLGVBQUE7O0FBbkVILEdBakRDLGdCQTRCQSxLQXFCQyxLQTZERCxFQUlDLEtBSUM7RUFDQyxtQkFBQTtFQUNBLGlCQUFBO0VBQ0EsZUFBQTtFQUNBLGdCQUFBO0VmNkNKLDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VlN0NyQixzQkFBQTtFQUNBLGNBQUE7RUFDQSxpQkFBQTtFQUNBLFlBQUE7O0FBR0MsR0FsSUosZ0JBNEJBLEtBcUJDLEtBNkRELEVBSUMsS0FJQyxPQVdFLElBQUksV0FDSDtBQUNELEdBbklKLGdCQTRCQSxLQXFCQyxLQTZERCxFQUlDLEtBSUMsT0FXRSxJQUFJLFdBRUg7RUFDQSxXQUFBO0VBQ0EseUJBQUE7RUFDQSx5QkFBQTs7QUFJRixHQTFJSCxnQkE0QkEsS0FxQkMsS0E2REQsRUFJQyxLQUlDLE9Bb0JFLEtBQUs7RUFDTCxlQUFBO0Vmd1FKLE9BQUE7RUFBUyx5QkFBQTtFQUNWLG9CQUFBO0VBQ0EsaUJBQUE7RUFDQSxZQUFBOztBZXJXQSxHQWpEQyxnQkE0QkEsS0FxQkMsS0FrR0Q7RUFDQyx5QkFBQTtFQUNBLFVBQUE7RUFDQSxXQUFBOztBQXJHRixHQWpEQyxnQkE0QkEsS0FxQkMsS0FrR0QsR0FNQztFQUNDLGtCQUFBO0VBQ0EscUJBQUE7RUFHQSxjQUFBOztBQUVBLEdBaEtGLGdCQTRCQSxLQXFCQyxLQWtHRCxHQU1DLEdBT0U7RUFDQSwwQkFBQTs7QUFFQSxHQW5LSCxnQkE0QkEsS0FxQkMsS0FrR0QsR0FNQyxHQU9FLHNCQUdDO0VBQ0EsYUFBQTs7QUFKRixHQWhLRixnQkE0QkEsS0FxQkMsS0FrR0QsR0FNQyxHQU9FLHNCQU9BO0VmQUosMEJBQUE7RUFBaUMsb0NBQUE7RUFDakMsdUJBQUE7RUFBOEIsNkJBQUE7RUFDOUIsa0JBQUE7RUFBeUIsNEJBQUE7RWVBcEIsY0FBQTs7QUFFQSxHQTNLSixnQkE0QkEsS0FxQkMsS0FrR0QsR0FNQyxHQU9FLHNCQU9BLHFCQUlFO0VBQ0EsK0JBQUE7O0FBWkgsR0FoS0YsZ0JBNEJBLEtBcUJDLEtBa0dELEdBTUMsR0FPRSxzQkFPQSxxQkFRQztFQUNDLHNCQUFBOztBQUtILEdBckxGLGdCQTRCQSxLQXFCQyxLQWtHRCxHQU1DLEdBNEJHO0FBQUssR0FyTFQsZ0JBNEJBLEtBcUJDLEtBa0dELEdBTUMsR0E0QlU7RUFDUixtQkFBQTtFQUNBLHNCQUFBOztBQXRJSixHQWpEQyxnQkE0QkEsS0FxQkMsS0FrR0QsR0FNQyxHQWtDQztFQUNDLFVBQUE7O0FBM0lKLEdBakRDLGdCQTRCQSxLQXFCQyxLQWtHRCxHQU1DLEdBa0NDLEdBSUM7RUFDQyxVQUFBO0VBQ0EscUJBQUE7RUFDQSxlQUFBO0VBQ0EscUJBQUE7O0FBbEpMLEdBakRDLGdCQTRCQSxLQXFCQyxLQWtHRCxHQU1DLEdBa0NDLEdBSUMsR0FPQztFQUNDLGVBQUE7RUFDQSxtQkFBQTs7QUF2Sk4sR0FqREMsZ0JBNEJBLEtBcUJDLEtBa0dELEdBTUMsR0FrQ0MsR0FJQyxHQVlDO0FBMUpMLEdBakRDLGdCQTRCQSxLQXFCQyxLQWtHRCxHQU1DLEdBa0NDLEdBSUMsR0FhQztFQUNDLGVBQUE7RUFDQSxTQUFBO0VBQ0Esc0JBQUE7RUFDQSxzQkFBQTtFQ2xTUCxrQkFBQTtFQUNBLG1CQUFBO0VBRUEsb0JBQUE7RUFDQSxvQkFBQTs7QUR3U0EsR0ExTkUsZ0JBME5BO0VBQ0QsZ0JBQUE7O0FBSUQsR0EvTkUsZ0JBK05EO0VBQ0EsWUFBQTtFQUNBLFlBQUE7RUFDQSxnQkFBQTtFQUNBLGdCQUFBO0VBQ0Esa0JBQUE7O0FBTEQsR0EvTkUsZ0JBK05ELE1BT0E7RUN4VEQsa0JBQUE7RUFDQSxrQkFBQTtFQUVBLG9CQUFBO0VBQ0Esb0JBQUE7RURzVEUscUJBQUE7RUFDQSxtQkFBQTtFQUNBLDZCQUFBO0VBQ0EsYUFBQTtFQUNBLG9CQUFBOztBQWJGLEdBL05FLGdCQStORCxNQWdCQTtFQUVDLG9CQUFBO0VBQ0EsZ0JBQUE7O0FBbkJGLEdBL05FLGdCQStORCxNQWdCQSxHQUtDO0VBQ0MsaUJBQUE7RUFDQSxTQUFBO0VBQ0EscUJBQUE7O0FBR0QsR0ExUEEsZ0JBK05ELE1BZ0JBLEdBV0c7RUFDRCxrQkFBQTs7QUE1QkgsR0EvTkUsZ0JBK05ELE1BZ0JBLEdBZUM7RUFDQyxXQUFBO0VBQ0EsVUFBQTtFQUNBLFdBQUE7RUFDQSxpQkFBQTtFQUNBLDBCQUFBO0VBQ0EsbUJBQUE7RUFDQSxtQkFBQTtFZmxFRiw4QkFBQTtFQUNBLDJCQUFBO0VBQ0Esc0JBQUE7O0FlMEJELEdBL05FLGdCQStORCxNQWdCQSxHQWVDLEdBVUM7RUFDQyxnQkFBQTtFQUNBLFlBQUE7RUFDQSxzQkFBQTs7QUE1Q0osR0EvTkUsZ0JBK05ELE1BZ0JBLEdBZ0NDO0VBQ0MsaUJBQUE7RUFDQSxZQUFBO0VBQ0Esb0JBQUE7O0FBbkRILEdBL05FLGdCQStORCxNQWdCQSxHQWdDQyxHQUtDO0VBQ0Msa0JBQUE7O0FBR0QsR0F4UkQsZ0JBK05ELE1BZ0JBLEdBZ0NDLEdBU0U7RUFDQSxTQUFTLE9BQVQ7RUFDQSxjQUFBO0VBQ0EsV0FBQTtFQUNBLFlBQUE7RUFDQSxTQUFBO0VBQ0EsUUFBQTs7QUFPTDtBQUNBLGdCQUFpQixTQUFRO0FBQ3pCO0VmaElFLDBCQUFBO0VBQWlDLG9DQUFBO0VBQ2pDLHVCQUFBO0VBQThCLDZCQUFBO0VBQzlCLGtCQUFBO0VBQXlCLDRCQUFBO0VlZ0kxQixzQkFBQTtFQzNYQSxrQkFBQTtFQUNBLG1CQUFBO0VBRUEsb0JBQUE7RUFDQSxvQkFBQTs7QUQyWEQsZ0JBQWlCLFNBQVE7QUFDekIsV0FBWTtBQUNaO0VDallDLGtCQUFBO0VBQ0EsbUJBQUE7RUFFQSxvQkFBQTtFQUNBLG9CQUFBO0VEK1hBLGdKQUFBOztBQUdELFdBQVk7RUFDWCxZQUFBO0VBQ0EsVUFBQTtFQUNBLFNBQUE7O0FBR0QsZ0JBQWlCLFNBQVE7RWZ2SHZCLDhCQUFBO0VBQ0EsMkJBQUE7RUFDQSxzQkFBQTtFZXVIRCxjQUFBO0VBQ0EsYUFBQTtFQUNBLFdBQUE7RUFDQSxpQkFBQTtFQUNBLFNBQUE7RUFDQSxZQUFBO0VBQ0EsYUFBQTtFQUNBLGdCQUFBO0VBQ0EsV0FBQTtFQUNBLGdCQUFBO0VBQ0EsaUJBQUE7RUFDQSxjQUFBOztBQUdELGlCQUFpQjtFQUNoQixVQUFBO0VBQ0EsY0FBQTtFQzlaQSxlQUFBO0VBQ0EsbUJBQUE7RUFFQSxtQkFBQTtFQUNBLG9CQUFBO0VEa2FBLGdKQUFBOztBQVZELGlCQUFpQixpQkFJaEI7RUFDQyxjQUFBO0VBQ0EsbUJBQUE7O0FBTUQsaUJBWmdCLGlCQVlkLEtBQUk7RUFDTCxtQkFBQTs7O0FBS0Y7RUFDQyxvQkFBQTs7QUFERCx1QkFHQyxTQUFTO0VBQ1IsbUJBQUE7RUFDQSxpQkFBQTs7QUFMRix1QkFRQztFQUVDLFlBQUE7RUFHQSxnQkFBQTs7QUFJRjtFQUNDLGVBQUE7RUFDQSxNQUFBO0VBQ0EsV0FBQTtFQUNBLFdBQUE7O0FBSkQsZ0JBTUM7RUFDQyxpQkFBQTs7QUFQRixnQkFNQyxrQkFHQztFQUNDLGdCQUFBOztBQVZILGdCQU1DLGtCQUdDLE9BR0M7RUFDQyxnQkFBQTs7QUFPSjtFQUNDLGtCQUFBO0VBQ0EsVUFBQTtFQUNBLFVBQUE7O0FBRUEsS0FBQztFQUNBLGFBQUEifQ== */
diff --git a/sources/samples/img/github-top.png b/sources/samples/img/github-top.png
new file mode 100644
index 0000000..7b9cbb1
--- /dev/null
+++ b/sources/samples/img/github-top.png
Binary files differ
diff --git a/sources/samples/img/header-bg.png b/sources/samples/img/header-bg.png
new file mode 100644
index 0000000..a14166a
--- /dev/null
+++ b/sources/samples/img/header-bg.png
Binary files differ
diff --git a/sources/samples/img/header-separator.png b/sources/samples/img/header-separator.png
new file mode 100644
index 0000000..8c4fb9b
--- /dev/null
+++ b/sources/samples/img/header-separator.png
Binary files differ
diff --git a/sources/samples/img/logo.png b/sources/samples/img/logo.png
new file mode 100644
index 0000000..96d86e2
--- /dev/null
+++ b/sources/samples/img/logo.png
Binary files differ
diff --git a/sources/samples/img/navigation-tip.png b/sources/samples/img/navigation-tip.png
new file mode 100644
index 0000000..2286114
--- /dev/null
+++ b/sources/samples/img/navigation-tip.png
Binary files differ
diff --git a/sources/samples/index.html b/sources/samples/index.html
new file mode 100644
index 0000000..3d274cf
--- /dev/null
+++ b/sources/samples/index.html
@@ -0,0 +1,128 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>CKEditor Sample</title>
10 <script src="../ckeditor.js"></script>
11 <script src="js/sample.js"></script>
12 <link rel="stylesheet" href="css/samples.css">
13 <link rel="stylesheet" href="toolbarconfigurator/lib/codemirror/neo.css">
14</head>
15<body id="main">
16
17<nav class="navigation-a">
18 <div class="grid-container">
19 <ul class="navigation-a-left grid-width-70">
20 <li><a href="http://ckeditor.com">Project Homepage</a></li>
21 <li><a href="http://dev.ckeditor.com/">I found a bug</a></li>
22 <li><a href="http://github.com/ckeditor/ckeditor-dev" class="icon-pos-right icon-navigation-a-github">Fork CKEditor on GitHub</a></li>
23 </ul>
24 <ul class="navigation-a-right grid-width-30">
25 <li><a href="http://ckeditor.com/blog-list">CKEditor Blog</a></li>
26 </ul>
27 </div>
28</nav>
29
30<header class="header-a">
31 <div class="grid-container">
32 <h1 class="header-a-logo grid-width-30">
33 <a href="index.html"><img src="img/logo.png" alt="CKEditor Sample"></a>
34 </h1>
35
36 <nav class="navigation-b grid-width-70">
37 <ul>
38 <li><a href="index.html" class="button-a button-a-background">Start</a></li>
39 <li><a href="toolbarconfigurator/index.html" class="button-a">Toolbar configurator <span class="balloon-a balloon-a-nw">Edit your toolbar now!</span></a></li>
40 </ul>
41 </nav>
42 </div>
43</header>
44
45<main>
46 <div class="adjoined-top">
47 <div class="grid-container">
48 <div class="content grid-width-100">
49 <h1>Congratulations!</h1>
50 <p>
51 If you can see CKEditor below, it means that the installation succeeded.
52 You can now try out your new editor version, see its features, and when you are ready to move on, check some of the <a href="#sample-customize">most useful resources</a> recommended below.
53 </p>
54 </div>
55 </div>
56 </div>
57 <div class="adjoined-bottom">
58 <div class="grid-container">
59 <div class="grid-width-100">
60 <div id="editor">
61 <h1>Hello world!</h1>
62 <p>I'm an instance of <a href="http://ckeditor.com">CKEditor</a>.</p>
63 </div>
64 </div>
65 </div>
66 </div>
67
68 <div class="grid-container">
69 <div class="content grid-width-100">
70 <section id="sample-customize">
71 <h2>Customize Your Editor</h2>
72 <p>Modular build and <a href="http://docs.ckeditor.com/#!/guide/dev_configuration">numerous configuration options</a> give you nearly endless possibilities to customize CKEditor. Replace the content of your <code><a href="../config.js">config.js</a></code> file with the following code and refresh this page (<strong>remember to clear the browser cache</strong>)!</p>
73 <pre class="cm-s-neo CodeMirror"><code><span style="padding-right: 0.1px;"><span class="cm-variable">CKEDITOR</span>.<span class="cm-property">editorConfig</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>( <span class="cm-def">config</span> ) {</span>
74<span style="padding-right: 0.1px;"><span class="cm-tab"> </span><span class="cm-variable-2">config</span>.<span class="cm-property">language</span> <span class="cm-operator">=</span> <span class="cm-string">'es'</span>;</span>
75<span style="padding-right: 0.1px;"><span class="cm-tab"> </span><span class="cm-variable-2">config</span>.<span class="cm-property">uiColor</span> <span class="cm-operator">=</span> <span class="cm-string">'#F7B42C'</span>;</span>
76<span style="padding-right: 0.1px;"><span class="cm-tab"> </span><span class="cm-variable-2">config</span>.<span class="cm-property">height</span> <span class="cm-operator">=</span> <span class="cm-number">300</span>;</span>
77<span style="padding-right: 0.1px;"><span class="cm-tab"> </span><span class="cm-variable-2">config</span>.<span class="cm-property">toolbarCanCollapse</span> <span class="cm-operator">=</span> <span class="cm-atom">true</span>;</span>
78<span style="padding-right: 0.1px;">};</span></code></pre>
79 </section>
80
81 <section>
82 <h2>Toolbar Configuration</h2>
83 <p>If you want to reorder toolbar buttons or remove some of them, check <a href="toolbarconfigurator/index.html">this handy tool</a>!</p>
84 </section>
85
86 <section>
87 <h2>More Samples!</h2>
88 <p>Visit the <a href="http://sdk.ckeditor.com">CKEditor SDK</a> for a huge collection of samples showcasing editor features, with source code readily available to copy and use in your own implementation.</p>
89 </section>
90
91 <section>
92 <h2>Developer's Guide</h2>
93 <p>The most important resource for all developers working with CKEditor, integrating it with their websites and applications, and customizing to their needs. You can start from here:</p>
94 <ul>
95 <li><a href="http://docs.ckeditor.com/#!/guide/dev_installation">Getting Started</a> &ndash; Explains most crucial editor concepts and practices as well as the installation process and integration with your website.</li>
96 <li><a href="http://docs.ckeditor.com/#!/guide/dev_advanced_installation">Advanced Installation Concepts</a> &ndash; Describes how to upgrade, install additional components (plugins, skins), or create a custom build.</li>
97 </ul>
98 <p>When you have the basics sorted out, feel free to browse some more advanced sections like:</p>
99 <ul>
100 <li><a href="http://docs.ckeditor.com/#!/guide/dev_features">Functionality Overview</a> &ndash; Descriptions and samples of various editor features.</li>
101 <li><a href="http://docs.ckeditor.com/#!/guide/plugin_sdk_intro">Plugin SDK</a>, <a href="http://docs.ckeditor.com/#!/guide/widget_sdk_intro">Widget SDK</a>, and <a href="http://docs.ckeditor.com/#!/guide/skin_sdk_intro">Skin SDK</a> &ndash; Useful when you want to create your own editor components.</li>
102 </ul>
103 </section>
104
105 <section>
106 <h2>CKEditor JavaScript API</h2>
107 <p>CKEditor boasts a rich <a href="http://docs.ckeditor.com/#!/api">JavaScript API</a> that you can use to adjust the editor to your needs and integrate it with your website or application.</p>
108 </section>
109 </div>
110 </div>
111</main>
112
113<footer class="footer-a grid-container">
114 <div class="grid-container">
115 <p class="grid-width-100">
116 CKEditor &ndash; The text editor for the Internet &ndash; <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
117 </p>
118 <p class="grid-width-100" id="copy">
119 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> &ndash; Frederico Knabben. All rights reserved.
120 </p>
121 </div>
122</footer>
123<script>
124 initSample();
125</script>
126
127</body>
128</html>
diff --git a/sources/samples/js/sample.js b/sources/samples/js/sample.js
new file mode 100644
index 0000000..70cf8d6
--- /dev/null
+++ b/sources/samples/js/sample.js
@@ -0,0 +1,54 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/* exported initSample */
7
8if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
9 CKEDITOR.tools.enableHtml5Elements( document );
10
11// The trick to keep the editor in the sample quite small
12// unless user specified own height.
13CKEDITOR.config.height = 150;
14CKEDITOR.config.width = 'auto';
15
16var initSample = ( function() {
17 var wysiwygareaAvailable = isWysiwygareaAvailable(),
18 isBBCodeBuiltIn = !!CKEDITOR.plugins.get( 'bbcode' );
19
20 return function() {
21 var editorElement = CKEDITOR.document.getById( 'editor' );
22
23 // :(((
24 if ( isBBCodeBuiltIn ) {
25 editorElement.setHtml(
26 'Hello world!\n\n' +
27 'I\'m an instance of [url=http://ckeditor.com]CKEditor[/url].'
28 );
29 }
30
31 // Depending on the wysiwygare plugin availability initialize classic or inline editor.
32 if ( wysiwygareaAvailable ) {
33 CKEDITOR.replace( 'editor' );
34 } else {
35 editorElement.setAttribute( 'contenteditable', 'true' );
36 CKEDITOR.inline( 'editor' );
37
38 // TODO we can consider displaying some info box that
39 // without wysiwygarea the classic editor may not work.
40 }
41 };
42
43 function isWysiwygareaAvailable() {
44 // If in development mode, then the wysiwygarea must be available.
45 // Split REV into two strings so builder does not replace it :D.
46 if ( CKEDITOR.revision == ( '%RE' + 'V%' ) ) {
47 return true;
48 }
49
50 return !!CKEDITOR.plugins.get( 'wysiwygarea' );
51 }
52} )();
53
54// %LEAVE_UNMINIFIED% %REMOVE_LINE%
diff --git a/sources/samples/js/sf.js b/sources/samples/js/sf.js
new file mode 100644
index 0000000..d42dbd8
--- /dev/null
+++ b/sources/samples/js/sf.js
@@ -0,0 +1,673 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5/* exported SF */
6
7'use strict';
8
9var SF = ( function() {
10 var SF = {};
11
12 SF.attachListener = function( elem, evtName, callback ) {
13 if ( elem.addEventListener ) {
14 elem.addEventListener( evtName, callback, false );
15 } else if ( elem.attachEvent ) {
16 elem.attachEvent( 'on' + evtName , function() {
17 callback.apply( elem, arguments );
18 } );
19 } else {
20 throw new Error( 'Could not attach event.' );
21 }
22 };
23
24 SF.indexOf = ( function() {
25 var indexOf = Array.prototype.indexOf;
26
27 if ( indexOf === 'function' ) {
28 return function( arr, elem ) {
29 return indexOf.call( arr, elem );
30 };
31 } else {
32 return function( arr, elem ) {
33 var max = arr.length;
34
35 for ( var i = 0; i < max; i++ ) {
36 if ( arr[ i ] === elem ) {
37 return i;
38 }
39 }
40
41 return -1;
42 };
43 }
44
45 }() );
46
47 SF.accept = function( node, visitor ) {
48 var children;
49
50 // Handling node as a node and array
51 if ( node.children ) {
52 children = node.children;
53
54 visitor( node );
55 } else if ( typeof node.length === 'number' ) {
56 children = node;
57 }
58
59 var i = children ? ( children.length || 0 ) : 0;
60 while ( i-- ) {
61 SF.accept( children[ i ], visitor );
62 }
63 };
64
65 SF.getByClass = ( function( ) {
66 var getByClass = document.getElementsByClassName;
67 if ( typeof getByClass === 'function' ) {
68 return function( root, className ) {
69 if ( typeof root === 'string' ) {
70 className = root;
71 root = document;
72 }
73
74 return getByClass.call( root, className );
75 };
76 }
77
78 return function( root, className ) {
79 if ( typeof root === 'string' ) {
80 className = root;
81 root = document.getElementsByTagName( 'html' )[ 0 ];
82 }
83 var results = [];
84
85 SF.accept( root, function( elem ) {
86 if ( SF.classList.contains( elem, className ) ) {
87 results.push( elem );
88 }
89 } );
90
91 return results;
92 };
93 }() );
94
95 SF.classList = {};
96
97 SF.classList.add = function( elem, className ) {
98 var classes = parseClasses( elem );
99 classes.push( className );
100
101 elem.attributes.setNamedItem( createClassAttr( classes ) );
102 };
103
104 SF.classList.remove = function( elem, className ) {
105 var classes = parseClasses( elem, className ),
106 foundAt = SF.indexOf( classes, className );
107
108 if ( foundAt === -1 ) {
109 return;
110 }
111
112 classes.splice( foundAt, 1 );
113 elem.attributes.setNamedItem( createClassAttr( classes ) );
114 };
115
116 SF.classList.contains = function( elem, className ) {
117 return findIndex( elem, className ) !== -1;
118 };
119
120 SF.classList.toggle = function( elem, className ) {
121 this.contains( elem, className ) ? this.remove( elem, className ) : this.add( elem, className );
122 };
123
124 function findIndex( elem, className ) {
125 return SF.indexOf( parseClasses( elem ), className );
126 }
127
128 function parseClasses( elem ) {
129 var classAttr = elem.attributes ? elem.attributes.getNamedItem( 'class' ) : null;
130
131 return classAttr ? classAttr.value.split( ' ' ) : [];
132 }
133
134 function createClassAttr( classesArray ) {
135 var attr = document.createAttribute( 'class' );
136
137 attr.value = classesArray.join( ' ' );
138
139 return attr;
140 }
141
142 return SF;
143}() );
144
145/* global SF, picoModal */
146
147'use strict';
148
149( function() {
150 // Purges all styles in passed object.
151 function purgeStyles( styles ) {
152 for ( var i in styles ) {
153 delete styles[ i ];
154 }
155 }
156
157 SF.modal = function( config ) {
158 // Modal should use the same style set as the rest of the page (.content component).
159 config.modalClass = 'modal content';
160 config.closeClass = 'modal-close';
161
162 // Purge all pre-defined pico styles. Use the lessfile instead.
163 config.modalStyles = purgeStyles;
164
165 // Close button styles are customized via lessfile.
166 config.closeStyles = purgeStyles;
167
168 var userDefinedAfterCreate = config.afterCreate,
169 userDefinedAfterClose = config.afterClose;
170
171 // Close modal on ESC key.
172 function onKeyDown( event ) {
173 if ( event.keyCode == 27 ) {
174 modal.close();
175 }
176 }
177
178 // Use afterCreate as a config option rather than function chain.
179 config.afterCreate = function( modal ) {
180 userDefinedAfterCreate && userDefinedAfterCreate( modal );
181
182 window.addEventListener( 'keydown', onKeyDown );
183 };
184
185 // Use afterClose as a config option rather than function chain.
186 config.afterClose = function( modal ) {
187 userDefinedAfterClose && userDefinedAfterClose( modal );
188
189 window.removeEventListener( 'keydown', onKeyDown );
190 };
191
192 var modal = new picoModal( config )
193 .afterCreate( config.afterCreate )
194 .afterClose( config.afterClose );
195
196 return modal;
197 };
198} )();
199'use strict';
200
201( function() {
202 // All .tree-a elements in DOM.
203 var expanders = SF.getByClass( 'toggler' );
204
205 var i = expanders.length;
206 while ( i-- ) {
207 var expander = expanders[ i ];
208
209 SF.attachListener( expander, 'click', function() {
210 var containsIcon = SF.classList.contains( this, 'icon-toggler-expanded' ) || SF.classList.contains( this, 'icon-toggler-collapsed' ),
211 related = document.getElementById( this.getAttribute( 'data-for' ) );
212
213 SF.classList.toggle( this, 'collapsed' );
214
215 if ( SF.classList.contains( this, 'collapsed' ) ) {
216 SF.classList.add( related, 'collapsed' );
217 if ( containsIcon ) {
218 SF.classList.remove( this, 'icon-toggler-expanded' );
219 SF.classList.add( this, 'icon-toggler-collapsed' );
220 }
221 } else {
222 SF.classList.remove( related, 'collapsed' );
223 if ( containsIcon ) {
224 SF.classList.remove( this, 'icon-toggler-collapsed' );
225 SF.classList.add( this, 'icon-toggler-expanded' );
226 }
227 }
228 } );
229 }
230} )();
231/* global SF */
232
233'use strict';
234
235( function() {
236 // All .tree-a elements in DOM.
237 var trees = SF.getByClass( 'tree-a' );
238
239 for ( var i = trees.length; i--; ) {
240 var tree = trees[ i ];
241
242 SF.attachListener( tree, 'click', function( evt ) {
243 var target = evt.target || evt.srcElement;
244
245 // Collapse or expand item groups.
246 if ( target.nodeName === 'H2' && !SF.classList.contains( target, 'tree-a-no-sub' ) ) {
247 SF.classList.toggle( target, 'tree-a-active' );
248 }
249 } );
250 }
251} )();
252// jshint ignore:start
253// jscs:disable
254/**
255 * Permission is hereby granted, free of charge, to any person obtaining a copy
256 * of this software and associated documentation files (the "Software"), to deal
257 * in the Software without restriction, including without limitation the rights
258 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
259 * copies of the Software, and to permit persons to whom the Software is
260 * furnished to do so, subject to the following conditions:
261 *
262 * The above copyright notice and this permission notice shall be included in
263 * all copies or substantial portions of the Software.
264 *
265 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
266 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
267 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
268 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
269 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
270 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
271 * SOFTWARE.
272 */
273
274/**
275 * A self-contained modal library
276 */
277(function(window, document) {
278 "use strict";
279
280 /** Returns whether a value is a dom node */
281 function isNode(value) {
282 if ( typeof Node === "object" ) {
283 return value instanceof Node;
284 }
285 else {
286 return value &&
287 typeof value === "object" &&
288 typeof value.nodeType === "number";
289 }
290 }
291
292 /** Returns whether a value is a string */
293 function isString(value) {
294 return typeof value === "string";
295 }
296
297 /**
298 * Generates observable objects that can be watched and triggered
299 */
300 function observable() {
301 var callbacks = [];
302 return {
303 watch: callbacks.push.bind(callbacks),
304 trigger: function( modal ) {
305
306 var unprevented = true;
307 var event = {
308 preventDefault: function preventDefault () {
309 unprevented = false;
310 }
311 };
312
313 for (var i = 0; i < callbacks.length; i++) {
314 callbacks[i](modal, event);
315 }
316
317 return unprevented;
318 }
319 };
320 }
321
322
323 /**
324 * A small interface for creating and managing a dom element
325 */
326 function Elem( elem ) {
327 this.elem = elem;
328 }
329
330 /**
331 * Creates a new div
332 */
333 Elem.div = function ( parent ) {
334 var elem = document.createElement('div');
335 (parent || document.body).appendChild(elem);
336 return new Elem(elem);
337 };
338
339 Elem.prototype = {
340
341 /** Creates a child of this node */
342 child: function () {
343 return Elem.div(this.elem);
344 },
345
346 /** Applies a set of styles to an element */
347 stylize: function(styles) {
348 styles = styles || {};
349
350 if ( typeof styles.opacity !== "undefined" ) {
351 styles.filter =
352 "alpha(opacity=" + (styles.opacity * 100) + ")";
353 }
354
355 for (var prop in styles) {
356 if (styles.hasOwnProperty(prop)) {
357 this.elem.style[prop] = styles[prop];
358 }
359 }
360
361 return this;
362 },
363
364 /** Adds a class name */
365 clazz: function (clazz) {
366 this.elem.className += " " + clazz;
367 return this;
368 },
369
370 /** Sets the HTML */
371 html: function (content) {
372 if ( isNode(content) ) {
373 this.elem.appendChild( content );
374 }
375 else {
376 this.elem.innerHTML = content;
377 }
378 return this;
379 },
380
381 /** Adds a click handler to this element */
382 onClick: function(callback) {
383 this.elem.addEventListener('click', callback);
384 return this;
385 },
386
387 /** Removes this element from the DOM */
388 destroy: function() {
389 document.body.removeChild(this.elem);
390 },
391
392 /** Hides this element */
393 hide: function() {
394 this.elem.style.display = "none";
395 },
396
397 /** Shows this element */
398 show: function() {
399 this.elem.style.display = "block";
400 },
401
402 /** Sets an attribute on this element */
403 attr: function ( name, value ) {
404 this.elem.setAttribute(name, value);
405 return this;
406 },
407
408 /** Executes a callback on all the ancestors of an element */
409 anyAncestor: function ( predicate ) {
410 var elem = this.elem;
411 while ( elem ) {
412 if ( predicate( new Elem(elem) ) ) {
413 return true;
414 }
415 else {
416 elem = elem.parentNode;
417 }
418 }
419 return false;
420 }
421 };
422
423
424 /** Generates the grey-out effect */
425 function buildOverlay( getOption, close ) {
426 return Elem.div()
427 .clazz("pico-overlay")
428 .clazz( getOption("overlayClass", "") )
429 .stylize({
430 display: "block",
431 position: "fixed",
432 top: "0px",
433 left: "0px",
434 height: "100%",
435 width: "100%",
436 zIndex: 10000
437 })
438 .stylize(getOption('overlayStyles', {
439 opacity: 0.5,
440 background: "#000"
441 }))
442 .onClick(function () {
443 if ( getOption('overlayClose', true) ) {
444 close();
445 }
446 });
447 }
448
449 /** Builds the content of a modal */
450 function buildModal( getOption, close ) {
451 var width = getOption('width', 'auto');
452 if ( typeof width === "number" ) {
453 width = "" + width + "px";
454 }
455
456 var elem = Elem.div()
457 .clazz("pico-content")
458 .clazz( getOption("modalClass", "") )
459 .stylize({
460 display: 'block',
461 position: 'fixed',
462 zIndex: 10001,
463 left: "50%",
464 top: "50px",
465 width: width,
466 '-ms-transform': 'translateX(-50%)',
467 '-moz-transform': 'translateX(-50%)',
468 '-webkit-transform': 'translateX(-50%)',
469 '-o-transform': 'translateX(-50%)',
470 'transform': 'translateX(-50%)'
471 })
472 .stylize(getOption('modalStyles', {
473 backgroundColor: "white",
474 padding: "20px",
475 borderRadius: "5px"
476 }))
477 .html( getOption('content') )
478 .attr("role", "dialog")
479 .onClick(function (event) {
480 var isCloseClick = new Elem(event.target)
481 .anyAncestor(function (elem) {
482 return /\bpico-close\b/.test(elem.elem.className);
483 });
484 if ( isCloseClick ) {
485 close();
486 }
487 });
488
489 return elem;
490 }
491
492 /** Builds the close button */
493 function buildClose ( elem, getOption ) {
494 if ( getOption('closeButton', true) ) {
495 return elem.child()
496 .html( getOption('closeHtml', "&#xD7;") )
497 .clazz("pico-close")
498 .clazz( getOption("closeClass") )
499 .stylize( getOption('closeStyles', {
500 borderRadius: "2px",
501 cursor: "pointer",
502 height: "15px",
503 width: "15px",
504 position: "absolute",
505 top: "5px",
506 right: "5px",
507 fontSize: "16px",
508 textAlign: "center",
509 lineHeight: "15px",
510 background: "#CCC"
511 }) );
512 }
513 }
514
515 /** Builds a method that calls a method and returns an element */
516 function buildElemAccessor( builder ) {
517 return function () {
518 return builder().elem;
519 };
520 }
521
522
523 /**
524 * Displays a modal
525 */
526 function picoModal(options) {
527
528 if ( isString(options) || isNode(options) ) {
529 options = { content: options };
530 }
531
532 var afterCreateEvent = observable();
533 var beforeShowEvent = observable();
534 var afterShowEvent = observable();
535 var beforeCloseEvent = observable();
536 var afterCloseEvent = observable();
537
538 /**
539 * Returns a named option if it has been explicitly defined. Otherwise,
540 * it returns the given default value
541 */
542 function getOption ( opt, defaultValue ) {
543 var value = options[opt];
544 if ( typeof value === "function" ) {
545 value = value( defaultValue );
546 }
547 return value === undefined ? defaultValue : value;
548 }
549
550 /** Hides this modal */
551 function forceClose () {
552 shadowElem().hide();
553 modalElem().hide();
554 afterCloseEvent.trigger(iface);
555 }
556
557 /** Gracefully hides this modal */
558 function close () {
559 if ( beforeCloseEvent.trigger(iface) ) {
560 forceClose();
561 }
562 }
563
564 /** Wraps a method so it returns the modal interface */
565 function returnIface ( callback ) {
566 return function () {
567 callback.apply(this, arguments);
568 return iface;
569 };
570 }
571
572
573 // The constructed dom nodes
574 var built;
575
576 /** Builds a method that calls a method and returns an element */
577 function build ( name ) {
578 if ( !built ) {
579 var modal = buildModal(getOption, close);
580 built = {
581 modal: modal,
582 overlay: buildOverlay(getOption, close),
583 close: buildClose(modal, getOption)
584 };
585 afterCreateEvent.trigger(iface);
586 }
587 return built[name];
588 }
589
590 var modalElem = build.bind(window, 'modal');
591 var shadowElem = build.bind(window, 'overlay');
592 var closeElem = build.bind(window, 'close');
593
594
595 var iface = {
596
597 /** Returns the wrapping modal element */
598 modalElem: buildElemAccessor(modalElem),
599
600 /** Returns the close button element */
601 closeElem: buildElemAccessor(closeElem),
602
603 /** Returns the overlay element */
604 overlayElem: buildElemAccessor(shadowElem),
605
606 /** Shows this modal */
607 show: function () {
608 if ( beforeShowEvent.trigger(iface) ) {
609 shadowElem().show();
610 closeElem();
611 modalElem().show();
612 afterShowEvent.trigger(iface);
613 }
614 return this;
615 },
616
617 /** Hides this modal */
618 close: returnIface(close),
619
620 /**
621 * Force closes this modal. This will not call beforeClose
622 * events and will just immediately hide the modal
623 */
624 forceClose: returnIface(forceClose),
625
626 /** Destroys this modal */
627 destroy: function () {
628 modalElem = modalElem().destroy();
629 shadowElem = shadowElem().destroy();
630 closeElem = undefined;
631 },
632
633 /**
634 * Updates the options for this modal. This will only let you
635 * change options that are re-evaluted regularly, such as
636 * `overlayClose`.
637 */
638 options: function ( opts ) {
639 options = opts;
640 },
641
642 /** Executes after the DOM nodes are created */
643 afterCreate: returnIface(afterCreateEvent.watch),
644
645 /** Executes a callback before this modal is closed */
646 beforeShow: returnIface(beforeShowEvent.watch),
647
648 /** Executes a callback after this modal is shown */
649 afterShow: returnIface(afterShowEvent.watch),
650
651 /** Executes a callback before this modal is closed */
652 beforeClose: returnIface(beforeCloseEvent.watch),
653
654 /** Executes a callback after this modal is closed */
655 afterClose: returnIface(afterCloseEvent.watch)
656 };
657
658 return iface;
659 }
660
661 if ( typeof window.define === "function" && window.define.amd ) {
662 window.define(function () {
663 return picoModal;
664 });
665 }
666 else {
667 window.picoModal = picoModal;
668 }
669
670}(window, document));
671
672// jscs:enable
673// jshint ignore:end
diff --git a/sources/samples/old/ajax.html b/sources/samples/old/ajax.html
new file mode 100644
index 0000000..852a086
--- /dev/null
+++ b/sources/samples/old/ajax.html
@@ -0,0 +1,85 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Ajax &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12 <script>
13
14 var editor, html = '';
15
16 function createEditor() {
17 if ( editor )
18 return;
19
20 // Create a new editor inside the <div id="editor">, setting its value to html
21 var config = {};
22 editor = CKEDITOR.appendTo( 'editor', config, html );
23 }
24
25 function removeEditor() {
26 if ( !editor )
27 return;
28
29 // Retrieve the editor contents. In an Ajax application, this data would be
30 // sent to the server or used in any other way.
31 document.getElementById( 'editorcontents' ).innerHTML = html = editor.getData();
32 document.getElementById( 'contents' ).style.display = '';
33
34 // Destroy the editor.
35 editor.destroy();
36 editor = null;
37 }
38
39 </script>
40</head>
41<body>
42 <h1 class="samples">
43 <a href="index.html">CKEditor Samples</a> &raquo; Create and Destroy Editor Instances for Ajax Applications
44 </h1>
45 <div class="warning deprecated">
46 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/saveajax.html">brand new version in CKEditor SDK</a>.
47 </div>
48 <div class="description">
49 <p>
50 This sample shows how to create and destroy CKEditor instances on the fly. After the removal of CKEditor the content created inside the editing
51 area will be displayed in a <code>&lt;div&gt;</code> element.
52 </p>
53 <p>
54 For details of how to create this setup check the source code of this sample page
55 for JavaScript code responsible for the creation and destruction of a CKEditor instance.
56 </p>
57 </div>
58 <p>Click the buttons to create and remove a CKEditor instance.</p>
59 <p>
60 <input onclick="createEditor();" type="button" value="Create Editor">
61 <input onclick="removeEditor();" type="button" value="Remove Editor">
62 </p>
63 <!-- This div will hold the editor. -->
64 <div id="editor">
65 </div>
66 <div id="contents" style="display: none">
67 <p>
68 Edited Contents:
69 </p>
70 <!-- This div will be used to display the editor contents. -->
71 <div id="editorcontents">
72 </div>
73 </div>
74 <div id="footer">
75 <hr>
76 <p>
77 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
78 </p>
79 <p id="copy">
80 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
81 Knabben. All rights reserved.
82 </p>
83 </div>
84</body>
85</html>
diff --git a/sources/samples/old/api.html b/sources/samples/old/api.html
new file mode 100644
index 0000000..682a719
--- /dev/null
+++ b/sources/samples/old/api.html
@@ -0,0 +1,210 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>API Usage &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12 <script>
13
14// The instanceReady event is fired, when an instance of CKEditor has finished
15// its initialization.
16CKEDITOR.on( 'instanceReady', function( ev ) {
17 // Show the editor name and description in the browser status bar.
18 document.getElementById( 'eMessage' ).innerHTML = 'Instance <code>' + ev.editor.name + '<\/code> loaded.';
19
20 // Show this sample buttons.
21 document.getElementById( 'eButtons' ).style.display = 'block';
22});
23
24function InsertHTML() {
25 // Get the editor instance that we want to interact with.
26 var editor = CKEDITOR.instances.editor1;
27 var value = document.getElementById( 'htmlArea' ).value;
28
29 // Check the active editing mode.
30 if ( editor.mode == 'wysiwyg' )
31 {
32 // Insert HTML code.
33 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertHtml
34 editor.insertHtml( value );
35 }
36 else
37 alert( 'You must be in WYSIWYG mode!' );
38}
39
40function InsertText() {
41 // Get the editor instance that we want to interact with.
42 var editor = CKEDITOR.instances.editor1;
43 var value = document.getElementById( 'txtArea' ).value;
44
45 // Check the active editing mode.
46 if ( editor.mode == 'wysiwyg' )
47 {
48 // Insert as plain text.
49 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertText
50 editor.insertText( value );
51 }
52 else
53 alert( 'You must be in WYSIWYG mode!' );
54}
55
56function SetContents() {
57 // Get the editor instance that we want to interact with.
58 var editor = CKEDITOR.instances.editor1;
59 var value = document.getElementById( 'htmlArea' ).value;
60
61 // Set editor contents (replace current contents).
62 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setData
63 editor.setData( value );
64}
65
66function GetContents() {
67 // Get the editor instance that you want to interact with.
68 var editor = CKEDITOR.instances.editor1;
69
70 // Get editor contents
71 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getData
72 alert( editor.getData() );
73}
74
75function ExecuteCommand( commandName ) {
76 // Get the editor instance that we want to interact with.
77 var editor = CKEDITOR.instances.editor1;
78
79 // Check the active editing mode.
80 if ( editor.mode == 'wysiwyg' )
81 {
82 // Execute the command.
83 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-execCommand
84 editor.execCommand( commandName );
85 }
86 else
87 alert( 'You must be in WYSIWYG mode!' );
88}
89
90function CheckDirty() {
91 // Get the editor instance that we want to interact with.
92 var editor = CKEDITOR.instances.editor1;
93 // Checks whether the current editor contents present changes when compared
94 // to the contents loaded into the editor at startup
95 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-checkDirty
96 alert( editor.checkDirty() );
97}
98
99function ResetDirty() {
100 // Get the editor instance that we want to interact with.
101 var editor = CKEDITOR.instances.editor1;
102 // Resets the "dirty state" of the editor (see CheckDirty())
103 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-resetDirty
104 editor.resetDirty();
105 alert( 'The "IsDirty" status has been reset' );
106}
107
108function Focus() {
109 CKEDITOR.instances.editor1.focus();
110}
111
112function onFocus() {
113 document.getElementById( 'eMessage' ).innerHTML = '<b>' + this.name + ' is focused </b>';
114}
115
116function onBlur() {
117 document.getElementById( 'eMessage' ).innerHTML = this.name + ' lost focus';
118}
119
120 </script>
121
122</head>
123<body>
124 <h1 class="samples">
125 <a href="index.html">CKEditor Samples</a> &raquo; Using CKEditor JavaScript API
126 </h1>
127 <div class="warning deprecated">
128 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/api.html">brand new version in CKEditor SDK</a>.
129 </div>
130 <div class="description">
131 <p>
132 This sample shows how to use the
133 <a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.editor">CKEditor JavaScript API</a>
134 to interact with the editor at runtime.
135 </p>
136 <p>
137 For details on how to create this setup check the source code of this sample page.
138 </p>
139 </div>
140
141 <!-- This <div> holds alert messages to be display in the sample page. -->
142 <div id="alerts">
143 <noscript>
144 <p>
145 <strong>CKEditor requires JavaScript to run</strong>. In a browser with no JavaScript
146 support, like yours, you should still see the contents (HTML data) and you should
147 be able to edit it normally, without a rich editor interface.
148 </p>
149 </noscript>
150 </div>
151 <form action="../../../samples/sample_posteddata.php" method="post">
152 <textarea cols="100" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
153
154 <script>
155 // Replace the <textarea id="editor1"> with an CKEditor instance.
156 CKEDITOR.replace( 'editor1', {
157 on: {
158 focus: onFocus,
159 blur: onBlur,
160
161 // Check for availability of corresponding plugins.
162 pluginsLoaded: function( evt ) {
163 var doc = CKEDITOR.document, ed = evt.editor;
164 if ( !ed.getCommand( 'bold' ) )
165 doc.getById( 'exec-bold' ).hide();
166 if ( !ed.getCommand( 'link' ) )
167 doc.getById( 'exec-link' ).hide();
168 }
169 }
170 });
171 </script>
172
173 <p id="eMessage">
174 </p>
175
176 <div id="eButtons" style="display: none">
177 <input id="exec-bold" onclick="ExecuteCommand('bold');" type="button" value="Execute &quot;bold&quot; Command">
178 <input id="exec-link" onclick="ExecuteCommand('link');" type="button" value="Execute &quot;link&quot; Command">
179 <input onclick="Focus();" type="button" value="Focus">
180 <br><br>
181 <input onclick="InsertHTML();" type="button" value="Insert HTML">
182 <input onclick="SetContents();" type="button" value="Set Editor Contents">
183 <input onclick="GetContents();" type="button" value="Get Editor Contents (HTML)">
184 <br>
185 <textarea cols="100" id="htmlArea" rows="3">&lt;h2&gt;Test&lt;/h2&gt;&lt;p&gt;This is some &lt;a href="/Test1.html"&gt;sample&lt;/a&gt; HTML code.&lt;/p&gt;</textarea>
186 <br>
187 <br>
188 <input onclick="InsertText();" type="button" value="Insert Text">
189 <br>
190 <textarea cols="100" id="txtArea" rows="3"> First line with some leading whitespaces.
191
192Second line of text preceded by two line breaks.</textarea>
193 <br>
194 <br>
195 <input onclick="CheckDirty();" type="button" value="checkDirty()">
196 <input onclick="ResetDirty();" type="button" value="resetDirty()">
197 </div>
198 </form>
199 <div id="footer">
200 <hr>
201 <p>
202 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
203 </p>
204 <p id="copy">
205 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
206 Knabben. All rights reserved.
207 </p>
208 </div>
209</body>
210</html>
diff --git a/sources/samples/old/appendto.html b/sources/samples/old/appendto.html
new file mode 100644
index 0000000..a984704
--- /dev/null
+++ b/sources/samples/old/appendto.html
@@ -0,0 +1,59 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Append To Page Element Using JavaScript Code &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12</head>
13<body>
14 <h1 class="samples">
15 <a href="index.html">CKEditor Samples</a> &raquo; Append To Page Element Using JavaScript Code
16 </h1>
17 <div class="warning deprecated">
18 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
19 </div>
20 <div id="section1">
21 <div class="description">
22 <p>
23 The <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR-method-appendTo">CKEDITOR.appendTo()</a></code> method serves to to place editors inside existing DOM elements. Unlike <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR-method-replace">CKEDITOR.replace()</a></code>,
24 a target container to be replaced is no longer necessary. A new editor
25 instance is inserted directly wherever it is desired.
26 </p>
27<pre class="samples">CKEDITOR.appendTo( '<em>container_id</em>',
28 { /* Configuration options to be used. */ }
29 'Editor content to be used.'
30);</pre>
31 </div>
32 <script>
33
34 // This call can be placed at any point after the
35 // DOM element to append CKEditor to or inside the <head><script>
36 // in a window.onload event handler.
37
38 // Append a CKEditor instance using the default configuration and the
39 // provided content to the <div> element of ID "section1".
40 CKEDITOR.appendTo( 'section1',
41 null,
42 '<p>This is some <strong>sample text</strong>. You are using <a href="http://ckeditor.com/">CKEditor</a>.</p>'
43 );
44
45 </script>
46 </div>
47 <br>
48 <div id="footer">
49 <hr>
50 <p>
51 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
52 </p>
53 <p id="copy">
54 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
55 Knabben. All rights reserved.
56 </p>
57 </div>
58</body>
59</html>
diff --git a/sources/samples/old/assets/inlineall/logo.png b/sources/samples/old/assets/inlineall/logo.png
new file mode 100644
index 0000000..b4d5979
--- /dev/null
+++ b/sources/samples/old/assets/inlineall/logo.png
Binary files differ
diff --git a/sources/samples/old/assets/outputxhtml/outputxhtml.css b/sources/samples/old/assets/outputxhtml/outputxhtml.css
new file mode 100644
index 0000000..b81e1d7
--- /dev/null
+++ b/sources/samples/old/assets/outputxhtml/outputxhtml.css
@@ -0,0 +1,204 @@
1/*
2 * Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 *
5 * Styles used by the XHTML 1.1 sample page (xhtml.html).
6 */
7
8/**
9 * Basic definitions for the editing area.
10 */
11body
12{
13 font-family: Arial, Verdana, sans-serif;
14 font-size: 80%;
15 color: #000000;
16 background-color: #ffffff;
17 padding: 5px;
18 margin: 0px;
19}
20
21/**
22 * Core styles.
23 */
24
25.Bold
26{
27 font-weight: bold;
28}
29
30.Italic
31{
32 font-style: italic;
33}
34
35.Underline
36{
37 text-decoration: underline;
38}
39
40.StrikeThrough
41{
42 text-decoration: line-through;
43}
44
45.Subscript
46{
47 vertical-align: sub;
48 font-size: smaller;
49}
50
51.Superscript
52{
53 vertical-align: super;
54 font-size: smaller;
55}
56
57/**
58 * Font faces.
59 */
60
61.FontComic
62{
63 font-family: 'Comic Sans MS';
64}
65
66.FontCourier
67{
68 font-family: 'Courier New';
69}
70
71.FontTimes
72{
73 font-family: 'Times New Roman';
74}
75
76/**
77 * Font sizes.
78 */
79
80.FontSmaller
81{
82 font-size: smaller;
83}
84
85.FontLarger
86{
87 font-size: larger;
88}
89
90.FontSmall
91{
92 font-size: 8pt;
93}
94
95.FontBig
96{
97 font-size: 14pt;
98}
99
100.FontDouble
101{
102 font-size: 200%;
103}
104
105/**
106 * Font colors.
107 */
108.FontColor1
109{
110 color: #ff9900;
111}
112
113.FontColor2
114{
115 color: #0066cc;
116}
117
118.FontColor3
119{
120 color: #ff0000;
121}
122
123.FontColor1BG
124{
125 background-color: #ff9900;
126}
127
128.FontColor2BG
129{
130 background-color: #0066cc;
131}
132
133.FontColor3BG
134{
135 background-color: #ff0000;
136}
137
138/**
139 * Indentation.
140 */
141
142.Indent1
143{
144 margin-left: 40px;
145}
146
147.Indent2
148{
149 margin-left: 80px;
150}
151
152.Indent3
153{
154 margin-left: 120px;
155}
156
157/**
158 * Alignment.
159 */
160
161.JustifyLeft
162{
163 text-align: left;
164}
165
166.JustifyRight
167{
168 text-align: right;
169}
170
171.JustifyCenter
172{
173 text-align: center;
174}
175
176.JustifyFull
177{
178 text-align: justify;
179}
180
181/**
182 * Other.
183 */
184
185code
186{
187 font-family: courier, monospace;
188 background-color: #eeeeee;
189 padding-left: 1px;
190 padding-right: 1px;
191 border: #c0c0c0 1px solid;
192}
193
194kbd
195{
196 padding: 0px 1px 0px 1px;
197 border-width: 1px 2px 2px 1px;
198 border-style: solid;
199}
200
201blockquote
202{
203 color: #808080;
204}
diff --git a/sources/samples/old/assets/posteddata.php b/sources/samples/old/assets/posteddata.php
new file mode 100644
index 0000000..ca43cc9
--- /dev/null
+++ b/sources/samples/old/assets/posteddata.php
@@ -0,0 +1,59 @@
1<!DOCTYPE html>
2<?php
3/*
4Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
5For licensing, see LICENSE.md or http://ckeditor.com/license
6*/
7?>
8<html>
9<head>
10 <meta charset="utf-8">
11 <title>Sample &mdash; CKEditor</title>
12 <link rel="stylesheet" href="sample.css">
13</head>
14<body>
15 <h1 class="samples">
16 CKEditor &mdash; Posted Data
17 </h1>
18 <table border="1" cellspacing="0" id="outputSample">
19 <colgroup><col width="120"></colgroup>
20 <thead>
21 <tr>
22 <th>Field&nbsp;Name</th>
23 <th>Value</th>
24 </tr>
25 </thead>
26<?php
27
28if (!empty($_POST))
29{
30 foreach ( $_POST as $key => $value )
31 {
32 if ( ( !is_string($value) && !is_numeric($value) ) || !is_string($key) )
33 continue;
34
35 if ( get_magic_quotes_gpc() )
36 $value = htmlspecialchars( stripslashes((string)$value) );
37 else
38 $value = htmlspecialchars( (string)$value );
39?>
40 <tr>
41 <th style="vertical-align: top"><?php echo htmlspecialchars( (string)$key ); ?></th>
42 <td><pre class="samples"><?php echo $value; ?></pre></td>
43 </tr>
44 <?php
45 }
46}
47?>
48 </table>
49 <div id="footer">
50 <hr>
51 <p>
52 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
53 </p>
54 <p id="copy">
55 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico Knabben. All rights reserved.
56 </p>
57 </div>
58</body>
59</html>
diff --git a/sources/samples/old/assets/sample.jpg b/sources/samples/old/assets/sample.jpg
new file mode 100644
index 0000000..9498271
--- /dev/null
+++ b/sources/samples/old/assets/sample.jpg
Binary files differ
diff --git a/sources/samples/old/assets/uilanguages/languages.js b/sources/samples/old/assets/uilanguages/languages.js
new file mode 100644
index 0000000..df6b2dc
--- /dev/null
+++ b/sources/samples/old/assets/uilanguages/languages.js
@@ -0,0 +1,92 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/* exported CKEDITOR_LANGS */
7
8var CKEDITOR_LANGS = ( function() {
9 var langs = {
10 af: 'Afrikaans',
11 ar: 'Arabic',
12 az: 'Azerbaijani',
13 bg: 'Bulgarian',
14 bn: 'Bengali/Bangla',
15 bs: 'Bosnian',
16 ca: 'Catalan',
17 cs: 'Czech',
18 cy: 'Welsh',
19 da: 'Danish',
20 de: 'German',
21 'de-ch': 'German (Switzerland)',
22 el: 'Greek',
23 en: 'English',
24 'en-au': 'English (Australia)',
25 'en-ca': 'English (Canadian)',
26 'en-gb': 'English (United Kingdom)',
27 eo: 'Esperanto',
28 es: 'Spanish',
29 et: 'Estonian',
30 eu: 'Basque',
31 fa: 'Persian',
32 fi: 'Finnish',
33 fo: 'Faroese',
34 fr: 'French',
35 'fr-ca': 'French (Canada)',
36 gl: 'Galician',
37 gu: 'Gujarati',
38 he: 'Hebrew',
39 hi: 'Hindi',
40 hr: 'Croatian',
41 hu: 'Hungarian',
42 id: 'Indonesian',
43 is: 'Icelandic',
44 it: 'Italian',
45 ja: 'Japanese',
46 ka: 'Georgian',
47 km: 'Khmer',
48 ko: 'Korean',
49 ku: 'Kurdish',
50 lt: 'Lithuanian',
51 lv: 'Latvian',
52 mk: 'Macedonian',
53 mn: 'Mongolian',
54 ms: 'Malay',
55 nb: 'Norwegian Bokmal',
56 nl: 'Dutch',
57 no: 'Norwegian',
58 oc: 'Occitan',
59 pl: 'Polish',
60 pt: 'Portuguese (Portugal)',
61 'pt-br': 'Portuguese (Brazil)',
62 ro: 'Romanian',
63 ru: 'Russian',
64 si: 'Sinhala',
65 sk: 'Slovak',
66 sq: 'Albanian',
67 sl: 'Slovenian',
68 sr: 'Serbian (Cyrillic)',
69 'sr-latn': 'Serbian (Latin)',
70 sv: 'Swedish',
71 th: 'Thai',
72 tr: 'Turkish',
73 tt: 'Tatar',
74 ug: 'Uighur',
75 uk: 'Ukrainian',
76 vi: 'Vietnamese',
77 zh: 'Chinese Traditional',
78 'zh-cn': 'Chinese Simplified'
79 };
80
81 var langsArray = [];
82
83 for ( var code in CKEDITOR.lang.languages ) {
84 langsArray.push( { code: code, name: ( langs[ code ] || code ) } );
85 }
86
87 langsArray.sort( function( a, b ) {
88 return ( a.name < b.name ) ? -1 : 1;
89 } );
90
91 return langsArray;
92} )();
diff --git a/sources/samples/old/datafiltering.html b/sources/samples/old/datafiltering.html
new file mode 100644
index 0000000..dd78ba5
--- /dev/null
+++ b/sources/samples/old/datafiltering.html
@@ -0,0 +1,508 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Data Filtering &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12 <script>
13 // Remove advanced tabs for all editors.
14 CKEDITOR.config.removeDialogTabs = 'image:advanced;link:advanced;flash:advanced;creatediv:advanced;editdiv:advanced';
15 </script>
16</head>
17<body>
18 <h1 class="samples">
19 <a href="index.html">CKEditor Samples</a> &raquo; Data Filtering and Features Activation
20 </h1>
21 <div class="warning deprecated">
22 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/acf.html">brand new version in CKEditor SDK</a>.
23 </div>
24 <div class="description">
25 <p>
26 This sample page demonstrates the idea of Advanced Content Filter
27 (<abbr title="Advanced Content Filter">ACF</abbr>), a sophisticated
28 tool that takes control over what kind of data is accepted by the editor and what
29 kind of output is produced.
30 </p>
31 <h2>When and what is being filtered?</h2>
32 <p>
33 <abbr title="Advanced Content Filter">ACF</abbr> controls
34 <strong>every single source of data</strong> that comes to the editor.
35 It process both HTML that is inserted manually (i.e. pasted by the user)
36 and programmatically like:
37 </p>
38<pre class="samples">
39editor.setData( '&lt;p&gt;Hello world!&lt;/p&gt;' );
40</pre>
41 <p>
42 <abbr title="Advanced Content Filter">ACF</abbr> discards invalid,
43 useless HTML tags and attributes so the editor remains "clean" during
44 runtime. <abbr title="Advanced Content Filter">ACF</abbr> behaviour
45 can be configured and adjusted for a particular case to prevent the
46 output HTML (i.e. in CMS systems) from being polluted.
47
48 This kind of filtering is a first, client-side line of defense
49 against "<a href="http://en.wikipedia.org/wiki/Tag_soup">tag soups</a>",
50 the tool that precisely restricts which tags, attributes and styles
51 are allowed (desired). When properly configured, <abbr title="Advanced Content Filter">ACF</abbr>
52 is an easy and fast way to produce a high-quality, intentionally filtered HTML.
53 </p>
54
55 <h3>How to configure or disable ACF?</h3>
56 <p>
57 Advanced Content Filter is enabled by default, working in "automatic mode", yet
58 it provides a set of easy rules that allow adjusting filtering rules
59 and disabling the entire feature when necessary. The config property
60 responsible for this feature is <code><a class="samples"
61 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">config.allowedContent</a></code>.
62 </p>
63 <p>
64 By "automatic mode" is meant that loaded plugins decide which kind
65 of content is enabled and which is not. For example, if the link
66 plugin is loaded it implies that <code>&lt;a&gt;</code> tag is
67 automatically allowed. Each plugin is given a set
68 of predefined <abbr title="Advanced Content Filter">ACF</abbr> rules
69 that control the editor until <code><a class="samples"
70 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">
71 config.allowedContent</a></code>
72 is defined manually.
73 </p>
74 <p>
75 Let's assume our intention is to restrict the editor to accept (produce) <strong>paragraphs
76 only: no attributes, no styles, no other tags</strong>.
77 With <abbr title="Advanced Content Filter">ACF</abbr>
78 this is very simple. Basically set <code><a class="samples"
79 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">
80 config.allowedContent</a></code> to <code>'p'</code>:
81 </p>
82<pre class="samples">
83var editor = CKEDITOR.replace( <em>textarea_id</em>, {
84 <strong>allowedContent: 'p'</strong>
85} );
86</pre>
87 <p>
88 Now try to play with allowed content:
89 </p>
90<pre class="samples">
91// Trying to insert disallowed tag and attribute.
92editor.setData( '&lt;p <strong>style="color: red"</strong>&gt;Hello <strong>&lt;em&gt;world&lt;/em&gt;</strong>!&lt;/p&gt;' );
93alert( editor.getData() );
94
95// Filtered data is returned.
96"&lt;p&gt;Hello world!&lt;/p&gt;"
97</pre>
98 <p>
99 What happened? Since <code>config.allowedContent: 'p'</code> is set the editor assumes
100 that only plain <code>&lt;p&gt;</code> are accepted. Nothing more. This is why
101 <code>style</code> attribute and <code>&lt;em&gt;</code> tag are gone. The same
102 filtering would happen if we pasted disallowed HTML into this editor.
103 </p>
104 <p>
105 This is just a small sample of what <abbr title="Advanced Content Filter">ACF</abbr>
106 can do. To know more, please refer to the sample section below and
107 <a href="http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter">the official Advanced Content Filter guide</a>.
108 </p>
109 <p>
110 You may, of course, want CKEditor to avoid filtering of any kind.
111 To get rid of <abbr title="Advanced Content Filter">ACF</abbr>,
112 basically set <code><a class="samples"
113 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">
114 config.allowedContent</a></code> to <code>true</code> like this:
115 </p>
116<pre class="samples">
117CKEDITOR.replace( <em>textarea_id</em>, {
118 <strong>allowedContent: true</strong>
119} );
120</pre>
121
122 <h2>Beyond data flow: Features activation</h2>
123 <p>
124 <abbr title="Advanced Content Filter">ACF</abbr> is far more than
125 <abbr title="Input/Output">I/O</abbr> control: the entire
126 <abbr title="User Interface">UI</abbr> of the editor is adjusted to what
127 filters restrict. For example: if <code>&lt;a&gt;</code> tag is
128 <strong>disallowed</strong>
129 by <abbr title="Advanced Content Filter">ACF</abbr>,
130 then accordingly <code>link</code> command, toolbar button and link dialog
131 are also disabled. Editor is smart: it knows which features must be
132 removed from the interface to match filtering rules.
133 </p>
134 <p>
135 CKEditor can be far more specific. If <code>&lt;a&gt;</code> tag is
136 <strong>allowed</strong> by filtering rules to be used but it is restricted
137 to have only one attribute (<code>href</code>)
138 <code>config.allowedContent = 'a[!href]'</code>, then
139 "Target" tab of the link dialog is automatically disabled as <code>target</code>
140 attribute isn't included in <abbr title="Advanced Content Filter">ACF</abbr> rules
141 for <code>&lt;a&gt;</code>. This behaviour applies to dialog fields, context
142 menus and toolbar buttons.
143 </p>
144
145 <h2>Sample configurations</h2>
146 <p>
147 There are several editor instances below that present different
148 <abbr title="Advanced Content Filter">ACF</abbr> setups. <strong>All of them,
149 except the inline instance, share the same HTML content</strong> to visualize
150 how different filtering rules affect the same input data.
151 </p>
152 </div>
153
154 <div>
155 <label for="editor1">
156 Editor 1:
157 </label>
158 <div class="description">
159 <p>
160 This editor is using default configuration ("automatic mode"). It means that
161 <code><a class="samples"
162 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">
163 config.allowedContent</a></code> is defined by loaded plugins.
164 Each plugin extends filtering rules to make it's own associated content
165 available for the user.
166 </p>
167 </div>
168 <textarea cols="80" id="editor1" name="editor1" rows="10">
169 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
170 </textarea>
171
172 <script>
173
174 CKEDITOR.replace( 'editor1' );
175
176 </script>
177 </div>
178
179 <br>
180
181 <div>
182 <label for="editor2">
183 Editor 2:
184 </label>
185 <div class="description">
186 <p>
187 This editor is using a custom configuration for
188 <abbr title="Advanced Content Filter">ACF</abbr>:
189 </p>
190<pre class="samples">
191CKEDITOR.replace( 'editor2', {
192 allowedContent:
193 'h1 h2 h3 p blockquote strong em;' +
194 'a[!href];' +
195 'img(left,right)[!src,alt,width,height];' +
196 'table tr th td caption;' +
197 'span{!font-family};' +'
198 'span{!color};' +
199 'span(!marker);' +
200 'del ins'
201} );
202</pre>
203 <p>
204 The following rules may require additional explanation:
205 </p>
206 <ul>
207 <li>
208 <code>h1 h2 h3 p blockquote strong em</code> - These tags
209 are accepted by the editor. Any tag attributes will be discarded.
210 </li>
211 <li>
212 <code>a[!href]</code> - <code>href</code> attribute is obligatory
213 for <code>&lt;a&gt;</code> tag. Tags without this attribute
214 are disarded. No other attribute will be accepted.
215 </li>
216 <li>
217 <code>img(left,right)[!src,alt,width,height]</code> - <code>src</code>
218 attribute is obligatory for <code>&lt;img&gt;</code> tag.
219 <code>alt</code>, <code>width</code>, <code>height</code>
220 and <code>class</code> attributes are accepted but
221 <code>class</code> must be either <code>class="left"</code>
222 or <code>class="right"</code>
223 </li>
224 <li>
225 <code>table tr th td caption</code> - These tags
226 are accepted by the editor. Any tag attributes will be discarded.
227 </li>
228 <li>
229 <code>span{!font-family}</code>, <code>span{!color}</code>,
230 <code>span(!marker)</code> - <code>&lt;span&gt;</code> tags
231 will be accepted if either <code>font-family</code> or
232 <code>color</code> style is set or <code>class="marker"</code>
233 is present.
234 </li>
235 <li>
236 <code>del ins</code> - These tags
237 are accepted by the editor. Any tag attributes will be discarded.
238 </li>
239 </ul>
240 <p>
241 Please note that <strong><abbr title="User Interface">UI</abbr> of the
242 editor is different</strong>. It's a response to what happened to the filters.
243 Since <code>text-align</code> isn't allowed, the align toolbar is gone.
244 The same thing happened to subscript/superscript, strike, underline
245 (<code>&lt;u&gt;</code>, <code>&lt;sub&gt;</code>, <code>&lt;sup&gt;</code>
246 are disallowed by <code><a class="samples"
247 href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent">
248 config.allowedContent</a></code>) and many other buttons.
249 </p>
250 </div>
251 <textarea cols="80" id="editor2" name="editor2" rows="10">
252 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
253 </textarea>
254 <script>
255
256 CKEDITOR.replace( 'editor2', {
257 allowedContent:
258 'h1 h2 h3 p blockquote strong em;' +
259 'a[!href];' +
260 'img(left,right)[!src,alt,width,height];' +
261 'table tr th td caption;' +
262 'span{!font-family};' +
263 'span{!color};' +
264 'span(!marker);' +
265 'del ins'
266 } );
267
268 </script>
269 </div>
270
271 <br>
272
273 <div>
274 <label for="editor3">
275 Editor 3:
276 </label>
277 <div class="description">
278 <p>
279 This editor is using a custom configuration for
280 <abbr title="Advanced Content Filter">ACF</abbr>.
281 Note that filters can be configured as an object literal
282 as an alternative to a string-based definition.
283 </p>
284<pre class="samples">
285CKEDITOR.replace( 'editor3', {
286 allowedContent: {
287 'b i ul ol big small': true,
288 'h1 h2 h3 p blockquote li': {
289 styles: 'text-align'
290 },
291 a: { attributes: '!href,target' },
292 img: {
293 attributes: '!src,alt',
294 styles: 'width,height',
295 classes: 'left,right'
296 }
297 }
298} );
299</pre>
300 </div>
301 <textarea cols="80" id="editor3" name="editor3" rows="10">
302 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
303 </textarea>
304 <script>
305
306 CKEDITOR.replace( 'editor3', {
307 allowedContent: {
308 'b i ul ol big small': true,
309 'h1 h2 h3 p blockquote li': {
310 styles: 'text-align'
311 },
312 a: { attributes: '!href,target' },
313 img: {
314 attributes: '!src,alt',
315 styles: 'width,height',
316 classes: 'left,right'
317 }
318 }
319 } );
320
321 </script>
322 </div>
323
324 <br>
325
326 <div>
327 <label for="editor4">
328 Editor 4:
329 </label>
330 <div class="description">
331 <p>
332 This editor is using a custom set of plugins and buttons.
333 </p>
334<pre class="samples">
335CKEDITOR.replace( 'editor4', {
336 removePlugins: 'bidi,font,forms,flash,horizontalrule,iframe,justify,table,tabletools,smiley',
337 removeButtons: 'Anchor,Underline,Strike,Subscript,Superscript,Image',
338 format_tags: 'p;h1;h2;h3;pre;address'
339} );
340</pre>
341 <p>
342 As you can see, removing plugins and buttons implies filtering.
343 Several tags are not allowed in the editor because there's no
344 plugin/button that is responsible for creating and editing this
345 kind of content (for example: the image is missing because
346 of <code>removeButtons: 'Image'</code>). The conclusion is that
347 <abbr title="Advanced Content Filter">ACF</abbr> works "backwards"
348 as well: <strong>modifying <abbr title="User Interface">UI</abbr>
349 elements is changing allowed content rules</strong>.
350 </p>
351 </div>
352 <textarea cols="80" id="editor4" name="editor4" rows="10">
353 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
354 </textarea>
355 <script>
356
357 CKEDITOR.replace( 'editor4', {
358 removePlugins: 'bidi,div,font,forms,flash,horizontalrule,iframe,justify,table,tabletools,smiley',
359 removeButtons: 'Anchor,Underline,Strike,Subscript,Superscript,Image',
360 format_tags: 'p;h1;h2;h3;pre;address'
361 } );
362
363 </script>
364 </div>
365
366 <br>
367
368 <div>
369 <label for="editor5">
370 Editor 5:
371 </label>
372 <div class="description">
373 <p>
374 This editor is built on editable <code>&lt;h1&gt;</code> element.
375 <abbr title="Advanced Content Filter">ACF</abbr> takes care of
376 what can be included in <code>&lt;h1&gt;</code>. Note that there
377 are no block styles in Styles combo. Also why lists, indentation,
378 blockquote, div, form and other buttons are missing.
379 </p>
380 <p>
381 <abbr title="Advanced Content Filter">ACF</abbr> makes sure that
382 no disallowed tags will come to <code>&lt;h1&gt;</code> so the final
383 markup is valid. If the user tried to paste some invalid HTML
384 into this editor (let's say a list), it would be automatically
385 converted into plain text.
386 </p>
387 </div>
388 <h1 id="editor5" contenteditable="true">
389 <em>Apollo 11</em> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC.
390 </h1>
391 </div>
392
393 <br>
394
395 <div>
396 <label for="editor3">
397 Editor 6:
398 </label>
399 <div class="description">
400 <p>
401 This editor is using a custom configuration for <abbr title="Advanced Content Filter">ACF</abbr>.
402 It's using the <a href="http://docs.ckeditor.com/#!/guide/dev_disallowed_content" rel="noopener noreferrer" target="_blank">
403 Disallowed Content</a> property of the filter to eliminate all <code>title</code> attributes.
404 </p>
405
406<pre class="samples">
407CKEDITOR.replace( 'editor6', {
408 allowedContent: {
409 'b i ul ol big small': true,
410 'h1 h2 h3 p blockquote li': {
411 styles: 'text-align'
412 },
413 a: {attributes: '!href,target'},
414 img: {
415 attributes: '!src,alt',
416 styles: 'width,height',
417 classes: 'left,right'
418 }
419 },
420 disallowedContent: '*{title*}'
421} );
422</pre>
423 </div>
424 <textarea cols="80" id="editor6" name="editor6" rows="10">
425 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
426 </textarea>
427 <script>
428
429 CKEDITOR.replace( 'editor6', {
430 allowedContent: {
431 'b i ul ol big small': true,
432 'h1 h2 h3 p blockquote li': {
433 styles: 'text-align'
434 },
435 a: {attributes: '!href,target'},
436 img: {
437 attributes: '!src,alt',
438 styles: 'width,height',
439 classes: 'left,right'
440 }
441 },
442 disallowedContent: '*{title*}'
443 } );
444
445 </script>
446 </div>
447
448 <br>
449
450 <div>
451 <label for="editor7">
452 Editor 7:
453 </label>
454 <div class="description">
455 <p>
456 This editor is using a custom configuration for <abbr title="Advanced Content Filter">ACF</abbr>.
457 It's using the <a href="http://docs.ckeditor.com/#!/guide/dev_disallowed_content" rel="noopener noreferrer" target="_blank">
458 Disallowed Content</a> property of the filter to eliminate all <code>a</code> and <code>img</code> tags,
459 while allowing all other tags.
460 </p>
461<pre class="samples">
462CKEDITOR.replace( 'editor7', {
463 allowedContent: {
464 // Allow all content.
465 $1: {
466 elements: CKEDITOR.dtd,
467 attributes: true,
468 styles: true,
469 classes: true
470 }
471 },
472 disallowedContent: 'img a'
473} );
474</pre>
475 </div>
476 <textarea cols="80" id="editor7" name="editor7" rows="10">
477 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
478 </textarea>
479 <script>
480
481 CKEDITOR.replace( 'editor7', {
482 allowedContent: {
483 // allow all content
484 $1: {
485 elements: CKEDITOR.dtd,
486 attributes: true,
487 styles: true,
488 classes: true
489 }
490 },
491 disallowedContent: 'img a'
492 } );
493
494 </script>
495 </div>
496
497 <div id="footer">
498 <hr>
499 <p>
500 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
501 </p>
502 <p id="copy">
503 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
504 Knabben. All rights reserved.
505 </p>
506 </div>
507</body>
508</html>
diff --git a/sources/samples/old/divreplace.html b/sources/samples/old/divreplace.html
new file mode 100644
index 0000000..e882b22
--- /dev/null
+++ b/sources/samples/old/divreplace.html
@@ -0,0 +1,144 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Replace DIV &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12 <style>
13
14 div.editable
15 {
16 border: solid 2px transparent;
17 padding-left: 15px;
18 padding-right: 15px;
19 }
20
21 div.editable:hover
22 {
23 border-color: black;
24 }
25
26 </style>
27 <script>
28
29 // Uncomment the following code to test the "Timeout Loading Method".
30 // CKEDITOR.loadFullCoreTimeout = 5;
31
32 window.onload = function() {
33 // Listen to the double click event.
34 if ( window.addEventListener )
35 document.body.addEventListener( 'dblclick', onDoubleClick, false );
36 else if ( window.attachEvent )
37 document.body.attachEvent( 'ondblclick', onDoubleClick );
38
39 };
40
41 function onDoubleClick( ev ) {
42 // Get the element which fired the event. This is not necessarily the
43 // element to which the event has been attached.
44 var element = ev.target || ev.srcElement;
45
46 // Find out the div that holds this element.
47 var name;
48
49 do {
50 element = element.parentNode;
51 }
52 while ( element && ( name = element.nodeName.toLowerCase() ) &&
53 ( name != 'div' || element.className.indexOf( 'editable' ) == -1 ) && name != 'body' );
54
55 if ( name == 'div' && element.className.indexOf( 'editable' ) != -1 )
56 replaceDiv( element );
57 }
58
59 var editor;
60
61 function replaceDiv( div ) {
62 if ( editor )
63 editor.destroy();
64
65 editor = CKEDITOR.replace( div );
66 }
67
68 </script>
69</head>
70<body>
71 <h1 class="samples">
72 <a href="index.html">CKEditor Samples</a> &raquo; Replace DIV with CKEditor on the Fly
73 </h1>
74 <div class="warning deprecated">
75 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
76 </div>
77 <div class="description">
78 <p>
79 This sample shows how to automatically replace <code>&lt;div&gt;</code> elements
80 with a CKEditor instance on the fly, following user's doubleclick. The content
81 that was previously placed inside the <code>&lt;div&gt;</code> element will now
82 be moved into CKEditor editing area.
83 </p>
84 <p>
85 For details on how to create this setup check the source code of this sample page.
86 </p>
87 </div>
88 <p>
89 Double-click any of the following <code>&lt;div&gt;</code> elements to transform them into
90 editor instances.
91 </p>
92 <div class="editable">
93 <h3>
94 Part 1
95 </h3>
96 <p>
97 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi
98 semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna
99 rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla
100 nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce
101 eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus.
102 </p>
103 </div>
104 <div class="editable">
105 <h3>
106 Part 2
107 </h3>
108 <p>
109 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi
110 semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna
111 rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla
112 nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce
113 eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus.
114 </p>
115 <p>
116 Donec velit. Mauris massa. Vestibulum non nulla. Nam suscipit arcu nec elit. Phasellus
117 sollicitudin iaculis ante. Ut non mauris et sapien tincidunt adipiscing. Vestibulum
118 vitae leo. Suspendisse nec mi tristique nulla laoreet vulputate.
119 </p>
120 </div>
121 <div class="editable">
122 <h3>
123 Part 3
124 </h3>
125 <p>
126 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi
127 semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna
128 rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla
129 nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce
130 eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus.
131 </p>
132 </div>
133 <div id="footer">
134 <hr>
135 <p>
136 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
137 </p>
138 <p id="copy">
139 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
140 Knabben. All rights reserved.
141 </p>
142 </div>
143</body>
144</html>
diff --git a/sources/samples/old/index.html b/sources/samples/old/index.html
new file mode 100644
index 0000000..999d110
--- /dev/null
+++ b/sources/samples/old/index.html
@@ -0,0 +1,111 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>CKEditor Samples</title>
10 <link rel="stylesheet" href="sample.css">
11</head>
12<body>
13 <h1 class="samples">
14 CKEditor Samples
15 </h1>
16 <div class="warning deprecated">
17 These samples are not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
18 </div>
19 <div class="twoColumns">
20 <div class="twoColumnsLeft">
21 <h2 class="samples">
22 Basic Samples
23 </h2>
24 <dl class="samples">
25 <dt><a class="samples" href="replacebyclass.html">Replace textarea elements by class name</a></dt>
26 <dd>Automatic replacement of all textarea elements of a given class with a CKEditor instance.</dd>
27
28 <dt><a class="samples" href="replacebycode.html">Replace textarea elements by code</a></dt>
29 <dd>Replacement of textarea elements with CKEditor instances by using a JavaScript call.</dd>
30
31 <dt><a class="samples" href="jquery.html">Create editors with jQuery</a></dt>
32 <dd>Creating standard and inline CKEditor instances with jQuery adapter.</dd>
33 </dl>
34
35 <h2 class="samples">
36 Basic Customization
37 </h2>
38 <dl class="samples">
39 <dt><a class="samples" href="uicolor.html">User Interface color</a></dt>
40 <dd>Changing CKEditor User Interface color and adding a toolbar button that lets the user set the UI color.</dd>
41
42 <dt><a class="samples" href="uilanguages.html">User Interface languages</a></dt>
43 <dd>Changing CKEditor User Interface language and adding a drop-down list that lets the user choose the UI language.</dd>
44 </dl>
45
46
47
48 <!-- PLUGINS_SAMPLES -->
49 </div>
50 <div class="twoColumnsRight">
51 <h2 class="samples">
52 Inline Editing
53 </h2>
54 <dl class="samples">
55 <dt><a class="samples" href="inlineall.html">Massive inline editor creation</a></dt>
56 <dd>Turn all elements with <code>contentEditable = true</code> attribute into inline editors.</dd>
57
58 <dt><a class="samples" href="inlinebycode.html">Convert element into an inline editor by code</a></dt>
59 <dd>Conversion of DOM elements into inline CKEditor instances by using a JavaScript call.</dd>
60
61 <dt><a class="samples" href="inlinetextarea.html">Replace textarea with inline editor</a> <span class="new">New!</span></dt>
62 <dd>A form with a textarea that is replaced by an inline editor at runtime.</dd>
63
64 <!-- INLINE_EDITING_SAMPLES -->
65 </dl>
66
67 <h2 class="samples">
68 Advanced Samples
69 </h2>
70 <dl class="samples">
71 <dt><a class="samples" href="datafiltering.html">Data filtering and features activation</a> <span class="new">New!</span></dt>
72 <dd>Data filtering and automatic features activation basing on configuration.</dd>
73
74 <dt><a class="samples" href="divreplace.html">Replace DIV elements on the fly</a></dt>
75 <dd>Transforming a <code>div</code> element into an instance of CKEditor with a mouse click.</dd>
76
77 <dt><a class="samples" href="appendto.html">Append editor instances</a></dt>
78 <dd>Appending editor instances to existing DOM elements.</dd>
79
80 <dt><a class="samples" href="ajax.html">Create and destroy editor instances for Ajax applications</a></dt>
81 <dd>Creating and destroying CKEditor instances on the fly and saving the contents entered into the editor window.</dd>
82
83 <dt><a class="samples" href="api.html">Basic usage of the API</a></dt>
84 <dd>Using the CKEditor JavaScript API to interact with the editor at runtime.</dd>
85
86 <dt><a class="samples" href="xhtmlstyle.html">XHTML-compliant style</a></dt>
87 <dd>Configuring CKEditor to produce XHTML 1.1 compliant attributes and styles.</dd>
88
89 <dt><a class="samples" href="readonly.html">Read-only mode</a></dt>
90 <dd>Using the readOnly API to block introducing changes to the editor contents.</dd>
91
92 <dt><a class="samples" href="tabindex.html">"Tab" key-based navigation</a></dt>
93 <dd>Navigating among editor instances with tab key.</dd>
94
95
96
97 <!-- ADVANCED_SAMPLES -->
98 </dl>
99 </div>
100 </div>
101 <div id="footer">
102 <hr>
103 <p>
104 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
105 </p>
106 <p id="copy">
107 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico Knabben. All rights reserved.
108 </p>
109 </div>
110</body>
111</html>
diff --git a/sources/samples/old/inlineall.html b/sources/samples/old/inlineall.html
new file mode 100644
index 0000000..8220ea5
--- /dev/null
+++ b/sources/samples/old/inlineall.html
@@ -0,0 +1,314 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Massive inline editing &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <script>
12
13 // This code is generally not necessary, but it is here to demonstrate
14 // how to customize specific editor instances on the fly. This fits well
15 // this demo because we have editable elements (like headers) that
16 // require less features.
17
18 // The "instanceCreated" event is fired for every editor instance created.
19 CKEDITOR.on( 'instanceCreated', function( event ) {
20 var editor = event.editor,
21 element = editor.element;
22
23 // Customize editors for headers and tag list.
24 // These editors don't need features like smileys, templates, iframes etc.
25 if ( element.is( 'h1', 'h2', 'h3' ) || element.getAttribute( 'id' ) == 'taglist' ) {
26 // Customize the editor configurations on "configLoaded" event,
27 // which is fired after the configuration file loading and
28 // execution. This makes it possible to change the
29 // configurations before the editor initialization takes place.
30 editor.on( 'configLoaded', function() {
31
32 // Remove unnecessary plugins to make the editor simpler.
33 editor.config.removePlugins = 'colorbutton,find,flash,font,' +
34 'forms,iframe,image,newpage,removeformat,' +
35 'smiley,specialchar,stylescombo,templates';
36
37 // Rearrange the layout of the toolbar.
38 editor.config.toolbarGroups = [
39 { name: 'editing', groups: [ 'basicstyles', 'links' ] },
40 { name: 'undo' },
41 { name: 'clipboard', groups: [ 'selection', 'clipboard' ] },
42 { name: 'about' }
43 ];
44 });
45 }
46 });
47
48 </script>
49 <link href="sample.css" rel="stylesheet">
50 <style>
51
52 /* The following styles are just to make the page look nice. */
53
54 /* Workaround to show Arial Black in Firefox. */
55 @font-face
56 {
57 font-family: 'arial-black';
58 src: local('Arial Black');
59 }
60
61 *[contenteditable="true"]
62 {
63 padding: 10px;
64 }
65
66 #container
67 {
68 width: 960px;
69 margin: 30px auto 0;
70 }
71
72 #header
73 {
74 overflow: hidden;
75 padding: 0 0 30px;
76 border-bottom: 5px solid #05B2D2;
77 position: relative;
78 }
79
80 #headerLeft,
81 #headerRight
82 {
83 width: 49%;
84 overflow: hidden;
85 }
86
87 #headerLeft
88 {
89 float: left;
90 padding: 10px 1px 1px;
91 }
92
93 #headerLeft h2,
94 #headerLeft h3
95 {
96 text-align: right;
97 margin: 0;
98 overflow: hidden;
99 font-weight: normal;
100 }
101
102 #headerLeft h2
103 {
104 font-family: "Arial Black",arial-black;
105 font-size: 4.6em;
106 line-height: 1.1;
107 text-transform: uppercase;
108 }
109
110 #headerLeft h3
111 {
112 font-size: 2.3em;
113 line-height: 1.1;
114 margin: .2em 0 0;
115 color: #666;
116 }
117
118 #headerRight
119 {
120 float: right;
121 padding: 1px;
122 }
123
124 #headerRight p
125 {
126 line-height: 1.8;
127 text-align: justify;
128 margin: 0;
129 }
130
131 #headerRight p + p
132 {
133 margin-top: 20px;
134 }
135
136 #headerRight > div
137 {
138 padding: 20px;
139 margin: 0 0 0 30px;
140 font-size: 1.4em;
141 color: #666;
142 }
143
144 #columns
145 {
146 color: #333;
147 overflow: hidden;
148 padding: 20px 0;
149 }
150
151 #columns > div
152 {
153 float: left;
154 width: 33.3%;
155 }
156
157 #columns #column1 > div
158 {
159 margin-left: 1px;
160 }
161
162 #columns #column3 > div
163 {
164 margin-right: 1px;
165 }
166
167 #columns > div > div
168 {
169 margin: 0px 10px;
170 padding: 10px 20px;
171 }
172
173 #columns blockquote
174 {
175 margin-left: 15px;
176 }
177
178 #tagLine
179 {
180 border-top: 5px solid #05B2D2;
181 padding-top: 20px;
182 }
183
184 #taglist {
185 display: inline-block;
186 margin-left: 20px;
187 font-weight: bold;
188 margin: 0 0 0 20px;
189 }
190
191 </style>
192</head>
193<body>
194<div>
195 <h1 class="samples"><a href="index.html">CKEditor Samples</a> &raquo; Massive inline editing</h1>
196 <div class="warning deprecated">
197 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/inline.html">brand new version in CKEditor SDK</a>.
198 </div>
199 <div class="description">
200 <p>This sample page demonstrates the inline editing feature - CKEditor instances will be created automatically from page elements with <strong>contentEditable</strong> attribute set to value <strong>true</strong>:</p>
201 <pre class="samples">&lt;div <strong>contenteditable="true</strong>" &gt; ... &lt;/div&gt;</pre>
202 <p>Click inside of any element below to start editing.</p>
203 </div>
204</div>
205<div id="container">
206 <div id="header">
207 <div id="headerLeft">
208 <h2 id="sampleTitle" contenteditable="true">
209 CKEditor<br> Goes Inline!
210 </h2>
211 <h3 contenteditable="true">
212 Lorem ipsum dolor sit amet dolor duis blandit vestibulum faucibus a, tortor.
213 </h3>
214 </div>
215 <div id="headerRight">
216 <div contenteditable="true">
217 <p>
218 Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies.
219 </p>
220 <p>
221 Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim. Phasellus fermentum in, dolor. Pellentesque facilisis. Nulla imperdiet sit amet magna. Vestibulum dapibus, mauris nec malesuada fames ac.
222 </p>
223 </div>
224 </div>
225 </div>
226 <div id="columns">
227 <div id="column1">
228 <div contenteditable="true">
229 <h3>
230 Fusce vitae porttitor
231 </h3>
232 <p>
233 <strong>
234 Lorem ipsum dolor sit amet dolor. Duis blandit vestibulum faucibus a, tortor.
235 </strong>
236 </p>
237 <p>
238 Proin nunc justo felis mollis tincidunt, risus risus pede, posuere cubilia Curae, Nullam euismod, enim. Etiam nibh ultricies dolor ac dignissim erat volutpat. Vivamus fermentum <a href="http://ckeditor.com/">nisl nulla sem in</a> metus. Maecenas wisi. Donec nec erat volutpat.
239 </p>
240 <blockquote>
241 <p>
242 Fusce vitae porttitor a, euismod convallis nisl, blandit risus tortor, pretium.
243 Vehicula vitae, imperdiet vel, ornare enim vel sodales rutrum
244 </p>
245 </blockquote>
246 <blockquote>
247 <p>
248 Libero nunc, rhoncus ante ipsum non ipsum. Nunc eleifend pede turpis id sollicitudin fringilla. Phasellus ultrices, velit ac arcu.
249 </p>
250 </blockquote>
251 <p>Pellentesque nunc. Donec suscipit erat. Pellentesque habitant morbi tristique ullamcorper.</p>
252 <p><s>Mauris mattis feugiat lectus nec mauris. Nullam vitae ante.</s></p>
253 </div>
254 </div>
255 <div id="column2">
256 <div contenteditable="true">
257 <h3>
258 Integer condimentum sit amet
259 </h3>
260 <p>
261 <strong>Aenean nonummy a, mattis varius. Cras aliquet.</strong>
262 Praesent <a href="http://ckeditor.com/">magna non mattis ac, rhoncus nunc</a>, rhoncus eget, cursus pulvinar mollis.</p>
263 <p>Proin id nibh. Sed eu libero posuere sed, lectus. Phasellus dui gravida gravida feugiat mattis ac, felis.</p>
264 <p>Integer condimentum sit amet, tempor elit odio, a dolor non ante at sapien. Sed ac lectus. Nulla ligula quis eleifend mi, id leo velit pede cursus arcu id nulla ac lectus. Phasellus vestibulum. Nunc viverra enim quis diam.</p>
265 </div>
266 <div contenteditable="true">
267 <h3>
268 Praesent wisi accumsan sit amet nibh
269 </h3>
270 <p>Donec ullamcorper, risus tortor, pretium porttitor. Morbi quam quis lectus non leo.</p>
271 <p style="margin-left: 40px; ">Integer faucibus scelerisque. Proin faucibus at, aliquet vulputate, odio at eros. Fusce <a href="http://ckeditor.com/">gravida, erat vitae augue</a>. Fusce urna fringilla gravida.</p>
272 <p>In hac habitasse platea dictumst. Praesent wisi accumsan sit amet nibh. Maecenas orci luctus a, lacinia quam sem, posuere commodo, odio condimentum tempor, pede semper risus. Suspendisse pede. In hac habitasse platea dictumst. Nam sed laoreet sit amet erat. Integer.</p>
273 </div>
274 </div>
275 <div id="column3">
276 <div contenteditable="true">
277 <p>
278 <img src="assets/inlineall/logo.png" alt="CKEditor logo" style="float:left">
279 </p>
280 <p>Quisque justo neque, mattis sed, fermentum ultrices <strong>posuere cubilia Curae</strong>, Vestibulum elit metus, quis placerat ut, lectus. Ut sagittis, nunc libero, egestas consequat lobortis velit rutrum ut, faucibus turpis. Fusce porttitor, nulla quis turpis. Nullam laoreet vel, consectetuer tellus suscipit ultricies, hendrerit wisi. Donec odio nec velit ac nunc sit amet, accumsan cursus aliquet. Vestibulum ante sit amet sagittis mi.</p>
281 <h3>
282 Nullam laoreet vel consectetuer tellus suscipit
283 </h3>
284 <ul>
285 <li>Ut sagittis, nunc libero, egestas consequat lobortis velit rutrum ut, faucibus turpis.</li>
286 <li>Fusce porttitor, nulla quis turpis. Nullam laoreet vel, consectetuer tellus suscipit ultricies, hendrerit wisi.</li>
287 <li>Mauris eget tellus. Donec non felis. Nam eget dolor. Vestibulum enim. Donec.</li>
288 </ul>
289 <p>Quisque justo neque, mattis sed, <a href="http://ckeditor.com/">fermentum ultrices posuere cubilia</a> Curae, Vestibulum elit metus, quis placerat ut, lectus.</p>
290 <p>Nullam laoreet vel, consectetuer tellus suscipit ultricies, hendrerit wisi. Ut sagittis, nunc libero, egestas consequat lobortis velit rutrum ut, faucibus turpis. Fusce porttitor, nulla quis turpis.</p>
291 <p>Donec odio nec velit ac nunc sit amet, accumsan cursus aliquet. Vestibulum ante sit amet sagittis mi. Sed in nonummy faucibus turpis. Mauris eget tellus. Donec non felis. Nam eget dolor. Vestibulum enim. Donec.</p>
292 </div>
293 </div>
294 </div>
295 <div id="tagLine">
296 Tags of this article:
297 <p id="taglist" contenteditable="true">
298 inline, editing, floating, CKEditor
299 </p>
300 </div>
301</div>
302<div id="footer">
303 <hr>
304 <p>
305 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">
306 http://ckeditor.com</a>
307 </p>
308 <p id="copy">
309 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a>
310 - Frederico Knabben. All rights reserved.
311 </p>
312</div>
313</body>
314</html>
diff --git a/sources/samples/old/inlinebycode.html b/sources/samples/old/inlinebycode.html
new file mode 100644
index 0000000..eea2723
--- /dev/null
+++ b/sources/samples/old/inlinebycode.html
@@ -0,0 +1,124 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Inline Editing by Code &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12 <style>
13
14 #editable
15 {
16 padding: 10px;
17 float: left;
18 }
19
20 </style>
21</head>
22<body>
23 <h1 class="samples">
24 <a href="index.html">CKEditor Samples</a> &raquo; Inline Editing by Code
25 </h1>
26 <div class="warning deprecated">
27 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/inline.html">brand new version in CKEditor SDK</a>.
28 </div>
29 <div class="description">
30 <p>
31 This sample shows how to create an inline editor instance of CKEditor. It is created
32 with a JavaScript call using the following code:
33 </p>
34<pre class="samples">
35// This property tells CKEditor to not activate every element with contenteditable=true element.
36CKEDITOR.disableAutoInline = true;
37
38var editor = CKEDITOR.inline( document.getElementById( 'editable' ) );
39</pre>
40 <p>
41 Note that <code>editable</code> in the code above is the <code>id</code>
42 attribute of the <code>&lt;div&gt;</code> element to be converted into an inline instance.
43 </p>
44 </div>
45 <div id="editable" contenteditable="true">
46 <h1><img alt="Saturn V carrying Apollo 11" class="right" src="assets/sample.jpg" /> Apollo 11</h1>
47
48 <p><b>Apollo 11</b> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p>
49
50 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
51
52 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
53
54 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
55
56 <blockquote>
57 <p>One small step for [a] man, one giant leap for mankind.</p>
58 </blockquote>
59
60 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
61
62 <blockquote>
63 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
64 </blockquote>
65
66 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
67
68 <table align="right" border="1" bordercolor="#ccc" cellpadding="5" cellspacing="0" style="border-collapse:collapse;margin:10px 0 10px 15px;">
69 <caption><strong>Mission crew</strong></caption>
70 <thead>
71 <tr>
72 <th scope="col">Position</th>
73 <th scope="col">Astronaut</th>
74 </tr>
75 </thead>
76 <tbody>
77 <tr>
78 <td>Commander</td>
79 <td>Neil A. Armstrong</td>
80 </tr>
81 <tr>
82 <td>Command Module Pilot</td>
83 <td>Michael Collins</td>
84 </tr>
85 <tr>
86 <td>Lunar Module Pilot</td>
87 <td>Edwin &quot;Buzz&quot; E. Aldrin, Jr.</td>
88 </tr>
89 </tbody>
90 </table>
91
92 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
93
94 <ol>
95 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
96 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
97 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
98 </ol>
99
100 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
101
102 <hr />
103 <p style="text-align: right;"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p>
104 </div>
105
106 <script>
107 // We need to turn off the automatic editor creation first.
108 CKEDITOR.disableAutoInline = true;
109
110 var editor = CKEDITOR.inline( 'editable' );
111 </script>
112 <div id="footer">
113 <hr>
114 <p contenteditable="true">
115 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">
116 http://ckeditor.com</a>
117 </p>
118 <p id="copy">
119 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a>
120 - Frederico Knabben. All rights reserved.
121 </p>
122 </div>
123</body>
124</html>
diff --git a/sources/samples/old/inlinetextarea.html b/sources/samples/old/inlinetextarea.html
new file mode 100644
index 0000000..57e664e
--- /dev/null
+++ b/sources/samples/old/inlinetextarea.html
@@ -0,0 +1,113 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Replace Textarea with Inline Editor &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12 <style>
13
14 /* Style the CKEditor element to look like a textfield */
15 .cke_textarea_inline
16 {
17 padding: 10px;
18 height: 200px;
19 overflow: auto;
20
21 border: 1px solid gray;
22 -webkit-appearance: textfield;
23 }
24
25 </style>
26</head>
27<body>
28 <h1 class="samples">
29 <a href="index.html">CKEditor Samples</a> &raquo; Replace Textarea with Inline Editor
30 </h1>
31 <div class="warning deprecated">
32 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/inline.html">brand new version in CKEditor SDK</a>.
33 </div>
34 <div class="description">
35 <p>
36 You can also create an inline editor from a <code>textarea</code>
37 element. In this case the <code>textarea</code> will be replaced
38 by a <code>div</code> element with inline editing enabled.
39 </p>
40<pre class="samples">
41// "article-body" is the name of a textarea element.
42var editor = CKEDITOR.inline( 'article-body' );
43</pre>
44 </div>
45 <form action="sample_posteddata.php" method="post">
46 <h2>This is a sample form with some fields</h2>
47 <p>
48 Title:<br>
49 <input type="text" name="title" value="Sample Form"></p>
50 <p>
51 Article Body (Textarea converted to CKEditor):<br>
52 <textarea name="article-body" style="height: 200px">
53 &lt;h2&gt;Technical details &lt;a id="tech-details" name="tech-details"&gt;&lt;/a&gt;&lt;/h2&gt;
54
55 &lt;table align="right" border="1" bordercolor="#ccc" cellpadding="5" cellspacing="0" style="border-collapse:collapse;margin:10px 0 10px 15px;"&gt;
56 &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt;
57 &lt;thead&gt;
58 &lt;tr&gt;
59 &lt;th scope="col"&gt;Position&lt;/th&gt;
60 &lt;th scope="col"&gt;Astronaut&lt;/th&gt;
61 &lt;/tr&gt;
62 &lt;/thead&gt;
63 &lt;tbody&gt;
64 &lt;tr&gt;
65 &lt;td&gt;Commander&lt;/td&gt;
66 &lt;td&gt;Neil A. Armstrong&lt;/td&gt;
67 &lt;/tr&gt;
68 &lt;tr&gt;
69 &lt;td&gt;Command Module Pilot&lt;/td&gt;
70 &lt;td&gt;Michael Collins&lt;/td&gt;
71 &lt;/tr&gt;
72 &lt;tr&gt;
73 &lt;td&gt;Lunar Module Pilot&lt;/td&gt;
74 &lt;td&gt;Edwin &quot;Buzz&quot; E. Aldrin, Jr.&lt;/td&gt;
75 &lt;/tr&gt;
76 &lt;/tbody&gt;
77 &lt;/table&gt;
78
79 &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center"&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href="http://en.wikipedia.org/wiki/NASA" title="NASA"&gt;NASA&lt;/a&gt;&#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt;
80
81 &lt;ol&gt;
82 &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt;
83 &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt;
84 &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt;
85 &lt;/ol&gt;
86
87 &lt;p&gt;After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis"&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean"&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt;
88
89 &lt;hr /&gt;
90 &lt;p style="text-align: right;"&gt;&lt;small&gt;Source: &lt;a href="http://en.wikipedia.org/wiki/Apollo_11"&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
91 </textarea>
92 </p>
93 <p>
94 <input type="submit" value="Submit">
95 </p>
96 </form>
97
98 <script>
99 CKEDITOR.inline( 'article-body' );
100 </script>
101 <div id="footer">
102 <hr>
103 <p>
104 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">
105 http://ckeditor.com</a>
106 </p>
107 <p id="copy">
108 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a>
109 - Frederico Knabben. All rights reserved.
110 </p>
111 </div>
112</body>
113</html>
diff --git a/sources/samples/old/jquery.html b/sources/samples/old/jquery.html
new file mode 100644
index 0000000..2f6d958
--- /dev/null
+++ b/sources/samples/old/jquery.html
@@ -0,0 +1,103 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>jQuery Adapter &mdash; CKEditor Sample</title>
10 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
11 <script src="../../ckeditor.js"></script>
12 <script src="../../adapters/jquery.js"></script>
13 <link href="sample.css" rel="stylesheet">
14 <style>
15
16 #editable
17 {
18 padding: 10px;
19 float: left;
20 }
21
22 </style>
23 <script>
24
25 CKEDITOR.disableAutoInline = true;
26
27 $( document ).ready( function() {
28 $( '#editor1' ).ckeditor(); // Use CKEDITOR.replace() if element is <textarea>.
29 $( '#editable' ).ckeditor(); // Use CKEDITOR.inline().
30 } );
31
32 function setValue() {
33 $( '#editor1' ).val( $( 'input#val' ).val() );
34 }
35
36 </script>
37</head>
38<body>
39 <h1 class="samples">
40 <a href="index.html" id="a-test">CKEditor Samples</a> &raquo; Create Editors with jQuery
41 </h1>
42 <div class="warning deprecated">
43 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
44 </div>
45 <form action="sample_posteddata.php" method="post">
46 <div class="description">
47 <p>
48 This sample shows how to use the <a href="http://docs.ckeditor.com/#!/guide/dev_jquery">jQuery adapter</a>.
49 Note that you have to include both CKEditor and jQuery scripts before including the adapter.
50 </p>
51
52<pre class="samples">
53&lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
54&lt;script src="/ckedit../../ckeditor.js"&gt;&lt;/script&gt;
55&lt;script src="/ckeditor/adapters/jquery.js"&gt;&lt;/script&gt;
56</pre>
57
58 <p>Then you can replace HTML elements with a CKEditor instance using the <code>ckeditor()</code> method.</p>
59
60<pre class="samples">
61$( document ).ready( function() {
62 $( 'textarea#editor1' ).ckeditor();
63} );
64</pre>
65 </div>
66
67 <h2 class="samples">Inline Example</h2>
68
69 <div id="editable" contenteditable="true">
70 <p><img alt="Saturn V carrying Apollo 11" class="right" src="assets/sample.jpg"/><b>Apollo 11</b> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p>
71 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.
72 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
73 <blockquote><p>One small step for [a] man, one giant leap for mankind.</p></blockquote> <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> <blockquote><p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p></blockquote>
74 </div>
75
76 <br style="clear: both">
77
78 <h2 class="samples">Classic (iframe-based) Example</h2>
79
80 <textarea cols="80" id="editor1" name="editor1" rows="10">
81 &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
82 </textarea>
83
84 <p style="overflow: hidden">
85 <input style="float: left" type="submit" value="Submit">
86 <span style="float: right">
87 <input type="text" id="val" value="I'm using jQuery val()!" size="30">
88 <input onclick="setValue();" type="button" value="Set value">
89 </span>
90 </p>
91 </form>
92 <div id="footer">
93 <hr>
94 <p>
95 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
96 </p>
97 <p id="copy">
98 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
99 Knabben. All rights reserved.
100 </p>
101 </div>
102</body>
103</html>
diff --git a/sources/samples/old/readonly.html b/sources/samples/old/readonly.html
new file mode 100644
index 0000000..084d6af
--- /dev/null
+++ b/sources/samples/old/readonly.html
@@ -0,0 +1,76 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Using the CKEditor Read-Only API &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12 <script>
13
14 var editor;
15
16 // The instanceReady event is fired, when an instance of CKEditor has finished
17 // its initialization.
18 CKEDITOR.on( 'instanceReady', function( ev ) {
19 editor = ev.editor;
20
21 // Show this "on" button.
22 document.getElementById( 'readOnlyOn' ).style.display = '';
23
24 // Event fired when the readOnly property changes.
25 editor.on( 'readOnly', function() {
26 document.getElementById( 'readOnlyOn' ).style.display = this.readOnly ? 'none' : '';
27 document.getElementById( 'readOnlyOff' ).style.display = this.readOnly ? '' : 'none';
28 });
29 });
30
31 function toggleReadOnly( isReadOnly ) {
32 // Change the read-only state of the editor.
33 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setReadOnly
34 editor.setReadOnly( isReadOnly );
35 }
36
37 </script>
38</head>
39<body>
40 <h1 class="samples">
41 <a href="index.html">CKEditor Samples</a> &raquo; Using the CKEditor Read-Only API
42 </h1>
43 <div class="warning deprecated">
44 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/readonly.html">brand new version in CKEditor SDK</a>.
45 </div>
46 <div class="description">
47 <p>
48 This sample shows how to use the
49 <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setReadOnly">setReadOnly</a></code>
50 API to put editor into the read-only state that makes it impossible for users to change the editor contents.
51 </p>
52 <p>
53 For details on how to create this setup check the source code of this sample page.
54 </p>
55 </div>
56 <form action="sample_posteddata.php" method="post">
57 <p>
58 <textarea class="ckeditor" id="editor1" name="editor1" cols="100" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
59 </p>
60 <p>
61 <input id="readOnlyOn" onclick="toggleReadOnly();" type="button" value="Make it read-only" style="display:none">
62 <input id="readOnlyOff" onclick="toggleReadOnly( false );" type="button" value="Make it editable again" style="display:none">
63 </p>
64 </form>
65 <div id="footer">
66 <hr>
67 <p>
68 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
69 </p>
70 <p id="copy">
71 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
72 Knabben. All rights reserved.
73 </p>
74 </div>
75</body>
76</html>
diff --git a/sources/samples/old/replacebyclass.html b/sources/samples/old/replacebyclass.html
new file mode 100644
index 0000000..23652d6
--- /dev/null
+++ b/sources/samples/old/replacebyclass.html
@@ -0,0 +1,60 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Replace Textareas by Class Name &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12</head>
13<body>
14 <h1 class="samples">
15 <a href="index.html">CKEditor Samples</a> &raquo; Replace Textarea Elements by Class Name
16 </h1>
17 <div class="warning deprecated">
18 This sample is not maintained anymore. Check out the <a href="http://sdk.ckeditor.com/">brand new samples in CKEditor SDK</a>.
19 </div>
20 <div class="description">
21 <p>
22 This sample shows how to automatically replace all <code>&lt;textarea&gt;</code> elements
23 of a given class with a CKEditor instance.
24 </p>
25 <p>
26 To replace a <code>&lt;textarea&gt;</code> element, simply assign it the <code>ckeditor</code>
27 class, as in the code below:
28 </p>
29<pre class="samples">
30&lt;textarea <strong>class="ckeditor</strong>" name="editor1"&gt;&lt;/textarea&gt;
31</pre>
32 <p>
33 Note that other <code>&lt;textarea&gt;</code> attributes (like <code>id</code> or <code>name</code>) need to be adjusted to your document.
34 </p>
35 </div>
36 <form action="sample_posteddata.php" method="post">
37 <p>
38 <label for="editor1">
39 Editor 1:
40 </label>
41 <textarea class="ckeditor" cols="80" id="editor1" name="editor1" rows="10">
42 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
43 </textarea>
44 </p>
45 <p>
46 <input type="submit" value="Submit">
47 </p>
48 </form>
49 <div id="footer">
50 <hr>
51 <p>
52 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
53 </p>
54 <p id="copy">
55 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
56 Knabben. All rights reserved.
57 </p>
58 </div>
59</body>
60</html>
diff --git a/sources/samples/old/replacebycode.html b/sources/samples/old/replacebycode.html
new file mode 100644
index 0000000..a4f4395
--- /dev/null
+++ b/sources/samples/old/replacebycode.html
@@ -0,0 +1,59 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Replace Textarea by Code &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12</head>
13<body>
14 <h1 class="samples">
15 <a href="index.html">CKEditor Samples</a> &raquo; Replace Textarea Elements Using JavaScript Code
16 </h1>
17 <div class="warning deprecated">
18 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/classic.html">brand new version in CKEditor SDK</a>.
19 </div>
20 <form action="sample_posteddata.php" method="post">
21 <div class="description">
22 <p>
23 This editor is using an <code>&lt;iframe&gt;</code> element-based editing area, provided by the <strong>Wysiwygarea</strong> plugin.
24 </p>
25<pre class="samples">
26CKEDITOR.replace( '<em>textarea_id</em>' )
27</pre>
28 </div>
29 <textarea cols="80" id="editor1" name="editor1" rows="10">
30 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
31 </textarea>
32 <script>
33
34 // This call can be placed at any point after the
35 // <textarea>, or inside a <head><script> in a
36 // window.onload event handler.
37
38 // Replace the <textarea id="editor"> with an CKEditor
39 // instance, using default configurations.
40
41 CKEDITOR.replace( 'editor1' );
42
43 </script>
44 <p>
45 <input type="submit" value="Submit">
46 </p>
47 </form>
48 <div id="footer">
49 <hr>
50 <p>
51 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
52 </p>
53 <p id="copy">
54 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
55 Knabben. All rights reserved.
56 </p>
57 </div>
58</body>
59</html>
diff --git a/sources/samples/old/sample.css b/sources/samples/old/sample.css
new file mode 100644
index 0000000..3304111
--- /dev/null
+++ b/sources/samples/old/sample.css
@@ -0,0 +1,357 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6html, body, h1, h2, h3, h4, h5, h6, div, span, blockquote, p, address, form, fieldset, img, ul, ol, dl, dt, dd, li, hr, table, td, th, strong, em, sup, sub, dfn, ins, del, q, cite, var, samp, code, kbd, tt, pre
7{
8 line-height: 1.5;
9}
10
11body
12{
13 padding: 10px 30px;
14}
15
16input, textarea, select, option, optgroup, button, td, th
17{
18 font-size: 100%;
19}
20
21pre
22{
23 -moz-tab-size: 4;
24 tab-size: 4;
25}
26
27pre, code, kbd, samp, tt
28{
29 font-family: monospace,monospace;
30 font-size: 1em;
31}
32
33body {
34 width: 960px;
35 margin: 0 auto;
36}
37
38code
39{
40 background: #f3f3f3;
41 border: 1px solid #ddd;
42 padding: 1px 4px;
43 border-radius: 3px;
44}
45
46abbr
47{
48 border-bottom: 1px dotted #555;
49 cursor: pointer;
50}
51
52.new, .beta
53{
54 text-transform: uppercase;
55 font-size: 10px;
56 font-weight: bold;
57 padding: 1px 4px;
58 margin: 0 0 0 5px;
59 color: #fff;
60 float: right;
61 border-radius: 3px;
62}
63
64.new
65{
66 background: #FF7E00;
67 border: 1px solid #DA8028;
68 text-shadow: 0 1px 0 #C97626;
69
70 box-shadow: 0 2px 3px 0 #FFA54E inset;
71}
72
73.beta
74{
75 background: #18C0DF;
76 border: 1px solid #19AAD8;
77 text-shadow: 0 1px 0 #048CAD;
78 font-style: italic;
79
80 box-shadow: 0 2px 3px 0 #50D4FD inset;
81}
82
83h1.samples
84{
85 color: #0782C1;
86 font-size: 200%;
87 font-weight: normal;
88 margin: 0;
89 padding: 0;
90}
91
92h1.samples a
93{
94 color: #0782C1;
95 text-decoration: none;
96 border-bottom: 1px dotted #0782C1;
97}
98
99.samples a:hover
100{
101 border-bottom: 1px dotted #0782C1;
102}
103
104h2.samples
105{
106 color: #000000;
107 font-size: 130%;
108 margin: 15px 0 0 0;
109 padding: 0;
110}
111
112p, blockquote, address, form, pre, dl, h1.samples, h2.samples
113{
114 margin-bottom: 15px;
115}
116
117ul.samples
118{
119 margin-bottom: 15px;
120}
121
122.clear
123{
124 clear: both;
125}
126
127fieldset
128{
129 margin: 0;
130 padding: 10px;
131}
132
133body, input, textarea
134{
135 color: #333333;
136 font-family: Arial, Helvetica, sans-serif;
137}
138
139body
140{
141 font-size: 75%;
142}
143
144a.samples
145{
146 color: #189DE1;
147 text-decoration: none;
148}
149
150form
151{
152 margin: 0;
153 padding: 0;
154}
155
156pre.samples
157{
158 background-color: #F7F7F7;
159 border: 1px solid #D7D7D7;
160 overflow: auto;
161 padding: 0.25em;
162 white-space: pre-wrap; /* CSS 2.1 */
163 word-wrap: break-word; /* IE7 */
164}
165
166#footer
167{
168 clear: both;
169 padding-top: 10px;
170}
171
172#footer hr
173{
174 margin: 10px 0 15px 0;
175 height: 1px;
176 border: solid 1px gray;
177 border-bottom: none;
178}
179
180#footer p
181{
182 margin: 0 10px 10px 10px;
183 float: left;
184}
185
186#footer #copy
187{
188 float: right;
189}
190
191#outputSample
192{
193 width: 100%;
194 table-layout: fixed;
195}
196
197#outputSample thead th
198{
199 color: #dddddd;
200 background-color: #999999;
201 padding: 4px;
202 white-space: nowrap;
203}
204
205#outputSample tbody th
206{
207 vertical-align: top;
208 text-align: left;
209}
210
211#outputSample pre
212{
213 margin: 0;
214 padding: 0;
215}
216
217.description
218{
219 border: 1px dotted #B7B7B7;
220 margin-bottom: 10px;
221 padding: 10px 10px 0;
222 overflow: hidden;
223}
224
225label
226{
227 display: block;
228 margin-bottom: 6px;
229}
230
231/**
232 * CKEditor editables are automatically set with the "cke_editable" class
233 * plus cke_editable_(inline|themed) depending on the editor type.
234 */
235
236/* Style a bit the inline editables. */
237.cke_editable.cke_editable_inline
238{
239 cursor: pointer;
240}
241
242/* Once an editable element gets focused, the "cke_focus" class is
243 added to it, so we can style it differently. */
244.cke_editable.cke_editable_inline.cke_focus
245{
246 box-shadow: inset 0px 0px 20px 3px #ddd, inset 0 0 1px #000;
247 outline: none;
248 background: #eee;
249 cursor: text;
250}
251
252/* Avoid pre-formatted overflows inline editable. */
253.cke_editable_inline pre
254{
255 white-space: pre-wrap;
256 word-wrap: break-word;
257}
258
259/**
260 * Samples index styles.
261 */
262
263.twoColumns,
264.twoColumnsLeft,
265.twoColumnsRight
266{
267 overflow: hidden;
268}
269
270.twoColumnsLeft,
271.twoColumnsRight
272{
273 width: 45%;
274}
275
276.twoColumnsLeft
277{
278 float: left;
279}
280
281.twoColumnsRight
282{
283 float: right;
284}
285
286dl.samples
287{
288 padding: 0 0 0 40px;
289}
290dl.samples > dt
291{
292 display: list-item;
293 list-style-type: disc;
294 list-style-position: outside;
295 margin: 0 0 3px;
296}
297dl.samples > dd
298{
299 margin: 0 0 3px;
300}
301.warning
302{
303 color: #ff0000;
304 background-color: #FFCCBA;
305 border: 2px dotted #ff0000;
306 padding: 15px 10px;
307 margin: 10px 0;
308}
309
310.warning.deprecated {
311 font-size: 1.3em;
312}
313
314/* Used on inline samples */
315
316blockquote
317{
318 font-style: italic;
319 font-family: Georgia, Times, "Times New Roman", serif;
320 padding: 2px 0;
321 border-style: solid;
322 border-color: #ccc;
323 border-width: 0;
324}
325
326.cke_contents_ltr blockquote
327{
328 padding-left: 20px;
329 padding-right: 8px;
330 border-left-width: 5px;
331}
332
333.cke_contents_rtl blockquote
334{
335 padding-left: 8px;
336 padding-right: 20px;
337 border-right-width: 5px;
338}
339
340img.right {
341 border: 1px solid #ccc;
342 float: right;
343 margin-left: 15px;
344 padding: 5px;
345}
346
347img.left {
348 border: 1px solid #ccc;
349 float: left;
350 margin-right: 15px;
351 padding: 5px;
352}
353
354.marker
355{
356 background-color: Yellow;
357}
diff --git a/sources/samples/old/sample.js b/sources/samples/old/sample.js
new file mode 100644
index 0000000..7d4c74e
--- /dev/null
+++ b/sources/samples/old/sample.js
@@ -0,0 +1,51 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6// Tool scripts for the sample pages.
7// This file can be ignored and is not required to make use of CKEditor.
8
9( function() {
10 CKEDITOR.on( 'instanceReady', function( ev ) {
11 // Check for sample compliance.
12 var editor = ev.editor,
13 meta = CKEDITOR.document.$.getElementsByName( 'ckeditor-sample-required-plugins' ),
14 requires = meta.length ? CKEDITOR.dom.element.get( meta[ 0 ] ).getAttribute( 'content' ).split( ',' ) : [],
15 missing = [],
16 i;
17
18 if ( requires.length ) {
19 for ( i = 0; i < requires.length; i++ ) {
20 if ( !editor.plugins[ requires[ i ] ] )
21 missing.push( '<code>' + requires[ i ] + '</code>' );
22 }
23
24 if ( missing.length ) {
25 var warn = CKEDITOR.dom.element.createFromHtml(
26 '<div class="warning">' +
27 '<span>To fully experience this demo, the ' + missing.join( ', ' ) + ' plugin' + ( missing.length > 1 ? 's are' : ' is' ) + ' required.</span>' +
28 '</div>'
29 );
30 warn.insertBefore( editor.container );
31 }
32 }
33
34 // Set icons.
35 var doc = new CKEDITOR.dom.document( document ),
36 icons = doc.find( '.button_icon' );
37
38 for ( i = 0; i < icons.count(); i++ ) {
39 var icon = icons.getItem( i ),
40 name = icon.getAttribute( 'data-icon' ),
41 style = CKEDITOR.skin.getIconStyle( name, ( CKEDITOR.lang.dir == 'rtl' ) );
42
43 icon.addClass( 'cke_button_icon' );
44 icon.addClass( 'cke_button__' + name + '_icon' );
45 icon.setAttribute( 'style', style );
46 icon.setStyle( 'float', 'none' );
47
48 }
49 } );
50} )();
51// %LEAVE_UNMINIFIED% %REMOVE_LINE%
diff --git a/sources/samples/old/sample_posteddata.php b/sources/samples/old/sample_posteddata.php
new file mode 100644
index 0000000..54e9b7c
--- /dev/null
+++ b/sources/samples/old/sample_posteddata.php
@@ -0,0 +1,16 @@
1<?php /* <body><pre>
2
3-------------------------------------------------------------------------------------------
4 CKEditor - Posted Data
5
6 We are sorry, but your Web server does not support the PHP language used in this script.
7
8 Please note that CKEditor can be used with any other server-side language than just PHP.
9 To save the content created with CKEditor you need to read the POST data on the server
10 side and write it to a file or the database.
11
12 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
13 For licensing, see LICENSE.md or http://ckeditor.com/license
14-------------------------------------------------------------------------------------------
15
16</pre><div style="display:none"></body> */ include "assets/posteddata.php"; ?>
diff --git a/sources/samples/old/tabindex.html b/sources/samples/old/tabindex.html
new file mode 100644
index 0000000..4238f33
--- /dev/null
+++ b/sources/samples/old/tabindex.html
@@ -0,0 +1,78 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>TAB Key-Based Navigation &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link href="sample.css" rel="stylesheet">
12 <style>
13
14 .cke_focused,
15 .cke_editable.cke_focused
16 {
17 outline: 3px dotted blue !important;
18 *border: 3px dotted blue !important; /* For IE7 */
19 }
20
21 </style>
22 <script>
23
24 CKEDITOR.on( 'instanceReady', function( evt ) {
25 var editor = evt.editor;
26 editor.setData( 'This editor has it\'s tabIndex set to <strong>' + editor.tabIndex + '</strong>' );
27
28 // Apply focus class name.
29 editor.on( 'focus', function() {
30 editor.container.addClass( 'cke_focused' );
31 });
32 editor.on( 'blur', function() {
33 editor.container.removeClass( 'cke_focused' );
34 });
35
36 // Put startup focus on the first editor in tab order.
37 if ( editor.tabIndex == 1 )
38 editor.focus();
39 });
40
41 </script>
42</head>
43<body>
44 <h1 class="samples">
45 <a href="index.html">CKEditor Samples</a> &raquo; TAB Key-Based Navigation
46 </h1>
47 <div class="warning deprecated">
48 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/tabindex.html">brand new version in CKEditor SDK</a>.
49 </div>
50 <div class="description">
51 <p>
52 This sample shows how tab key navigation among editor instances is
53 affected by the <code>tabIndex</code> attribute from
54 the original page element. Use TAB key to move between the editors.
55 </p>
56 </div>
57 <p>
58 <textarea class="ckeditor" cols="80" id="editor4" rows="10" tabindex="1"></textarea>
59 </p>
60 <div class="ckeditor" contenteditable="true" id="editor1" tabindex="4"></div>
61 <p>
62 <textarea class="ckeditor" cols="80" id="editor2" rows="10" tabindex="2"></textarea>
63 </p>
64 <p>
65 <textarea class="ckeditor" cols="80" id="editor3" rows="10" tabindex="3"></textarea>
66 </p>
67 <div id="footer">
68 <hr>
69 <p>
70 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
71 </p>
72 <p id="copy">
73 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
74 Knabben. All rights reserved.
75 </p>
76 </div>
77</body>
78</html>
diff --git a/sources/samples/old/uicolor.html b/sources/samples/old/uicolor.html
new file mode 100644
index 0000000..fb61b1f
--- /dev/null
+++ b/sources/samples/old/uicolor.html
@@ -0,0 +1,72 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>UI Color Picker &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <link rel="stylesheet" href="sample.css">
12</head>
13<body>
14 <h1 class="samples">
15 <a href="index.html">CKEditor Samples</a> &raquo; UI Color
16 </h1>
17 <div class="warning deprecated">
18 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/uicolor.html">brand new version in CKEditor SDK</a>.
19 </div>
20 <div class="description">
21 <p>
22 This sample shows how to automatically replace <code>&lt;textarea&gt;</code> elements
23 with a CKEditor instance with an option to change the color of its user interface.<br>
24 <strong>Note:</strong>The UI skin color feature depends on the CKEditor skin
25 compatibility. The Moono and Kama skins are examples of skins that work with it.
26 </p>
27 </div>
28 <form action="sample_posteddata.php" method="post">
29 <p>
30 This editor instance has a UI color value defined in configuration to change the skin color,
31 To specify the color of the user interface, set the <code>uiColor</code> property:
32 </p>
33 <pre class="samples">
34CKEDITOR.replace( '<em>textarea_id</em>', {
35 <strong>uiColor: '#14B8C4'</strong>
36});</pre>
37 <p>
38 Note that <code><em>textarea_id</em></code> in the code above is the <code>id</code> attribute of
39 the <code>&lt;textarea&gt;</code> element to be replaced.
40 </p>
41 <p>
42 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
43 <script>
44
45 // Replace the <textarea id="editor"> with an CKEditor
46 // instance, using default configurations.
47 CKEDITOR.replace( 'editor1', {
48 uiColor: '#14B8C4',
49 toolbar: [
50 [ 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink' ],
51 [ 'FontSize', 'TextColor', 'BGColor' ]
52 ]
53 });
54
55 </script>
56 </p>
57 <p>
58 <input type="submit" value="Submit">
59 </p>
60 </form>
61 <div id="footer">
62 <hr>
63 <p>
64 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
65 </p>
66 <p id="copy">
67 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
68 Knabben. All rights reserved.
69 </p>
70 </div>
71</body>
72</html>
diff --git a/sources/samples/old/uilanguages.html b/sources/samples/old/uilanguages.html
new file mode 100644
index 0000000..76749cb
--- /dev/null
+++ b/sources/samples/old/uilanguages.html
@@ -0,0 +1,122 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>User Interface Globalization &mdash; CKEditor Sample</title>
10 <script src="../../ckeditor.js"></script>
11 <script src="assets/uilanguages/languages.js"></script>
12 <link rel="stylesheet" href="sample.css">
13</head>
14<body>
15 <h1 class="samples">
16 <a href="index.html">CKEditor Samples</a> &raquo; User Interface Languages
17 </h1>
18 <div class="warning deprecated">
19 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/uilanguages.html">brand new version in CKEditor SDK</a>.
20 </div>
21 <div class="description">
22 <p>
23 This sample shows how to automatically replace <code>&lt;textarea&gt;</code> elements
24 with a CKEditor instance with an option to change the language of its user interface.
25 </p>
26 <p>
27 It pulls the language list from CKEditor <code>_languages.js</code> file that contains the list of supported languages and creates
28 a drop-down list that lets the user change the UI language.
29 </p>
30 <p>
31 By default, CKEditor automatically localizes the editor to the language of the user.
32 The UI language can be controlled with two configuration options:
33 <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-language">language</a></code> and
34 <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-defaultLanguage">
35 defaultLanguage</a></code>. The <code>defaultLanguage</code> setting specifies the
36 default CKEditor language to be used when a localization suitable for user's settings is not available.
37 </p>
38 <p>
39 To specify the user interface language that will be used no matter what language is
40 specified in user's browser or operating system, set the <code>language</code> property:
41 </p>
42<pre class="samples">
43CKEDITOR.replace( '<em>textarea_id</em>', {
44 // Load the German interface.
45 <strong>language: 'de'</strong>
46});</pre>
47 <p>
48 Note that <code><em>textarea_id</em></code> in the code above is the <code>id</code> attribute of
49 the <code>&lt;textarea&gt;</code> element to be replaced.
50 </p>
51 </div>
52 <form action="sample_posteddata.php" method="post">
53 <p>
54 Available languages (<span id="count"> </span> languages!):<br>
55 <script>
56
57 document.write( '<select disabled="disabled" id="languages" onchange="createEditor( this.value );">' );
58
59 // Get the language list from the _languages.js file.
60 for ( var i = 0 ; i < window.CKEDITOR_LANGS.length ; i++ ) {
61 document.write(
62 '<option value="' + window.CKEDITOR_LANGS[i].code + '">' +
63 window.CKEDITOR_LANGS[i].name +
64 '</option>' );
65 }
66
67 document.write( '</select>' );
68
69 </script>
70 <br>
71 <span style="color: #888888">
72 (You may see strange characters if your system does not support the selected language)
73 </span>
74 </p>
75 <p>
76 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
77 <script>
78
79 // Set the number of languages.
80 document.getElementById( 'count' ).innerHTML = window.CKEDITOR_LANGS.length;
81
82 var editor;
83
84 function createEditor( languageCode ) {
85 if ( editor )
86 editor.destroy();
87
88 // Replace the <textarea id="editor"> with an CKEditor
89 // instance, using default configurations.
90 editor = CKEDITOR.replace( 'editor1', {
91 language: languageCode,
92
93 on: {
94 instanceReady: function() {
95 // Wait for the editor to be ready to set
96 // the language combo.
97 var languages = document.getElementById( 'languages' );
98 languages.value = this.langCode;
99 languages.disabled = false;
100 }
101 }
102 });
103 }
104
105 // At page startup, load the default language:
106 createEditor( '' );
107
108 </script>
109 </p>
110 </form>
111 <div id="footer">
112 <hr>
113 <p>
114 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
115 </p>
116 <p id="copy">
117 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
118 Knabben. All rights reserved.
119 </p>
120 </div>
121</body>
122</html>
diff --git a/sources/samples/old/xhtmlstyle.html b/sources/samples/old/xhtmlstyle.html
new file mode 100644
index 0000000..c918766
--- /dev/null
+++ b/sources/samples/old/xhtmlstyle.html
@@ -0,0 +1,234 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>XHTML Compliant Output &mdash; CKEditor Sample</title>
10 <meta name="ckeditor-sample-required-plugins" content="sourcearea">
11 <script src="../../ckeditor.js"></script>
12 <script src="sample.js"></script>
13 <link href="sample.css" rel="stylesheet">
14</head>
15<body>
16 <h1 class="samples">
17 <a href="index.html">CKEditor Samples</a> &raquo; Producing XHTML Compliant Output
18 </h1>
19 <div class="warning deprecated">
20 This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/basicstyles.html">brand new version in CKEditor SDK</a>.
21 </div>
22 <div class="description">
23 <p>
24 This sample shows how to configure CKEditor to output valid
25 <a class="samples" href="http://www.w3.org/TR/xhtml11/">XHTML 1.1</a> code.
26 Deprecated elements (<code>&lt;font&gt;</code>, <code>&lt;u&gt;</code>) or attributes
27 (<code>size</code>, <code>face</code>) will be replaced with XHTML compliant code.
28 </p>
29 <p>
30 To add a CKEditor instance outputting valid XHTML code, load the editor using a standard
31 JavaScript call and define CKEditor features to use the XHTML compliant elements and styles.
32 </p>
33 <p>
34 A snippet of the configuration code can be seen below; check the source of this page for
35 full definition:
36 </p>
37<pre class="samples">
38CKEDITOR.replace( '<em>textarea_id</em>', {
39 contentsCss: 'assets/outputxhtml.css',
40
41 coreStyles_bold: {
42 element: 'span',
43 attributes: { 'class': 'Bold' }
44 },
45 coreStyles_italic: {
46 element: 'span',
47 attributes: { 'class': 'Italic' }
48 },
49
50 ...
51});</pre>
52 </div>
53 <form action="sample_posteddata.php" method="post">
54 <p>
55 <label for="editor1">
56 Editor 1:
57 </label>
58 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;span class="Bold"&gt;sample text&lt;/span&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
59 <script>
60
61 CKEDITOR.replace( 'editor1', {
62 /*
63 * Style sheet for the contents
64 */
65 contentsCss: 'assets/outputxhtml/outputxhtml.css',
66
67 /*
68 * Special allowed content rules for spans used by
69 * font face, size, and color buttons.
70 *
71 * Note: all rules have been written separately so
72 * it was possible to specify required classes.
73 */
74 extraAllowedContent: 'span(!FontColor1);span(!FontColor2);span(!FontColor3);' +
75 'span(!FontColor1BG);span(!FontColor2BG);span(!FontColor3BG);' +
76 'span(!FontComic);span(!FontCourier);span(!FontTimes);' +
77 'span(!FontSmaller);span(!FontLarger);span(!FontSmall);span(!FontBig);span(!FontDouble)',
78
79 /*
80 * Core styles.
81 */
82 coreStyles_bold: {
83 element: 'span',
84 attributes: { 'class': 'Bold' }
85 },
86 coreStyles_italic: {
87 element: 'span',
88 attributes: { 'class': 'Italic' }
89 },
90 coreStyles_underline: {
91 element: 'span',
92 attributes: { 'class': 'Underline' }
93 },
94 coreStyles_strike: {
95 element: 'span',
96 attributes: { 'class': 'StrikeThrough' },
97 overrides: 'strike'
98 },
99 coreStyles_subscript: {
100 element: 'span',
101 attributes: { 'class': 'Subscript' },
102 overrides: 'sub'
103 },
104 coreStyles_superscript: {
105 element: 'span',
106 attributes: { 'class': 'Superscript' },
107 overrides: 'sup'
108 },
109
110 /*
111 * Font face.
112 */
113
114 // List of fonts available in the toolbar combo. Each font definition is
115 // separated by a semi-colon (;). We are using class names here, so each font
116 // is defined by {Combo Label}/{Class Name}.
117 font_names: 'Comic Sans MS/FontComic;Courier New/FontCourier;Times New Roman/FontTimes',
118
119 // Define the way font elements will be applied to the document. The "span"
120 // element will be used. When a font is selected, the font name defined in the
121 // above list is passed to this definition with the name "Font", being it
122 // injected in the "class" attribute.
123 // We must also instruct the editor to replace span elements that are used to
124 // set the font (Overrides).
125 font_style: {
126 element: 'span',
127 attributes: { 'class': '#(family)' },
128 overrides: [
129 {
130 element: 'span',
131 attributes: {
132 'class': /^Font(?:Comic|Courier|Times)$/
133 }
134 }
135 ]
136 },
137
138 /*
139 * Font sizes.
140 */
141 fontSize_sizes: 'Smaller/FontSmaller;Larger/FontLarger;8pt/FontSmall;14pt/FontBig;Double Size/FontDouble',
142 fontSize_style: {
143 element: 'span',
144 attributes: { 'class': '#(size)' },
145 overrides: [
146 {
147 element: 'span',
148 attributes: {
149 'class': /^Font(?:Smaller|Larger|Small|Big|Double)$/
150 }
151 }
152 ]
153 } ,
154
155 /*
156 * Font colors.
157 */
158 colorButton_enableMore: false,
159
160 colorButton_colors: 'FontColor1/FF9900,FontColor2/0066CC,FontColor3/F00',
161 colorButton_foreStyle: {
162 element: 'span',
163 attributes: { 'class': '#(color)' },
164 overrides: [
165 {
166 element: 'span',
167 attributes: {
168 'class': /^FontColor(?:1|2|3)$/
169 }
170 }
171 ]
172 },
173
174 colorButton_backStyle: {
175 element: 'span',
176 attributes: { 'class': '#(color)BG' },
177 overrides: [
178 {
179 element: 'span',
180 attributes: {
181 'class': /^FontColor(?:1|2|3)BG$/
182 }
183 }
184 ]
185 },
186
187 /*
188 * Indentation.
189 */
190 indentClasses: [ 'Indent1', 'Indent2', 'Indent3' ],
191
192 /*
193 * Paragraph justification.
194 */
195 justifyClasses: [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyFull' ],
196
197 /*
198 * Styles combo.
199 */
200 stylesSet: [
201 { name: 'Strong Emphasis', element: 'strong' },
202 { name: 'Emphasis', element: 'em' },
203
204 { name: 'Computer Code', element: 'code' },
205 { name: 'Keyboard Phrase', element: 'kbd' },
206 { name: 'Sample Text', element: 'samp' },
207 { name: 'Variable', element: 'var' },
208
209 { name: 'Deleted Text', element: 'del' },
210 { name: 'Inserted Text', element: 'ins' },
211
212 { name: 'Cited Work', element: 'cite' },
213 { name: 'Inline Quotation', element: 'q' }
214 ]
215 });
216
217 </script>
218 </p>
219 <p>
220 <input type="submit" value="Submit">
221 </p>
222 </form>
223 <div id="footer">
224 <hr>
225 <p>
226 CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
227 </p>
228 <p id="copy">
229 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
230 Knabben. All rights reserved.
231 </p>
232 </div>
233</body>
234</html>
diff --git a/sources/samples/toolbarconfigurator/bender.js b/sources/samples/toolbarconfigurator/bender.js
new file mode 100644
index 0000000..d592866
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/bender.js
@@ -0,0 +1,52 @@
1/* jshint browser: false, node: true */
2
3'use strict';
4
5var config = {
6
7 applications: {
8 ckeditor: {
9 path: '../../',
10 files: [
11 'ckeditor.js'
12 ]
13 },
14
15 codemirror: {
16 path: '.',
17 files: [
18 'js/lib/codemirror/codemirror.js'
19 ]
20 },
21
22 toolbartool: {
23 path: '.',
24 files: [
25 'js/fulltoolbareditor.js',
26 'js/abstracttoolbarmodifier.js',
27 'js/toolbarmodifier.js',
28 'js/toolbartextmodifier.js'
29 ]
30 }
31 },
32
33 plugins: [
34 'node_modules/benderjs-mocha',
35 'node_modules/benderjs-chai'
36 ],
37
38 framework: 'mocha',
39
40 tests: {
41 'main': {
42 applications: [ 'ckeditor', 'codemirror', 'toolbartool' ],
43 basePath: 'tests/',
44 paths: [
45 '**',
46 '!**/_*/**'
47 ]
48 }
49 }
50};
51
52module.exports = config;
diff --git a/sources/samples/toolbarconfigurator/css/fontello.css b/sources/samples/toolbarconfigurator/css/fontello.css
new file mode 100644
index 0000000..bb32199
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/css/fontello.css
@@ -0,0 +1,55 @@
1@font-face {
2 font-family: 'fontello';
3 src: url('../font/fontello.eot?89024372');
4 src: url('../font/fontello.eot?89024372#iefix') format('embedded-opentype'),
5 url('../font/fontello.woff?89024372') format('woff'),
6 url('../font/fontello.ttf?89024372') format('truetype'),
7 url('../font/fontello.svg?89024372#fontello') format('svg');
8 font-weight: normal;
9 font-style: normal;
10}
11/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
12/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
13/*
14@media screen and (-webkit-min-device-pixel-ratio:0) {
15 @font-face {
16 font-family: 'fontello';
17 src: url('../font/fontello.svg?89024372#fontello') format('svg');
18 }
19}
20*/
21
22 [class^="icon-"]:before, [class*=" icon-"]:before {
23 font-family: "fontello";
24 font-style: normal;
25 font-weight: normal;
26 speak: none;
27
28 display: inline-block;
29 text-decoration: inherit;
30 width: 1em;
31 margin-right: .2em;
32 text-align: center;
33 /* opacity: .8; */
34
35 /* For safety - reset parent styles, that can break glyph codes*/
36 font-variant: normal;
37 text-transform: none;
38
39 /* fix buttons height, for twitter bootstrap */
40 line-height: 1em;
41
42 /* Animation center compensation - margins should be symmetric */
43 /* remove if not needed */
44 margin-left: .2em;
45
46 /* you can be more comfortable with increased icons size */
47 /* font-size: 120%; */
48
49 /* Uncomment for 3D effect */
50 /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
51}
52
53.icon-trash:before { content: '\e802'; } /* '' */
54.icon-down-big:before { content: '\e800'; } /* '' */
55.icon-up-big:before { content: '\e801'; } /* '' */ \ No newline at end of file
diff --git a/sources/samples/toolbarconfigurator/font/LICENSE.txt b/sources/samples/toolbarconfigurator/font/LICENSE.txt
new file mode 100644
index 0000000..b511054
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/LICENSE.txt
@@ -0,0 +1,12 @@
1Font license info
2
3
4## Font Awesome
5
6 Copyright (C) 2012 by Dave Gandy
7
8 Author: Dave Gandy
9 License: SIL ()
10 Homepage: http://fortawesome.github.com/Font-Awesome/
11
12
diff --git a/sources/samples/toolbarconfigurator/font/config.json b/sources/samples/toolbarconfigurator/font/config.json
new file mode 100644
index 0000000..94809d7
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/config.json
@@ -0,0 +1,28 @@
1{
2 "name": "",
3 "css_prefix_text": "icon-",
4 "css_use_suffix": false,
5 "hinting": true,
6 "units_per_em": 1000,
7 "ascent": 850,
8 "glyphs": [
9 {
10 "uid": "f48ae54adfb27d8ada53d0fd9e34ee10",
11 "css": "trash-empty",
12 "code": 59392,
13 "src": "fontawesome"
14 },
15 {
16 "uid": "1c4068ed75209e21af36017df8871802",
17 "css": "down-big",
18 "code": 59393,
19 "src": "fontawesome"
20 },
21 {
22 "uid": "95376bf082bfec6ce06ea1cda7bd7ead",
23 "css": "up-big",
24 "code": 59394,
25 "src": "fontawesome"
26 }
27 ]
28} \ No newline at end of file
diff --git a/sources/samples/toolbarconfigurator/font/fontello.eot b/sources/samples/toolbarconfigurator/font/fontello.eot
new file mode 100644
index 0000000..2732fad
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/fontello.eot
Binary files differ
diff --git a/sources/samples/toolbarconfigurator/font/fontello.svg b/sources/samples/toolbarconfigurator/font/fontello.svg
new file mode 100644
index 0000000..33d14ac
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/fontello.svg
@@ -0,0 +1,14 @@
1<?xml version="1.0" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3<svg xmlns="http://www.w3.org/2000/svg">
4<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
5<defs>
6<font id="fontello" horiz-adv-x="1000" >
7<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8<missing-glyph horiz-adv-x="1000" />
9<glyph glyph-name="trash" unicode="&#xe802;" d="m286 439v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m143 0v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m142 0v-321q0-8-5-13t-12-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q7 0 12-5t5-13z m72-404v529h-500v-529q0-12 4-22t8-15t6-5h464q2 0 6 5t8 15t4 22z m-375 601h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q22 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />
10<glyph glyph-name="down-big" unicode="&#xe800;" d="m899 386q0-30-21-50l-363-364q-22-21-51-21q-29 0-50 21l-363 364q-21 20-21 50q0 29 21 51l41 41q22 21 51 21q29 0 50-21l164-164v393q0 29 21 50t51 22h71q29 0 50-22t21-50v-393l164 164q21 21 51 21q29 0 50-21l42-42q21-21 21-50z" horiz-adv-x="928.6" />
11<glyph glyph-name="up-big" unicode="&#xe801;" d="m899 308q0-28-21-50l-42-42q-21-21-50-21q-30 0-51 21l-164 164v-393q0-29-20-47t-51-19h-71q-30 0-51 19t-21 47v393l-164-164q-20-21-50-21t-50 21l-42 42q-21 21-21 50q0 30 21 51l363 363q20 21 50 21q30 0 51-21l363-363q21-22 21-51z" horiz-adv-x="928.6" />
12</font>
13</defs>
14</svg> \ No newline at end of file
diff --git a/sources/samples/toolbarconfigurator/font/fontello.ttf b/sources/samples/toolbarconfigurator/font/fontello.ttf
new file mode 100644
index 0000000..fbcbf06
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/fontello.ttf
Binary files differ
diff --git a/sources/samples/toolbarconfigurator/font/fontello.woff b/sources/samples/toolbarconfigurator/font/fontello.woff
new file mode 100644
index 0000000..e1d5647
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/font/fontello.woff
Binary files differ
diff --git a/sources/samples/toolbarconfigurator/index.html b/sources/samples/toolbarconfigurator/index.html
new file mode 100644
index 0000000..4d31289
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/index.html
@@ -0,0 +1,446 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<!--[if IE 8]><html class="ie8"><![endif]-->
7<!--[if gt IE 8]><html><![endif]-->
8<!--[if !IE]><!--><html><!--<![endif]-->
9<head>
10 <meta charset="utf-8">
11 <title>Toolbar Configurator</title>
12 <script src="../../ckeditor.js"></script>
13 <script>
14 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 )
15 CKEDITOR.tools.enableHtml5Elements( document );
16 </script>
17 <link rel="stylesheet" href="lib/codemirror/codemirror.css">
18 <link rel="stylesheet" href="lib/codemirror/show-hint.css">
19 <link rel="stylesheet" href="lib/codemirror/neo.css">
20 <link rel="stylesheet" href="css/fontello.css">
21 <link rel="stylesheet" href="../css/samples.css">
22</head>
23<body id="toolbar">
24
25<nav class="navigation-a">
26 <div class="grid-container">
27 <ul class="navigation-a-left grid-width-70">
28 <li><a href="http://ckeditor.com">Project Homepage</a></li>
29 <li><a href="http://dev.ckeditor.com/">I found a bug</a></li>
30 <li><a href="http://github.com/ckeditor/ckeditor-dev" class="icon-pos-right icon-navigation-a-github">Fork CKEditor on GitHub</a></li>
31 </ul>
32 <ul class="navigation-a-right grid-width-30">
33 <li><a href="http://ckeditor.com/blog-list">CKEditor Blog</a></li>
34 </ul>
35 </div>
36</nav>
37
38<header class="header-a">
39 <div class="grid-container">
40 <h1 class="header-a-logo grid-width-30">
41 <a href="../index.html"><img src="../img/logo.png" alt="CKEditor Logo"></a>
42 </h1>
43 <nav class="navigation-b grid-width-70">
44 <ul>
45 <li><a href="../index.html" class="button-a">Start</a></li>
46 <li><a href="index.html" class="button-a button-a-background">Toolbar configurator</a></li>
47 </ul>
48 </nav>
49 </div>
50</header>
51
52<main>
53 <div class="adjoined-top">
54 <div class="grid-container">
55 <div class="content grid-width-100">
56 <div class="grid-container-nested">
57 <h1 class="grid-width-60">
58 Toolbar Configurator
59 <a href="#help-content" type="button" title="Configurator help" id="help" class="button-a button-a-background button-a-no-text icon-pos-left icon-question-mark">Help</a>
60 </h1>
61
62 <div class="grid-width-40 grid-switch-magic">
63 <div class="switch">
64 <span class="balloon-a balloon-a-se">Select configurator type</span>
65 <input type="radio" name="radio" data-num="1" id="radio-basic" />
66 <input type="radio" name="radio" data-num="2" id="radio-advanced" />
67 <label data-for="1" for="radio-basic">Basic</label>
68 <span class="switch-inner">
69 <span class="handler"></span>
70 </span>
71 <label data-for="2" for="radio-advanced">Advanced</label>
72 </div>
73 </div>
74 </div>
75 </div>
76 </div>
77 </div>
78 <div class="adjoined-bottom">
79 <div class="grid-container">
80 <div class="grid-width-100">
81 <div class="editors-container">
82 <div id="editor-basic"></div>
83 <div id="editor-advanced"></div>
84 </div>
85 </div>
86 </div>
87 </div>
88
89 <div class="grid-container configurator">
90 <div class="content grid-width-100">
91 <div class="configurator">
92 <div>
93 <div id="toolbarModifierWrapper"></div>
94 </div>
95 </div>
96 </div>
97 </div>
98
99 <div id="help-content">
100 <div class="grid-container">
101 <div class="grid-width-100">
102 <h2>What Am I Doing Here?</h2>
103
104 <div class="grid-container grid-container-nested">
105 <div class="basic">
106 <div class="grid-width-50">
107 <p>Arrange <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-toolbarGroups">toolbar groups</a>, toggle <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-removeButtons">button visibility</a> according to your needs and get your toolbar configuration.</p>
108 <p>You can replace the content of the <a href="../../config.js"><code>config.js</code></a> file with the generated configuration. If you already set some configuration options you will need to merge both configurations.</p>
109 </div>
110 <div class="grid-width-50">
111 <p>Read more about different ways of <a href="http://docs.ckeditor.com/#!/guide/dev_configuration">setting configuration</a> and do not forget about <strong>clearing browser cache</strong>.</p>
112 <p>Arranging toolbar groups is the recommended way of configuring the toolbar, but if you need more freedom you can use the <a href="#advanced">advanced configurator</a>.</p>
113 </div>
114 </div>
115 <div class="advanced" style="display: none;">
116 <div class="grid-width-50">
117 <p>With this code editor you can edit your <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-toolbar">toolbar configuration</a> live.</p>
118 <p>You can replace the content of the <a href="../../config.js"><code>config.js</code></a> file with the generated configuration. If you already set some configuration options you will need to merge both configurations.</p>
119 </div>
120 <div class="grid-width-50">
121 <p>Read more about different ways of <a href="http://docs.ckeditor.com/#!/guide/dev_configuration">setting configuration</a> and do not forget about <strong>clearing browser cache</strong>.</p>
122 </div>
123 </div>
124 </div>
125
126 <p class="grid-container grid-container-nested">
127 <button type="button" class="help-content-close grid-width-100 button-a button-a-background">Got it. Let's play!</button>
128 </p>
129 </div>
130 </div>
131 </div>
132</main>
133
134<footer class="footer-a grid-container">
135 <p class="grid-width-100">
136 CKEditor &ndash; The text editor for the Internet &ndash; <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
137 </p>
138 <p class="grid-width-100" id="copy">
139 Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> &ndash; Frederico Knabben. All rights reserved.
140 </p>
141</footer>
142
143<script src="lib/codemirror/codemirror.js"></script>
144<script src="lib/codemirror/javascript.js"></script>
145<script src="lib/codemirror/show-hint.js"></script>
146
147<script src="js/fulltoolbareditor.js"></script>
148<script src="js/abstracttoolbarmodifier.js"></script>
149<script src="js/toolbarmodifier.js"></script>
150<script src="js/toolbartextmodifier.js"></script>
151<script src="../js/sf.js"></script>
152
153<script>
154 ( function() {
155 'use strict';
156
157 var mode = ( window.location.hash.substr( 1 ) === 'advanced' ) ? 'advanced' : 'basic',
158 configuratorSection = CKEDITOR.document.findOne( 'main > .grid-container.configurator' ),
159 basicInstruction = CKEDITOR.document.findOne( '#help-content .basic' ),
160 advancedInstruction = CKEDITOR.document.findOne( '#help-content .advanced' ),
161
162 // Configurator mode switcher.
163 modeSwitchBasic = CKEDITOR.document.getById( 'radio-basic' ),
164 modeSwitchAdvanced = CKEDITOR.document.getById( 'radio-advanced' );
165
166 // Initial setup
167 function updateSwitcher() {
168 if ( mode === 'advanced' ) {
169 modeSwitchAdvanced.$.checked = true;
170 } else {
171 modeSwitchBasic.$.checked = true;
172 }
173 }
174
175 updateSwitcher();
176
177 CKEDITOR.document.getWindow().on( 'hashchange', function( e ) {
178 var hash = window.location.hash.substr( 1 );
179 if ( !( hash === 'advanced' || hash === 'basic' ) ) {
180 return;
181 }
182 mode = hash;
183 onToolbarsDone( mode );
184 } );
185
186 CKEDITOR.document.getWindow().on( 'resize', function() {
187 updateToolbar( ( mode === 'basic' ? toolbarModifier : toolbarTextModifier )[ 'editorInstance' ] );
188 } );
189
190 function onRefresh( modifier ) {
191 modifier = modifier || this;
192
193 if ( mode === 'basic' && modifier instanceof ToolbarConfigurator.ToolbarTextModifier ) {
194 return;
195 }
196
197 // CodeMirror container becomes visible, so we need to refresh and to avoid rendering problems.
198 if ( mode === 'advanced' && modifier instanceof ToolbarConfigurator.ToolbarTextModifier ) {
199 modifier.codeContainer.refresh();
200 }
201
202 updateToolbar( modifier.editorInstance );
203 }
204
205 function updateToolbar( editor ) {
206 var editorContainer = editor.container;
207
208 // Not always editor is loaded.
209 if ( !editorContainer ) {
210 return;
211 }
212
213 var displayStyle = editorContainer.getStyle( 'display' );
214
215 editorContainer.setStyle( 'display', 'block' );
216
217 var newHeight = editorContainer.getSize( 'height' );
218
219 var newMarginTop = parseInt( editorContainer.getComputedStyle( 'margin-top' ), 10 );
220 newMarginTop = ( isNaN( newMarginTop ) ? 0 : Number( newMarginTop ) );
221
222 var newMarginBottom = parseInt( editorContainer.getComputedStyle( 'margin-bottom' ), 10 );
223 newMarginBottom = ( isNaN( newMarginBottom ) ? 0 : Number( newMarginBottom ) );
224
225 var result = newHeight + newMarginTop + newMarginBottom;
226
227 editorContainer.setStyle( 'display', displayStyle );
228
229 editor.container.getAscendant( 'div' ).setStyle( 'height', result + 'px' );
230 }
231
232 var toolbarModifier = new ToolbarConfigurator.ToolbarModifier( 'editor-basic' );
233
234 var done = 0;
235 toolbarModifier.init( onToolbarInit );
236 toolbarModifier.onRefresh = onRefresh;
237
238 CKEDITOR.document.getById( 'toolbarModifierWrapper' ).append( toolbarModifier.mainContainer );
239
240 var toolbarTextModifier = new ToolbarConfigurator.ToolbarTextModifier( 'editor-advanced' );
241 toolbarTextModifier.init( onToolbarInit );
242 toolbarTextModifier.onRefresh = onRefresh;
243
244 function onToolbarInit() {
245 if ( ++done === 2 ) {
246 onToolbarsDone();
247
248 positionSticky.watch( CKEDITOR.document.findOne( '.toolbar' ), function() {
249 return mode === 'advanced';
250 } );
251 }
252 }
253
254 function onToolbarsDone() {
255 if ( mode === 'basic' ) {
256 toggleModeBasic( false );
257 } else {
258 toggleModeAdvanced( false );
259 }
260
261 updateSwitcher();
262
263 setTimeout( function() {
264 CKEDITOR.document.findOne( '.editors-container' ).addClass( 'active' );
265 CKEDITOR.document.findOne( '#toolbarModifierWrapper' ).addClass( 'active' );
266 }, 200 );
267 }
268
269 CKEDITOR.document.getById( 'toolbarModifierWrapper' ).append( toolbarTextModifier.mainContainer );
270
271 function toogleModeSwitch( onElement, offElement, onModifier, offModifier ) {
272 onElement.addClass( 'fancy-button-active' );
273 offElement.removeClass( 'fancy-button-active' );
274
275 onModifier.showUI();
276 offModifier.hideUI();
277 }
278
279 function toggleModeBasic( callOnRefresh ) {
280 callOnRefresh = ( callOnRefresh !== false );
281 mode = 'basic';
282 window.location.hash = '#basic';
283 toogleModeSwitch( modeSwitchBasic, modeSwitchAdvanced, toolbarModifier, toolbarTextModifier );
284
285 configuratorSection.removeClass( 'freed-width' );
286 basicInstruction.show();
287 advancedInstruction.hide();
288
289 callOnRefresh && onRefresh( toolbarModifier );
290 }
291
292 function toggleModeAdvanced( callOnRefresh ) {
293 callOnRefresh = ( callOnRefresh !== false );
294 mode = 'advanced';
295 window.location.hash = '#advanced';
296 toogleModeSwitch( modeSwitchAdvanced, modeSwitchBasic, toolbarTextModifier, toolbarModifier );
297
298 configuratorSection.addClass( 'freed-width' );
299 advancedInstruction.show();
300 basicInstruction.hide();
301
302 callOnRefresh && onRefresh( toolbarTextModifier );
303 }
304
305 modeSwitchBasic.on( 'click', toggleModeBasic );
306 modeSwitchAdvanced.on( 'click', toggleModeAdvanced );
307
308 //
309 // Position:sticky for the toolbar.
310 //
311
312 // Will make elements behave like they were styled with position:sticky.
313 var positionSticky = {
314 // Store object: {
315 // element: CKEDITOR.dom.element, // Element which will float.
316 // placeholder: CKEDITOR.dom.element, // Placeholder which is place to prevent page bounce.
317 // isFixed: boolean // Whether element float now.
318 // }
319 watched: [],
320
321 active: [],
322
323 staticContainer: null,
324
325 init: function() {
326 var element = CKEDITOR.dom.element.createFromHtml(
327 '<div class="staticContainer">' +
328 '<div class="grid-container" >' +
329 '<div class="grid-width-100">' +
330 '<div class="inner"></div>' +
331 '</div>' +
332 '</div>' +
333 '</div>' );
334
335 this.staticContainer = element.findOne( '.inner' );
336
337 CKEDITOR.document.getBody().append( element );
338 },
339
340 watch: function( element, preventFunc ) {
341 this.watched.push( {
342 element: element,
343 placeholder: new CKEDITOR.dom.element( 'div' ),
344 isFixed: false,
345 preventFunc: preventFunc
346 } );
347 },
348
349 checkAll: function() {
350 for ( var i = 0; i < this.watched.length; i++ ) {
351 this.check( this.watched[ i ] );
352 }
353 },
354
355 check: function( element ) {
356 var isFixed = element.isFixed;
357 var shouldBeFixed = this.shouldBeFixed( element );
358
359 // Nothing to be done.
360 if ( isFixed === shouldBeFixed ) {
361 return;
362 }
363
364 var placeholder = element.placeholder;
365
366 if ( isFixed ) {
367 // Unfixing.
368
369 element.element.insertBefore( placeholder );
370 placeholder.remove();
371
372 element.element.removeStyle( 'margin' );
373
374 this.active.splice( CKEDITOR.tools.indexOf( this.active, element ), 1 );
375
376 } else {
377 // Fixing.
378 placeholder.setStyle( 'width', element.element.getSize( 'width' ) + 'px' );
379 placeholder.setStyle( 'height', element.element.getSize( 'height' ) + 'px' );
380 placeholder.setStyle( 'margin-bottom', element.element.getComputedStyle( 'margin-bottom' ) );
381 placeholder.setStyle( 'display', element.element.getComputedStyle( 'display' ) );
382 placeholder.insertAfter( element.element );
383
384 this.staticContainer.append( element.element );
385
386 this.active.push( element );
387 }
388
389 element.isFixed = !element.isFixed;
390 },
391
392 shouldBeFixed: function( element ) {
393 if ( element.preventFunc && element.preventFunc() ) {
394 return false;
395 }
396
397 // If element is already fixed we are checking it's placeholder.
398 var related = ( element.isFixed ? element.placeholder : element.element ),
399 clientRect = related.$.getBoundingClientRect(),
400 staticHeight = this.staticContainer.getSize('height' ),
401 elemHeight = element.element.getSize( 'height' );
402
403 if ( element.isFixed ) {
404 return ( clientRect.top + elemHeight < staticHeight );
405 } else {
406 return ( clientRect.top < staticHeight );
407 }
408 }
409 };
410
411 positionSticky.init();
412
413 CKEDITOR.document.getWindow().on( 'scroll',
414 new CKEDITOR.tools.eventsBuffer( 100, positionSticky.checkAll, positionSticky ).input
415 );
416
417 // Make the toolbar sticky.
418 positionSticky.watch( CKEDITOR.document.findOne( '.editors-container' ) );
419
420 // Help button and help-content.
421 ( function() {
422 var helpButton = CKEDITOR.document.getById( 'help' ),
423 helpContent = CKEDITOR.document.getById( 'help-content' );
424
425 // Don't show help button on IE8 because it's unsupported by Pico Modal.
426 if ( CKEDITOR.env.ie && CKEDITOR.env.version == 8 ) {
427 helpButton.hide();
428 } else {
429 // Display help modal when the button is clicked.
430 helpButton.on( 'click', function( evt ) {
431 SF.modal( {
432 // Clone modal content from DOM.
433 content: helpContent.getHtml(),
434
435 afterCreate: function( modal ) {
436 // Enable modal content button to close the modal.
437 new CKEDITOR.dom.element( modal.modalElem() ).findOne( '.help-content-close' ).once( 'click', modal.close );
438 }
439 } ).show();
440 } );
441 }
442 } )();
443 } )();
444</script>
445</body>
446</html>
diff --git a/sources/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js b/sources/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js
new file mode 100644
index 0000000..af6cd62
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js
@@ -0,0 +1,566 @@
1/* global ToolbarConfigurator */
2
3'use strict';
4
5// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
6if ( typeof Object.create != 'function' ) {
7 ( function() {
8 var F = function() {};
9 Object.create = function( o ) {
10 if ( arguments.length > 1 ) {
11 throw Error( 'Second argument not supported' );
12 }
13 if ( o === null ) {
14 throw Error( 'Cannot set a null [[Prototype]]' );
15 }
16 if ( typeof o != 'object' ) {
17 throw TypeError( 'Argument must be an object' );
18 }
19 F.prototype = o;
20 return new F();
21 };
22 } )();
23}
24
25// Copy of the divarea plugin (with some enhancements), so we always have some editable mode, regardless of the build's config.
26CKEDITOR.plugins.add( 'toolbarconfiguratorarea', {
27 // Use afterInit to override wysiwygarea's mode. May still fail to override divarea, but divarea is nice.
28 afterInit: function( editor ) {
29 editor.addMode( 'wysiwyg', function( callback ) {
30 var editingBlock = CKEDITOR.dom.element.createFromHtml( '<div class="cke_wysiwyg_div cke_reset" hidefocus="true"></div>' );
31
32 var contentSpace = editor.ui.space( 'contents' );
33 contentSpace.append( editingBlock );
34
35 editingBlock = editor.editable( editingBlock );
36
37 editingBlock.detach = CKEDITOR.tools.override( editingBlock.detach,
38 function( org ) {
39 return function() {
40 org.apply( this, arguments );
41 this.remove();
42 };
43 } );
44
45 editor.setData( editor.getData( 1 ), callback );
46 editor.fire( 'contentDom' );
47 } );
48
49 // Additions to the divarea.
50
51 // Speed up data processing.
52 editor.dataProcessor.toHtml = function( html ) {
53 return html;
54 };
55 editor.dataProcessor.toDataFormat = function( html ) {
56 return html;
57 };
58
59 // End of the additions.
60 }
61} );
62
63// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
64if ( !Object.keys ) {
65 Object.keys = ( function() {
66 var hasOwnProperty = Object.prototype.hasOwnProperty,
67 hasDontEnumBug = !( { toString: null } ).propertyIsEnumerable( 'toString' ),
68 dontEnums = [
69 'toString',
70 'toLocaleString',
71 'valueOf',
72 'hasOwnProperty',
73 'isPrototypeOf',
74 'propertyIsEnumerable',
75 'constructor'
76 ],
77 dontEnumsLength = dontEnums.length;
78
79 return function( obj ) {
80 if ( typeof obj !== 'object' && ( typeof obj !== 'function' || obj === null ) )
81 throw new TypeError( 'Object.keys called on non-object' );
82
83 var result = [], prop, i;
84
85 for ( prop in obj ) {
86 if ( hasOwnProperty.call( obj, prop ) )
87 result.push( prop );
88
89 }
90
91 if ( hasDontEnumBug ) {
92 for ( i = 0; i < dontEnumsLength; i++ ) {
93 if ( hasOwnProperty.call( obj, dontEnums[ i ] ) )
94 result.push( dontEnums[ i ] );
95
96 }
97 }
98 return result;
99 };
100 }() );
101}
102
103( function() {
104 /**
105 * @class ToolbarConfigurator.AbstractToolbarModifier
106 * @param {String} editorId An id of modified editor
107 * @constructor
108 */
109 function AbstractToolbarModifier( editorId, cfg ) {
110 this.cfg = cfg || {};
111 this.hidden = false;
112 this.editorId = editorId;
113 this.fullToolbarEditor = new ToolbarConfigurator.FullToolbarEditor();
114
115 this.mainContainer = null;
116
117 this.originalConfig = null;
118 this.actualConfig = null;
119
120 this.waitForReady = false;
121 this.isEditableVisible = false;
122
123 this.toolbarContainer = null;
124 this.toolbarButtons = [];
125 }
126
127 // Expose the class.
128 ToolbarConfigurator.AbstractToolbarModifier = AbstractToolbarModifier;
129
130 /**
131 * @param {String} config
132 */
133 AbstractToolbarModifier.prototype.setConfig = function( config ) {
134 this._onInit( undefined, config, true );
135 };
136
137 /**
138 * @param {Function} [callback]
139 */
140 AbstractToolbarModifier.prototype.init = function( callback ) {
141 var that = this;
142
143 this.mainContainer = new CKEDITOR.dom.element( 'div' );
144
145 if ( this.fullToolbarEditor.editorInstance !== null ) {
146 throw 'Only one instance of ToolbarModifier is allowed';
147 }
148
149 if ( !this.editorInstance ) {
150 // Do not refresh yet, let's wait for the full toolbar editor (see below).
151 this._createEditor( false );
152 }
153
154 this.editorInstance.once( 'loaded', function() {
155 that.fullToolbarEditor.init( function() {
156 that._onInit( callback );
157
158 if ( typeof that.onRefresh == 'function' ) {
159 that.onRefresh();
160 }
161 }, that.editorInstance.config );
162 } );
163
164 return this.mainContainer;
165 };
166
167 /**
168 * Called editor initialization finished.
169 *
170 * @param {Function} callback
171 * @param {String} [actualConfig]
172 * @private
173 */
174 AbstractToolbarModifier.prototype._onInit = function( callback, actualConfig ) {
175 this.originalConfig = this.editorInstance.config;
176
177 if ( !actualConfig ) {
178 this.actualConfig = JSON.parse( JSON.stringify( this.originalConfig ) );
179 } else {
180 this.actualConfig = JSON.parse( actualConfig );
181 }
182
183 if ( !this.actualConfig.toolbarGroups && !this.actualConfig.toolbar ) {
184 this.actualConfig.toolbarGroups = getDefaultToolbarGroups( this.editorInstance );
185 }
186
187 if ( typeof callback === 'function' )
188 callback( this.mainContainer );
189
190 // Here we are going to keep only `name` and `groups` data from editor `toolbar` property.
191 function getDefaultToolbarGroups( editor ) {
192 var toolbarGroups = editor.toolbar,
193 copy = [];
194
195 var max = toolbarGroups.length;
196 for ( var i = 0; i < max; i++ ) {
197 var group = toolbarGroups[ i ];
198
199 if ( typeof group == 'string' ) {
200 copy.push( group ); // separator
201 } else {
202 copy.push( {
203 name: group.name,
204 groups: group.groups ? group.groups.slice() : []
205 } );
206 }
207 }
208
209 return copy;
210 }
211 };
212
213 /**
214 * Creates DOM structure of tool.
215 *
216 * @returns {CKEDITOR.dom.element}
217 * @private
218 */
219 AbstractToolbarModifier.prototype._createModifier = function() {
220 this.mainContainer.addClass( 'unselectable' );
221
222 if ( this.modifyContainer ) {
223 this.modifyContainer.remove();
224 }
225
226 this.modifyContainer = new CKEDITOR.dom.element( 'div' );
227 this.modifyContainer.addClass( 'toolbarModifier' );
228
229 this.mainContainer.append( this.modifyContainer );
230
231 return this.mainContainer;
232 };
233
234 /**
235 * Find editable area in CKEditor instance DOM container
236 *
237 * @returns {CKEDITOR.dom.element}
238 */
239 AbstractToolbarModifier.prototype.getEditableArea = function() {
240 var selector = ( '#' + this.editorInstance.id + '_contents' );
241
242 return this.editorInstance.container.findOne( selector );
243 };
244
245 /**
246 * Hide editable area in modified editor by sets its height to 0.
247 *
248 * @private
249 */
250 AbstractToolbarModifier.prototype._hideEditable = function() {
251 var area = this.getEditableArea();
252
253 this.isEditableVisible = false;
254
255 this.lastEditableAreaHeight = area.getStyle( 'height' );
256 area.setStyle( 'height', '0' );
257 };
258
259 /**
260 * Show editable area in modified editor.
261 *
262 * @private
263 */
264 AbstractToolbarModifier.prototype._showEditable = function() {
265 this.isEditableVisible = true;
266
267 this.getEditableArea().setStyle( 'height', this.lastEditableAreaHeight || 'auto' );
268 };
269
270 /**
271 * Toggle editable area visibility.
272 *
273 * @private
274 */
275 AbstractToolbarModifier.prototype._toggleEditable = function() {
276 if ( this.isEditableVisible )
277 this._hideEditable();
278 else
279 this._showEditable();
280 };
281
282 /**
283 * Usually called when configuration changes.
284 *
285 * @private
286 */
287 AbstractToolbarModifier.prototype._refreshEditor = function() {
288 var that = this,
289 status = this.editorInstance.status;
290
291 // Wait for ready only once.
292 if ( this.waitForReady )
293 return;
294
295 // Not ready.
296 if ( status == 'unloaded' || status == 'loaded' ) {
297 this.waitForReady = true;
298
299 this.editorInstance.once( 'instanceReady', function() {
300 refresh();
301 }, this );
302 // Ready or destroyed.
303 } else {
304 refresh();
305 }
306
307 function refresh() {
308 that.editorInstance.destroy();
309 that._createEditor( true, that.getActualConfig() );
310 that.waitForReady = false;
311 }
312 };
313
314 /**
315 * Creates editor that can be used to present the toolbar configuration.
316 *
317 * @private
318 */
319 AbstractToolbarModifier.prototype._createEditor = function( doRefresh, configOverrides ) {
320 var that = this;
321
322 this.editorInstance = CKEDITOR.replace( this.editorId );
323
324 this.editorInstance.on( 'configLoaded', function() {
325 var config = that.editorInstance.config;
326
327 if ( configOverrides ) {
328 CKEDITOR.tools.extend( config, configOverrides, true );
329 }
330
331 AbstractToolbarModifier.extendPluginsConfig( config );
332 } );
333
334 // Prevent creating any other space than the top one.
335 this.editorInstance.on( 'uiSpace', function( evt ) {
336 if ( evt.data.space != 'top' ) {
337 evt.stop();
338 }
339 }, null, null, -999 );
340
341 this.editorInstance.once( 'loaded', function() {
342 var btns = that.editorInstance.ui.instances;
343
344 for ( var i in btns ) {
345 if ( btns[ i ] ) {
346 btns[ i ].click = empty;
347 btns[ i ].onClick = empty;
348 }
349 }
350
351 if ( !that.isEditableVisible ) {
352 that._hideEditable();
353 }
354
355 if ( that.currentActive && that.currentActive.name ) {
356 that._highlightGroup( that.currentActive.name );
357 }
358
359 if ( that.hidden ) {
360 that.hideUI();
361 } else {
362 that.showUI();
363 }
364
365 if ( doRefresh && ( typeof that.onRefresh === 'function' ) ) {
366 that.onRefresh();
367 }
368 } );
369
370 function empty() {}
371 };
372
373 /**
374 * Always returns copy of config.
375 *
376 * @returns {Object}
377 */
378 AbstractToolbarModifier.prototype.getActualConfig = function() {
379 return JSON.parse( JSON.stringify( this.actualConfig ) );
380 };
381
382 /**
383 * Creates toolbar in tool.
384 *
385 * @private
386 */
387 AbstractToolbarModifier.prototype._createToolbar = function() {
388 if ( !this.toolbarButtons.length ) {
389 return;
390 }
391
392 this.toolbarContainer = new CKEDITOR.dom.element( 'div' );
393 this.toolbarContainer.addClass( 'toolbar' );
394
395 var max = this.toolbarButtons.length;
396 for ( var i = 0; i < max; i += 1 ) {
397 this._createToolbarBtn( this.toolbarButtons[ i ] );
398 }
399 };
400
401 /**
402 * Create toolbar button and add it to toolbar container
403 *
404 * @param {Object} cfg
405 * @returns {CKEDITOR.dom.element}
406 * @private
407 */
408 AbstractToolbarModifier.prototype._createToolbarBtn = function( cfg ) {
409 var btnText = ( typeof cfg.text === 'string' ? cfg.text : cfg.text.inactive ),
410 btn = ToolbarConfigurator.FullToolbarEditor.createButton( btnText, cfg.cssClass );
411
412 this.toolbarContainer.append( btn );
413 btn.data( 'group', cfg.group );
414 btn.addClass( cfg.position );
415 btn.on( 'click', function() {
416 cfg.clickCallback.call( this, btn, cfg );
417 }, this );
418
419 return btn;
420 };
421
422 /**
423 * @private
424 * @param {Object} config
425 */
426 AbstractToolbarModifier.prototype._fixGroups = function( config ) {
427 var groups = config.toolbarGroups || [];
428
429 var max = groups.length;
430 for ( var i = 0; i < max; i += 1 ) {
431 var currentGroup = groups[ i ];
432
433 // separator, in config, is in raw format
434 // need to make it more sophisticated to keep unique id
435 // for each one
436 if ( currentGroup == '/' ) {
437 currentGroup = groups[ i ] = {};
438 currentGroup.type = 'separator';
439 currentGroup.name = ( 'separator' + CKEDITOR.tools.getNextNumber() );
440 continue;
441 }
442
443 // sometimes subgroups are not set (basic package), so need to
444 // create them artifically
445 currentGroup.groups = currentGroup.groups || [];
446
447 // when there is no subgroup with same name like its parent name
448 // then it have to be added artificially
449 // in order to maintain consistency between user interface and config
450 if ( CKEDITOR.tools.indexOf( currentGroup.groups, currentGroup.name ) == -1 ) {
451 this.editorInstance.ui.addToolbarGroup( currentGroup.name, currentGroup.groups[ currentGroup.groups.length - 1 ], currentGroup.name );
452 currentGroup.groups.push( currentGroup.name );
453 }
454
455 this._fixSubgroups( currentGroup );
456 }
457 };
458
459 /**
460 * Transform subgroup string to object literal
461 * with keys: {String} name and {Number} totalBtns
462 * Please note: this method modify Object provided in first argument
463 *
464 * input:
465 * [
466 * { groups: [ 'nameOne', 'nameTwo' ] }
467 * ]
468 *
469 * output:
470 * [
471 * { groups: [ { name: 'nameOne', totalBtns: 3 }, { name: 'nameTwo', totalBtns: 5 } ] }
472 * ]
473 *
474 * @param {Object} group
475 * @private
476 */
477 AbstractToolbarModifier.prototype._fixSubgroups = function( group ) {
478 var subGroups = group.groups;
479
480 var max = subGroups.length;
481 for ( var i = 0; i < max; i += 1 ) {
482 var subgroupName = subGroups[ i ];
483
484 subGroups[ i ] = {
485 name: subgroupName,
486 totalBtns: ToolbarConfigurator.ToolbarModifier.getTotalSubGroupButtonsNumber( subgroupName, this.fullToolbarEditor )
487 };
488 }
489 };
490
491 /**
492 * Same as JSON.stringify method but returned string is in one line
493 *
494 * @param {Object} json
495 * @param {Object} opts
496 * @param {Boolean} opts.addSpaces
497 * @param {Boolean} opts.noQuotesOnKey
498 * @param {Boolean} opts.singleQuotes
499 * @returns {Object}
500 */
501 AbstractToolbarModifier.stringifyJSONintoOneLine = function( json, opts ) {
502 opts = opts || {};
503 var stringJSON = JSON.stringify( json, null, '' );
504
505 // IE8 make new line characters
506 stringJSON = stringJSON.replace( /\n/g, '' );
507
508 if ( opts.addSpaces ) {
509 stringJSON = stringJSON.replace( /(\{|:|,|\[|\])/g, function( sentence ) {
510 return sentence + ' ';
511 } );
512
513 stringJSON = stringJSON.replace( /(\])/g, function( sentence ) {
514 return ' ' + sentence;
515 } );
516 }
517
518 if ( opts.noQuotesOnKey ) {
519 stringJSON = stringJSON.replace( /"(\w*)":/g, function( sentence, word ) {
520 return word + ':';
521 } );
522 }
523
524 if ( opts.singleQuotes ) {
525 stringJSON = stringJSON.replace( /\"/g, '\'' );
526 }
527
528 return stringJSON;
529 };
530
531 /**
532 * Hide toolbar configurator
533 */
534 AbstractToolbarModifier.prototype.hideUI = function() {
535 this.hidden = true;
536 this.mainContainer.hide();
537 if ( this.editorInstance.container ) {
538 this.editorInstance.container.hide();
539 }
540 };
541
542 /**
543 * Show toolbar configurator
544 */
545 AbstractToolbarModifier.prototype.showUI = function() {
546 this.hidden = false;
547 this.mainContainer.show();
548 if ( this.editorInstance.container ) {
549 this.editorInstance.container.show();
550 }
551 };
552
553
554 /**
555 * Extends plugins setttings in the specified config with settings useful for
556 * the toolbar configurator.
557 *
558 * @static
559 */
560 AbstractToolbarModifier.extendPluginsConfig = function( config ) {
561 var extraPlugins = config.extraPlugins;
562
563 // Enable the special, lightweight area to replace wysiwygarea.
564 config.extraPlugins = ( extraPlugins ? extraPlugins + ',' : '' ) + 'toolbarconfiguratorarea';
565 };
566} )();
diff --git a/sources/samples/toolbarconfigurator/js/fulltoolbareditor.js b/sources/samples/toolbarconfigurator/js/fulltoolbareditor.js
new file mode 100644
index 0000000..2b9f15f
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/js/fulltoolbareditor.js
@@ -0,0 +1,365 @@
1/* exported ToolbarConfigurator */
2/* global ToolbarConfigurator */
3
4'use strict';
5
6window.ToolbarConfigurator = {};
7
8( function() {
9 /**
10 * @class ToolbarConfigurator.FullToolbarEditor
11 * @constructor
12 */
13 function FullToolbarEditor() {
14 this.instanceid = 'fte' + CKEDITOR.tools.getNextId();
15 this.textarea = new CKEDITOR.dom.element( 'textarea' );
16 this.textarea.setAttributes( {
17 id: this.instanceid,
18 name: this.instanceid,
19 contentEditable: true
20 } );
21
22 this.buttons = null;
23 this.editorInstance = null;
24 }
25
26 // Expose the class.
27 ToolbarConfigurator.FullToolbarEditor = FullToolbarEditor;
28
29 /**
30 * @param {Function} callback
31 * @param {Object} cfg
32 */
33 FullToolbarEditor.prototype.init = function( callback ) {
34 var that = this;
35
36 document.body.appendChild( this.textarea.$ );
37
38 CKEDITOR.replace( this.instanceid );
39
40 this.editorInstance = CKEDITOR.instances[ this.instanceid ];
41
42 this.editorInstance.once( 'configLoaded', function( e ) {
43 var cfg = e.editor.config;
44
45 // We want all the buttons.
46 delete cfg.removeButtons;
47 delete cfg.toolbarGroups;
48 delete cfg.toolbar;
49 ToolbarConfigurator.AbstractToolbarModifier.extendPluginsConfig( cfg );
50
51 e.editor.once( 'loaded', function() {
52 that.buttons = FullToolbarEditor.toolbarToButtons( that.editorInstance.toolbar );
53
54 that.buttonsByGroup = FullToolbarEditor.groupButtons( that.buttons );
55
56 that.buttonNamesByGroup = that.groupButtonNamesByGroup( that.buttons );
57
58 e.editor.container.hide();
59
60 if ( typeof callback === 'function' )
61 callback( that.buttons );
62 } );
63 } );
64 };
65
66 /**
67 * Group array of button names by their group parents.
68 *
69 * @param {Array} buttons
70 * @returns {Object}
71 */
72 FullToolbarEditor.prototype.groupButtonNamesByGroup = function( buttons ) {
73 var that = this,
74 groups = FullToolbarEditor.groupButtons( buttons );
75
76 for ( var groupName in groups ) {
77 var currGroup = groups[ groupName ];
78
79 groups[ groupName ] = FullToolbarEditor.map( currGroup, function( button ) {
80 return that.getCamelCasedButtonName( button.name );
81 } );
82 }
83
84 return groups;
85 };
86
87 /**
88 * Returns group literal.
89 *
90 * @param {String} name
91 * @returns {Object}
92 */
93 FullToolbarEditor.prototype.getGroupByName = function( name ) {
94 var groups = this.editorInstance.config.toolbarGroups || this.getFullToolbarGroupsConfig();
95
96 var max = groups.length;
97 for ( var i = 0; i < max; i += 1 ) {
98 if ( groups[ i ].name === name )
99 return groups[ i ];
100 }
101
102 return null;
103 };
104
105 /**
106 * @param {String} name
107 * @returns {String | null}
108 */
109 FullToolbarEditor.prototype.getCamelCasedButtonName = function( name ) {
110 var items = this.editorInstance.ui.items;
111
112 for ( var key in items ) {
113 if ( items[ key ].name == name )
114 return key;
115 }
116
117 return null;
118 };
119
120 /**
121 * Returns full toolbarGroups config value which is used when
122 * there is no toolbarGroups field in config.
123 *
124 * @param {Boolean} [pickSeparators=false]
125 * @returns {Array}
126 */
127 FullToolbarEditor.prototype.getFullToolbarGroupsConfig = function( pickSeparators ) {
128 pickSeparators = ( pickSeparators === true ? true : false );
129
130 var result = [],
131 toolbarGroups = this.editorInstance.toolbar;
132
133 var max = toolbarGroups.length;
134 for ( var i = 0; i < max; i += 1 ) {
135 var currentGroup = toolbarGroups[ i ],
136 copiedGroup = {};
137
138 if ( typeof currentGroup.name != 'string' ) {
139 // this is not a group
140 if ( pickSeparators ) {
141 result.push( '/' );
142 }
143 continue;
144 }
145
146 copiedGroup.name = currentGroup.name;
147 if ( currentGroup.groups )
148 copiedGroup.groups = Array.prototype.slice.call( currentGroup.groups );
149
150 result.push( copiedGroup );
151 }
152
153 return result;
154 };
155
156 /**
157 * Filters array items based on checker provided in second argument.
158 * Returns new array.
159 *
160 * @param {Array} arr
161 * @param {Function} checker
162 * @returns {Array}
163 */
164 FullToolbarEditor.filter = function( arr, checker ) {
165 var max = ( arr && arr.length ? arr.length : 0 ),
166 result = [];
167
168 for ( var i = 0; i < max; i += 1 ) {
169 if ( checker( arr[ i ] ) )
170 result.push( arr[ i ] );
171 }
172
173 return result;
174 };
175
176 /**
177 * Simplified http://underscorejs.org/#map functionality
178 *
179 * @param {Array | Object} enumerable
180 * @param {Function} modifier
181 * @returns {Array | Object}
182 */
183 FullToolbarEditor.map = function( enumerable, modifier ) {
184 var result;
185
186 if ( CKEDITOR.tools.isArray( enumerable ) ) {
187 result = [];
188
189 var max = enumerable.length;
190 for ( var i = 0; i < max; i += 1 )
191 result.push( modifier( enumerable[ i ] ) );
192 } else {
193 result = {};
194
195 for ( var key in enumerable )
196 result[ key ] = modifier( enumerable[ key ] );
197 }
198
199 return result;
200 };
201
202 /**
203 * Group buttons by their parent names.
204 *
205 * @static
206 * @param {Array} buttons
207 * @returns {Object} The object (`name => group`) representing CKEDITOR.ui.button or CKEDITOR.ui.richCombo
208 */
209 FullToolbarEditor.groupButtons = function( buttons ) {
210 var groups = {};
211
212 var max = buttons.length;
213 for ( var i = 0; i < max; i += 1 ) {
214 var currBtn = buttons[ i ],
215 currBtnGroupName = currBtn.toolbar.split( ',' )[ 0 ];
216
217 groups[ currBtnGroupName ] = groups[ currBtnGroupName ] || [];
218
219 groups[ currBtnGroupName ].push( currBtn );
220 }
221
222 return groups;
223 };
224
225 /**
226 * Pick all buttons from toolbar.
227 *
228 * @static
229 * @param {Array} groups
230 * @returns {Array}
231 */
232 FullToolbarEditor.toolbarToButtons = function( groups ) {
233 var buttons = [];
234
235 var max = groups.length;
236 for ( var i = 0; i < max; i += 1 ) {
237 var currentGroup = groups[ i ];
238
239 if ( typeof currentGroup == 'object' )
240 buttons = buttons.concat( FullToolbarEditor.groupToButtons( groups[ i ] ) );
241 }
242
243 return buttons;
244 };
245
246 /**
247 * Creates HTML button representation for view.
248 *
249 * @static
250 * @param {CKEDITOR.ui.button | CKEDITOR.ui.richCombo} button
251 * @returns {CKEDITOR.dom.element}
252 */
253 FullToolbarEditor.createToolbarButton = function( button ) {
254 var $button = new CKEDITOR.dom.element( 'a' ),
255 icon = FullToolbarEditor.createIcon( button.name, button.icon, button.command );
256
257 $button.setStyle( 'float', 'none' );
258
259 $button.addClass( 'cke_' + ( CKEDITOR.lang.dir == 'rtl' ? 'rtl' : 'ltr' ) );
260
261 if ( button instanceof CKEDITOR.ui.button ) {
262 $button.addClass( 'cke_button' );
263 $button.addClass( 'cke_toolgroup' );
264
265 $button.append( icon );
266 } else if ( CKEDITOR.ui.richCombo && button instanceof CKEDITOR.ui.richCombo ) {
267 var comboLabel = new CKEDITOR.dom.element( 'span' ),
268 comboOpen = new CKEDITOR.dom.element( 'span' ),
269 comboArrow = new CKEDITOR.dom.element( 'span' );
270
271 $button.addClass( 'cke_combo_button' );
272
273 comboLabel.addClass( 'cke_combo_text' );
274 comboLabel.addClass( 'cke_combo_inlinelabel' );
275 comboLabel.setText( button.label );
276
277 comboOpen.addClass( 'cke_combo_open' );
278 comboArrow.addClass( 'cke_combo_arrow' );
279 comboOpen.append( comboArrow );
280
281 $button.append( comboLabel );
282 $button.append( comboOpen );
283 }
284
285 return $button;
286 };
287
288 /**
289 * Create and return icon element.
290 *
291 * @param {String} name
292 * @param {String} icon
293 * @param {String} command
294 * @static
295 * @returns {CKEDITOR.dom.element}
296 */
297 FullToolbarEditor.createIcon = function( name, icon, command ) {
298 var iconStyle = CKEDITOR.skin.getIconStyle( name, ( CKEDITOR.lang.dir == 'rtl' ) );
299
300 // We don't know exactly how to get icon style. Especially for extra plugins,
301 // Which definition may vary.
302 iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( icon, ( CKEDITOR.lang.dir == 'rtl' ) );
303 iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( command, ( CKEDITOR.lang.dir == 'rtl' ) );
304
305 var iconElement = new CKEDITOR.dom.element( 'span' );
306
307 iconElement.addClass( 'cke_button_icon' );
308 iconElement.addClass( 'cke_button__' + name + '_icon' );
309 iconElement.setAttribute( 'style', iconStyle );
310 iconElement.setStyle( 'float', 'none' );
311
312 return iconElement;
313 };
314
315 /**
316 * Create and return button element
317 *
318 * @param {String} text
319 * @param {String} cssClasses
320 * @returns {CKEDITOR.dom.element}
321 */
322 FullToolbarEditor.createButton = function( text, cssClasses ) {
323 var $button = new CKEDITOR.dom.element( 'button' );
324
325 $button.addClass( 'button-a' );
326
327 $button.setAttribute( 'type', 'button' );
328
329 if ( typeof cssClasses == 'string' ) {
330 cssClasses = cssClasses.split( ' ' );
331
332 var i = cssClasses.length;
333 while ( i-- ) {
334 $button.addClass( cssClasses[ i ] );
335 }
336 }
337
338 $button.setHtml( text );
339
340 return $button;
341 };
342
343 /**
344 * @static
345 * @param {Object} group
346 * @returns {Array} representing HTML buttons for view
347 */
348 FullToolbarEditor.groupToButtons = function( group ) {
349 var buttons = [],
350 items = group.items;
351
352 var max = items ? items.length : 0;
353 for ( var i = 0; i < max; i += 1 ) {
354 var item = items[ i ];
355
356 if ( item instanceof CKEDITOR.ui.button || CKEDITOR.ui.richCombo && item instanceof CKEDITOR.ui.richCombo ) {
357 item.$ = FullToolbarEditor.createToolbarButton( item );
358 buttons.push( item );
359 }
360 }
361
362 return buttons;
363 };
364
365} )();
diff --git a/sources/samples/toolbarconfigurator/js/toolbarmodifier.js b/sources/samples/toolbarconfigurator/js/toolbarmodifier.js
new file mode 100644
index 0000000..bd33d24
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/js/toolbarmodifier.js
@@ -0,0 +1,1366 @@
1/* global ToolbarConfigurator, alert */
2
3'use strict';
4
5( function() {
6 var AbstractToolbarModifier = ToolbarConfigurator.AbstractToolbarModifier;
7
8 /**
9 * @class ToolbarConfigurator.ToolbarModifier
10 * @param {String} editorId An id of modified editor
11 * @param {Object} cfg
12 * @extends AbstractToolbarModifier
13 * @constructor
14 */
15 function ToolbarModifier( editorId, cfg ) {
16 AbstractToolbarModifier.call( this, editorId, cfg );
17
18 this.removedButtons = null;
19 this.originalConfig = null;
20 this.actualConfig = null;
21 this.emptyVisible = false;
22
23 // edit, paste, config
24 this.state = 'edit';
25
26 this.toolbarButtons = [
27 {
28 text: {
29 active: 'Hide empty toolbar groups',
30 inactive: 'Show empty toolbar groups'
31 },
32 group: 'edit',
33 position: 'left',
34 cssClass: 'button-a-soft',
35 clickCallback: function( button, buttonDefinition ) {
36 var className = 'button-a-background';
37
38 button[ button.hasClass( className ) ? 'removeClass' : 'addClass' ]( className );
39
40 this._toggleVisibilityEmptyElements();
41
42 if ( this.emptyVisible ) {
43 button.setText( buttonDefinition.text.active );
44 } else {
45 button.setText( buttonDefinition.text.inactive );
46 }
47 }
48 },
49 {
50 text: 'Add row separator',
51 group: 'edit',
52 position: 'left',
53 cssClass: 'button-a-soft',
54 clickCallback: function() {
55 this._addSeparator();
56 }
57 },
58 /*{
59 text: 'Paste config',
60 group: 'edit',
61 position: 'left',
62 clickCallback: function() {
63 this.state = 'paste';
64
65 this.modifyContainer.addClass( 'hidden' );
66 this.configContainer.removeClass( 'hidden' );
67 this.configContainer.setHtml( '<textarea></textarea>' );
68 this.showToolbarBtnsByGroupName( 'config' );
69 }
70 },*/
71 {
72 text: 'Select config',
73 group: 'config',
74 position: 'left',
75 cssClass: 'button-a-soft',
76 clickCallback: function() {
77 this.configContainer.findOne( 'textarea' ).$.select();
78 }
79 },
80 {
81 text: 'Back to configurator',
82 group: 'config',
83 position: 'right',
84 cssClass: 'button-a-background',
85 clickCallback: function() {
86 if ( this.state === 'paste' ) {
87 var cfg = this.configContainer.findOne( 'textarea' ).getValue();
88 cfg = ToolbarModifier.evaluateToolbarGroupsConfig( cfg );
89
90 if ( cfg ) {
91 this.setConfig( cfg );
92 } else {
93 alert( 'Your pasted config is wrong.' );
94 }
95 }
96
97 this.state = 'edit';
98 this._showConfigurationTool();
99 this.showToolbarBtnsByGroupName( this.state );
100 }
101 },
102 {
103 text: 'Get toolbar <span class="highlight">config</span>',
104 group: 'edit',
105 position: 'right',
106 cssClass: 'button-a-background icon-pos-left icon-download',
107 clickCallback: function() {
108 this.state = 'config';
109 this._showConfig();
110 this.showToolbarBtnsByGroupName( this.state );
111 }
112 }
113 ];
114
115 this.cachedActiveElement = null;
116 }
117
118 // Expose the class.
119 ToolbarConfigurator.ToolbarModifier = ToolbarModifier;
120
121 ToolbarModifier.prototype = Object.create( ToolbarConfigurator.AbstractToolbarModifier.prototype );
122
123 /**
124 * @returns {Object}
125 */
126 ToolbarModifier.prototype.getActualConfig = function() {
127 var copy = AbstractToolbarModifier.prototype.getActualConfig.call( this );
128
129 if ( copy.toolbarGroups ) {
130
131 var max = copy.toolbarGroups.length;
132 for ( var i = 0; i < max; i += 1 ) {
133 var currentGroup = copy.toolbarGroups[ i ];
134
135 copy.toolbarGroups[ i ] = ToolbarModifier.parseGroupToConfigValue( currentGroup );
136 }
137
138 }
139
140 return copy;
141 };
142
143 /**
144 * @param {Function} callback
145 * @param {String} [config]
146 * @param {Boolean} [forceKeepRemoveButtons=false]
147 * @private
148 */
149 ToolbarModifier.prototype._onInit = function( callback, config, forceKeepRemoveButtons ) {
150 forceKeepRemoveButtons = ( forceKeepRemoveButtons === true );
151 AbstractToolbarModifier.prototype._onInit.call( this, undefined, config );
152
153 this.removedButtons = [];
154
155 if ( forceKeepRemoveButtons ) {
156 if ( this.actualConfig.removeButtons ) {
157 this.removedButtons = this.actualConfig.removeButtons.split( ',' );
158 } else {
159 this.removedButtons = [];
160 }
161 } else {
162 if ( !( 'removeButtons' in this.originalConfig ) ) {
163 this.originalConfig.removeButtons = '';
164 this.removedButtons = [];
165 } else {
166 this.removedButtons = this.originalConfig.removeButtons ? this.originalConfig.removeButtons.split( ',' ) : [];
167 }
168 }
169
170 if ( !this.actualConfig.toolbarGroups )
171 this.actualConfig.toolbarGroups = this.fullToolbarEditor.getFullToolbarGroupsConfig();
172
173 this._fixGroups( this.actualConfig );
174 this._calculateTotalBtns();
175
176 this._createModifier();
177 this._refreshMoveBtnsAvalibility();
178 this._refreshBtnTabIndexes();
179
180 if ( typeof callback === 'function' )
181 callback( this.mainContainer );
182 };
183
184 /**
185 * @private
186 */
187 ToolbarModifier.prototype._showConfigurationTool = function() {
188 this.configContainer.addClass( 'hidden' );
189 this.modifyContainer.removeClass( 'hidden' );
190 };
191
192 /**
193 * Show configuration file in tool
194 *
195 * @private
196 */
197 ToolbarModifier.prototype._showConfig = function() {
198 var that = this,
199 actualConfig = this.getActualConfig(),
200 cfg = {};
201 if ( actualConfig.toolbarGroups ) {
202 cfg.toolbarGroups = actualConfig.toolbarGroups;
203
204 var groups = prepareGroups( actualConfig.toolbarGroups, this.cfg.trimEmptyGroups );
205
206 cfg.toolbarGroups = '\n\t\t' + groups.join( ',\n\t\t' );
207 }
208
209 function prepareGroups( toolbarGroups, trimEmptyGroups ) {
210 var groups = [],
211 max = toolbarGroups.length;
212
213 for ( var i = 0; i < max; i++ ) {
214 var group = toolbarGroups[ i ];
215
216 if ( group === '/' ) {
217 groups.push( '\'/\'' );
218 continue;
219 }
220
221 if ( trimEmptyGroups ) {
222 var max2 = group.groups.length;
223 while ( max2-- ) {
224 var subgroup = group.groups[ max2 ];
225
226 if ( ToolbarModifier.getTotalSubGroupButtonsNumber( subgroup, that.fullToolbarEditor ) === 0 ) {
227 group.groups.splice( max2, 1 );
228 }
229 }
230 }
231
232 if ( !( trimEmptyGroups && group.groups.length === 0 ) ) {
233 groups.push( AbstractToolbarModifier.stringifyJSONintoOneLine( group, {
234 addSpaces: true,
235 noQuotesOnKey: true,
236 singleQuotes: true
237 } ) );
238 }
239 }
240
241 return groups;
242 }
243
244 if ( actualConfig.removeButtons ) {
245 cfg.removeButtons = actualConfig.removeButtons;
246 }
247
248 var content = [
249 '<textarea class="configCode" readonly>',
250 'CKEDITOR.editorConfig = function( config ) {\n',
251 ( cfg.toolbarGroups ? '\tconfig.toolbarGroups = [' + cfg.toolbarGroups + '\n\t];' : '' ),
252 ( cfg.removeButtons ? '\n\n' : '' ),
253 ( cfg.removeButtons ? '\tconfig.removeButtons = \'' + cfg.removeButtons + '\';' : '' ),
254 '\n};',
255 '</textarea>'
256 ].join( '' );
257
258
259
260 this.modifyContainer.addClass( 'hidden' );
261 this.configContainer.removeClass( 'hidden' );
262
263 this.configContainer.setHtml( content );
264 };
265
266 /**
267 * Toggle empty groups and subgroups visibility.
268 *
269 * @private
270 */
271 ToolbarModifier.prototype._toggleVisibilityEmptyElements = function() {
272 if ( this.modifyContainer.hasClass( 'empty-visible' ) ) {
273 this.modifyContainer.removeClass( 'empty-visible' );
274 this.emptyVisible = false;
275 } else {
276 this.modifyContainer.addClass( 'empty-visible' );
277 this.emptyVisible = true;
278 }
279
280 this._refreshMoveBtnsAvalibility();
281 };
282
283 /**
284 * Creates HTML main container of modifier.
285 *
286 * @returns {CKEDITOR.dom.element}
287 * @private
288 */
289 ToolbarModifier.prototype._createModifier = function() {
290 var that = this;
291
292 AbstractToolbarModifier.prototype._createModifier.call( this );
293
294 this.modifyContainer.setHtml( this._toolbarConfigToListString() );
295
296 var groupLi = this.modifyContainer.find( 'li[data-type="group"]' );
297
298 this.modifyContainer.on( 'mouseleave', function() {
299 this._dehighlightActiveToolGroup();
300 }, this );
301
302 var max = groupLi.count();
303 for ( var i = 0; i < max; i += 1 ) {
304 groupLi.getItem( i ).on( 'mouseenter', onGroupHover );
305 }
306
307 function onGroupHover() {
308 that._highlightGroup( this.data( 'name' ) );
309 }
310
311 CKEDITOR.document.on( 'keypress', function( e ) {
312 var nativeEvent = e.data.$,
313 keyCode = nativeEvent.keyCode,
314 spaceOrEnter = ( keyCode === 32 || keyCode === 13 ),
315 active = new CKEDITOR.dom.element( CKEDITOR.document.$.activeElement );
316
317 var mainContainer = active.getAscendant( function( node ) {
318 return node.$ === that.mainContainer.$;
319 } );
320
321 if ( !mainContainer || !spaceOrEnter ) {
322 return;
323 }
324
325 if ( active.data( 'type' ) === 'button' ) {
326 active.findOne( 'input' ).$.click();
327 }
328 } );
329
330 this.modifyContainer.on( 'click', function( e ) {
331 var origEvent = e.data.$,
332 target = new CKEDITOR.dom.element( ( origEvent.target || origEvent.srcElement ) ),
333 relativeGroupOrSeparatorLi = ToolbarModifier.getGroupOrSeparatorLiAncestor( target );
334
335 if ( !relativeGroupOrSeparatorLi ) {
336 return;
337 }
338
339 that.cachedActiveElement = document.activeElement;
340
341 // checkbox clicked
342 if ( target.$ instanceof HTMLInputElement )
343 that._handleCheckboxClicked( target );
344
345 // link clicked
346 else if ( target.$ instanceof HTMLButtonElement ) {
347 if ( origEvent.preventDefault )
348 origEvent.preventDefault();
349 else
350 origEvent.returnValue = false;
351
352 var result = that._handleAnchorClicked( target.$ );
353
354 if ( result && result.action == 'remove' )
355 return;
356
357 }
358
359 var elementType = relativeGroupOrSeparatorLi.data( 'type' ),
360 elementName = relativeGroupOrSeparatorLi.data( 'name' );
361
362 that._setActiveElement( elementType, elementName );
363
364 if ( that.cachedActiveElement )
365 that.cachedActiveElement.focus();
366 } );
367
368 if ( !this.toolbarContainer ) {
369 this._createToolbar();
370 this.toolbarContainer.insertBefore( this.mainContainer.getChildren().getItem( 0 ) );
371 }
372
373 this.showToolbarBtnsByGroupName( 'edit' );
374
375 if ( !this.configContainer ) {
376 this.configContainer = new CKEDITOR.dom.element( 'div' );
377 this.configContainer.addClass( 'configContainer' );
378 this.configContainer.addClass( 'hidden' );
379
380 this.mainContainer.append( this.configContainer );
381 }
382
383 return this.mainContainer;
384 };
385
386 /**
387 * Show toolbar buttons related to group name provided in argument
388 * and hide other buttons
389 * Please note: this method works on toolbar in tool, which is located
390 * on top of the tool
391 *
392 * @param {String} groupName
393 */
394 ToolbarModifier.prototype.showToolbarBtnsByGroupName = function( groupName ) {
395 if ( !this.toolbarContainer ) {
396 return;
397 }
398
399 var allButtons = this.toolbarContainer.find( 'button' );
400
401 var max = allButtons.count();
402 for ( var i = 0; i < max; i += 1 ) {
403 var currentBtn = allButtons.getItem( i );
404
405 if ( currentBtn.data( 'group' ) == groupName )
406 currentBtn.removeClass( 'hidden' );
407 else
408 currentBtn.addClass( 'hidden' );
409
410 }
411 };
412
413 /**
414 * Parse group "model" to configuration value
415 *
416 * @param {Object} group
417 * @returns {Object}
418 * @private
419 */
420 ToolbarModifier.parseGroupToConfigValue = function( group ) {
421 if ( group.type == 'separator' ) {
422 return '/';
423 }
424
425 var groups = group.groups,
426 max = groups.length;
427
428 delete group.totalBtns;
429 for ( var i = 0; i < max; i += 1 ) {
430 groups[ i ] = groups[ i ].name;
431 }
432
433 return group;
434 };
435
436 /**
437 * Find closest Li ancestor in DOM tree which is group or separator element
438 *
439 * @param {CKEDITOR.dom.element} element
440 * @returns {CKEDITOR.dom.element}
441 */
442 ToolbarModifier.getGroupOrSeparatorLiAncestor = function( element ) {
443 if ( element.$ instanceof HTMLLIElement && element.data( 'type' ) == 'group' )
444 return element;
445 else {
446 return ToolbarModifier.getFirstAncestor( element, function( ancestor ) {
447 var type = ancestor.data( 'type' );
448
449 return ( type == 'group' || type == 'separator' );
450 } );
451 }
452 };
453
454 /**
455 * Set active element in tool by provided type and name.
456 *
457 * @param {String} type
458 * @param {String} name
459 */
460 ToolbarModifier.prototype._setActiveElement = function( type, name ) {
461 // clear current active element
462 if ( this.currentActive )
463 this.currentActive.elem.removeClass( 'active' );
464
465 if ( type === null ) {
466 this._dehighlightActiveToolGroup();
467 this.currentActive = null;
468 return;
469 }
470
471 var liElem = this.mainContainer.findOne( 'ul[data-type=table-body] li[data-type="' + type + '"][data-name="' + name + '"]' );
472
473 liElem.addClass( 'active' );
474
475 // setup model
476 this.currentActive = {
477 type: type,
478 name: name,
479 elem: liElem
480 };
481
482 // highlight group in toolbar
483 if ( type == 'group' )
484 this._highlightGroup( name );
485
486 if ( type == 'separator' )
487 this._dehighlightActiveToolGroup();
488 };
489
490 /**
491 * @returns {CKEDITOR.dom.element|null}
492 */
493 ToolbarModifier.prototype.getActiveToolGroup = function() {
494 if ( this.editorInstance.container )
495 return this.editorInstance.container.findOne( '.cke_toolgroup.active, .cke_toolbar.active' );
496 else
497 return null;
498 };
499
500 /**
501 * @private
502 */
503 ToolbarModifier.prototype._dehighlightActiveToolGroup = function() {
504 var currentActive = this.getActiveToolGroup();
505
506 if ( currentActive )
507 currentActive.removeClass( 'active' );
508
509 // @see ToolbarModifier.prototype._highlightGroup.
510 if ( this.editorInstance.container ) {
511 this.editorInstance.container.removeClass( 'some-toolbar-active' );
512 }
513 };
514
515 /**
516 * Highlight group by its name, and dehighlight current group.
517 *
518 * @param {String} name
519 */
520 ToolbarModifier.prototype._highlightGroup = function( name ) {
521 if ( !this.editorInstance.container )
522 return;
523
524 var foundBtnName = this.getFirstEnabledButtonInGroup( name ),
525 foundBtn = this.editorInstance.container.findOne( '.cke_button__' + foundBtnName + ', .cke_combo__' + foundBtnName );
526
527 this._dehighlightActiveToolGroup();
528
529 // Helpful to dim other toolbar groups if one is highlighted.
530 if ( this.editorInstance.container ) {
531 this.editorInstance.container.addClass( 'some-toolbar-active' );
532 }
533
534 if ( foundBtn ) {
535 var btnToolbar = ToolbarModifier.getFirstAncestor( foundBtn, function( ancestor ) {
536 return ancestor.hasClass( 'cke_toolbar' );
537 } );
538
539 if ( btnToolbar )
540 btnToolbar.addClass( 'active' );
541 }
542 };
543
544 /**
545 * @param {String} groupName
546 * @return {String|null}
547 */
548 ToolbarModifier.prototype.getFirstEnabledButtonInGroup = function( groupName ) {
549 var groups = this.actualConfig.toolbarGroups,
550 groupIndex = this.getGroupIndex( groupName ),
551 group = groups[ groupIndex ];
552
553 if ( groupIndex === -1 ) {
554 return null;
555 }
556
557 var max = group.groups ? group.groups.length : 0;
558 for ( var i = 0; i < max; i += 1 ) {
559 var currSubgroupName = group.groups[ i ].name,
560 firstEnabled = this.getFirstEnabledButtonInSubgroup( currSubgroupName );
561
562 if ( firstEnabled )
563 return firstEnabled;
564 }
565 return null;
566 };
567
568 /**
569 * @param {String} subgroupName
570 * @returns {String|null}
571 */
572 ToolbarModifier.prototype.getFirstEnabledButtonInSubgroup = function( subgroupName ) {
573 var subgroupBtns = this.fullToolbarEditor.buttonsByGroup[ subgroupName ];
574
575 var max = subgroupBtns ? subgroupBtns.length : 0;
576 for ( var i = 0; i < max; i += 1 ) {
577 var currBtnName = subgroupBtns[ i ].name;
578 if ( !this.isButtonRemoved( currBtnName ) )
579 return currBtnName;
580 }
581
582 return null;
583 };
584
585 /**
586 * Sets up parameters and call adequate action.
587 *
588 * @param {CKEDITOR.dom.element} checkbox
589 * @private
590 */
591 ToolbarModifier.prototype._handleCheckboxClicked = function( checkbox ) {
592 var closestLi = checkbox.getAscendant( 'li' ),
593 elementName = closestLi.data( 'name' ),
594 aboutToAddToRemoved = !checkbox.$.checked;
595
596 if ( aboutToAddToRemoved )
597 this._addButtonToRemoved( elementName );
598 else
599 this._removeButtonFromRemoved( elementName );
600 };
601
602 /**
603 * Sets up parameters and call adequate action.
604 *
605 * @param {HTMLAnchorElement} anchor
606 * @private
607 */
608 ToolbarModifier.prototype._handleAnchorClicked = function( anchor ) {
609 var anchorDOM = new CKEDITOR.dom.element( anchor ),
610 relativeLi = anchorDOM.getAscendant( 'li' ),
611 relativeUl = relativeLi.getAscendant( 'ul' ),
612 elementType = relativeLi.data( 'type' ),
613 elementName = relativeLi.data( 'name' ),
614 direction = anchorDOM.data( 'direction' ),
615 nearestLi = ( direction === 'up' ? relativeLi.getPrevious() : relativeLi.getNext() ),
616 groupName,
617 subgroupName,
618 newIndex;
619
620 // nothing to do
621 if ( anchorDOM.hasClass( 'disabled' ) )
622 return null;
623
624 // remove separator and nothing else
625 if ( anchorDOM.hasClass( 'remove' ) ) {
626 relativeLi.remove();
627 this._removeSeparator( relativeLi.data( 'name' ) );
628 this._setActiveElement( null );
629 return { action: 'remove' };
630 }
631
632 if ( !anchorDOM.hasClass( 'move' ) || !nearestLi )
633 return { action: null };
634
635 // move group or separator
636 if ( elementType === 'group' || elementType === 'separator' ) {
637 groupName = elementName;
638 newIndex = this._moveGroup( direction, groupName );
639 }
640
641 // move subgroup
642 if ( elementType === 'subgroup' ) {
643 subgroupName = elementName;
644 groupName = relativeLi.getAscendant( 'li' ).data( 'name' );
645 newIndex = this._moveSubgroup( direction, groupName, subgroupName );
646 }
647
648 // Visual effect
649 if ( direction === 'up' )
650 relativeLi.insertBefore( relativeUl.getChild( newIndex ) );
651
652 if ( direction === 'down' )
653 relativeLi.insertAfter( relativeUl.getChild( newIndex ) );
654
655 // Should know whether there is next li element after modifications.
656 var nextLi = relativeLi;
657
658 // We are looking for next li element in list (to check whether current one is the last one)
659 var found;
660 while ( nextLi = ( direction === 'up' ? nextLi.getPrevious() : nextLi.getNext() ) ) {
661 if ( !this.emptyVisible && nextLi.hasClass( 'empty' ) ) {
662 continue;
663 }
664
665 found = nextLi;
666 break;
667 }
668
669 // If not found, it means that we reached end.
670 if ( !found ) {
671 var selector = ( '[data-direction="' + ( direction === 'up' ? 'down' : 'up' ) + '"]' );
672
673 // Shifting direction.
674 this.cachedActiveElement = anchorDOM.getParent().findOne( selector );
675 }
676
677 this._refreshMoveBtnsAvalibility();
678 this._refreshBtnTabIndexes();
679
680 return {
681 action: 'move'
682 };
683 };
684
685 /**
686 * First element can not be moved up, and last element can not be moved down,
687 * so they are disabled.
688 */
689 ToolbarModifier.prototype._refreshMoveBtnsAvalibility = function() {
690 var that = this,
691 disabledBtns = this.mainContainer.find( 'ul[data-type=table-body] li > p > span > button.move.disabled' );
692
693 // enabling all disabled buttons
694 var max = disabledBtns.count();
695 for ( var i = 0; i < max; i += 1 ) {
696 var currentBtn = disabledBtns.getItem( i );
697 currentBtn.removeClass( 'disabled' );
698 }
699
700
701 function disableElementsInLists( ulList ) {
702 var max = ulList.count();
703 for ( i = 0; i < max; i += 1 ) {
704 that._disableElementsInList( ulList.getItem( i ) );
705 }
706 }
707
708 // Disable buttons in toolbars.
709 disableElementsInLists( this.mainContainer.find( 'ul[data-type=table-body]' ) );
710
711 // Disable buttons in toolbar groups.
712 disableElementsInLists( this.mainContainer.find( 'ul[data-type=table-body] > li > ul' ) );
713 };
714
715 /**
716 * @private
717 */
718 ToolbarModifier.prototype._refreshBtnTabIndexes = function() {
719 var tabindexed = this.mainContainer.find( '[data-tab="true"]' );
720
721 var max = tabindexed.count();
722 for ( var i = 0; i < max; i++ ) {
723 var item = tabindexed.getItem( i ),
724 disabled = item.hasClass( 'disabled' );
725
726 item.setAttribute( 'tabindex', disabled ? -1 : i );
727 }
728 };
729
730 /**
731 * Disable buttons to move elements up and down which should be disabled.
732 *
733 * @param {CKEDITOR.dom.element} ul
734 * @private
735 */
736 ToolbarModifier.prototype._disableElementsInList = function( ul ) {
737 var liList = ul.getChildren();
738
739 if ( !liList.count() )
740 return;
741
742 var firstDisabled, lastDisabled;
743 if ( this.emptyVisible ) {
744 firstDisabled = ul.getFirst();
745 lastDisabled = ul.getLast();
746 } else {
747 firstDisabled = ul.getFirst( isNotEmptyChecker );
748 lastDisabled = ul.getLast( isNotEmptyChecker );
749 }
750
751 function isNotEmptyChecker( element ) {
752 return !element.hasClass( 'empty' );
753 }
754
755 if ( firstDisabled )
756 var firstDisabledBtn = firstDisabled.findOne( 'p button[data-direction="up"]' );
757
758 if ( lastDisabled )
759 var lastDisabledBtn = lastDisabled.findOne( 'p button[data-direction="down"]' );
760
761 if ( firstDisabledBtn ) {
762 firstDisabledBtn.addClass( 'disabled' );
763 firstDisabledBtn.setAttribute( 'tabindex', '-1' );
764 }
765
766 if ( lastDisabledBtn ) {
767 lastDisabledBtn.addClass( 'disabled' );
768 lastDisabledBtn.setAttribute( 'tabindex', '-1' );
769 }
770 };
771
772 /**
773 * Gets group index in actual config toolbarGroups
774 *
775 * @param {String} name
776 * @returns {Number}
777 */
778 ToolbarModifier.prototype.getGroupIndex = function( name ) {
779 var groups = this.actualConfig.toolbarGroups;
780
781 var max = groups.length;
782 for ( var i = 0; i < max; i += 1 ) {
783 if ( groups[ i ].name === name )
784 return i;
785 }
786
787 return -1;
788 };
789
790 /**
791 * Handle adding separator.
792 *
793 * @private
794 */
795 ToolbarModifier.prototype._addSeparator = function() {
796 var separatorIndex = this._determineSeparatorToAddIndex(),
797 separator = ToolbarModifier.createSeparatorLiteral(),
798 domSeparator = CKEDITOR.dom.element.createFromHtml( ToolbarModifier.getToolbarSeparatorString( separator ) );
799
800 this.actualConfig.toolbarGroups.splice( separatorIndex, 0, separator );
801
802 domSeparator.insertBefore( this.modifyContainer.findOne( 'ul[data-type=table-body]' ).getChild( separatorIndex ) );
803
804 this._setActiveElement( 'separator', separator.name );
805 this._refreshMoveBtnsAvalibility();
806 this._refreshBtnTabIndexes();
807 this._refreshEditor();
808 };
809
810 /**
811 * Handle removing separator.
812 *
813 * @param {String} name
814 */
815 ToolbarModifier.prototype._removeSeparator = function( name ) {
816 var separatorIndex = CKEDITOR.tools.indexOf( this.actualConfig.toolbarGroups, function( group ) {
817 return group.type == 'separator' && group.name == name;
818 } );
819
820 this.actualConfig.toolbarGroups.splice( separatorIndex, 1 );
821
822 this._refreshMoveBtnsAvalibility();
823 this._refreshBtnTabIndexes();
824 this._refreshEditor();
825 };
826
827 /**
828 * Determine index where separator should be added, based on currently selected element.
829 *
830 * @returns {Number}
831 * @private
832 */
833 ToolbarModifier.prototype._determineSeparatorToAddIndex = function() {
834 if ( !this.currentActive )
835 return 0;
836
837 var groupLi;
838 if ( this.currentActive.elem.data( 'type' ) == 'group' || this.currentActive.elem.data( 'type' ) == 'separator' )
839 groupLi = this.currentActive.elem;
840 else
841 groupLi = this.currentActive.elem.getAscendant( 'li' );
842
843 return groupLi.getIndex();
844 };
845
846 /**
847 * @param {Array} elementsArray
848 * @param {Number} elementIndex
849 * @param {String} direction
850 * @returns {Number}
851 * @private
852 */
853 ToolbarModifier.prototype._moveElement = function( elementsArray, elementIndex, direction ) {
854 var nextIndex;
855
856 if ( this.emptyVisible )
857 nextIndex = ( direction == 'down' ? elementIndex + 1 : elementIndex - 1 );
858 else {
859 // When empty elements are not visible, there is need to skip them.
860 nextIndex = ToolbarModifier.getFirstElementIndexWith( elementsArray, elementIndex, direction, isEmptyOrSeparatorChecker );
861 }
862
863 function isEmptyOrSeparatorChecker( element ) {
864 return element.totalBtns || element.type == 'separator';
865 }
866
867 var offset = nextIndex - elementIndex;
868
869 return ToolbarModifier.moveTo( offset, elementsArray, elementIndex );
870 };
871
872 /**
873 * Moves group located in config level up or down and refresh editor.
874 *
875 * @param {String} direction
876 * @param {String} groupName
877 * @returns {Number}
878 */
879 ToolbarModifier.prototype._moveGroup = function( direction, groupName ) {
880 var groupIndex = this.getGroupIndex( groupName ),
881 groups = this.actualConfig.toolbarGroups,
882 newIndex = this._moveElement( groups, groupIndex, direction );
883
884 this._refreshMoveBtnsAvalibility();
885 this._refreshBtnTabIndexes();
886 this._refreshEditor();
887
888 return newIndex;
889 };
890
891 /**
892 * Moves subgroup located in config level up or down and refresh editor.
893 *
894 * @param {String} direction
895 * @param {String} groupName
896 * @param {String} subgroupName
897 * @private
898 */
899 ToolbarModifier.prototype._moveSubgroup = function( direction, groupName, subgroupName ) {
900 var groupIndex = this.getGroupIndex( groupName ),
901 groups = this.actualConfig.toolbarGroups,
902 group = groups[ groupIndex ],
903 subgroupIndex = CKEDITOR.tools.indexOf( group.groups, function( subgroup ) {
904 return subgroup.name == subgroupName;
905 } ),
906 newIndex = this._moveElement( group.groups, subgroupIndex, direction );
907
908 this._refreshEditor();
909
910 return newIndex;
911 };
912
913 /**
914 * Set `totalBtns` property in `actualConfig.toolbarGroups` elements.
915 *
916 * @private
917 */
918 ToolbarModifier.prototype._calculateTotalBtns = function() {
919 var groups = this.actualConfig.toolbarGroups;
920
921 var i = groups.length;
922 // from the end
923 while ( i-- ) {
924 var currentGroup = groups[ i ],
925 totalBtns = ToolbarModifier.getTotalGroupButtonsNumber( currentGroup, this.fullToolbarEditor );
926
927 if ( currentGroup.type == 'separator' ) {
928 // nothing to do with separator
929 continue;
930 }
931
932 currentGroup.totalBtns = totalBtns;
933 }
934 };
935
936 /**
937 * Add button to removeButtons field in config and refresh editor.
938 *
939 * @param {String} buttonName
940 * @private
941 */
942 ToolbarModifier.prototype._addButtonToRemoved = function( buttonName ) {
943 if ( CKEDITOR.tools.indexOf( this.removedButtons, buttonName ) != -1 )
944 throw 'Button already added to removed';
945
946 this.removedButtons.push( buttonName );
947 this.actualConfig.removeButtons = this.removedButtons.join( ',' );
948 this._refreshEditor();
949 };
950
951 /**
952 * Remove button from removeButtons field in config and refresh editor.
953 *
954 * @param {String} buttonName
955 * @private
956 */
957 ToolbarModifier.prototype._removeButtonFromRemoved = function( buttonName ) {
958 var foundAtIndex = CKEDITOR.tools.indexOf( this.removedButtons, buttonName );
959
960 if ( foundAtIndex === -1 )
961 throw 'Trying to remove button from removed, but not found';
962
963 this.removedButtons.splice( foundAtIndex, 1 );
964 this.actualConfig.removeButtons = this.removedButtons.join( ',' );
965 this._refreshEditor();
966 };
967
968 /**
969 * Parse group "model" to configuration value
970 *
971 * @param {Object} group
972 * @returns {Object}
973 * @static
974 */
975 ToolbarModifier.parseGroupToConfigValue = function( group ) {
976 if ( group.type == 'separator' ) {
977 return '/';
978 }
979
980 var groups = group.groups,
981 max = groups.length;
982
983 delete group.totalBtns;
984 for ( var i = 0; i < max; i += 1 ) {
985 groups[ i ] = groups[ i ].name;
986 }
987
988 return group;
989 };
990
991 /**
992 * Find closest Li ancestor in DOM tree which is group or separator element
993 *
994 * @param {CKEDITOR.dom.element} element
995 * @returns {CKEDITOR.dom.element}
996 * @static
997 */
998 ToolbarModifier.getGroupOrSeparatorLiAncestor = function( element ) {
999 if ( element.$ instanceof HTMLLIElement && element.data( 'type' ) == 'group' )
1000 return element;
1001 else {
1002 return ToolbarModifier.getFirstAncestor( element, function( ancestor ) {
1003 var type = ancestor.data( 'type' );
1004
1005 return ( type == 'group' || type == 'separator' );
1006 } );
1007 }
1008 };
1009
1010 /**
1011 * Create separator literal with unique id.
1012 *
1013 * @public
1014 * @static
1015 * @return {Object}
1016 */
1017 ToolbarModifier.createSeparatorLiteral = function() {
1018 return {
1019 type: 'separator',
1020 name: ( 'separator' + CKEDITOR.tools.getNextNumber() )
1021 };
1022 };
1023
1024 /**
1025 * Creates HTML unordered list string based on toolbarGroups field in config.
1026 *
1027 * @returns {String}
1028 * @static
1029 */
1030 ToolbarModifier.prototype._toolbarConfigToListString = function() {
1031 var groups = this.actualConfig.toolbarGroups || [],
1032 listString = '<ul data-type="table-body">';
1033
1034 var max = groups.length;
1035 for ( var i = 0; i < max; i += 1 ) {
1036 var currentGroup = groups[ i ];
1037
1038 if ( currentGroup.type === 'separator' )
1039 listString += ToolbarModifier.getToolbarSeparatorString( currentGroup );
1040 else
1041 listString += this._getToolbarGroupString( currentGroup );
1042 }
1043
1044 listString += '</ul>';
1045
1046 var headerString = ToolbarModifier.getToolbarHeaderString();
1047
1048 return headerString + listString;
1049 };
1050
1051 /**
1052 * Created HTML group list element based on group field in config.
1053 *
1054 * @param {Object} group
1055 * @returns {String}
1056 * @private
1057 */
1058 ToolbarModifier.prototype._getToolbarGroupString = function( group ) {
1059 var subgroups = group.groups,
1060 groupString = '';
1061
1062 groupString += [
1063 '<li ',
1064 'data-type="group" ',
1065 'data-name="', group.name, '" ',
1066 ( group.totalBtns ? '' : 'class="empty"' ),
1067 '>'
1068 ].join( '' );
1069 groupString += ToolbarModifier.getToolbarElementPreString( group ) + '<ul>';
1070
1071 var max = subgroups.length;
1072
1073 for ( var i = 0; i < max; i += 1 ) {
1074 var currentSubgroup = subgroups[ i ],
1075 subgroupBtns = this.fullToolbarEditor.buttonsByGroup[ currentSubgroup.name ];
1076
1077 groupString += this._getToolbarSubgroupString( currentSubgroup, subgroupBtns );
1078 }
1079 groupString += '</ul></li>';
1080
1081 return groupString;
1082 };
1083
1084 /**
1085 * @param {Object} separator
1086 * @returns {String}
1087 * @static
1088 */
1089 ToolbarModifier.getToolbarSeparatorString = function( separator ) {
1090 return [
1091 '<li ',
1092 'data-type="', separator.type , '" ',
1093 'data-name="', separator.name , '"',
1094 '>',
1095 ToolbarModifier.getToolbarElementPreString( 'row separator' ),
1096 '</li>'
1097 ].join( '' );
1098 };
1099
1100 /**
1101 * @returns {string}
1102 */
1103 ToolbarModifier.getToolbarHeaderString = function() {
1104 return '<ul data-type="table-header">' +
1105 '<li data-type="header">' +
1106 '<p>Toolbars</p>' +
1107 '<ul>' +
1108 '<li>' +
1109 '<p>Toolbar groups</p>' +
1110 '<p>Toolbar group items</p>' +
1111 '</li>' +
1112 '</ul>' +
1113 '</li>' +
1114 '</ul>';
1115 };
1116
1117 /**
1118 * Find and return first ancestor of element provided in first argument
1119 * which match the criteria checked in function provided in second argument.
1120 *
1121 * @param {CKEDITOR.dom.element} element
1122 * @param {Function} checker
1123 * @returns {CKEDITOR.dom.element|null}
1124 */
1125 ToolbarModifier.getFirstAncestor = function( element, checker ) {
1126 var ancestors = element.getParents(),
1127 i = ancestors.length;
1128
1129 while ( i-- ) {
1130 if ( checker( ancestors[ i ] ) )
1131 return ancestors[ i ];
1132 }
1133
1134 return null;
1135 };
1136
1137 /**
1138 * Looking through array elements start from index provided in second argument
1139 * and go 'up' or 'down' in array
1140 * last argument is condition checker which should return Boolean value
1141 *
1142 * User cases:
1143 *
1144 * ToolbarModifier.getFirstElementIndexWith( [3, 4, 8, 1, 4], 2, 'down', function( elem ) { return elem == 4; } ); // 4
1145 * ToolbarModifier.getFirstElementIndexWith( [3, 4, 8, 1, 4], 2, 'up', function( elem ) { return elem == 4; } ); // 1
1146 *
1147 * @param {Array} array
1148 * @param {Number} i
1149 * @param {String} direction 'up' or 'down'
1150 * @param {Function} conditionChecker
1151 * @static
1152 * @returns {Number} index of found element
1153 */
1154 ToolbarModifier.getFirstElementIndexWith = function( array, i, direction, conditionChecker ) {
1155 function whileChecker() {
1156 var result;
1157 if ( direction === 'up' )
1158 result = i--;
1159 else
1160 result = ( ++i < array.length );
1161
1162 return result;
1163 }
1164
1165 while ( whileChecker() ) {
1166 if ( conditionChecker( array[ i ] ) )
1167 return i;
1168
1169 }
1170
1171 return -1;
1172 };
1173
1174 /**
1175 * Moves array element at index level up or down.
1176 *
1177 * @static
1178 * @param {String} direction
1179 * @param {Array} array
1180 * @param {Number} index
1181 * @returns {Number}
1182 */
1183 ToolbarModifier.moveTo = function( offset, array, index ) {
1184 var element, newIndex;
1185
1186 if ( index !== -1 )
1187 element = array.splice( index, 1 )[ 0 ];
1188
1189 newIndex = index + offset;
1190
1191 array.splice( newIndex, 0, element );
1192
1193 return newIndex;
1194 };
1195
1196 /**
1197 * @static
1198 * @param {Object} subgroup
1199 * @returns {Number}
1200 */
1201 ToolbarModifier.getTotalSubGroupButtonsNumber = function( subgroup, fullToolbarEditor ) {
1202 var subgroupName = ( typeof subgroup == 'string' ? subgroup : subgroup.name ),
1203 subgroupBtns = fullToolbarEditor.buttonsByGroup[ subgroupName ];
1204
1205 return ( subgroupBtns ? subgroupBtns.length : 0 );
1206 };
1207
1208 /**
1209 * Returns all buttons number in group which are nested in subgroups also.
1210 *
1211 * @param {Object} group
1212 * @param {ToolbarModifier.FullToolbarEditor}
1213 * @static
1214 * @returns {Number}
1215 */
1216 ToolbarModifier.getTotalGroupButtonsNumber = function( group, fullToolbarEditor ) {
1217 var total = 0,
1218 subgroups = group.groups;
1219
1220 var max = subgroups ? subgroups.length : 0;
1221 for ( var i = 0; i < max; i += 1 )
1222 total += ToolbarModifier.getTotalSubGroupButtonsNumber( subgroups[ i ], fullToolbarEditor );
1223
1224 return total;
1225 };
1226
1227 /**
1228 * Creates HTML subgroup list element based on subgroup field in config.
1229 *
1230 * @param {Object} subgroup
1231 * @param {Array} groupBtns
1232 * @returns {String}
1233 * @private
1234 */
1235 ToolbarModifier.prototype._getToolbarSubgroupString = function( subgroup, groupBtns ) {
1236 var subgroupString = '';
1237
1238 subgroupString += [
1239 '<li ',
1240 'data-type="subgroup" ',
1241 'data-name="', subgroup.name, '" ',
1242 ( subgroup.totalBtns ? '' : 'class="empty" ' ),
1243 '>'
1244 ].join( '' );
1245 subgroupString += ToolbarModifier.getToolbarElementPreString( subgroup.name );
1246 subgroupString += '<ul>';
1247
1248 var max = groupBtns ? groupBtns.length : 0;
1249 for ( var i = 0; i < max; i += 1 )
1250 subgroupString += this.getButtonString( groupBtns[ i ] );
1251
1252 subgroupString += '</ul>';
1253
1254 subgroupString += '</li>';
1255
1256 return subgroupString;
1257 };
1258
1259 /**
1260 * @param {String} buttonName
1261 * @returns {String|null}
1262 * @private
1263 */
1264 ToolbarModifier.prototype._getConfigButtonName = function( buttonName ) {
1265 var items = this.fullToolbarEditor.editorInstance.ui.items;
1266
1267 var name;
1268 for ( name in items ) {
1269 if ( items[ name ].name == buttonName )
1270 return name;
1271 }
1272
1273 return null;
1274 };
1275
1276 /**
1277 * @param {String} buttonName
1278 * @returns {Boolean}
1279 */
1280 ToolbarModifier.prototype.isButtonRemoved = function( buttonName ) {
1281 return CKEDITOR.tools.indexOf( this.removedButtons, this._getConfigButtonName( buttonName ) ) != -1;
1282 };
1283
1284 /**
1285 * @param {CKEDITOR.ui.button/CKEDITOR.ui.richCombo} button
1286 * @returns {String}
1287 * @public
1288 */
1289 ToolbarModifier.prototype.getButtonString = function( button ) {
1290 var checked = ( this.isButtonRemoved( button.name ) ? '' : 'checked="checked"' );
1291
1292 return [
1293 '<li data-tab="true" data-type="button" data-name="', this._getConfigButtonName( button.name ), '">',
1294 '<label title="', button.label, '" >',
1295 '<input ',
1296 'tabindex="-1"',
1297 'type="checkbox"',
1298 checked,
1299 '/>',
1300 button.$.getOuterHtml(),
1301 '</label>',
1302 '</li>'
1303 ].join( '' );
1304 };
1305
1306 /**
1307 * Creates group header string.
1308 *
1309 * @param {Object|String} group
1310 * @returns {String}
1311 * @static
1312 */
1313 ToolbarModifier.getToolbarElementPreString = function( group ) {
1314 var name = ( group.name ? group.name : group );
1315
1316 return [
1317 '<p>',
1318 '<span>',
1319 '<button title="Move element upward" data-tab="true" data-direction="up" class="move icon-up-big"></button>',
1320 '<button title="Move element downward" data-tab="true" data-direction="down" class="move icon-down-big"></button>',
1321 ( name == 'row separator' ? '<button title="Remove element" data-tab="true" class="remove icon-trash"></button>' : '' ),
1322 name,
1323 '</span>',
1324 '</p>'
1325 ].join( '' );
1326 };
1327
1328 /**
1329 * @static
1330 * @param {String} cfg
1331 * @returns {String}
1332 */
1333 ToolbarModifier.evaluateToolbarGroupsConfig = function( cfg ) {
1334 cfg = ( function( cfg ) {
1335 var config = {}, result;
1336
1337 /*jshint -W002 */
1338 try {
1339 result = eval( '(' + cfg + ')' );
1340 } catch ( e ) {
1341 try {
1342 result = eval( cfg );
1343 } catch ( e ) {
1344 return null;
1345 }
1346 }
1347 /*jshint +W002 */
1348
1349 if ( config.toolbarGroups && typeof config.toolbarGroups.length === 'number' ) {
1350 return JSON.stringify( config );
1351 } else if ( result && typeof result.length === 'number' ) {
1352 return JSON.stringify( { toolbarGroups: result } );
1353 } else if ( result && result.toolbarGroups ) {
1354 return JSON.stringify( result );
1355 } else {
1356 return null;
1357 }
1358
1359 }( cfg ) );
1360
1361 return cfg;
1362 };
1363
1364 return ToolbarModifier;
1365} )();
1366
diff --git a/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js b/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js
new file mode 100644
index 0000000..4c14dd2
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js
@@ -0,0 +1,623 @@
1/* global CodeMirror, ToolbarConfigurator */
2
3'use strict';
4
5( function() {
6 var AbstractToolbarModifier = ToolbarConfigurator.AbstractToolbarModifier,
7 FullToolbarEditor = ToolbarConfigurator.FullToolbarEditor;
8
9 /**
10 * @class ToolbarConfigurator.ToolbarTextModifier
11 * @param {String} editorId An id of modified editor
12 * @extends AbstractToolbarModifier
13 * @constructor
14 */
15 function ToolbarTextModifier( editorId ) {
16 AbstractToolbarModifier.call( this, editorId );
17
18 this.codeContainer = null;
19 this.hintContainer = null;
20 }
21
22 // Expose the class.
23 ToolbarConfigurator.ToolbarTextModifier = ToolbarTextModifier;
24
25 ToolbarTextModifier.prototype = Object.create( AbstractToolbarModifier.prototype );
26
27 /**
28 * @param {Function} callback
29 * @param {String} [config]
30 * @private
31 */
32 ToolbarTextModifier.prototype._onInit = function( callback, config ) {
33 AbstractToolbarModifier.prototype._onInit.call( this, undefined, config );
34
35 this._createModifier( config ? this.actualConfig : undefined );
36
37 if ( typeof callback === 'function' )
38 callback( this.mainContainer );
39 };
40
41 /**
42 * Creates HTML main container of modifier.
43 *
44 * @param {String} cfg
45 * @returns {CKEDITOR.dom.element}
46 * @private
47 */
48 ToolbarTextModifier.prototype._createModifier = function( cfg ) {
49 var that = this;
50
51 this._createToolbar();
52
53 if ( this.toolbarContainer ) {
54 this.mainContainer.append( this.toolbarContainer );
55 }
56
57 AbstractToolbarModifier.prototype._createModifier.call( this );
58
59 this._setupActualConfig( cfg );
60
61 var toolbarCfg = this.actualConfig.toolbar,
62 cfgValue;
63
64 if ( CKEDITOR.tools.isArray( toolbarCfg ) ) {
65 var stringifiedToolbar = '[\n\t\t' + FullToolbarEditor.map( toolbarCfg, function( json ) {
66 return AbstractToolbarModifier.stringifyJSONintoOneLine( json, {
67 addSpaces: true,
68 noQuotesOnKey: true,
69 singleQuotes: true
70 } );
71 } ).join( ',\n\t\t' ) + '\n\t]';
72
73 cfgValue = '\tconfig.toolbar = ' + stringifiedToolbar + ';';
74 } else {
75 cfgValue = 'config.toolbar = [];';
76 }
77
78 cfgValue = [
79 'CKEDITOR.editorConfig = function( config ) {\n',
80 cfgValue,
81 '\n};'
82 ].join( '' );
83
84 function hint( cm ) {
85 var data = setupData( cm );
86
87 if ( data.charsBetween === null ) {
88 return;
89 }
90
91 var unused = that.getUnusedButtonsArray( that.actualConfig.toolbar, true, data.charsBetween ),
92 to = cm.getCursor(),
93 from = CodeMirror.Pos( to.line, ( to.ch - ( data.charsBetween.length ) ) ),
94 token = cm.getTokenAt( to ),
95 prevToken = cm.getTokenAt( { line: to.line, ch: token.start } );
96
97 // determine that we are at beginning of group,
98 // so first key is "name"
99 if ( prevToken.string === '{' )
100 unused = [ 'name' ];
101
102 // preventing close with special character and move cursor forward
103 // when no autocomplete
104 if ( unused.length === 0 )
105 return;
106
107 return new HintData( from, to, unused );
108 }
109
110 function HintData( from, to, list ) {
111 this.from = from;
112 this.to = to;
113 this.list = list;
114 this._handlers = [];
115 }
116
117 function setupData( cm, character ) {
118 var result = {};
119
120 result.cur = cm.getCursor();
121 result.tok = cm.getTokenAt( result.cur );
122
123 result[ 'char' ] = character || result.tok.string.charAt( result.tok.string.length - 1 );
124
125 // Getting string between begin of line and cursor.
126 var curLineTillCur = cm.getRange( CodeMirror.Pos( result.cur.line, 0 ), result.cur );
127
128 // Reverse string.
129 var currLineTillCurReversed = curLineTillCur.split( '' ).reverse().join( '' );
130
131 // Removing proper string definitions :
132 // FROM:
133 // R' ,'odeR' ,'odnU' [ :smeti{
134 // ^^^^^^ ^^^^^^
135 // TO:
136 // R' , [ :smeti{
137 currLineTillCurReversed = currLineTillCurReversed.replace( /(['|"]\w*['|"])/g, '' );
138
139 // Matching letters till ' or " character and end string char.
140 // R' , [ :smeti{
141 // ^
142 result.charsBetween = currLineTillCurReversed.match( /(^\w*)(['|"])/ );
143
144 if ( result.charsBetween ) {
145 result.endChar = result.charsBetween[ 2 ];
146
147 // And reverse string (bring to original state).
148 result.charsBetween = result.charsBetween[ 1 ].split( '' ).reverse().join( '' );
149 }
150
151 return result;
152 }
153
154 function complete( cm ) {
155 setTimeout( function() {
156 if ( !cm.state.completionActive ) {
157 CodeMirror.showHint( cm, hint, {
158 hintsClass: 'toolbar-modifier',
159 completeSingle: false
160 } );
161 }
162 }, 100 );
163
164 return CodeMirror.Pass;
165 }
166
167 var codeMirrorWrapper = new CKEDITOR.dom.element( 'div' );
168 codeMirrorWrapper.addClass( 'codemirror-wrapper' );
169 this.modifyContainer.append( codeMirrorWrapper );
170 this.codeContainer = CodeMirror( codeMirrorWrapper.$, {
171 mode: { name: 'javascript', json: true },
172 // For some reason (most likely CM's bug) gutter breaks CM's height.
173 // Refreshing CM does not help.
174 lineNumbers: false,
175 lineWrapping: true,
176 // Trick to make CM autogrow. http://codemirror.net/demo/resize.html
177 viewportMargin: Infinity,
178 value: cfgValue,
179 smartIndent: false,
180 indentWithTabs: true,
181 indentUnit: 4,
182 tabSize: 4,
183 theme: 'neo',
184 extraKeys: {
185 'Left': complete,
186 'Right': complete,
187 "'''": complete,
188 "'\"'": complete,
189 Backspace: complete,
190 Delete: complete,
191 'Shift-Tab': 'indentLess'
192 }
193 } );
194
195 this.codeContainer.on( 'endCompletion', function( cm, completionData ) {
196 var data = setupData( cm );
197
198 // preventing close with special character and move cursor forward
199 // when no autocomplete
200 if ( completionData === undefined )
201 return;
202
203 cm.replaceSelection( data.endChar );
204 } );
205
206 this.codeContainer.on( 'change', function() {
207 var value = that.codeContainer.getValue();
208
209 value = that._evaluateValue( value );
210
211 if ( value !== null ) {
212 that.actualConfig.toolbar = ( value.toolbar ? value.toolbar : that.actualConfig.toolbar );
213
214 that._fillHintByUnusedElements();
215 that._refreshEditor();
216
217 that.mainContainer.removeClass( 'invalid' );
218 } else {
219 that.mainContainer.addClass( 'invalid' );
220 }
221 } );
222
223 this.hintContainer = new CKEDITOR.dom.element( 'div' );
224 this.hintContainer.addClass( 'toolbarModifier-hints' );
225
226 this._fillHintByUnusedElements();
227 this.hintContainer.insertBefore( codeMirrorWrapper );
228 };
229
230 /**
231 * Create DOM string and set to hint container,
232 * show proper information when no unused element left.
233 *
234 * @private
235 */
236 ToolbarTextModifier.prototype._fillHintByUnusedElements = function() {
237 var unused = this.getUnusedButtonsArray( this.actualConfig.toolbar, true );
238 unused = this.groupButtonNamesByGroup( unused );
239
240 var unusedElements = FullToolbarEditor.map( unused, function( elem ) {
241 var buttonsList = FullToolbarEditor.map( elem.buttons, function( buttonName ) {
242 return '<code>' + buttonName + '</code> ';
243 } ).join( '' );
244
245 return [
246 '<dt>',
247 '<code>', elem.name, '</code>',
248 '</dt>',
249 '<dd>',
250 buttonsList,
251 '</dd>'
252 ].join( '' );
253 } ).join( ' ' );
254
255 var listHeader = [
256 '<dt class="list-header">Toolbar group</dt>',
257 '<dd class="list-header">Unused items</dd>'
258 ].join( '' );
259
260 var header = '<h3>Unused toolbar items</h3>';
261
262 if ( !unused.length ) {
263 listHeader = '<p>All items are in use.</p>';
264 }
265
266 this.codeContainer.refresh();
267
268 this.hintContainer.setHtml( header + '<dl>' + listHeader + unusedElements + '</dl>' );
269 };
270
271 /**
272 * @param {String} buttonName
273 * @returns {String}
274 */
275 ToolbarTextModifier.prototype.getToolbarGroupByButtonName = function( buttonName ) {
276 var buttonNames = this.fullToolbarEditor.buttonNamesByGroup;
277
278 for ( var groupName in buttonNames ) {
279 var buttons = buttonNames[ groupName ];
280
281 var i = buttons.length;
282 while ( i-- ) {
283 if ( buttonName === buttons[ i ] ) {
284 return groupName;
285 }
286 }
287
288 }
289
290 return null;
291 };
292
293 /**
294 * Filter all available toolbar elements by array of elements provided in first argument.
295 * Returns elements which are not used.
296 *
297 * @param {Object} toolbar
298 * @param {Boolean} [sorted=false]
299 * @param {String} prefix
300 * @returns {Array}
301 */
302 ToolbarTextModifier.prototype.getUnusedButtonsArray = function( toolbar, sorted, prefix ) {
303 sorted = ( sorted === true ? true : false );
304 var providedElements = ToolbarTextModifier.mapToolbarCfgToElementsList( toolbar ),
305 allElements = Object.keys( this.fullToolbarEditor.editorInstance.ui.items );
306
307 // get rid of "-" elements
308 allElements = FullToolbarEditor.filter( allElements, function( elem ) {
309 var isSeparator = ( elem === '-' ),
310 matchPrefix = ( prefix === undefined || elem.toLowerCase().indexOf( prefix.toLowerCase() ) === 0 );
311
312 return !isSeparator && matchPrefix;
313 } );
314
315 var elementsNotUsed = FullToolbarEditor.filter( allElements, function( elem ) {
316 return CKEDITOR.tools.indexOf( providedElements, elem ) == -1;
317 } );
318
319 if ( sorted )
320 elementsNotUsed.sort();
321
322 return elementsNotUsed;
323 };
324
325 /**
326 *
327 * @param {Array} buttons
328 * @returns {Array}
329 */
330 ToolbarTextModifier.prototype.groupButtonNamesByGroup = function( buttons ) {
331 var result = [],
332 groupedBtns = JSON.parse( JSON.stringify( this.fullToolbarEditor.buttonNamesByGroup ) );
333
334 for ( var groupName in groupedBtns ) {
335 var currGroup = groupedBtns[ groupName ];
336 currGroup = FullToolbarEditor.filter( currGroup, function( btnName ) {
337 return CKEDITOR.tools.indexOf( buttons, btnName ) !== -1;
338 } );
339
340 if ( currGroup.length ) {
341 result.push( {
342 name: groupName,
343 buttons: currGroup
344 } );
345 }
346
347 }
348
349 return result;
350 };
351
352 /**
353 * Map toolbar config value to flat items list.
354 *
355 * input:
356 * [
357 * { name: "basicstyles", items: ["Bold", "Italic"] },
358 * { name: "advancedstyles", items: ["Bold", "Outdent", "Indent"] }
359 * ]
360 *
361 * output:
362 * ["Bold", "Italic", "Outdent", "Indent"]
363 *
364 * @param {Object} toolbar
365 * @returns {Array}
366 */
367 ToolbarTextModifier.mapToolbarCfgToElementsList = function( toolbar ) {
368 var elements = [];
369
370 var max = toolbar.length;
371 for ( var i = 0; i < max; i += 1 ) {
372 if ( !toolbar[ i ] || typeof toolbar[ i ] === 'string' )
373 continue;
374
375 elements = elements.concat( FullToolbarEditor.filter( toolbar[ i ].items, checker ) );
376 }
377
378 function checker( elem ) {
379 return elem !== '-';
380 }
381
382 return elements;
383 };
384
385 /**
386 * @param {String} cfg
387 * @private
388 */
389 ToolbarTextModifier.prototype._setupActualConfig = function( cfg ) {
390 cfg = cfg || this.editorInstance.config;
391
392 // if toolbar already exists in config, there is nothing to do
393 if ( CKEDITOR.tools.isArray( cfg.toolbar ) )
394 return;
395
396 // if toolbar group not present, we need to pick them from full toolbar instance
397 if ( !cfg.toolbarGroups )
398 cfg.toolbarGroups = this.fullToolbarEditor.getFullToolbarGroupsConfig( true );
399
400 this._fixGroups( cfg );
401
402 cfg.toolbar = this._mapToolbarGroupsToToolbar( cfg.toolbarGroups, this.actualConfig.removeButtons );
403
404 this.actualConfig.toolbar = cfg.toolbar;
405 this.actualConfig.removeButtons = '';
406 };
407
408 /**
409 * **Please note:** This method modify element provided in first argument.
410 *
411 * @param {Array} toolbarGroups
412 * @returns {Array}
413 * @private
414 */
415 ToolbarTextModifier.prototype._mapToolbarGroupsToToolbar = function( toolbarGroups, removedBtns ) {
416 removedBtns = removedBtns || this.editorInstance.config.removedBtns;
417 removedBtns = typeof removedBtns == 'string' ? removedBtns.split( ',' ) : [];
418
419 // from the end, because array indexes may change
420 var i = toolbarGroups.length;
421 while ( i-- ) {
422 var mappedSubgroup = this._mapToolbarSubgroup( toolbarGroups[ i ], removedBtns );
423
424 if ( toolbarGroups[ i ].type === 'separator' ) {
425 toolbarGroups[ i ] = '/';
426 continue;
427 }
428
429 // don't want empty groups
430 if ( CKEDITOR.tools.isArray( mappedSubgroup ) && mappedSubgroup.length === 0 ) {
431 toolbarGroups.splice( i, 1 );
432 continue;
433 }
434
435 if ( typeof mappedSubgroup == 'string' )
436 toolbarGroups[ i ] = mappedSubgroup;
437 else {
438 toolbarGroups[ i ] = {
439 name: toolbarGroups[ i ].name,
440 items: mappedSubgroup
441 };
442 }
443 }
444
445 return toolbarGroups;
446 };
447
448 /**
449 *
450 * @param {String|Object} group
451 * @param {Array} removedBtns
452 * @returns {Array}
453 * @private
454 */
455 ToolbarTextModifier.prototype._mapToolbarSubgroup = function( group, removedBtns ) {
456 var totalBtns = 0;
457 if ( typeof group == 'string' )
458 return group;
459
460 var max = group.groups ? group.groups.length : 0,
461 result = [];
462 for ( var i = 0; i < max; i += 1 ) {
463 var currSubgroup = group.groups[ i ];
464
465 var buttons = this.fullToolbarEditor.buttonsByGroup[ typeof currSubgroup === 'string' ? currSubgroup : currSubgroup.name ] || [];
466 buttons = this._mapButtonsToButtonsNames( buttons, removedBtns );
467 var currTotalBtns = buttons.length;
468 totalBtns += currTotalBtns;
469 result = result.concat( buttons );
470
471 if ( currTotalBtns )
472 result.push( '-' );
473 }
474
475 if ( result[ result.length - 1 ] == '-' )
476 result.pop();
477
478 return result;
479 };
480
481 /**
482 *
483 * @param {Array} buttons
484 * @param {Array} removedBtns
485 * @returns {Array}
486 * @private
487 */
488 ToolbarTextModifier.prototype._mapButtonsToButtonsNames = function( buttons, removedBtns ) {
489 var i = buttons.length;
490 while ( i-- ) {
491 var currBtn = buttons[ i ],
492 camelCasedName;
493
494 if ( typeof currBtn === 'string' ) {
495 camelCasedName = currBtn;
496 } else {
497 camelCasedName = this.fullToolbarEditor.getCamelCasedButtonName( currBtn.name );
498 }
499
500 if ( CKEDITOR.tools.indexOf( removedBtns, camelCasedName ) !== -1 ) {
501 buttons.splice( i, 1 );
502 continue;
503 }
504
505 buttons[ i ] = camelCasedName;
506 }
507
508 return buttons;
509 };
510
511 /**
512 * @param {String} val
513 * @returns {Object}
514 * @private
515 */
516 ToolbarTextModifier.prototype._evaluateValue = function( val ) {
517 var parsed;
518
519 try {
520 var config = {};
521 ( function() {
522 var CKEDITOR = Function( 'var CKEDITOR = {}; ' + val + '; return CKEDITOR;' )();
523
524 CKEDITOR.editorConfig( config );
525 parsed = config;
526 } )();
527
528 // CKEditor does not handle empty arrays in configuration files
529 // on IE8
530 var i = parsed.toolbar.length;
531 while ( i-- )
532 if ( !parsed.toolbar[ i ] ) parsed.toolbar.splice( i, 1 );
533
534 } catch ( e ) {
535 parsed = null;
536 }
537
538 return parsed;
539 };
540
541 /**
542 * @param {Array} toolbar
543 * @returns {{toolbarGroups: Array, removeButtons: string}}
544 */
545 ToolbarTextModifier.prototype.mapToolbarToToolbarGroups = function( toolbar ) {
546 var usedGroups = {},
547 removeButtons = [],
548 toolbarGroups = [];
549
550 var max = toolbar.length;
551 for ( var i = 0; i < max; i++ ) {
552 if ( toolbar[ i ] === '/' ) {
553 toolbarGroups.push( '/' );
554 continue;
555 }
556
557 var items = toolbar[ i ].items;
558
559 var toolbarGroup = {};
560 toolbarGroup.name = toolbar[ i ].name;
561 toolbarGroup.groups = [];
562
563 var max2 = items.length;
564 for ( var j = 0; j < max2; j++ ) {
565 var item = items[ j ];
566
567 if ( item === '-' ) {
568 continue;
569 }
570
571 var groupName = this.getToolbarGroupByButtonName( item );
572
573 var groupIndex = toolbarGroup.groups.indexOf( groupName );
574 if ( groupIndex === -1 ) {
575 toolbarGroup.groups.push( groupName );
576 }
577
578 usedGroups[ groupName ] = usedGroups[ groupName ] || {};
579
580 var buttons = ( usedGroups[ groupName ].buttons = usedGroups[ groupName ].buttons || {} );
581
582 buttons[ item ] = buttons[ item ] || { used: 0, origin: toolbarGroup.name };
583 buttons[ item ].used++;
584 }
585
586 toolbarGroups.push( toolbarGroup );
587 }
588
589 // Handling removed buttons
590 removeButtons = prepareRemovedButtons( usedGroups, this.fullToolbarEditor.buttonNamesByGroup );
591
592 function prepareRemovedButtons( usedGroups, buttonNames ) {
593 var removed = [];
594
595 for ( var groupName in usedGroups ) {
596 var group = usedGroups[ groupName ];
597 var allButtonsInGroup = buttonNames[ groupName ].slice();
598
599 removed = removed.concat( removeStuffFromArray( allButtonsInGroup, Object.keys( group.buttons ) ) );
600 }
601
602 return removed;
603 }
604
605 function removeStuffFromArray( array, stuff ) {
606 array = array.slice();
607 var i = stuff.length;
608
609 while ( i-- ) {
610 var atIndex = array.indexOf( stuff[ i ] );
611 if ( atIndex !== -1 ) {
612 array.splice( atIndex, 1 );
613 }
614 }
615
616 return array;
617 }
618
619 return { toolbarGroups: toolbarGroups, removeButtons: removeButtons.join( ',' ) };
620 };
621
622 return ToolbarTextModifier;
623} )();
diff --git a/sources/samples/toolbarconfigurator/less/base.less b/sources/samples/toolbarconfigurator/less/base.less
new file mode 100644
index 0000000..0a212ff
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/less/base.less
@@ -0,0 +1,38 @@
1// Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
2// For licensing, see LICENSE.html or http://cksource.com/ckeditor/license
3
4@base-font-size: 16px;
5@base-line-height: 24px;
6@base-line-ratio: 1.8;
7
8@sample-font-stack: Arial, Helvetica, sans-serif;
9@sample-font-stack-monospace: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
10@sample-font-maven: "Maven Pro";
11@sample-font-indie: "Indie Flower";
12@sample-text-color: #575757;
13
14@sample-link-color: #cf5d4e;
15@sample-link-color-hover: lighten( @sample-link-color, -10% );
16
17@sample-box-background-color: #f5f5f5;
18@sample-box-border-color: #ddd;
19
20@sample-top-navigation-background: #454545;
21
22// Standard gaps
23@sample-standard-vgap: 1.2em;
24@sample-standard-hgap: 1.5em;
25
26// Generic font-size/line-height mixin.
27.font-size( @remSize ) {
28 @pxSize: round( @remSize * @base-font-size, 2 );
29
30 @remHeight: round( @remSize * @base-line-ratio, 2 );
31 @pxHeight: round( @pxSize * @base-line-ratio, 2 );
32
33 font-size: ~"@{pxSize}";
34 font-size: ~"@{remSize}rem";
35
36 line-height: ~"@{pxHeight}";
37 line-height: ~"@{remHeight}rem";
38}
diff --git a/sources/samples/toolbarconfigurator/less/toolbarmodifier.less b/sources/samples/toolbarconfigurator/less/toolbarmodifier.less
new file mode 100644
index 0000000..8aa5d08
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/less/toolbarmodifier.less
@@ -0,0 +1,508 @@
1// Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
2// For licensing, see LICENSE.html or http://cksource.com/ckeditor/license
3
4@import "base.less";
5
6@modifier-group-hover-color: #fffbe3;
7@modifier-group-active-color: #f0fafb;
8
9@modifier-active-toolbar-color: darken( @modifier-group-hover-color, 10% );
10
11@modifier-toolbar-border-color: #ccc;
12@modifier-toolbar-group-border-color: #ddd;
13@modifier-toolbar-group-vpadding: 2px;
14@modifier-toolbar-hgap: 5px;
15
16@modifier-toolbar-button-color: #e7e7e7;
17
18#toolbar .cke_toolbar {
19 pointer-events: none;
20 .user-select( none );
21 cursor: default;
22}
23
24// Dim all but active toolbars if some is active.
25.some-toolbar-active .cke_toolbar {
26 .opacity( .5 );
27}
28
29.cke_toolbar.active {
30 position: relative;
31
32 // Active toolbar is always highlighted.
33 .opacity( 1 );
34
35 &:after {
36 content: '';
37 display: block;
38 position: absolute;
39 top: 0;
40 right: 6px;
41 bottom: 5px;
42 left: 0;
43 .border-radius( 5px );
44 .box-shadow( 0px 0px 15px 3px @modifier-active-toolbar-color );
45 }
46
47 .cke_toolgroup {
48 .box-shadow( none );
49 border-color: darken( @modifier-active-toolbar-color, 40% );
50 }
51
52 .cke_combo,
53 .cke_toolgroup {
54 position: relative;
55 z-index: 2;
56 }
57
58 .cke_combo_button {
59 .box-shadow( none );
60 }
61}
62
63.unselectable {
64 .user-select( none );
65}
66.toolbar {
67 padding: 5px 0;
68 margin-bottom: 2 * @sample-standard-vgap;
69 overflow: hidden;
70 background: #fff;
71
72 button.button-a {
73 &.cke_button {
74 cursor: pointer;
75
76 display: inline-block;
77 padding: 4px 6px;
78 outline: 0;
79 border: 1px solid #a6a6a6;
80 }
81
82 &.hidden {
83 display: none;
84 }
85
86 &.left {
87 float: left;
88 margin-right: 8px;
89 }
90
91 &.right {
92 float: right;
93 margin-left: 8px;
94 }
95
96 .highlight {
97 color: #ffefc1;
98 }
99 }
100}
101
102// Styles applied when configurator is hidden and code is being displayed (and vice-versa).
103.configContainer.hidden,
104.toolbarModifier.hidden,
105.toolbarModifier-hints.hidden {
106 display: none;
107}
108
109.toolbarModifier :focus,
110.toolbar button:focus,
111.configContainer textarea.configCode:focus {
112 outline: none;
113}
114
115div.toolbarModifier {
116 padding: 0;
117 overflow: hidden;
118 width: 100%;
119 position: relative;
120 display: table;
121 border-collapse: collapse;
122
123 ::-moz-focus-inner {
124 border: 0;
125 }
126
127 .empty {
128 display: none;
129 }
130
131 &.empty-visible .empty {
132 display: table-row;
133 .opacity( 0.6 );
134 }
135
136 // Give empty toolbar groups height similar to height of non empty groups.
137 // Non empty groups are stretched by contained toolbar buttons.
138 .empty > p {
139 line-height: 31px;
140 }
141
142 // List of toolbars.
143 & > ul {
144 padding: 0;
145 margin: 0;
146 border-top: 1px solid @modifier-toolbar-border-color;
147 width: 100%;
148
149 &[data-type="table-header"] {
150 display: table-header-group;
151 }
152
153 &[data-type="table-body"] {
154 display: table-row-group;
155 }
156
157 // Override global margins and paddings.
158 p {
159 padding: 0;
160 margin: 0;
161 }
162
163 // A single toolbar.
164 & > li {
165 display: table-row;
166
167 &[data-type="header"] {
168 font-weight: bold;
169 user-select: none;
170 cursor: default;
171 }
172
173 &[data-type="group"],
174 &[data-type="separator"] {
175 border-bottom: 1px solid @modifier-toolbar-border-color;
176 }
177
178 &[data-type="subgroup"] {
179 border-top: 1px solid #eee;
180
181 &:first-child {
182 border-top: none;
183 }
184 }
185
186 &[data-type="group"].active,
187 &[data-type="group"]:hover,
188 &[data-type="separator"].active,
189 &[data-type="separator"]:hover {
190 overflow: hidden;
191 z-index: 2;
192 }
193
194 &[data-type="group"].active,
195 &[data-type="separator"].active,
196 &[data-type="group"].active:hover,
197 &[data-type="separator"].active:hover {
198 background: @modifier-group-active-color;
199 }
200
201 &[data-type="group"]:hover,
202 &[data-type="separator"]:hover {
203 background: @modifier-group-hover-color;
204 }
205
206 &[data-type="separator"] {
207 &:after {
208 content: '';
209 width: 100%;
210 }
211
212 background: #f5f5f5;
213
214 & > p {
215 padding: @modifier-toolbar-group-vpadding @modifier-toolbar-hgap;
216 }
217 }
218
219 & > p, & > ul {
220 display: table-cell;
221 vertical-align: middle;
222 }
223
224 // Note: this also controls the list of toolbar groups.
225 p {
226 padding-left: @modifier-toolbar-hgap;
227 min-width: 200px;
228
229 span {
230 white-space: nowrap;
231 cursor: default;
232
233 button {
234 font-size: 12.666px;
235 margin-right: 5px;
236 cursor: pointer;
237 background: #fff;
238 .border-radius( 5px );
239 border: 1px solid #bbb;
240 padding: 0 7px;
241 line-height: 12px;
242 height: 20px;
243
244 &:not(.disabled) {
245 &:hover,
246 &:focus {
247 color: #fff;
248 background-color: @sample-top-navigation-background;
249 border-color: transparent;
250 }
251 }
252
253 &.move.disabled {
254 cursor: default;
255 .opacity( 0.2 );
256 }
257 }
258 }
259 }
260
261 // List of toolbar groups.
262 ul {
263 border-collapse: collapse;
264 padding: 0;
265 width: 100%;
266
267 // A single toolbar group.
268 li {
269 display: table-row;
270 list-style-type: none;
271 // Resets slightly increased lists' lh which is bigger than button's height
272 // so it stretches columns.
273 line-height: 1;
274
275 &[data-type="subgroup"] {
276 border-top: 1px solid @modifier-toolbar-group-border-color;
277
278 &:first-child {
279 border-top: 0;
280 }
281
282 [data-type="button"] {
283 .border-radius( 3px );
284 padding: 0 2px;
285
286 &:focus {
287 background: rgba(0, 0, 0, 0.04);
288 }
289
290 input {
291 vertical-align: middle;
292 }
293 }
294 }
295
296 & > p, & > ul {
297 display: table-cell;
298 vertical-align: middle;
299 }
300
301 // List of buttons in a group.
302 ul {
303 padding: 0;
304
305 // A single button in a group.
306 li {
307 padding: 0;
308 display: inline-block;
309 cursor: pointer;
310 margin: @modifier-toolbar-group-vpadding 5px @modifier-toolbar-group-vpadding 0;
311
312 // Enforce styles to save space.
313 .cke_combo_text {
314 cursor: pointer;
315 white-space: nowrap;
316 }
317
318 .cke_toolgroup,
319 .cke_combo_button {
320 cursor: pointer;
321 margin: 0;
322 vertical-align: middle;
323 border: 1px solid #ddd;
324 .font-size( .713 );
325 }
326 }
327 }
328 }
329 }
330 }
331 }
332
333 & > .codemirror-wrapper {
334 overflow-y: auto;
335 }
336
337 // Advanced configurator: list of unused elements.
338 &-hints {
339 float: right;
340 width: 350px;
341 min-width: 150px;
342 overflow-y: auto;
343 margin-left: @sample-standard-hgap;
344
345 h3 {
346 .font-size( 1.13 );
347 padding: .3*@sample-standard-vgap @sample-standard-hgap;
348 background: @sample-box-background-color;
349 border-bottom: 1px solid @sample-box-border-color;
350 margin-top: 0;
351 margin-bottom: @sample-standard-vgap;
352 }
353
354 dl {
355 //margin-top: 0;
356 margin-bottom: @sample-standard-vgap;
357 overflow: hidden;
358
359 .list-header {
360 font-weight: bold;
361 border: 0;
362 padding-bottom: .5*@sample-standard-vgap;
363 }
364
365 & > p {
366 text-align: center;
367 }
368
369 dt {
370 float: left;
371 width: 9em;
372 clear: both;
373 text-align: right;
374 border-top: 1px solid @sample-box-border-color;
375 padding-left: @sample-standard-hgap;
376 padding-right: .1em;
377 .box-sizing( border-box );
378
379 code {
380 background: none;
381 border: none;
382 vertical-align: middle;
383 }
384 }
385
386 dd {
387 margin-left: 10em;
388 clear: right;
389 padding-right: @sample-standard-hgap;
390
391 code {
392 line-height: 2.2em;
393 }
394
395 &:after {
396 content: '\00a0';
397 display: block;
398 clear: left;
399 float: right;
400 height: 0;
401 width: 0;
402 }
403 }
404 }
405 }
406}
407
408.toolbarModifier-hints,
409.configContainer textarea.configCode,
410.CodeMirror {
411 .border-radius( 3px );
412 border: 1px solid #ccc;
413 .font-size( .813 );
414}
415
416.configContainer textarea.configCode,
417.CodeMirror pre,
418.CodeMirror-linenumber {
419 .font-size( .813 );
420 font-family: @sample-font-stack-monospace;
421}
422
423.CodeMirror pre {
424 border: none;
425 padding: 0;
426 margin: 0;
427}
428
429.configContainer textarea.configCode {
430 .box-sizing( border-box );
431 color: @sample-text-color;
432 padding: 10px;
433 width: 100%;
434 min-height: 500px;
435 margin: 0;
436 resize: none;
437 outline: none;
438 -moz-tab-size: 4;
439 tab-size: 4;
440 white-space: pre;
441 word-wrap: normal;
442 overflow: auto;
443}
444
445.CodeMirror-hints.toolbar-modifier {
446 padding: 0;
447 color: @sample-text-color;
448
449 .CodeMirror-hint-active {
450 color: @sample-text-color;
451 background: @modifier-group-active-color;
452 }
453
454 .font-size( .875 );
455 font-family: @sample-font-stack-monospace;
456
457 & > li:hover {
458 background: @modifier-group-hover-color;
459 }
460}
461
462/* Text modifier */
463#toolbarModifierWrapper {
464 margin-bottom: @sample-standard-vgap;
465
466 .invalid .CodeMirror {
467 background: #fff8f8;
468 border-color: red;
469 }
470
471 .CodeMirror {
472 // Autogrow. http://codemirror.net/demo/resize.html
473 height: auto;
474 // Complementory with std's CodeMirror-lines vertical padding.
475 // Not needed when we use lines number, but we can't due to a bug in CM.
476 padding: 0 @sample-standard-vgap/2;
477 }
478}
479
480.staticContainer {
481 position: fixed;
482 top: 0;
483 width: 100%;
484 z-index: 10;
485
486 > .grid-container {
487 max-width: 1044px + 2 * @grid-gutter-width;
488
489 .inner {
490 background: #fff;
491
492 .toolbar {
493 margin-bottom: 0;
494 }
495 }
496 }
497}
498
499// Help button to display information about configurator.
500#help {
501 position: relative;
502 top: -15px;
503 left: -5px;
504
505 &-content {
506 display: none;
507 }
508}
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/LICENSE b/sources/samples/toolbarconfigurator/lib/codemirror/LICENSE
new file mode 100644
index 0000000..d21bbea
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/LICENSE
@@ -0,0 +1,19 @@
1Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/README.md b/sources/samples/toolbarconfigurator/lib/codemirror/README.md
new file mode 100644
index 0000000..38156a7
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/README.md
@@ -0,0 +1,12 @@
1# CodeMirror
2[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
3[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
4[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?again)](https://marijnhaverbeke.nl/fund/)
5
6CodeMirror is a JavaScript component that provides a code editor in
7the browser. When a mode is available for the language you are coding
8in, it will color your code, and optionally help with indentation.
9
10The project page is http://codemirror.net
11The manual is at http://codemirror.net/doc/manual.html
12The contributing guidelines are in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.css b/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.css
new file mode 100644
index 0000000..ceacd13
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.css
@@ -0,0 +1,325 @@
1/* BASICS */
2
3.CodeMirror {
4 /* Set height, width, borders, and global font properties here */
5 font-family: monospace;
6 height: 300px;
7 color: black;
8}
9
10/* PADDING */
11
12.CodeMirror-lines {
13 padding: 4px 0; /* Vertical padding around content */
14}
15.CodeMirror pre {
16 padding: 0 4px; /* Horizontal padding of content */
17}
18
19.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
20 background-color: white; /* The little square between H and V scrollbars */
21}
22
23/* GUTTER */
24
25.CodeMirror-gutters {
26 border-right: 1px solid #ddd;
27 background-color: #f7f7f7;
28 white-space: nowrap;
29}
30.CodeMirror-linenumbers {}
31.CodeMirror-linenumber {
32 padding: 0 3px 0 5px;
33 min-width: 20px;
34 text-align: right;
35 color: #999;
36 white-space: nowrap;
37}
38
39.CodeMirror-guttermarker { color: black; }
40.CodeMirror-guttermarker-subtle { color: #999; }
41
42/* CURSOR */
43
44.CodeMirror div.CodeMirror-cursor {
45 border-left: 1px solid black;
46}
47/* Shown when moving in bi-directional text */
48.CodeMirror div.CodeMirror-secondarycursor {
49 border-left: 1px solid silver;
50}
51.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
52 width: auto;
53 border: 0;
54 background: #7e7;
55}
56.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
57 z-index: 1;
58}
59
60.cm-animate-fat-cursor {
61 width: auto;
62 border: 0;
63 -webkit-animation: blink 1.06s steps(1) infinite;
64 -moz-animation: blink 1.06s steps(1) infinite;
65 animation: blink 1.06s steps(1) infinite;
66}
67@-moz-keyframes blink {
68 0% { background: #7e7; }
69 50% { background: none; }
70 100% { background: #7e7; }
71}
72@-webkit-keyframes blink {
73 0% { background: #7e7; }
74 50% { background: none; }
75 100% { background: #7e7; }
76}
77@keyframes blink {
78 0% { background: #7e7; }
79 50% { background: none; }
80 100% { background: #7e7; }
81}
82
83/* Can style cursor different in overwrite (non-insert) mode */
84div.CodeMirror-overwrite div.CodeMirror-cursor {}
85
86.cm-tab { display: inline-block; text-decoration: inherit; }
87
88.CodeMirror-ruler {
89 border-left: 1px solid #ccc;
90 position: absolute;
91}
92
93/* DEFAULT THEME */
94
95.cm-s-default .cm-keyword {color: #708;}
96.cm-s-default .cm-atom {color: #219;}
97.cm-s-default .cm-number {color: #164;}
98.cm-s-default .cm-def {color: #00f;}
99.cm-s-default .cm-variable,
100.cm-s-default .cm-punctuation,
101.cm-s-default .cm-property,
102.cm-s-default .cm-operator {}
103.cm-s-default .cm-variable-2 {color: #05a;}
104.cm-s-default .cm-variable-3 {color: #085;}
105.cm-s-default .cm-comment {color: #a50;}
106.cm-s-default .cm-string {color: #a11;}
107.cm-s-default .cm-string-2 {color: #f50;}
108.cm-s-default .cm-meta {color: #555;}
109.cm-s-default .cm-qualifier {color: #555;}
110.cm-s-default .cm-builtin {color: #30a;}
111.cm-s-default .cm-bracket {color: #997;}
112.cm-s-default .cm-tag {color: #170;}
113.cm-s-default .cm-attribute {color: #00c;}
114.cm-s-default .cm-header {color: blue;}
115.cm-s-default .cm-quote {color: #090;}
116.cm-s-default .cm-hr {color: #999;}
117.cm-s-default .cm-link {color: #00c;}
118
119.cm-negative {color: #d44;}
120.cm-positive {color: #292;}
121.cm-header, .cm-strong {font-weight: bold;}
122.cm-em {font-style: italic;}
123.cm-link {text-decoration: underline;}
124.cm-strikethrough {text-decoration: line-through;}
125
126.cm-s-default .cm-error {color: #f00;}
127.cm-invalidchar {color: #f00;}
128
129.CodeMirror-composing { border-bottom: 2px solid; }
130
131/* Default styles for common addons */
132
133div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
134div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
135.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
136.CodeMirror-activeline-background {background: #e8f2ff;}
137
138/* STOP */
139
140/* The rest of this file contains styles related to the mechanics of
141 the editor. You probably shouldn't touch them. */
142
143.CodeMirror {
144 position: relative;
145 overflow: hidden;
146 background: white;
147}
148
149.CodeMirror-scroll {
150 overflow: scroll !important; /* Things will break if this is overridden */
151 /* 30px is the magic margin used to hide the element's real scrollbars */
152 /* See overflow: hidden in .CodeMirror */
153 margin-bottom: -30px; margin-right: -30px;
154 padding-bottom: 30px;
155 height: 100%;
156 outline: none; /* Prevent dragging from highlighting the element */
157 position: relative;
158}
159.CodeMirror-sizer {
160 position: relative;
161 border-right: 30px solid transparent;
162}
163
164/* The fake, visible scrollbars. Used to force redraw during scrolling
165 before actuall scrolling happens, thus preventing shaking and
166 flickering artifacts. */
167.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
168 position: absolute;
169 z-index: 6;
170 display: none;
171}
172.CodeMirror-vscrollbar {
173 right: 0; top: 0;
174 overflow-x: hidden;
175 overflow-y: scroll;
176}
177.CodeMirror-hscrollbar {
178 bottom: 0; left: 0;
179 overflow-y: hidden;
180 overflow-x: scroll;
181}
182.CodeMirror-scrollbar-filler {
183 right: 0; bottom: 0;
184}
185.CodeMirror-gutter-filler {
186 left: 0; bottom: 0;
187}
188
189.CodeMirror-gutters {
190 position: absolute; left: 0; top: 0;
191 z-index: 3;
192}
193.CodeMirror-gutter {
194 white-space: normal;
195 height: 100%;
196 display: inline-block;
197 margin-bottom: -30px;
198 /* Hack to make IE7 behave */
199 *zoom:1;
200 *display:inline;
201}
202.CodeMirror-gutter-wrapper {
203 position: absolute;
204 z-index: 4;
205 height: 100%;
206}
207.CodeMirror-gutter-elt {
208 position: absolute;
209 cursor: default;
210 z-index: 4;
211}
212.CodeMirror-gutter-wrapper {
213 -webkit-user-select: none;
214 -moz-user-select: none;
215 user-select: none;
216}
217
218.CodeMirror-lines {
219 cursor: text;
220 min-height: 1px; /* prevents collapsing before first draw */
221}
222.CodeMirror pre {
223 /* Reset some styles that the rest of the page might have set */
224 -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
225 border-width: 0;
226 background: transparent;
227 font-family: inherit;
228 font-size: inherit;
229 margin: 0;
230 white-space: pre;
231 word-wrap: normal;
232 line-height: inherit;
233 color: inherit;
234 z-index: 2;
235 position: relative;
236 overflow: visible;
237 -webkit-tap-highlight-color: transparent;
238}
239.CodeMirror-wrap pre {
240 word-wrap: break-word;
241 white-space: pre-wrap;
242 word-break: normal;
243}
244
245.CodeMirror-linebackground {
246 position: absolute;
247 left: 0; right: 0; top: 0; bottom: 0;
248 z-index: 0;
249}
250
251.CodeMirror-linewidget {
252 position: relative;
253 z-index: 2;
254 overflow: auto;
255}
256
257.CodeMirror-widget {}
258
259.CodeMirror-code {
260 outline: none;
261}
262
263/* Force content-box sizing for the elements where we expect it */
264.CodeMirror-scroll,
265.CodeMirror-sizer,
266.CodeMirror-gutter,
267.CodeMirror-gutters,
268.CodeMirror-linenumber {
269 -moz-box-sizing: content-box;
270 box-sizing: content-box;
271}
272
273.CodeMirror-measure {
274 position: absolute;
275 width: 100%;
276 height: 0;
277 overflow: hidden;
278 visibility: hidden;
279}
280.CodeMirror-measure pre { position: static; }
281
282.CodeMirror div.CodeMirror-cursor {
283 position: absolute;
284 border-right: none;
285 width: 0;
286}
287
288div.CodeMirror-cursors {
289 visibility: hidden;
290 position: relative;
291 z-index: 3;
292}
293.CodeMirror-focused div.CodeMirror-cursors {
294 visibility: visible;
295}
296
297.CodeMirror-selected { background: #d9d9d9; }
298.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
299.CodeMirror-crosshair { cursor: crosshair; }
300.CodeMirror ::selection { background: #d7d4f0; }
301.CodeMirror ::-moz-selection { background: #d7d4f0; }
302
303.cm-searching {
304 background: #ffa;
305 background: rgba(255, 255, 0, .4);
306}
307
308/* IE7 hack to prevent it from returning funny offsetTops on the spans */
309.CodeMirror span { *vertical-align: text-bottom; }
310
311/* Used to force a border model for a node */
312.cm-force-border { padding-right: .1px; }
313
314@media print {
315 /* Hide the cursor when printing */
316 .CodeMirror div.CodeMirror-cursors {
317 visibility: hidden;
318 }
319}
320
321/* See issue #2901 */
322.cm-tab-wrap-hack:after { content: ''; }
323
324/* Help users use markselection to safely style text background */
325span.CodeMirror-selectedtext { background: none; }
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.js b/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.js
new file mode 100644
index 0000000..37e2685
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/codemirror.js
@@ -0,0 +1,8738 @@
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4// This is CodeMirror (http://codemirror.net), a code editor
5// implemented in JavaScript on top of the browser's DOM.
6//
7// You can find some technical background for some of the code below
8// at http://marijnhaverbeke.nl/blog/#cm-internals .
9
10(function(mod) {
11 if (typeof exports == "object" && typeof module == "object") // CommonJS
12 module.exports = mod();
13 else if (typeof define == "function" && define.amd) // AMD
14 return define([], mod);
15 else // Plain browser env
16 this.CodeMirror = mod();
17})(function() {
18 "use strict";
19
20 // BROWSER SNIFFING
21
22 // Kludges for bugs and behavior differences that can't be feature
23 // detected are enabled based on userAgent etc sniffing.
24
25 var gecko = /gecko\/\d/i.test(navigator.userAgent);
26 var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
27 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
28 var ie = ie_upto10 || ie_11up;
29 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
30 var webkit = /WebKit\//.test(navigator.userAgent);
31 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
32 var chrome = /Chrome\//.test(navigator.userAgent);
33 var presto = /Opera\//.test(navigator.userAgent);
34 var safari = /Apple Computer/.test(navigator.vendor);
35 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
36 var phantom = /PhantomJS/.test(navigator.userAgent);
37
38 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
39 // This is woefully incomplete. Suggestions for alternative methods welcome.
40 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
41 var mac = ios || /Mac/.test(navigator.platform);
42 var windows = /win/i.test(navigator.platform);
43
44 var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
45 if (presto_version) presto_version = Number(presto_version[1]);
46 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
47 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
48 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
49 var captureRightClick = gecko || (ie && ie_version >= 9);
50
51 // Optimize some code when these features are not used.
52 var sawReadOnlySpans = false, sawCollapsedSpans = false;
53
54 // EDITOR CONSTRUCTOR
55
56 // A CodeMirror instance represents an editor. This is the object
57 // that user code is usually dealing with.
58
59 function CodeMirror(place, options) {
60 if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
61
62 this.options = options = options ? copyObj(options) : {};
63 // Determine effective options based on given values and defaults.
64 copyObj(defaults, options, false);
65 setGuttersForLineNumbers(options);
66
67 var doc = options.value;
68 if (typeof doc == "string") doc = new Doc(doc, options.mode);
69 this.doc = doc;
70
71 var input = new CodeMirror.inputStyles[options.inputStyle](this);
72 var display = this.display = new Display(place, doc, input);
73 display.wrapper.CodeMirror = this;
74 updateGutters(this);
75 themeChanged(this);
76 if (options.lineWrapping)
77 this.display.wrapper.className += " CodeMirror-wrap";
78 if (options.autofocus && !mobile) display.input.focus();
79 initScrollbars(this);
80
81 this.state = {
82 keyMaps: [], // stores maps added by addKeyMap
83 overlays: [], // highlighting overlays, as added by addOverlay
84 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
85 overwrite: false,
86 delayingBlurEvent: false,
87 focused: false,
88 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
89 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
90 draggingText: false,
91 highlight: new Delayed(), // stores highlight worker timeout
92 keySeq: null, // Unfinished key sequence
93 specialChars: null
94 };
95
96 var cm = this;
97
98 // Override magic textarea content restore that IE sometimes does
99 // on our hidden textarea on reload
100 if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
101
102 registerEventHandlers(this);
103 ensureGlobalHandlers();
104
105 startOperation(this);
106 this.curOp.forceUpdate = true;
107 attachDoc(this, doc);
108
109 if ((options.autofocus && !mobile) || cm.hasFocus())
110 setTimeout(bind(onFocus, this), 20);
111 else
112 onBlur(this);
113
114 for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
115 optionHandlers[opt](this, options[opt], Init);
116 maybeUpdateLineNumberWidth(this);
117 if (options.finishInit) options.finishInit(this);
118 for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
119 endOperation(this);
120 // Suppress optimizelegibility in Webkit, since it breaks text
121 // measuring on line wrapping boundaries.
122 if (webkit && options.lineWrapping &&
123 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
124 display.lineDiv.style.textRendering = "auto";
125 }
126
127 // DISPLAY CONSTRUCTOR
128
129 // The display handles the DOM integration, both for input reading
130 // and content drawing. It holds references to DOM nodes and
131 // display-related state.
132
133 function Display(place, doc, input) {
134 var d = this;
135 this.input = input;
136
137 // Covers bottom-right square when both scrollbars are present.
138 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
139 d.scrollbarFiller.setAttribute("cm-not-content", "true");
140 // Covers bottom of gutter when coverGutterNextToScrollbar is on
141 // and h scrollbar is present.
142 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
143 d.gutterFiller.setAttribute("cm-not-content", "true");
144 // Will contain the actual code, positioned to cover the viewport.
145 d.lineDiv = elt("div", null, "CodeMirror-code");
146 // Elements are added to these to represent selection and cursors.
147 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
148 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
149 // A visibility: hidden element used to find the size of things.
150 d.measure = elt("div", null, "CodeMirror-measure");
151 // When lines outside of the viewport are measured, they are drawn in this.
152 d.lineMeasure = elt("div", null, "CodeMirror-measure");
153 // Wraps everything that needs to exist inside the vertically-padded coordinate system
154 d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
155 null, "position: relative; outline: none");
156 // Moved around its parent to cover visible view.
157 d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
158 // Set to the height of the document, allowing scrolling.
159 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
160 d.sizerWidth = null;
161 // Behavior of elts with overflow: auto and padding is
162 // inconsistent across browsers. This is used to ensure the
163 // scrollable area is big enough.
164 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
165 // Will contain the gutters, if any.
166 d.gutters = elt("div", null, "CodeMirror-gutters");
167 d.lineGutter = null;
168 // Actual scrollable element.
169 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
170 d.scroller.setAttribute("tabIndex", "-1");
171 // The element in which the editor lives.
172 d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
173
174 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
175 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
176 if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
177
178 if (place) {
179 if (place.appendChild) place.appendChild(d.wrapper);
180 else place(d.wrapper);
181 }
182
183 // Current rendered range (may be bigger than the view window).
184 d.viewFrom = d.viewTo = doc.first;
185 d.reportedViewFrom = d.reportedViewTo = doc.first;
186 // Information about the rendered lines.
187 d.view = [];
188 d.renderedView = null;
189 // Holds info about a single rendered line when it was rendered
190 // for measurement, while not in view.
191 d.externalMeasured = null;
192 // Empty space (in pixels) above the view
193 d.viewOffset = 0;
194 d.lastWrapHeight = d.lastWrapWidth = 0;
195 d.updateLineNumbers = null;
196
197 d.nativeBarWidth = d.barHeight = d.barWidth = 0;
198 d.scrollbarsClipped = false;
199
200 // Used to only resize the line number gutter when necessary (when
201 // the amount of lines crosses a boundary that makes its width change)
202 d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
203 // Set to true when a non-horizontal-scrolling line widget is
204 // added. As an optimization, line widget aligning is skipped when
205 // this is false.
206 d.alignWidgets = false;
207
208 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
209
210 // Tracks the maximum line length so that the horizontal scrollbar
211 // can be kept static when scrolling.
212 d.maxLine = null;
213 d.maxLineLength = 0;
214 d.maxLineChanged = false;
215
216 // Used for measuring wheel scrolling granularity
217 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
218
219 // True when shift is held down.
220 d.shift = false;
221
222 // Used to track whether anything happened since the context menu
223 // was opened.
224 d.selForContextMenu = null;
225
226 d.activeTouch = null;
227
228 input.init(d);
229 }
230
231 // STATE UPDATES
232
233 // Used to get the editor into a consistent state again when options change.
234
235 function loadMode(cm) {
236 cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
237 resetModeState(cm);
238 }
239
240 function resetModeState(cm) {
241 cm.doc.iter(function(line) {
242 if (line.stateAfter) line.stateAfter = null;
243 if (line.styles) line.styles = null;
244 });
245 cm.doc.frontier = cm.doc.first;
246 startWorker(cm, 100);
247 cm.state.modeGen++;
248 if (cm.curOp) regChange(cm);
249 }
250
251 function wrappingChanged(cm) {
252 if (cm.options.lineWrapping) {
253 addClass(cm.display.wrapper, "CodeMirror-wrap");
254 cm.display.sizer.style.minWidth = "";
255 cm.display.sizerWidth = null;
256 } else {
257 rmClass(cm.display.wrapper, "CodeMirror-wrap");
258 findMaxLine(cm);
259 }
260 estimateLineHeights(cm);
261 regChange(cm);
262 clearCaches(cm);
263 setTimeout(function(){updateScrollbars(cm);}, 100);
264 }
265
266 // Returns a function that estimates the height of a line, to use as
267 // first approximation until the line becomes visible (and is thus
268 // properly measurable).
269 function estimateHeight(cm) {
270 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
271 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
272 return function(line) {
273 if (lineIsHidden(cm.doc, line)) return 0;
274
275 var widgetsHeight = 0;
276 if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
277 if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
278 }
279
280 if (wrapping)
281 return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
282 else
283 return widgetsHeight + th;
284 };
285 }
286
287 function estimateLineHeights(cm) {
288 var doc = cm.doc, est = estimateHeight(cm);
289 doc.iter(function(line) {
290 var estHeight = est(line);
291 if (estHeight != line.height) updateLineHeight(line, estHeight);
292 });
293 }
294
295 function themeChanged(cm) {
296 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
297 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
298 clearCaches(cm);
299 }
300
301 function guttersChanged(cm) {
302 updateGutters(cm);
303 regChange(cm);
304 setTimeout(function(){alignHorizontally(cm);}, 20);
305 }
306
307 // Rebuild the gutter elements, ensure the margin to the left of the
308 // code matches their width.
309 function updateGutters(cm) {
310 var gutters = cm.display.gutters, specs = cm.options.gutters;
311 removeChildren(gutters);
312 for (var i = 0; i < specs.length; ++i) {
313 var gutterClass = specs[i];
314 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
315 if (gutterClass == "CodeMirror-linenumbers") {
316 cm.display.lineGutter = gElt;
317 gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
318 }
319 }
320 gutters.style.display = i ? "" : "none";
321 updateGutterSpace(cm);
322 }
323
324 function updateGutterSpace(cm) {
325 var width = cm.display.gutters.offsetWidth;
326 cm.display.sizer.style.marginLeft = width + "px";
327 }
328
329 // Compute the character length of a line, taking into account
330 // collapsed ranges (see markText) that might hide parts, and join
331 // other lines onto it.
332 function lineLength(line) {
333 if (line.height == 0) return 0;
334 var len = line.text.length, merged, cur = line;
335 while (merged = collapsedSpanAtStart(cur)) {
336 var found = merged.find(0, true);
337 cur = found.from.line;
338 len += found.from.ch - found.to.ch;
339 }
340 cur = line;
341 while (merged = collapsedSpanAtEnd(cur)) {
342 var found = merged.find(0, true);
343 len -= cur.text.length - found.from.ch;
344 cur = found.to.line;
345 len += cur.text.length - found.to.ch;
346 }
347 return len;
348 }
349
350 // Find the longest line in the document.
351 function findMaxLine(cm) {
352 var d = cm.display, doc = cm.doc;
353 d.maxLine = getLine(doc, doc.first);
354 d.maxLineLength = lineLength(d.maxLine);
355 d.maxLineChanged = true;
356 doc.iter(function(line) {
357 var len = lineLength(line);
358 if (len > d.maxLineLength) {
359 d.maxLineLength = len;
360 d.maxLine = line;
361 }
362 });
363 }
364
365 // Make sure the gutters options contains the element
366 // "CodeMirror-linenumbers" when the lineNumbers option is true.
367 function setGuttersForLineNumbers(options) {
368 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
369 if (found == -1 && options.lineNumbers) {
370 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
371 } else if (found > -1 && !options.lineNumbers) {
372 options.gutters = options.gutters.slice(0);
373 options.gutters.splice(found, 1);
374 }
375 }
376
377 // SCROLLBARS
378
379 // Prepare DOM reads needed to update the scrollbars. Done in one
380 // shot to minimize update/measure roundtrips.
381 function measureForScrollbars(cm) {
382 var d = cm.display, gutterW = d.gutters.offsetWidth;
383 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
384 return {
385 clientHeight: d.scroller.clientHeight,
386 viewHeight: d.wrapper.clientHeight,
387 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
388 viewWidth: d.wrapper.clientWidth,
389 barLeft: cm.options.fixedGutter ? gutterW : 0,
390 docHeight: docH,
391 scrollHeight: docH + scrollGap(cm) + d.barHeight,
392 nativeBarWidth: d.nativeBarWidth,
393 gutterWidth: gutterW
394 };
395 }
396
397 function NativeScrollbars(place, scroll, cm) {
398 this.cm = cm;
399 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
400 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
401 place(vert); place(horiz);
402
403 on(vert, "scroll", function() {
404 if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
405 });
406 on(horiz, "scroll", function() {
407 if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
408 });
409
410 this.checkedOverlay = false;
411 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
412 if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
413 }
414
415 NativeScrollbars.prototype = copyObj({
416 update: function(measure) {
417 var needsH = measure.scrollWidth > measure.clientWidth + 1;
418 var needsV = measure.scrollHeight > measure.clientHeight + 1;
419 var sWidth = measure.nativeBarWidth;
420
421 if (needsV) {
422 this.vert.style.display = "block";
423 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
424 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
425 // A bug in IE8 can cause this value to be negative, so guard it.
426 this.vert.firstChild.style.height =
427 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
428 } else {
429 this.vert.style.display = "";
430 this.vert.firstChild.style.height = "0";
431 }
432
433 if (needsH) {
434 this.horiz.style.display = "block";
435 this.horiz.style.right = needsV ? sWidth + "px" : "0";
436 this.horiz.style.left = measure.barLeft + "px";
437 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
438 this.horiz.firstChild.style.width =
439 (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
440 } else {
441 this.horiz.style.display = "";
442 this.horiz.firstChild.style.width = "0";
443 }
444
445 if (!this.checkedOverlay && measure.clientHeight > 0) {
446 if (sWidth == 0) this.overlayHack();
447 this.checkedOverlay = true;
448 }
449
450 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
451 },
452 setScrollLeft: function(pos) {
453 if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
454 },
455 setScrollTop: function(pos) {
456 if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
457 },
458 overlayHack: function() {
459 var w = mac && !mac_geMountainLion ? "12px" : "18px";
460 this.horiz.style.minHeight = this.vert.style.minWidth = w;
461 var self = this;
462 var barMouseDown = function(e) {
463 if (e_target(e) != self.vert && e_target(e) != self.horiz)
464 operation(self.cm, onMouseDown)(e);
465 };
466 on(this.vert, "mousedown", barMouseDown);
467 on(this.horiz, "mousedown", barMouseDown);
468 },
469 clear: function() {
470 var parent = this.horiz.parentNode;
471 parent.removeChild(this.horiz);
472 parent.removeChild(this.vert);
473 }
474 }, NativeScrollbars.prototype);
475
476 function NullScrollbars() {}
477
478 NullScrollbars.prototype = copyObj({
479 update: function() { return {bottom: 0, right: 0}; },
480 setScrollLeft: function() {},
481 setScrollTop: function() {},
482 clear: function() {}
483 }, NullScrollbars.prototype);
484
485 CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
486
487 function initScrollbars(cm) {
488 if (cm.display.scrollbars) {
489 cm.display.scrollbars.clear();
490 if (cm.display.scrollbars.addClass)
491 rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
492 }
493
494 cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
495 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
496 // Prevent clicks in the scrollbars from killing focus
497 on(node, "mousedown", function() {
498 if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
499 });
500 node.setAttribute("cm-not-content", "true");
501 }, function(pos, axis) {
502 if (axis == "horizontal") setScrollLeft(cm, pos);
503 else setScrollTop(cm, pos);
504 }, cm);
505 if (cm.display.scrollbars.addClass)
506 addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
507 }
508
509 function updateScrollbars(cm, measure) {
510 if (!measure) measure = measureForScrollbars(cm);
511 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
512 updateScrollbarsInner(cm, measure);
513 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
514 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
515 updateHeightsInViewport(cm);
516 updateScrollbarsInner(cm, measureForScrollbars(cm));
517 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
518 }
519 }
520
521 // Re-synchronize the fake scrollbars with the actual size of the
522 // content.
523 function updateScrollbarsInner(cm, measure) {
524 var d = cm.display;
525 var sizes = d.scrollbars.update(measure);
526
527 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
528 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
529
530 if (sizes.right && sizes.bottom) {
531 d.scrollbarFiller.style.display = "block";
532 d.scrollbarFiller.style.height = sizes.bottom + "px";
533 d.scrollbarFiller.style.width = sizes.right + "px";
534 } else d.scrollbarFiller.style.display = "";
535 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
536 d.gutterFiller.style.display = "block";
537 d.gutterFiller.style.height = sizes.bottom + "px";
538 d.gutterFiller.style.width = measure.gutterWidth + "px";
539 } else d.gutterFiller.style.display = "";
540 }
541
542 // Compute the lines that are visible in a given viewport (defaults
543 // the the current scroll position). viewport may contain top,
544 // height, and ensure (see op.scrollToPos) properties.
545 function visibleLines(display, doc, viewport) {
546 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
547 top = Math.floor(top - paddingTop(display));
548 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
549
550 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
551 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
552 // forces those lines into the viewport (if possible).
553 if (viewport && viewport.ensure) {
554 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
555 if (ensureFrom < from) {
556 from = ensureFrom;
557 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
558 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
559 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
560 to = ensureTo;
561 }
562 }
563 return {from: from, to: Math.max(to, from + 1)};
564 }
565
566 // LINE NUMBERS
567
568 // Re-align line numbers and gutter marks to compensate for
569 // horizontal scrolling.
570 function alignHorizontally(cm) {
571 var display = cm.display, view = display.view;
572 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
573 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
574 var gutterW = display.gutters.offsetWidth, left = comp + "px";
575 for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
576 if (cm.options.fixedGutter && view[i].gutter)
577 view[i].gutter.style.left = left;
578 var align = view[i].alignable;
579 if (align) for (var j = 0; j < align.length; j++)
580 align[j].style.left = left;
581 }
582 if (cm.options.fixedGutter)
583 display.gutters.style.left = (comp + gutterW) + "px";
584 }
585
586 // Used to ensure that the line number gutter is still the right
587 // size for the current document size. Returns true when an update
588 // is needed.
589 function maybeUpdateLineNumberWidth(cm) {
590 if (!cm.options.lineNumbers) return false;
591 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
592 if (last.length != display.lineNumChars) {
593 var test = display.measure.appendChild(elt("div", [elt("div", last)],
594 "CodeMirror-linenumber CodeMirror-gutter-elt"));
595 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
596 display.lineGutter.style.width = "";
597 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
598 display.lineNumWidth = display.lineNumInnerWidth + padding;
599 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
600 display.lineGutter.style.width = display.lineNumWidth + "px";
601 updateGutterSpace(cm);
602 return true;
603 }
604 return false;
605 }
606
607 function lineNumberFor(options, i) {
608 return String(options.lineNumberFormatter(i + options.firstLineNumber));
609 }
610
611 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
612 // but using getBoundingClientRect to get a sub-pixel-accurate
613 // result.
614 function compensateForHScroll(display) {
615 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
616 }
617
618 // DISPLAY DRAWING
619
620 function DisplayUpdate(cm, viewport, force) {
621 var display = cm.display;
622
623 this.viewport = viewport;
624 // Store some values that we'll need later (but don't want to force a relayout for)
625 this.visible = visibleLines(display, cm.doc, viewport);
626 this.editorIsHidden = !display.wrapper.offsetWidth;
627 this.wrapperHeight = display.wrapper.clientHeight;
628 this.wrapperWidth = display.wrapper.clientWidth;
629 this.oldDisplayWidth = displayWidth(cm);
630 this.force = force;
631 this.dims = getDimensions(cm);
632 this.events = [];
633 }
634
635 DisplayUpdate.prototype.signal = function(emitter, type) {
636 if (hasHandler(emitter, type))
637 this.events.push(arguments);
638 };
639 DisplayUpdate.prototype.finish = function() {
640 for (var i = 0; i < this.events.length; i++)
641 signal.apply(null, this.events[i]);
642 };
643
644 function maybeClipScrollbars(cm) {
645 var display = cm.display;
646 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
647 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
648 display.heightForcer.style.height = scrollGap(cm) + "px";
649 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
650 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
651 display.scrollbarsClipped = true;
652 }
653 }
654
655 // Does the actual updating of the line display. Bails out
656 // (returning false) when there is nothing to be done and forced is
657 // false.
658 function updateDisplayIfNeeded(cm, update) {
659 var display = cm.display, doc = cm.doc;
660
661 if (update.editorIsHidden) {
662 resetView(cm);
663 return false;
664 }
665
666 // Bail out if the visible area is already rendered and nothing changed.
667 if (!update.force &&
668 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
669 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
670 display.renderedView == display.view && countDirtyView(cm) == 0)
671 return false;
672
673 if (maybeUpdateLineNumberWidth(cm)) {
674 resetView(cm);
675 update.dims = getDimensions(cm);
676 }
677
678 // Compute a suitable new viewport (from & to)
679 var end = doc.first + doc.size;
680 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
681 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
682 if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
683 if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
684 if (sawCollapsedSpans) {
685 from = visualLineNo(cm.doc, from);
686 to = visualLineEndNo(cm.doc, to);
687 }
688
689 var different = from != display.viewFrom || to != display.viewTo ||
690 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
691 adjustView(cm, from, to);
692
693 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
694 // Position the mover div to align with the current scroll position
695 cm.display.mover.style.top = display.viewOffset + "px";
696
697 var toUpdate = countDirtyView(cm);
698 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
699 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
700 return false;
701
702 // For big changes, we hide the enclosing element during the
703 // update, since that speeds up the operations on most browsers.
704 var focused = activeElt();
705 if (toUpdate > 4) display.lineDiv.style.display = "none";
706 patchDisplay(cm, display.updateLineNumbers, update.dims);
707 if (toUpdate > 4) display.lineDiv.style.display = "";
708 display.renderedView = display.view;
709 // There might have been a widget with a focused element that got
710 // hidden or updated, if so re-focus it.
711 if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
712
713 // Prevent selection and cursors from interfering with the scroll
714 // width and height.
715 removeChildren(display.cursorDiv);
716 removeChildren(display.selectionDiv);
717 display.gutters.style.height = 0;
718
719 if (different) {
720 display.lastWrapHeight = update.wrapperHeight;
721 display.lastWrapWidth = update.wrapperWidth;
722 startWorker(cm, 400);
723 }
724
725 display.updateLineNumbers = null;
726
727 return true;
728 }
729
730 function postUpdateDisplay(cm, update) {
731 var force = update.force, viewport = update.viewport;
732 for (var first = true;; first = false) {
733 if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) {
734 force = true;
735 } else {
736 force = false;
737 // Clip forced viewport to actual scrollable area.
738 if (viewport && viewport.top != null)
739 viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
740 // Updated line heights might result in the drawn area not
741 // actually covering the viewport. Keep looping until it does.
742 update.visible = visibleLines(cm.display, cm.doc, viewport);
743 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
744 break;
745 }
746 if (!updateDisplayIfNeeded(cm, update)) break;
747 updateHeightsInViewport(cm);
748 var barMeasure = measureForScrollbars(cm);
749 updateSelection(cm);
750 setDocumentHeight(cm, barMeasure);
751 updateScrollbars(cm, barMeasure);
752 }
753
754 update.signal(cm, "update", cm);
755 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
756 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
757 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
758 }
759 }
760
761 function updateDisplaySimple(cm, viewport) {
762 var update = new DisplayUpdate(cm, viewport);
763 if (updateDisplayIfNeeded(cm, update)) {
764 updateHeightsInViewport(cm);
765 postUpdateDisplay(cm, update);
766 var barMeasure = measureForScrollbars(cm);
767 updateSelection(cm);
768 setDocumentHeight(cm, barMeasure);
769 updateScrollbars(cm, barMeasure);
770 update.finish();
771 }
772 }
773
774 function setDocumentHeight(cm, measure) {
775 cm.display.sizer.style.minHeight = measure.docHeight + "px";
776 var total = measure.docHeight + cm.display.barHeight;
777 cm.display.heightForcer.style.top = total + "px";
778 cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
779 }
780
781 // Read the actual heights of the rendered lines, and update their
782 // stored heights to match.
783 function updateHeightsInViewport(cm) {
784 var display = cm.display;
785 var prevBottom = display.lineDiv.offsetTop;
786 for (var i = 0; i < display.view.length; i++) {
787 var cur = display.view[i], height;
788 if (cur.hidden) continue;
789 if (ie && ie_version < 8) {
790 var bot = cur.node.offsetTop + cur.node.offsetHeight;
791 height = bot - prevBottom;
792 prevBottom = bot;
793 } else {
794 var box = cur.node.getBoundingClientRect();
795 height = box.bottom - box.top;
796 }
797 var diff = cur.line.height - height;
798 if (height < 2) height = textHeight(display);
799 if (diff > .001 || diff < -.001) {
800 updateLineHeight(cur.line, height);
801 updateWidgetHeight(cur.line);
802 if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
803 updateWidgetHeight(cur.rest[j]);
804 }
805 }
806 }
807
808 // Read and store the height of line widgets associated with the
809 // given line.
810 function updateWidgetHeight(line) {
811 if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
812 line.widgets[i].height = line.widgets[i].node.offsetHeight;
813 }
814
815 // Do a bulk-read of the DOM positions and sizes needed to draw the
816 // view, so that we don't interleave reading and writing to the DOM.
817 function getDimensions(cm) {
818 var d = cm.display, left = {}, width = {};
819 var gutterLeft = d.gutters.clientLeft;
820 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
821 left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
822 width[cm.options.gutters[i]] = n.clientWidth;
823 }
824 return {fixedPos: compensateForHScroll(d),
825 gutterTotalWidth: d.gutters.offsetWidth,
826 gutterLeft: left,
827 gutterWidth: width,
828 wrapperWidth: d.wrapper.clientWidth};
829 }
830
831 // Sync the actual display DOM structure with display.view, removing
832 // nodes for lines that are no longer in view, and creating the ones
833 // that are not there yet, and updating the ones that are out of
834 // date.
835 function patchDisplay(cm, updateNumbersFrom, dims) {
836 var display = cm.display, lineNumbers = cm.options.lineNumbers;
837 var container = display.lineDiv, cur = container.firstChild;
838
839 function rm(node) {
840 var next = node.nextSibling;
841 // Works around a throw-scroll bug in OS X Webkit
842 if (webkit && mac && cm.display.currentWheelTarget == node)
843 node.style.display = "none";
844 else
845 node.parentNode.removeChild(node);
846 return next;
847 }
848
849 var view = display.view, lineN = display.viewFrom;
850 // Loop over the elements in the view, syncing cur (the DOM nodes
851 // in display.lineDiv) with the view as we go.
852 for (var i = 0; i < view.length; i++) {
853 var lineView = view[i];
854 if (lineView.hidden) {
855 } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
856 var node = buildLineElement(cm, lineView, lineN, dims);
857 container.insertBefore(node, cur);
858 } else { // Already drawn
859 while (cur != lineView.node) cur = rm(cur);
860 var updateNumber = lineNumbers && updateNumbersFrom != null &&
861 updateNumbersFrom <= lineN && lineView.lineNumber;
862 if (lineView.changes) {
863 if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
864 updateLineForChanges(cm, lineView, lineN, dims);
865 }
866 if (updateNumber) {
867 removeChildren(lineView.lineNumber);
868 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
869 }
870 cur = lineView.node.nextSibling;
871 }
872 lineN += lineView.size;
873 }
874 while (cur) cur = rm(cur);
875 }
876
877 // When an aspect of a line changes, a string is added to
878 // lineView.changes. This updates the relevant part of the line's
879 // DOM structure.
880 function updateLineForChanges(cm, lineView, lineN, dims) {
881 for (var j = 0; j < lineView.changes.length; j++) {
882 var type = lineView.changes[j];
883 if (type == "text") updateLineText(cm, lineView);
884 else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
885 else if (type == "class") updateLineClasses(lineView);
886 else if (type == "widget") updateLineWidgets(cm, lineView, dims);
887 }
888 lineView.changes = null;
889 }
890
891 // Lines with gutter elements, widgets or a background class need to
892 // be wrapped, and have the extra elements added to the wrapper div
893 function ensureLineWrapped(lineView) {
894 if (lineView.node == lineView.text) {
895 lineView.node = elt("div", null, null, "position: relative");
896 if (lineView.text.parentNode)
897 lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
898 lineView.node.appendChild(lineView.text);
899 if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
900 }
901 return lineView.node;
902 }
903
904 function updateLineBackground(lineView) {
905 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
906 if (cls) cls += " CodeMirror-linebackground";
907 if (lineView.background) {
908 if (cls) lineView.background.className = cls;
909 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
910 } else if (cls) {
911 var wrap = ensureLineWrapped(lineView);
912 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
913 }
914 }
915
916 // Wrapper around buildLineContent which will reuse the structure
917 // in display.externalMeasured when possible.
918 function getLineContent(cm, lineView) {
919 var ext = cm.display.externalMeasured;
920 if (ext && ext.line == lineView.line) {
921 cm.display.externalMeasured = null;
922 lineView.measure = ext.measure;
923 return ext.built;
924 }
925 return buildLineContent(cm, lineView);
926 }
927
928 // Redraw the line's text. Interacts with the background and text
929 // classes because the mode may output tokens that influence these
930 // classes.
931 function updateLineText(cm, lineView) {
932 var cls = lineView.text.className;
933 var built = getLineContent(cm, lineView);
934 if (lineView.text == lineView.node) lineView.node = built.pre;
935 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
936 lineView.text = built.pre;
937 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
938 lineView.bgClass = built.bgClass;
939 lineView.textClass = built.textClass;
940 updateLineClasses(lineView);
941 } else if (cls) {
942 lineView.text.className = cls;
943 }
944 }
945
946 function updateLineClasses(lineView) {
947 updateLineBackground(lineView);
948 if (lineView.line.wrapClass)
949 ensureLineWrapped(lineView).className = lineView.line.wrapClass;
950 else if (lineView.node != lineView.text)
951 lineView.node.className = "";
952 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
953 lineView.text.className = textClass || "";
954 }
955
956 function updateLineGutter(cm, lineView, lineN, dims) {
957 if (lineView.gutter) {
958 lineView.node.removeChild(lineView.gutter);
959 lineView.gutter = null;
960 }
961 var markers = lineView.line.gutterMarkers;
962 if (cm.options.lineNumbers || markers) {
963 var wrap = ensureLineWrapped(lineView);
964 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
965 (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
966 "px; width: " + dims.gutterTotalWidth + "px");
967 cm.display.input.setUneditable(gutterWrap);
968 wrap.insertBefore(gutterWrap, lineView.text);
969 if (lineView.line.gutterClass)
970 gutterWrap.className += " " + lineView.line.gutterClass;
971 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
972 lineView.lineNumber = gutterWrap.appendChild(
973 elt("div", lineNumberFor(cm.options, lineN),
974 "CodeMirror-linenumber CodeMirror-gutter-elt",
975 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
976 + cm.display.lineNumInnerWidth + "px"));
977 if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
978 var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
979 if (found)
980 gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
981 dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
982 }
983 }
984 }
985
986 function updateLineWidgets(cm, lineView, dims) {
987 if (lineView.alignable) lineView.alignable = null;
988 for (var node = lineView.node.firstChild, next; node; node = next) {
989 var next = node.nextSibling;
990 if (node.className == "CodeMirror-linewidget")
991 lineView.node.removeChild(node);
992 }
993 insertLineWidgets(cm, lineView, dims);
994 }
995
996 // Build a line's DOM representation from scratch
997 function buildLineElement(cm, lineView, lineN, dims) {
998 var built = getLineContent(cm, lineView);
999 lineView.text = lineView.node = built.pre;
1000 if (built.bgClass) lineView.bgClass = built.bgClass;
1001 if (built.textClass) lineView.textClass = built.textClass;
1002
1003 updateLineClasses(lineView);
1004 updateLineGutter(cm, lineView, lineN, dims);
1005 insertLineWidgets(cm, lineView, dims);
1006 return lineView.node;
1007 }
1008
1009 // A lineView may contain multiple logical lines (when merged by
1010 // collapsed spans). The widgets for all of them need to be drawn.
1011 function insertLineWidgets(cm, lineView, dims) {
1012 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
1013 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
1014 insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
1015 }
1016
1017 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
1018 if (!line.widgets) return;
1019 var wrap = ensureLineWrapped(lineView);
1020 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
1021 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
1022 if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
1023 positionLineWidget(widget, node, lineView, dims);
1024 cm.display.input.setUneditable(node);
1025 if (allowAbove && widget.above)
1026 wrap.insertBefore(node, lineView.gutter || lineView.text);
1027 else
1028 wrap.appendChild(node);
1029 signalLater(widget, "redraw");
1030 }
1031 }
1032
1033 function positionLineWidget(widget, node, lineView, dims) {
1034 if (widget.noHScroll) {
1035 (lineView.alignable || (lineView.alignable = [])).push(node);
1036 var width = dims.wrapperWidth;
1037 node.style.left = dims.fixedPos + "px";
1038 if (!widget.coverGutter) {
1039 width -= dims.gutterTotalWidth;
1040 node.style.paddingLeft = dims.gutterTotalWidth + "px";
1041 }
1042 node.style.width = width + "px";
1043 }
1044 if (widget.coverGutter) {
1045 node.style.zIndex = 5;
1046 node.style.position = "relative";
1047 if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
1048 }
1049 }
1050
1051 // POSITION OBJECT
1052
1053 // A Pos instance represents a position within the text.
1054 var Pos = CodeMirror.Pos = function(line, ch) {
1055 if (!(this instanceof Pos)) return new Pos(line, ch);
1056 this.line = line; this.ch = ch;
1057 };
1058
1059 // Compare two positions, return 0 if they are the same, a negative
1060 // number when a is less, and a positive number otherwise.
1061 var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
1062
1063 function copyPos(x) {return Pos(x.line, x.ch);}
1064 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
1065 function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
1066
1067 // INPUT HANDLING
1068
1069 function ensureFocus(cm) {
1070 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
1071 }
1072
1073 function isReadOnly(cm) {
1074 return cm.options.readOnly || cm.doc.cantEdit;
1075 }
1076
1077 // This will be set to an array of strings when copying, so that,
1078 // when pasting, we know what kind of selections the copied text
1079 // was made out of.
1080 var lastCopied = null;
1081
1082 function applyTextInput(cm, inserted, deleted, sel, origin) {
1083 var doc = cm.doc;
1084 cm.display.shift = false;
1085 if (!sel) sel = doc.sel;
1086
1087 var textLines = splitLines(inserted), multiPaste = null;
1088 // When pasing N lines into N selections, insert one line per selection
1089 if (cm.state.pasteIncoming && sel.ranges.length > 1) {
1090 if (lastCopied && lastCopied.join("\n") == inserted)
1091 multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
1092 else if (textLines.length == sel.ranges.length)
1093 multiPaste = map(textLines, function(l) { return [l]; });
1094 }
1095
1096 // Normal behavior is to insert the new text into every selection
1097 for (var i = sel.ranges.length - 1; i >= 0; i--) {
1098 var range = sel.ranges[i];
1099 var from = range.from(), to = range.to();
1100 if (range.empty()) {
1101 if (deleted && deleted > 0) // Handle deletion
1102 from = Pos(from.line, from.ch - deleted);
1103 else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite
1104 to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
1105 }
1106 var updateInput = cm.curOp.updateInput;
1107 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
1108 origin: origin || (cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
1109 makeChange(cm.doc, changeEvent);
1110 signalLater(cm, "inputRead", cm, changeEvent);
1111 // When an 'electric' character is inserted, immediately trigger a reindent
1112 if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
1113 cm.options.smartIndent && range.head.ch < 100 &&
1114 (!i || sel.ranges[i - 1].head.line != range.head.line)) {
1115 var mode = cm.getModeAt(range.head);
1116 var end = changeEnd(changeEvent);
1117 var indented = false;
1118 if (mode.electricChars) {
1119 for (var j = 0; j < mode.electricChars.length; j++)
1120 if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
1121 indented = indentLine(cm, end.line, "smart");
1122 break;
1123 }
1124 } else if (mode.electricInput) {
1125 if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
1126 indented = indentLine(cm, end.line, "smart");
1127 }
1128 if (indented) signalLater(cm, "electricInput", cm, end.line);
1129 }
1130 }
1131 ensureCursorVisible(cm);
1132 cm.curOp.updateInput = updateInput;
1133 cm.curOp.typing = true;
1134 cm.state.pasteIncoming = cm.state.cutIncoming = false;
1135 }
1136
1137 function copyableRanges(cm) {
1138 var text = [], ranges = [];
1139 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
1140 var line = cm.doc.sel.ranges[i].head.line;
1141 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
1142 ranges.push(lineRange);
1143 text.push(cm.getRange(lineRange.anchor, lineRange.head));
1144 }
1145 return {text: text, ranges: ranges};
1146 }
1147
1148 function disableBrowserMagic(field) {
1149 field.setAttribute("autocorrect", "off");
1150 field.setAttribute("autocapitalize", "off");
1151 field.setAttribute("spellcheck", "false");
1152 }
1153
1154 // TEXTAREA INPUT STYLE
1155
1156 function TextareaInput(cm) {
1157 this.cm = cm;
1158 // See input.poll and input.reset
1159 this.prevInput = "";
1160
1161 // Flag that indicates whether we expect input to appear real soon
1162 // now (after some event like 'keypress' or 'input') and are
1163 // polling intensively.
1164 this.pollingFast = false;
1165 // Self-resetting timeout for the poller
1166 this.polling = new Delayed();
1167 // Tracks when input.reset has punted to just putting a short
1168 // string into the textarea instead of the full selection.
1169 this.inaccurateSelection = false;
1170 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
1171 this.hasSelection = false;
1172 this.composing = null;
1173 };
1174
1175 function hiddenTextarea() {
1176 var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
1177 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
1178 // The textarea is kept positioned near the cursor to prevent the
1179 // fact that it'll be scrolled into view on input from scrolling
1180 // our fake cursor out of view. On webkit, when wrap=off, paste is
1181 // very slow. So make the area wide instead.
1182 if (webkit) te.style.width = "1000px";
1183 else te.setAttribute("wrap", "off");
1184 // If border: 0; -- iOS fails to open keyboard (issue #1287)
1185 if (ios) te.style.border = "1px solid black";
1186 disableBrowserMagic(te);
1187 return div;
1188 }
1189
1190 TextareaInput.prototype = copyObj({
1191 init: function(display) {
1192 var input = this, cm = this.cm;
1193
1194 // Wraps and hides input textarea
1195 var div = this.wrapper = hiddenTextarea();
1196 // The semihidden textarea that is focused when the editor is
1197 // focused, and receives input.
1198 var te = this.textarea = div.firstChild;
1199 display.wrapper.insertBefore(div, display.wrapper.firstChild);
1200
1201 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
1202 if (ios) te.style.width = "0px";
1203
1204 on(te, "input", function() {
1205 if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
1206 input.poll();
1207 });
1208
1209 on(te, "paste", function() {
1210 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
1211 // Add a char to the end of textarea before paste occur so that
1212 // selection doesn't span to the end of textarea.
1213 if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
1214 var start = te.selectionStart, end = te.selectionEnd;
1215 te.value += "$";
1216 // The selection end needs to be set before the start, otherwise there
1217 // can be an intermediate non-empty selection between the two, which
1218 // can override the middle-click paste buffer on linux and cause the
1219 // wrong thing to get pasted.
1220 te.selectionEnd = end;
1221 te.selectionStart = start;
1222 cm.state.fakedLastChar = true;
1223 }
1224 cm.state.pasteIncoming = true;
1225 input.fastPoll();
1226 });
1227
1228 function prepareCopyCut(e) {
1229 if (cm.somethingSelected()) {
1230 lastCopied = cm.getSelections();
1231 if (input.inaccurateSelection) {
1232 input.prevInput = "";
1233 input.inaccurateSelection = false;
1234 te.value = lastCopied.join("\n");
1235 selectInput(te);
1236 }
1237 } else if (!cm.options.lineWiseCopyCut) {
1238 return;
1239 } else {
1240 var ranges = copyableRanges(cm);
1241 lastCopied = ranges.text;
1242 if (e.type == "cut") {
1243 cm.setSelections(ranges.ranges, null, sel_dontScroll);
1244 } else {
1245 input.prevInput = "";
1246 te.value = ranges.text.join("\n");
1247 selectInput(te);
1248 }
1249 }
1250 if (e.type == "cut") cm.state.cutIncoming = true;
1251 }
1252 on(te, "cut", prepareCopyCut);
1253 on(te, "copy", prepareCopyCut);
1254
1255 on(display.scroller, "paste", function(e) {
1256 if (eventInWidget(display, e)) return;
1257 cm.state.pasteIncoming = true;
1258 input.focus();
1259 });
1260
1261 // Prevent normal selection in the editor (we handle our own)
1262 on(display.lineSpace, "selectstart", function(e) {
1263 if (!eventInWidget(display, e)) e_preventDefault(e);
1264 });
1265
1266 on(te, "compositionstart", function() {
1267 var start = cm.getCursor("from");
1268 input.composing = {
1269 start: start,
1270 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
1271 };
1272 });
1273 on(te, "compositionend", function() {
1274 if (input.composing) {
1275 input.poll();
1276 input.composing.range.clear();
1277 input.composing = null;
1278 }
1279 });
1280 },
1281
1282 prepareSelection: function() {
1283 // Redraw the selection and/or cursor
1284 var cm = this.cm, display = cm.display, doc = cm.doc;
1285 var result = prepareSelection(cm);
1286
1287 // Move the hidden textarea near the cursor to prevent scrolling artifacts
1288 if (cm.options.moveInputWithCursor) {
1289 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
1290 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
1291 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
1292 headPos.top + lineOff.top - wrapOff.top));
1293 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
1294 headPos.left + lineOff.left - wrapOff.left));
1295 }
1296
1297 return result;
1298 },
1299
1300 showSelection: function(drawn) {
1301 var cm = this.cm, display = cm.display;
1302 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
1303 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
1304 if (drawn.teTop != null) {
1305 this.wrapper.style.top = drawn.teTop + "px";
1306 this.wrapper.style.left = drawn.teLeft + "px";
1307 }
1308 },
1309
1310 // Reset the input to correspond to the selection (or to be empty,
1311 // when not typing and nothing is selected)
1312 reset: function(typing) {
1313 if (this.contextMenuPending) return;
1314 var minimal, selected, cm = this.cm, doc = cm.doc;
1315 if (cm.somethingSelected()) {
1316 this.prevInput = "";
1317 var range = doc.sel.primary();
1318 minimal = hasCopyEvent &&
1319 (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
1320 var content = minimal ? "-" : selected || cm.getSelection();
1321 this.textarea.value = content;
1322 if (cm.state.focused) selectInput(this.textarea);
1323 if (ie && ie_version >= 9) this.hasSelection = content;
1324 } else if (!typing) {
1325 this.prevInput = this.textarea.value = "";
1326 if (ie && ie_version >= 9) this.hasSelection = null;
1327 }
1328 this.inaccurateSelection = minimal;
1329 },
1330
1331 getField: function() { return this.textarea; },
1332
1333 supportsTouch: function() { return false; },
1334
1335 focus: function() {
1336 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
1337 try { this.textarea.focus(); }
1338 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
1339 }
1340 },
1341
1342 blur: function() { this.textarea.blur(); },
1343
1344 resetPosition: function() {
1345 this.wrapper.style.top = this.wrapper.style.left = 0;
1346 },
1347
1348 receivedFocus: function() { this.slowPoll(); },
1349
1350 // Poll for input changes, using the normal rate of polling. This
1351 // runs as long as the editor is focused.
1352 slowPoll: function() {
1353 var input = this;
1354 if (input.pollingFast) return;
1355 input.polling.set(this.cm.options.pollInterval, function() {
1356 input.poll();
1357 if (input.cm.state.focused) input.slowPoll();
1358 });
1359 },
1360
1361 // When an event has just come in that is likely to add or change
1362 // something in the input textarea, we poll faster, to ensure that
1363 // the change appears on the screen quickly.
1364 fastPoll: function() {
1365 var missed = false, input = this;
1366 input.pollingFast = true;
1367 function p() {
1368 var changed = input.poll();
1369 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
1370 else {input.pollingFast = false; input.slowPoll();}
1371 }
1372 input.polling.set(20, p);
1373 },
1374
1375 // Read input from the textarea, and update the document to match.
1376 // When something is selected, it is present in the textarea, and
1377 // selected (unless it is huge, in which case a placeholder is
1378 // used). When nothing is selected, the cursor sits after previously
1379 // seen text (can be empty), which is stored in prevInput (we must
1380 // not reset the textarea when typing, because that breaks IME).
1381 poll: function() {
1382 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
1383 // Since this is called a *lot*, try to bail out as cheaply as
1384 // possible when it is clear that nothing happened. hasSelection
1385 // will be the case when there is a lot of text in the textarea,
1386 // in which case reading its value would be expensive.
1387 if (!cm.state.focused || (hasSelection(input) && !prevInput) ||
1388 isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
1389 return false;
1390 // See paste handler for more on the fakedLastChar kludge
1391 if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
1392 input.value = input.value.substring(0, input.value.length - 1);
1393 cm.state.fakedLastChar = false;
1394 }
1395 var text = input.value;
1396 // If nothing changed, bail.
1397 if (text == prevInput && !cm.somethingSelected()) return false;
1398 // Work around nonsensical selection resetting in IE9/10, and
1399 // inexplicable appearance of private area unicode characters on
1400 // some key combos in Mac (#2689).
1401 if (ie && ie_version >= 9 && this.hasSelection === text ||
1402 mac && /[\uf700-\uf7ff]/.test(text)) {
1403 cm.display.input.reset();
1404 return false;
1405 }
1406
1407 if (cm.doc.sel == cm.display.selForContextMenu) {
1408 var first = text.charCodeAt(0);
1409 if (first == 0x200b && !prevInput) prevInput = "\u200b";
1410 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
1411 }
1412 // Find the part of the input that is actually new
1413 var same = 0, l = Math.min(prevInput.length, text.length);
1414 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
1415
1416 var self = this;
1417 runInOp(cm, function() {
1418 applyTextInput(cm, text.slice(same), prevInput.length - same,
1419 null, self.composing ? "*compose" : null);
1420
1421 // Don't leave long text in the textarea, since it makes further polling slow
1422 if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
1423 else self.prevInput = text;
1424
1425 if (self.composing) {
1426 self.composing.range.clear();
1427 self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
1428 {className: "CodeMirror-composing"});
1429 }
1430 });
1431 return true;
1432 },
1433
1434 ensurePolled: function() {
1435 if (this.pollingFast && this.poll()) this.pollingFast = false;
1436 },
1437
1438 onKeyPress: function() {
1439 if (ie && ie_version >= 9) this.hasSelection = null;
1440 this.fastPoll();
1441 },
1442
1443 onContextMenu: function(e) {
1444 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
1445 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
1446 if (!pos || presto) return; // Opera is difficult.
1447
1448 // Reset the current text selection only if the click is done outside of the selection
1449 // and 'resetSelectionOnContextMenu' option is true.
1450 var reset = cm.options.resetSelectionOnContextMenu;
1451 if (reset && cm.doc.sel.contains(pos) == -1)
1452 operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
1453
1454 var oldCSS = te.style.cssText;
1455 input.wrapper.style.position = "absolute";
1456 te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1457 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
1458 (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
1459 "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1460 if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
1461 display.input.focus();
1462 if (webkit) window.scrollTo(null, oldScrollY);
1463 display.input.reset();
1464 // Adds "Select all" to context menu in FF
1465 if (!cm.somethingSelected()) te.value = input.prevInput = " ";
1466 input.contextMenuPending = true;
1467 display.selForContextMenu = cm.doc.sel;
1468 clearTimeout(display.detectingSelectAll);
1469
1470 // Select-all will be greyed out if there's nothing to select, so
1471 // this adds a zero-width space so that we can later check whether
1472 // it got selected.
1473 function prepareSelectAllHack() {
1474 if (te.selectionStart != null) {
1475 var selected = cm.somethingSelected();
1476 var extval = "\u200b" + (selected ? te.value : "");
1477 te.value = "\u21da"; // Used to catch context-menu undo
1478 te.value = extval;
1479 input.prevInput = selected ? "" : "\u200b";
1480 te.selectionStart = 1; te.selectionEnd = extval.length;
1481 // Re-set this, in case some other handler touched the
1482 // selection in the meantime.
1483 display.selForContextMenu = cm.doc.sel;
1484 }
1485 }
1486 function rehide() {
1487 input.contextMenuPending = false;
1488 input.wrapper.style.position = "relative";
1489 te.style.cssText = oldCSS;
1490 if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
1491
1492 // Try to detect the user choosing select-all
1493 if (te.selectionStart != null) {
1494 if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
1495 var i = 0, poll = function() {
1496 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
1497 te.selectionEnd > 0 && input.prevInput == "\u200b")
1498 operation(cm, commands.selectAll)(cm);
1499 else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
1500 else display.input.reset();
1501 };
1502 display.detectingSelectAll = setTimeout(poll, 200);
1503 }
1504 }
1505
1506 if (ie && ie_version >= 9) prepareSelectAllHack();
1507 if (captureRightClick) {
1508 e_stop(e);
1509 var mouseup = function() {
1510 off(window, "mouseup", mouseup);
1511 setTimeout(rehide, 20);
1512 };
1513 on(window, "mouseup", mouseup);
1514 } else {
1515 setTimeout(rehide, 50);
1516 }
1517 },
1518
1519 setUneditable: nothing,
1520
1521 needsContentAttribute: false
1522 }, TextareaInput.prototype);
1523
1524 // CONTENTEDITABLE INPUT STYLE
1525
1526 function ContentEditableInput(cm) {
1527 this.cm = cm;
1528 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
1529 this.polling = new Delayed();
1530 this.gracePeriod = false;
1531 }
1532
1533 ContentEditableInput.prototype = copyObj({
1534 init: function(display) {
1535 var input = this, cm = input.cm;
1536 var div = input.div = display.lineDiv;
1537 div.contentEditable = "true";
1538 disableBrowserMagic(div);
1539
1540 on(div, "paste", function(e) {
1541 var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
1542 if (pasted) {
1543 e.preventDefault();
1544 cm.replaceSelection(pasted, null, "paste");
1545 }
1546 });
1547
1548 on(div, "compositionstart", function(e) {
1549 var data = e.data;
1550 input.composing = {sel: cm.doc.sel, data: data, startData: data};
1551 if (!data) return;
1552 var prim = cm.doc.sel.primary();
1553 var line = cm.getLine(prim.head.line);
1554 var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
1555 if (found > -1 && found <= prim.head.ch)
1556 input.composing.sel = simpleSelection(Pos(prim.head.line, found),
1557 Pos(prim.head.line, found + data.length));
1558 });
1559 on(div, "compositionupdate", function(e) {
1560 input.composing.data = e.data;
1561 });
1562 on(div, "compositionend", function(e) {
1563 var ours = input.composing;
1564 if (!ours) return;
1565 if (e.data != ours.startData && !/\u200b/.test(e.data))
1566 ours.data = e.data;
1567 // Need a small delay to prevent other code (input event,
1568 // selection polling) from doing damage when fired right after
1569 // compositionend.
1570 setTimeout(function() {
1571 if (!ours.handled)
1572 input.applyComposition(ours);
1573 if (input.composing == ours)
1574 input.composing = null;
1575 }, 50);
1576 });
1577
1578 on(div, "touchstart", function() {
1579 input.forceCompositionEnd();
1580 });
1581
1582 on(div, "input", function() {
1583 if (input.composing) return;
1584 if (!input.pollContent())
1585 runInOp(input.cm, function() {regChange(cm);});
1586 });
1587
1588 function onCopyCut(e) {
1589 if (cm.somethingSelected()) {
1590 lastCopied = cm.getSelections();
1591 if (e.type == "cut") cm.replaceSelection("", null, "cut");
1592 } else if (!cm.options.lineWiseCopyCut) {
1593 return;
1594 } else {
1595 var ranges = copyableRanges(cm);
1596 lastCopied = ranges.text;
1597 if (e.type == "cut") {
1598 cm.operation(function() {
1599 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
1600 cm.replaceSelection("", null, "cut");
1601 });
1602 }
1603 }
1604 // iOS exposes the clipboard API, but seems to discard content inserted into it
1605 if (e.clipboardData && !ios) {
1606 e.preventDefault();
1607 e.clipboardData.clearData();
1608 e.clipboardData.setData("text/plain", lastCopied.join("\n"));
1609 } else {
1610 // Old-fashioned briefly-focus-a-textarea hack
1611 var kludge = hiddenTextarea(), te = kludge.firstChild;
1612 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
1613 te.value = lastCopied.join("\n");
1614 var hadFocus = document.activeElement;
1615 selectInput(te);
1616 setTimeout(function() {
1617 cm.display.lineSpace.removeChild(kludge);
1618 hadFocus.focus();
1619 }, 50);
1620 }
1621 }
1622 on(div, "copy", onCopyCut);
1623 on(div, "cut", onCopyCut);
1624 },
1625
1626 prepareSelection: function() {
1627 var result = prepareSelection(this.cm, false);
1628 result.focus = this.cm.state.focused;
1629 return result;
1630 },
1631
1632 showSelection: function(info) {
1633 if (!info || !this.cm.display.view.length) return;
1634 if (info.focus) this.showPrimarySelection();
1635 this.showMultipleSelections(info);
1636 },
1637
1638 showPrimarySelection: function() {
1639 var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
1640 var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
1641 var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
1642 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
1643 cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
1644 cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
1645 return;
1646
1647 var start = posToDOM(this.cm, prim.from());
1648 var end = posToDOM(this.cm, prim.to());
1649 if (!start && !end) return;
1650
1651 var view = this.cm.display.view;
1652 var old = sel.rangeCount && sel.getRangeAt(0);
1653 if (!start) {
1654 start = {node: view[0].measure.map[2], offset: 0};
1655 } else if (!end) { // FIXME dangerously hacky
1656 var measure = view[view.length - 1].measure;
1657 var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
1658 end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
1659 }
1660
1661 try { var rng = range(start.node, start.offset, end.offset, end.node); }
1662 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
1663 if (rng) {
1664 sel.removeAllRanges();
1665 sel.addRange(rng);
1666 if (old && sel.anchorNode == null) sel.addRange(old);
1667 else if (gecko) this.startGracePeriod();
1668 }
1669 this.rememberSelection();
1670 },
1671
1672 startGracePeriod: function() {
1673 var input = this;
1674 clearTimeout(this.gracePeriod);
1675 this.gracePeriod = setTimeout(function() {
1676 input.gracePeriod = false;
1677 if (input.selectionChanged())
1678 input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
1679 }, 20);
1680 },
1681
1682 showMultipleSelections: function(info) {
1683 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
1684 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
1685 },
1686
1687 rememberSelection: function() {
1688 var sel = window.getSelection();
1689 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
1690 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
1691 },
1692
1693 selectionInEditor: function() {
1694 var sel = window.getSelection();
1695 if (!sel.rangeCount) return false;
1696 var node = sel.getRangeAt(0).commonAncestorContainer;
1697 return contains(this.div, node);
1698 },
1699
1700 focus: function() {
1701 if (this.cm.options.readOnly != "nocursor") this.div.focus();
1702 },
1703 blur: function() { this.div.blur(); },
1704 getField: function() { return this.div; },
1705
1706 supportsTouch: function() { return true; },
1707
1708 receivedFocus: function() {
1709 var input = this;
1710 if (this.selectionInEditor())
1711 this.pollSelection();
1712 else
1713 runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
1714
1715 function poll() {
1716 if (input.cm.state.focused) {
1717 input.pollSelection();
1718 input.polling.set(input.cm.options.pollInterval, poll);
1719 }
1720 }
1721 this.polling.set(this.cm.options.pollInterval, poll);
1722 },
1723
1724 selectionChanged: function() {
1725 var sel = window.getSelection();
1726 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
1727 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
1728 },
1729
1730 pollSelection: function() {
1731 if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
1732 var sel = window.getSelection(), cm = this.cm;
1733 this.rememberSelection();
1734 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
1735 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
1736 if (anchor && head) runInOp(cm, function() {
1737 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
1738 if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
1739 });
1740 }
1741 },
1742
1743 pollContent: function() {
1744 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
1745 var from = sel.from(), to = sel.to();
1746 if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
1747
1748 var fromIndex;
1749 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
1750 var fromLine = lineNo(display.view[0].line);
1751 var fromNode = display.view[0].node;
1752 } else {
1753 var fromLine = lineNo(display.view[fromIndex].line);
1754 var fromNode = display.view[fromIndex - 1].node.nextSibling;
1755 }
1756 var toIndex = findViewIndex(cm, to.line);
1757 if (toIndex == display.view.length - 1) {
1758 var toLine = display.viewTo - 1;
1759 var toNode = display.view[toIndex].node;
1760 } else {
1761 var toLine = lineNo(display.view[toIndex + 1].line) - 1;
1762 var toNode = display.view[toIndex + 1].node.previousSibling;
1763 }
1764
1765 var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
1766 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
1767 while (newText.length > 1 && oldText.length > 1) {
1768 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
1769 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
1770 else break;
1771 }
1772
1773 var cutFront = 0, cutEnd = 0;
1774 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
1775 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
1776 ++cutFront;
1777 var newBot = lst(newText), oldBot = lst(oldText);
1778 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
1779 oldBot.length - (oldText.length == 1 ? cutFront : 0));
1780 while (cutEnd < maxCutEnd &&
1781 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
1782 ++cutEnd;
1783
1784 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
1785 newText[0] = newText[0].slice(cutFront);
1786
1787 var chFrom = Pos(fromLine, cutFront);
1788 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
1789 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
1790 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
1791 return true;
1792 }
1793 },
1794
1795 ensurePolled: function() {
1796 this.forceCompositionEnd();
1797 },
1798 reset: function() {
1799 this.forceCompositionEnd();
1800 },
1801 forceCompositionEnd: function() {
1802 if (!this.composing || this.composing.handled) return;
1803 this.applyComposition(this.composing);
1804 this.composing.handled = true;
1805 this.div.blur();
1806 this.div.focus();
1807 },
1808 applyComposition: function(composing) {
1809 if (composing.data && composing.data != composing.startData)
1810 operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
1811 },
1812
1813 setUneditable: function(node) {
1814 node.setAttribute("contenteditable", "false");
1815 },
1816
1817 onKeyPress: function(e) {
1818 e.preventDefault();
1819 operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
1820 },
1821
1822 onContextMenu: nothing,
1823 resetPosition: nothing,
1824
1825 needsContentAttribute: true
1826 }, ContentEditableInput.prototype);
1827
1828 function posToDOM(cm, pos) {
1829 var view = findViewForLine(cm, pos.line);
1830 if (!view || view.hidden) return null;
1831 var line = getLine(cm.doc, pos.line);
1832 var info = mapFromLineView(view, line, pos.line);
1833
1834 var order = getOrder(line), side = "left";
1835 if (order) {
1836 var partPos = getBidiPartAt(order, pos.ch);
1837 side = partPos % 2 ? "right" : "left";
1838 }
1839 var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left");
1840 result.offset = result.collapse == "right" ? result.end : result.start;
1841 return result;
1842 }
1843
1844 function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
1845
1846 function domToPos(cm, node, offset) {
1847 var lineNode;
1848 if (node == cm.display.lineDiv) {
1849 lineNode = cm.display.lineDiv.childNodes[offset];
1850 if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
1851 node = null; offset = 0;
1852 } else {
1853 for (lineNode = node;; lineNode = lineNode.parentNode) {
1854 if (!lineNode || lineNode == cm.display.lineDiv) return null;
1855 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
1856 }
1857 }
1858 for (var i = 0; i < cm.display.view.length; i++) {
1859 var lineView = cm.display.view[i];
1860 if (lineView.node == lineNode)
1861 return locateNodeInLineView(lineView, node, offset);
1862 }
1863 }
1864
1865 function locateNodeInLineView(lineView, node, offset) {
1866 var wrapper = lineView.text.firstChild, bad = false;
1867 if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
1868 if (node == wrapper) {
1869 bad = true;
1870 node = wrapper.childNodes[offset];
1871 offset = 0;
1872 if (!node) {
1873 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
1874 return badPos(Pos(lineNo(line), line.text.length), bad);
1875 }
1876 }
1877
1878 var textNode = node.nodeType == 3 ? node : null, topNode = node;
1879 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
1880 textNode = node.firstChild;
1881 if (offset) offset = textNode.nodeValue.length;
1882 }
1883 while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
1884 var measure = lineView.measure, maps = measure.maps;
1885
1886 function find(textNode, topNode, offset) {
1887 for (var i = -1; i < (maps ? maps.length : 0); i++) {
1888 var map = i < 0 ? measure.map : maps[i];
1889 for (var j = 0; j < map.length; j += 3) {
1890 var curNode = map[j + 2];
1891 if (curNode == textNode || curNode == topNode) {
1892 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
1893 var ch = map[j] + offset;
1894 if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
1895 return Pos(line, ch);
1896 }
1897 }
1898 }
1899 }
1900 var found = find(textNode, topNode, offset);
1901 if (found) return badPos(found, bad);
1902
1903 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
1904 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
1905 found = find(after, after.firstChild, 0);
1906 if (found)
1907 return badPos(Pos(found.line, found.ch - dist), bad);
1908 else
1909 dist += after.textContent.length;
1910 }
1911 for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
1912 found = find(before, before.firstChild, -1);
1913 if (found)
1914 return badPos(Pos(found.line, found.ch + dist), bad);
1915 else
1916 dist += after.textContent.length;
1917 }
1918 }
1919
1920 function domTextBetween(cm, from, to, fromLine, toLine) {
1921 var text = "", closing = false;
1922 function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
1923 function walk(node) {
1924 if (node.nodeType == 1) {
1925 var cmText = node.getAttribute("cm-text");
1926 if (cmText != null) {
1927 if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
1928 text += cmText;
1929 return;
1930 }
1931 var markerID = node.getAttribute("cm-marker"), range;
1932 if (markerID) {
1933 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
1934 if (found.length && (range = found[0].find()))
1935 text += getBetween(cm.doc, range.from, range.to).join("\n");
1936 return;
1937 }
1938 if (node.getAttribute("contenteditable") == "false") return;
1939 for (var i = 0; i < node.childNodes.length; i++)
1940 walk(node.childNodes[i]);
1941 if (/^(pre|div|p)$/i.test(node.nodeName))
1942 closing = true;
1943 } else if (node.nodeType == 3) {
1944 var val = node.nodeValue;
1945 if (!val) return;
1946 if (closing) {
1947 text += "\n";
1948 closing = false;
1949 }
1950 text += val;
1951 }
1952 }
1953 for (;;) {
1954 walk(from);
1955 if (from == to) break;
1956 from = from.nextSibling;
1957 }
1958 return text;
1959 }
1960
1961 CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
1962
1963 // SELECTION / CURSOR
1964
1965 // Selection objects are immutable. A new one is created every time
1966 // the selection changes. A selection is one or more non-overlapping
1967 // (and non-touching) ranges, sorted, and an integer that indicates
1968 // which one is the primary selection (the one that's scrolled into
1969 // view, that getCursor returns, etc).
1970 function Selection(ranges, primIndex) {
1971 this.ranges = ranges;
1972 this.primIndex = primIndex;
1973 }
1974
1975 Selection.prototype = {
1976 primary: function() { return this.ranges[this.primIndex]; },
1977 equals: function(other) {
1978 if (other == this) return true;
1979 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
1980 for (var i = 0; i < this.ranges.length; i++) {
1981 var here = this.ranges[i], there = other.ranges[i];
1982 if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
1983 }
1984 return true;
1985 },
1986 deepCopy: function() {
1987 for (var out = [], i = 0; i < this.ranges.length; i++)
1988 out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
1989 return new Selection(out, this.primIndex);
1990 },
1991 somethingSelected: function() {
1992 for (var i = 0; i < this.ranges.length; i++)
1993 if (!this.ranges[i].empty()) return true;
1994 return false;
1995 },
1996 contains: function(pos, end) {
1997 if (!end) end = pos;
1998 for (var i = 0; i < this.ranges.length; i++) {
1999 var range = this.ranges[i];
2000 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
2001 return i;
2002 }
2003 return -1;
2004 }
2005 };
2006
2007 function Range(anchor, head) {
2008 this.anchor = anchor; this.head = head;
2009 }
2010
2011 Range.prototype = {
2012 from: function() { return minPos(this.anchor, this.head); },
2013 to: function() { return maxPos(this.anchor, this.head); },
2014 empty: function() {
2015 return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
2016 }
2017 };
2018
2019 // Take an unsorted, potentially overlapping set of ranges, and
2020 // build a selection out of it. 'Consumes' ranges array (modifying
2021 // it).
2022 function normalizeSelection(ranges, primIndex) {
2023 var prim = ranges[primIndex];
2024 ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
2025 primIndex = indexOf(ranges, prim);
2026 for (var i = 1; i < ranges.length; i++) {
2027 var cur = ranges[i], prev = ranges[i - 1];
2028 if (cmp(prev.to(), cur.from()) >= 0) {
2029 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
2030 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
2031 if (i <= primIndex) --primIndex;
2032 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
2033 }
2034 }
2035 return new Selection(ranges, primIndex);
2036 }
2037
2038 function simpleSelection(anchor, head) {
2039 return new Selection([new Range(anchor, head || anchor)], 0);
2040 }
2041
2042 // Most of the external API clips given positions to make sure they
2043 // actually exist within the document.
2044 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
2045 function clipPos(doc, pos) {
2046 if (pos.line < doc.first) return Pos(doc.first, 0);
2047 var last = doc.first + doc.size - 1;
2048 if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
2049 return clipToLen(pos, getLine(doc, pos.line).text.length);
2050 }
2051 function clipToLen(pos, linelen) {
2052 var ch = pos.ch;
2053 if (ch == null || ch > linelen) return Pos(pos.line, linelen);
2054 else if (ch < 0) return Pos(pos.line, 0);
2055 else return pos;
2056 }
2057 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
2058 function clipPosArray(doc, array) {
2059 for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
2060 return out;
2061 }
2062
2063 // SELECTION UPDATES
2064
2065 // The 'scroll' parameter given to many of these indicated whether
2066 // the new cursor position should be scrolled into view after
2067 // modifying the selection.
2068
2069 // If shift is held or the extend flag is set, extends a range to
2070 // include a given position (and optionally a second position).
2071 // Otherwise, simply returns the range between the given positions.
2072 // Used for cursor motion and such.
2073 function extendRange(doc, range, head, other) {
2074 if (doc.cm && doc.cm.display.shift || doc.extend) {
2075 var anchor = range.anchor;
2076 if (other) {
2077 var posBefore = cmp(head, anchor) < 0;
2078 if (posBefore != (cmp(other, anchor) < 0)) {
2079 anchor = head;
2080 head = other;
2081 } else if (posBefore != (cmp(head, other) < 0)) {
2082 head = other;
2083 }
2084 }
2085 return new Range(anchor, head);
2086 } else {
2087 return new Range(other || head, head);
2088 }
2089 }
2090
2091 // Extend the primary selection range, discard the rest.
2092 function extendSelection(doc, head, other, options) {
2093 setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
2094 }
2095
2096 // Extend all selections (pos is an array of selections with length
2097 // equal the number of selections)
2098 function extendSelections(doc, heads, options) {
2099 for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
2100 out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
2101 var newSel = normalizeSelection(out, doc.sel.primIndex);
2102 setSelection(doc, newSel, options);
2103 }
2104
2105 // Updates a single range in the selection.
2106 function replaceOneSelection(doc, i, range, options) {
2107 var ranges = doc.sel.ranges.slice(0);
2108 ranges[i] = range;
2109 setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
2110 }
2111
2112 // Reset the selection to a single range.
2113 function setSimpleSelection(doc, anchor, head, options) {
2114 setSelection(doc, simpleSelection(anchor, head), options);
2115 }
2116
2117 // Give beforeSelectionChange handlers a change to influence a
2118 // selection update.
2119 function filterSelectionChange(doc, sel) {
2120 var obj = {
2121 ranges: sel.ranges,
2122 update: function(ranges) {
2123 this.ranges = [];
2124 for (var i = 0; i < ranges.length; i++)
2125 this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
2126 clipPos(doc, ranges[i].head));
2127 }
2128 };
2129 signal(doc, "beforeSelectionChange", doc, obj);
2130 if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
2131 if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
2132 else return sel;
2133 }
2134
2135 function setSelectionReplaceHistory(doc, sel, options) {
2136 var done = doc.history.done, last = lst(done);
2137 if (last && last.ranges) {
2138 done[done.length - 1] = sel;
2139 setSelectionNoUndo(doc, sel, options);
2140 } else {
2141 setSelection(doc, sel, options);
2142 }
2143 }
2144
2145 // Set a new selection.
2146 function setSelection(doc, sel, options) {
2147 setSelectionNoUndo(doc, sel, options);
2148 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
2149 }
2150
2151 function setSelectionNoUndo(doc, sel, options) {
2152 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
2153 sel = filterSelectionChange(doc, sel);
2154
2155 var bias = options && options.bias ||
2156 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
2157 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
2158
2159 if (!(options && options.scroll === false) && doc.cm)
2160 ensureCursorVisible(doc.cm);
2161 }
2162
2163 function setSelectionInner(doc, sel) {
2164 if (sel.equals(doc.sel)) return;
2165
2166 doc.sel = sel;
2167
2168 if (doc.cm) {
2169 doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
2170 signalCursorActivity(doc.cm);
2171 }
2172 signalLater(doc, "cursorActivity", doc);
2173 }
2174
2175 // Verify that the selection does not partially select any atomic
2176 // marked ranges.
2177 function reCheckSelection(doc) {
2178 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
2179 }
2180
2181 // Return a selection that does not partially select any atomic
2182 // ranges.
2183 function skipAtomicInSelection(doc, sel, bias, mayClear) {
2184 var out;
2185 for (var i = 0; i < sel.ranges.length; i++) {
2186 var range = sel.ranges[i];
2187 var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
2188 var newHead = skipAtomic(doc, range.head, bias, mayClear);
2189 if (out || newAnchor != range.anchor || newHead != range.head) {
2190 if (!out) out = sel.ranges.slice(0, i);
2191 out[i] = new Range(newAnchor, newHead);
2192 }
2193 }
2194 return out ? normalizeSelection(out, sel.primIndex) : sel;
2195 }
2196
2197 // Ensure a given position is not inside an atomic range.
2198 function skipAtomic(doc, pos, bias, mayClear) {
2199 var flipped = false, curPos = pos;
2200 var dir = bias || 1;
2201 doc.cantEdit = false;
2202 search: for (;;) {
2203 var line = getLine(doc, curPos.line);
2204 if (line.markedSpans) {
2205 for (var i = 0; i < line.markedSpans.length; ++i) {
2206 var sp = line.markedSpans[i], m = sp.marker;
2207 if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
2208 (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
2209 if (mayClear) {
2210 signal(m, "beforeCursorEnter");
2211 if (m.explicitlyCleared) {
2212 if (!line.markedSpans) break;
2213 else {--i; continue;}
2214 }
2215 }
2216 if (!m.atomic) continue;
2217 var newPos = m.find(dir < 0 ? -1 : 1);
2218 if (cmp(newPos, curPos) == 0) {
2219 newPos.ch += dir;
2220 if (newPos.ch < 0) {
2221 if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
2222 else newPos = null;
2223 } else if (newPos.ch > line.text.length) {
2224 if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
2225 else newPos = null;
2226 }
2227 if (!newPos) {
2228 if (flipped) {
2229 // Driven in a corner -- no valid cursor position found at all
2230 // -- try again *with* clearing, if we didn't already
2231 if (!mayClear) return skipAtomic(doc, pos, bias, true);
2232 // Otherwise, turn off editing until further notice, and return the start of the doc
2233 doc.cantEdit = true;
2234 return Pos(doc.first, 0);
2235 }
2236 flipped = true; newPos = pos; dir = -dir;
2237 }
2238 }
2239 curPos = newPos;
2240 continue search;
2241 }
2242 }
2243 }
2244 return curPos;
2245 }
2246 }
2247
2248 // SELECTION DRAWING
2249
2250 function updateSelection(cm) {
2251 cm.display.input.showSelection(cm.display.input.prepareSelection());
2252 }
2253
2254 function prepareSelection(cm, primary) {
2255 var doc = cm.doc, result = {};
2256 var curFragment = result.cursors = document.createDocumentFragment();
2257 var selFragment = result.selection = document.createDocumentFragment();
2258
2259 for (var i = 0; i < doc.sel.ranges.length; i++) {
2260 if (primary === false && i == doc.sel.primIndex) continue;
2261 var range = doc.sel.ranges[i];
2262 var collapsed = range.empty();
2263 if (collapsed || cm.options.showCursorWhenSelecting)
2264 drawSelectionCursor(cm, range, curFragment);
2265 if (!collapsed)
2266 drawSelectionRange(cm, range, selFragment);
2267 }
2268 return result;
2269 }
2270
2271 // Draws a cursor for the given range
2272 function drawSelectionCursor(cm, range, output) {
2273 var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
2274
2275 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
2276 cursor.style.left = pos.left + "px";
2277 cursor.style.top = pos.top + "px";
2278 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
2279
2280 if (pos.other) {
2281 // Secondary cursor, shown when on a 'jump' in bi-directional text
2282 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
2283 otherCursor.style.display = "";
2284 otherCursor.style.left = pos.other.left + "px";
2285 otherCursor.style.top = pos.other.top + "px";
2286 otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
2287 }
2288 }
2289
2290 // Draws the given range as a highlighted selection
2291 function drawSelectionRange(cm, range, output) {
2292 var display = cm.display, doc = cm.doc;
2293 var fragment = document.createDocumentFragment();
2294 var padding = paddingH(cm.display), leftSide = padding.left;
2295 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
2296
2297 function add(left, top, width, bottom) {
2298 if (top < 0) top = 0;
2299 top = Math.round(top);
2300 bottom = Math.round(bottom);
2301 fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
2302 "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
2303 "px; height: " + (bottom - top) + "px"));
2304 }
2305
2306 function drawForLine(line, fromArg, toArg) {
2307 var lineObj = getLine(doc, line);
2308 var lineLen = lineObj.text.length;
2309 var start, end;
2310 function coords(ch, bias) {
2311 return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
2312 }
2313
2314 iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
2315 var leftPos = coords(from, "left"), rightPos, left, right;
2316 if (from == to) {
2317 rightPos = leftPos;
2318 left = right = leftPos.left;
2319 } else {
2320 rightPos = coords(to - 1, "right");
2321 if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
2322 left = leftPos.left;
2323 right = rightPos.right;
2324 }
2325 if (fromArg == null && from == 0) left = leftSide;
2326 if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
2327 add(left, leftPos.top, null, leftPos.bottom);
2328 left = leftSide;
2329 if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
2330 }
2331 if (toArg == null && to == lineLen) right = rightSide;
2332 if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
2333 start = leftPos;
2334 if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
2335 end = rightPos;
2336 if (left < leftSide + 1) left = leftSide;
2337 add(left, rightPos.top, right - left, rightPos.bottom);
2338 });
2339 return {start: start, end: end};
2340 }
2341
2342 var sFrom = range.from(), sTo = range.to();
2343 if (sFrom.line == sTo.line) {
2344 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
2345 } else {
2346 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
2347 var singleVLine = visualLine(fromLine) == visualLine(toLine);
2348 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
2349 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
2350 if (singleVLine) {
2351 if (leftEnd.top < rightStart.top - 2) {
2352 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
2353 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
2354 } else {
2355 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
2356 }
2357 }
2358 if (leftEnd.bottom < rightStart.top)
2359 add(leftSide, leftEnd.bottom, null, rightStart.top);
2360 }
2361
2362 output.appendChild(fragment);
2363 }
2364
2365 // Cursor-blinking
2366 function restartBlink(cm) {
2367 if (!cm.state.focused) return;
2368 var display = cm.display;
2369 clearInterval(display.blinker);
2370 var on = true;
2371 display.cursorDiv.style.visibility = "";
2372 if (cm.options.cursorBlinkRate > 0)
2373 display.blinker = setInterval(function() {
2374 display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
2375 }, cm.options.cursorBlinkRate);
2376 else if (cm.options.cursorBlinkRate < 0)
2377 display.cursorDiv.style.visibility = "hidden";
2378 }
2379
2380 // HIGHLIGHT WORKER
2381
2382 function startWorker(cm, time) {
2383 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
2384 cm.state.highlight.set(time, bind(highlightWorker, cm));
2385 }
2386
2387 function highlightWorker(cm) {
2388 var doc = cm.doc;
2389 if (doc.frontier < doc.first) doc.frontier = doc.first;
2390 if (doc.frontier >= cm.display.viewTo) return;
2391 var end = +new Date + cm.options.workTime;
2392 var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
2393 var changedLines = [];
2394
2395 doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
2396 if (doc.frontier >= cm.display.viewFrom) { // Visible
2397 var oldStyles = line.styles;
2398 var highlighted = highlightLine(cm, line, state, true);
2399 line.styles = highlighted.styles;
2400 var oldCls = line.styleClasses, newCls = highlighted.classes;
2401 if (newCls) line.styleClasses = newCls;
2402 else if (oldCls) line.styleClasses = null;
2403 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
2404 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
2405 for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
2406 if (ischange) changedLines.push(doc.frontier);
2407 line.stateAfter = copyState(doc.mode, state);
2408 } else {
2409 processLine(cm, line.text, state);
2410 line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
2411 }
2412 ++doc.frontier;
2413 if (+new Date > end) {
2414 startWorker(cm, cm.options.workDelay);
2415 return true;
2416 }
2417 });
2418 if (changedLines.length) runInOp(cm, function() {
2419 for (var i = 0; i < changedLines.length; i++)
2420 regLineChange(cm, changedLines[i], "text");
2421 });
2422 }
2423
2424 // Finds the line to start with when starting a parse. Tries to
2425 // find a line with a stateAfter, so that it can start with a
2426 // valid state. If that fails, it returns the line with the
2427 // smallest indentation, which tends to need the least context to
2428 // parse correctly.
2429 function findStartLine(cm, n, precise) {
2430 var minindent, minline, doc = cm.doc;
2431 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
2432 for (var search = n; search > lim; --search) {
2433 if (search <= doc.first) return doc.first;
2434 var line = getLine(doc, search - 1);
2435 if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
2436 var indented = countColumn(line.text, null, cm.options.tabSize);
2437 if (minline == null || minindent > indented) {
2438 minline = search - 1;
2439 minindent = indented;
2440 }
2441 }
2442 return minline;
2443 }
2444
2445 function getStateBefore(cm, n, precise) {
2446 var doc = cm.doc, display = cm.display;
2447 if (!doc.mode.startState) return true;
2448 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
2449 if (!state) state = startState(doc.mode);
2450 else state = copyState(doc.mode, state);
2451 doc.iter(pos, n, function(line) {
2452 processLine(cm, line.text, state);
2453 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
2454 line.stateAfter = save ? copyState(doc.mode, state) : null;
2455 ++pos;
2456 });
2457 if (precise) doc.frontier = pos;
2458 return state;
2459 }
2460
2461 // POSITION MEASUREMENT
2462
2463 function paddingTop(display) {return display.lineSpace.offsetTop;}
2464 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
2465 function paddingH(display) {
2466 if (display.cachedPaddingH) return display.cachedPaddingH;
2467 var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
2468 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
2469 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
2470 if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
2471 return data;
2472 }
2473
2474 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
2475 function displayWidth(cm) {
2476 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
2477 }
2478 function displayHeight(cm) {
2479 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
2480 }
2481
2482 // Ensure the lineView.wrapping.heights array is populated. This is
2483 // an array of bottom offsets for the lines that make up a drawn
2484 // line. When lineWrapping is on, there might be more than one
2485 // height.
2486 function ensureLineHeights(cm, lineView, rect) {
2487 var wrapping = cm.options.lineWrapping;
2488 var curWidth = wrapping && displayWidth(cm);
2489 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
2490 var heights = lineView.measure.heights = [];
2491 if (wrapping) {
2492 lineView.measure.width = curWidth;
2493 var rects = lineView.text.firstChild.getClientRects();
2494 for (var i = 0; i < rects.length - 1; i++) {
2495 var cur = rects[i], next = rects[i + 1];
2496 if (Math.abs(cur.bottom - next.bottom) > 2)
2497 heights.push((cur.bottom + next.top) / 2 - rect.top);
2498 }
2499 }
2500 heights.push(rect.bottom - rect.top);
2501 }
2502 }
2503
2504 // Find a line map (mapping character offsets to text nodes) and a
2505 // measurement cache for the given line number. (A line view might
2506 // contain multiple lines when collapsed ranges are present.)
2507 function mapFromLineView(lineView, line, lineN) {
2508 if (lineView.line == line)
2509 return {map: lineView.measure.map, cache: lineView.measure.cache};
2510 for (var i = 0; i < lineView.rest.length; i++)
2511 if (lineView.rest[i] == line)
2512 return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
2513 for (var i = 0; i < lineView.rest.length; i++)
2514 if (lineNo(lineView.rest[i]) > lineN)
2515 return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
2516 }
2517
2518 // Render a line into the hidden node display.externalMeasured. Used
2519 // when measurement is needed for a line that's not in the viewport.
2520 function updateExternalMeasurement(cm, line) {
2521 line = visualLine(line);
2522 var lineN = lineNo(line);
2523 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
2524 view.lineN = lineN;
2525 var built = view.built = buildLineContent(cm, view);
2526 view.text = built.pre;
2527 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
2528 return view;
2529 }
2530
2531 // Get a {top, bottom, left, right} box (in line-local coordinates)
2532 // for a given character.
2533 function measureChar(cm, line, ch, bias) {
2534 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
2535 }
2536
2537 // Find a line view that corresponds to the given line number.
2538 function findViewForLine(cm, lineN) {
2539 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
2540 return cm.display.view[findViewIndex(cm, lineN)];
2541 var ext = cm.display.externalMeasured;
2542 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
2543 return ext;
2544 }
2545
2546 // Measurement can be split in two steps, the set-up work that
2547 // applies to the whole line, and the measurement of the actual
2548 // character. Functions like coordsChar, that need to do a lot of
2549 // measurements in a row, can thus ensure that the set-up work is
2550 // only done once.
2551 function prepareMeasureForLine(cm, line) {
2552 var lineN = lineNo(line);
2553 var view = findViewForLine(cm, lineN);
2554 if (view && !view.text)
2555 view = null;
2556 else if (view && view.changes)
2557 updateLineForChanges(cm, view, lineN, getDimensions(cm));
2558 if (!view)
2559 view = updateExternalMeasurement(cm, line);
2560
2561 var info = mapFromLineView(view, line, lineN);
2562 return {
2563 line: line, view: view, rect: null,
2564 map: info.map, cache: info.cache, before: info.before,
2565 hasHeights: false
2566 };
2567 }
2568
2569 // Given a prepared measurement object, measures the position of an
2570 // actual character (or fetches it from the cache).
2571 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
2572 if (prepared.before) ch = -1;
2573 var key = ch + (bias || ""), found;
2574 if (prepared.cache.hasOwnProperty(key)) {
2575 found = prepared.cache[key];
2576 } else {
2577 if (!prepared.rect)
2578 prepared.rect = prepared.view.text.getBoundingClientRect();
2579 if (!prepared.hasHeights) {
2580 ensureLineHeights(cm, prepared.view, prepared.rect);
2581 prepared.hasHeights = true;
2582 }
2583 found = measureCharInner(cm, prepared, ch, bias);
2584 if (!found.bogus) prepared.cache[key] = found;
2585 }
2586 return {left: found.left, right: found.right,
2587 top: varHeight ? found.rtop : found.top,
2588 bottom: varHeight ? found.rbottom : found.bottom};
2589 }
2590
2591 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
2592
2593 function nodeAndOffsetInLineMap(map, ch, bias) {
2594 var node, start, end, collapse;
2595 // First, search the line map for the text node corresponding to,
2596 // or closest to, the target character.
2597 for (var i = 0; i < map.length; i += 3) {
2598 var mStart = map[i], mEnd = map[i + 1];
2599 if (ch < mStart) {
2600 start = 0; end = 1;
2601 collapse = "left";
2602 } else if (ch < mEnd) {
2603 start = ch - mStart;
2604 end = start + 1;
2605 } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
2606 end = mEnd - mStart;
2607 start = end - 1;
2608 if (ch >= mEnd) collapse = "right";
2609 }
2610 if (start != null) {
2611 node = map[i + 2];
2612 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2613 collapse = bias;
2614 if (bias == "left" && start == 0)
2615 while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
2616 node = map[(i -= 3) + 2];
2617 collapse = "left";
2618 }
2619 if (bias == "right" && start == mEnd - mStart)
2620 while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
2621 node = map[(i += 3) + 2];
2622 collapse = "right";
2623 }
2624 break;
2625 }
2626 }
2627 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
2628 }
2629
2630 function measureCharInner(cm, prepared, ch, bias) {
2631 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
2632 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
2633
2634 var rect;
2635 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
2636 for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
2637 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
2638 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
2639 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
2640 rect = node.parentNode.getBoundingClientRect();
2641 } else if (ie && cm.options.lineWrapping) {
2642 var rects = range(node, start, end).getClientRects();
2643 if (rects.length)
2644 rect = rects[bias == "right" ? rects.length - 1 : 0];
2645 else
2646 rect = nullRect;
2647 } else {
2648 rect = range(node, start, end).getBoundingClientRect() || nullRect;
2649 }
2650 if (rect.left || rect.right || start == 0) break;
2651 end = start;
2652 start = start - 1;
2653 collapse = "right";
2654 }
2655 if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
2656 } else { // If it is a widget, simply get the box for the whole widget.
2657 if (start > 0) collapse = bias = "right";
2658 var rects;
2659 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
2660 rect = rects[bias == "right" ? rects.length - 1 : 0];
2661 else
2662 rect = node.getBoundingClientRect();
2663 }
2664 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
2665 var rSpan = node.parentNode.getClientRects()[0];
2666 if (rSpan)
2667 rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
2668 else
2669 rect = nullRect;
2670 }
2671
2672 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
2673 var mid = (rtop + rbot) / 2;
2674 var heights = prepared.view.measure.heights;
2675 for (var i = 0; i < heights.length - 1; i++)
2676 if (mid < heights[i]) break;
2677 var top = i ? heights[i - 1] : 0, bot = heights[i];
2678 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
2679 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
2680 top: top, bottom: bot};
2681 if (!rect.left && !rect.right) result.bogus = true;
2682 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
2683
2684 return result;
2685 }
2686
2687 // Work around problem with bounding client rects on ranges being
2688 // returned incorrectly when zoomed on IE10 and below.
2689 function maybeUpdateRectForZooming(measure, rect) {
2690 if (!window.screen || screen.logicalXDPI == null ||
2691 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
2692 return rect;
2693 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
2694 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
2695 return {left: rect.left * scaleX, right: rect.right * scaleX,
2696 top: rect.top * scaleY, bottom: rect.bottom * scaleY};
2697 }
2698
2699 function clearLineMeasurementCacheFor(lineView) {
2700 if (lineView.measure) {
2701 lineView.measure.cache = {};
2702 lineView.measure.heights = null;
2703 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
2704 lineView.measure.caches[i] = {};
2705 }
2706 }
2707
2708 function clearLineMeasurementCache(cm) {
2709 cm.display.externalMeasure = null;
2710 removeChildren(cm.display.lineMeasure);
2711 for (var i = 0; i < cm.display.view.length; i++)
2712 clearLineMeasurementCacheFor(cm.display.view[i]);
2713 }
2714
2715 function clearCaches(cm) {
2716 clearLineMeasurementCache(cm);
2717 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
2718 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
2719 cm.display.lineNumChars = null;
2720 }
2721
2722 function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
2723 function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
2724
2725 // Converts a {top, bottom, left, right} box from line-local
2726 // coordinates into another coordinate system. Context may be one of
2727 // "line", "div" (display.lineDiv), "local"/null (editor), "window",
2728 // or "page".
2729 function intoCoordSystem(cm, lineObj, rect, context) {
2730 if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
2731 var size = widgetHeight(lineObj.widgets[i]);
2732 rect.top += size; rect.bottom += size;
2733 }
2734 if (context == "line") return rect;
2735 if (!context) context = "local";
2736 var yOff = heightAtLine(lineObj);
2737 if (context == "local") yOff += paddingTop(cm.display);
2738 else yOff -= cm.display.viewOffset;
2739 if (context == "page" || context == "window") {
2740 var lOff = cm.display.lineSpace.getBoundingClientRect();
2741 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
2742 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
2743 rect.left += xOff; rect.right += xOff;
2744 }
2745 rect.top += yOff; rect.bottom += yOff;
2746 return rect;
2747 }
2748
2749 // Coverts a box from "div" coords to another coordinate system.
2750 // Context may be "window", "page", "div", or "local"/null.
2751 function fromCoordSystem(cm, coords, context) {
2752 if (context == "div") return coords;
2753 var left = coords.left, top = coords.top;
2754 // First move into "page" coordinate system
2755 if (context == "page") {
2756 left -= pageScrollX();
2757 top -= pageScrollY();
2758 } else if (context == "local" || !context) {
2759 var localBox = cm.display.sizer.getBoundingClientRect();
2760 left += localBox.left;
2761 top += localBox.top;
2762 }
2763
2764 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
2765 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
2766 }
2767
2768 function charCoords(cm, pos, context, lineObj, bias) {
2769 if (!lineObj) lineObj = getLine(cm.doc, pos.line);
2770 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
2771 }
2772
2773 // Returns a box for a given cursor position, which may have an
2774 // 'other' property containing the position of the secondary cursor
2775 // on a bidi boundary.
2776 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
2777 lineObj = lineObj || getLine(cm.doc, pos.line);
2778 if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
2779 function get(ch, right) {
2780 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
2781 if (right) m.left = m.right; else m.right = m.left;
2782 return intoCoordSystem(cm, lineObj, m, context);
2783 }
2784 function getBidi(ch, partPos) {
2785 var part = order[partPos], right = part.level % 2;
2786 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
2787 part = order[--partPos];
2788 ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
2789 right = true;
2790 } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
2791 part = order[++partPos];
2792 ch = bidiLeft(part) - part.level % 2;
2793 right = false;
2794 }
2795 if (right && ch == part.to && ch > part.from) return get(ch - 1);
2796 return get(ch, right);
2797 }
2798 var order = getOrder(lineObj), ch = pos.ch;
2799 if (!order) return get(ch);
2800 var partPos = getBidiPartAt(order, ch);
2801 var val = getBidi(ch, partPos);
2802 if (bidiOther != null) val.other = getBidi(ch, bidiOther);
2803 return val;
2804 }
2805
2806 // Used to cheaply estimate the coordinates for a position. Used for
2807 // intermediate scroll updates.
2808 function estimateCoords(cm, pos) {
2809 var left = 0, pos = clipPos(cm.doc, pos);
2810 if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
2811 var lineObj = getLine(cm.doc, pos.line);
2812 var top = heightAtLine(lineObj) + paddingTop(cm.display);
2813 return {left: left, right: left, top: top, bottom: top + lineObj.height};
2814 }
2815
2816 // Positions returned by coordsChar contain some extra information.
2817 // xRel is the relative x position of the input coordinates compared
2818 // to the found position (so xRel > 0 means the coordinates are to
2819 // the right of the character position, for example). When outside
2820 // is true, that means the coordinates lie outside the line's
2821 // vertical range.
2822 function PosWithInfo(line, ch, outside, xRel) {
2823 var pos = Pos(line, ch);
2824 pos.xRel = xRel;
2825 if (outside) pos.outside = true;
2826 return pos;
2827 }
2828
2829 // Compute the character position closest to the given coordinates.
2830 // Input must be lineSpace-local ("div" coordinate system).
2831 function coordsChar(cm, x, y) {
2832 var doc = cm.doc;
2833 y += cm.display.viewOffset;
2834 if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
2835 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
2836 if (lineN > last)
2837 return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
2838 if (x < 0) x = 0;
2839
2840 var lineObj = getLine(doc, lineN);
2841 for (;;) {
2842 var found = coordsCharInner(cm, lineObj, lineN, x, y);
2843 var merged = collapsedSpanAtEnd(lineObj);
2844 var mergedPos = merged && merged.find(0, true);
2845 if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
2846 lineN = lineNo(lineObj = mergedPos.to.line);
2847 else
2848 return found;
2849 }
2850 }
2851
2852 function coordsCharInner(cm, lineObj, lineNo, x, y) {
2853 var innerOff = y - heightAtLine(lineObj);
2854 var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
2855 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
2856
2857 function getX(ch) {
2858 var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
2859 wrongLine = true;
2860 if (innerOff > sp.bottom) return sp.left - adjust;
2861 else if (innerOff < sp.top) return sp.left + adjust;
2862 else wrongLine = false;
2863 return sp.left;
2864 }
2865
2866 var bidi = getOrder(lineObj), dist = lineObj.text.length;
2867 var from = lineLeft(lineObj), to = lineRight(lineObj);
2868 var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
2869
2870 if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
2871 // Do a binary search between these bounds.
2872 for (;;) {
2873 if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
2874 var ch = x < fromX || x - fromX <= toX - x ? from : to;
2875 var xDiff = x - (ch == from ? fromX : toX);
2876 while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
2877 var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
2878 xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
2879 return pos;
2880 }
2881 var step = Math.ceil(dist / 2), middle = from + step;
2882 if (bidi) {
2883 middle = from;
2884 for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
2885 }
2886 var middleX = getX(middle);
2887 if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
2888 else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
2889 }
2890 }
2891
2892 var measureText;
2893 // Compute the default text height.
2894 function textHeight(display) {
2895 if (display.cachedTextHeight != null) return display.cachedTextHeight;
2896 if (measureText == null) {
2897 measureText = elt("pre");
2898 // Measure a bunch of lines, for browsers that compute
2899 // fractional heights.
2900 for (var i = 0; i < 49; ++i) {
2901 measureText.appendChild(document.createTextNode("x"));
2902 measureText.appendChild(elt("br"));
2903 }
2904 measureText.appendChild(document.createTextNode("x"));
2905 }
2906 removeChildrenAndAdd(display.measure, measureText);
2907 var height = measureText.offsetHeight / 50;
2908 if (height > 3) display.cachedTextHeight = height;
2909 removeChildren(display.measure);
2910 return height || 1;
2911 }
2912
2913 // Compute the default character width.
2914 function charWidth(display) {
2915 if (display.cachedCharWidth != null) return display.cachedCharWidth;
2916 var anchor = elt("span", "xxxxxxxxxx");
2917 var pre = elt("pre", [anchor]);
2918 removeChildrenAndAdd(display.measure, pre);
2919 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
2920 if (width > 2) display.cachedCharWidth = width;
2921 return width || 10;
2922 }
2923
2924 // OPERATIONS
2925
2926 // Operations are used to wrap a series of changes to the editor
2927 // state in such a way that each change won't have to update the
2928 // cursor and display (which would be awkward, slow, and
2929 // error-prone). Instead, display updates are batched and then all
2930 // combined and executed at once.
2931
2932 var operationGroup = null;
2933
2934 var nextOpId = 0;
2935 // Start a new operation.
2936 function startOperation(cm) {
2937 cm.curOp = {
2938 cm: cm,
2939 viewChanged: false, // Flag that indicates that lines might need to be redrawn
2940 startHeight: cm.doc.height, // Used to detect need to update scrollbar
2941 forceUpdate: false, // Used to force a redraw
2942 updateInput: null, // Whether to reset the input textarea
2943 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
2944 changeObjs: null, // Accumulated changes, for firing change events
2945 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
2946 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
2947 selectionChanged: false, // Whether the selection needs to be redrawn
2948 updateMaxLine: false, // Set when the widest line needs to be determined anew
2949 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
2950 scrollToPos: null, // Used to scroll to a specific position
2951 focus: false,
2952 id: ++nextOpId // Unique ID
2953 };
2954 if (operationGroup) {
2955 operationGroup.ops.push(cm.curOp);
2956 } else {
2957 cm.curOp.ownsGroup = operationGroup = {
2958 ops: [cm.curOp],
2959 delayedCallbacks: []
2960 };
2961 }
2962 }
2963
2964 function fireCallbacksForOps(group) {
2965 // Calls delayed callbacks and cursorActivity handlers until no
2966 // new ones appear
2967 var callbacks = group.delayedCallbacks, i = 0;
2968 do {
2969 for (; i < callbacks.length; i++)
2970 callbacks[i]();
2971 for (var j = 0; j < group.ops.length; j++) {
2972 var op = group.ops[j];
2973 if (op.cursorActivityHandlers)
2974 while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
2975 op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
2976 }
2977 } while (i < callbacks.length);
2978 }
2979
2980 // Finish an operation, updating the display and signalling delayed events
2981 function endOperation(cm) {
2982 var op = cm.curOp, group = op.ownsGroup;
2983 if (!group) return;
2984
2985 try { fireCallbacksForOps(group); }
2986 finally {
2987 operationGroup = null;
2988 for (var i = 0; i < group.ops.length; i++)
2989 group.ops[i].cm.curOp = null;
2990 endOperations(group);
2991 }
2992 }
2993
2994 // The DOM updates done when an operation finishes are batched so
2995 // that the minimum number of relayouts are required.
2996 function endOperations(group) {
2997 var ops = group.ops;
2998 for (var i = 0; i < ops.length; i++) // Read DOM
2999 endOperation_R1(ops[i]);
3000 for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
3001 endOperation_W1(ops[i]);
3002 for (var i = 0; i < ops.length; i++) // Read DOM
3003 endOperation_R2(ops[i]);
3004 for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
3005 endOperation_W2(ops[i]);
3006 for (var i = 0; i < ops.length; i++) // Read DOM
3007 endOperation_finish(ops[i]);
3008 }
3009
3010 function endOperation_R1(op) {
3011 var cm = op.cm, display = cm.display;
3012 maybeClipScrollbars(cm);
3013 if (op.updateMaxLine) findMaxLine(cm);
3014
3015 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
3016 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
3017 op.scrollToPos.to.line >= display.viewTo) ||
3018 display.maxLineChanged && cm.options.lineWrapping;
3019 op.update = op.mustUpdate &&
3020 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
3021 }
3022
3023 function endOperation_W1(op) {
3024 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
3025 }
3026
3027 function endOperation_R2(op) {
3028 var cm = op.cm, display = cm.display;
3029 if (op.updatedDisplay) updateHeightsInViewport(cm);
3030
3031 op.barMeasure = measureForScrollbars(cm);
3032
3033 // If the max line changed since it was last measured, measure it,
3034 // and ensure the document's width matches it.
3035 // updateDisplay_W2 will use these properties to do the actual resizing
3036 if (display.maxLineChanged && !cm.options.lineWrapping) {
3037 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
3038 cm.display.sizerWidth = op.adjustWidthTo;
3039 op.barMeasure.scrollWidth =
3040 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
3041 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
3042 }
3043
3044 if (op.updatedDisplay || op.selectionChanged)
3045 op.preparedSelection = display.input.prepareSelection();
3046 }
3047
3048 function endOperation_W2(op) {
3049 var cm = op.cm;
3050
3051 if (op.adjustWidthTo != null) {
3052 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
3053 if (op.maxScrollLeft < cm.doc.scrollLeft)
3054 setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
3055 cm.display.maxLineChanged = false;
3056 }
3057
3058 if (op.preparedSelection)
3059 cm.display.input.showSelection(op.preparedSelection);
3060 if (op.updatedDisplay)
3061 setDocumentHeight(cm, op.barMeasure);
3062 if (op.updatedDisplay || op.startHeight != cm.doc.height)
3063 updateScrollbars(cm, op.barMeasure);
3064
3065 if (op.selectionChanged) restartBlink(cm);
3066
3067 if (cm.state.focused && op.updateInput)
3068 cm.display.input.reset(op.typing);
3069 if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
3070 }
3071
3072 function endOperation_finish(op) {
3073 var cm = op.cm, display = cm.display, doc = cm.doc;
3074
3075 if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
3076
3077 // Abort mouse wheel delta measurement, when scrolling explicitly
3078 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
3079 display.wheelStartX = display.wheelStartY = null;
3080
3081 // Propagate the scroll position to the actual DOM scroller
3082 if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
3083 doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
3084 display.scrollbars.setScrollTop(doc.scrollTop);
3085 display.scroller.scrollTop = doc.scrollTop;
3086 }
3087 if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
3088 doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
3089 display.scrollbars.setScrollLeft(doc.scrollLeft);
3090 display.scroller.scrollLeft = doc.scrollLeft;
3091 alignHorizontally(cm);
3092 }
3093 // If we need to scroll a specific position into view, do so.
3094 if (op.scrollToPos) {
3095 var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
3096 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
3097 if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
3098 }
3099
3100 // Fire events for markers that are hidden/unidden by editing or
3101 // undoing
3102 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
3103 if (hidden) for (var i = 0; i < hidden.length; ++i)
3104 if (!hidden[i].lines.length) signal(hidden[i], "hide");
3105 if (unhidden) for (var i = 0; i < unhidden.length; ++i)
3106 if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
3107
3108 if (display.wrapper.offsetHeight)
3109 doc.scrollTop = cm.display.scroller.scrollTop;
3110
3111 // Fire change events, and delayed event handlers
3112 if (op.changeObjs)
3113 signal(cm, "changes", cm, op.changeObjs);
3114 if (op.update)
3115 op.update.finish();
3116 }
3117
3118 // Run the given function in an operation
3119 function runInOp(cm, f) {
3120 if (cm.curOp) return f();
3121 startOperation(cm);
3122 try { return f(); }
3123 finally { endOperation(cm); }
3124 }
3125 // Wraps a function in an operation. Returns the wrapped function.
3126 function operation(cm, f) {
3127 return function() {
3128 if (cm.curOp) return f.apply(cm, arguments);
3129 startOperation(cm);
3130 try { return f.apply(cm, arguments); }
3131 finally { endOperation(cm); }
3132 };
3133 }
3134 // Used to add methods to editor and doc instances, wrapping them in
3135 // operations.
3136 function methodOp(f) {
3137 return function() {
3138 if (this.curOp) return f.apply(this, arguments);
3139 startOperation(this);
3140 try { return f.apply(this, arguments); }
3141 finally { endOperation(this); }
3142 };
3143 }
3144 function docMethodOp(f) {
3145 return function() {
3146 var cm = this.cm;
3147 if (!cm || cm.curOp) return f.apply(this, arguments);
3148 startOperation(cm);
3149 try { return f.apply(this, arguments); }
3150 finally { endOperation(cm); }
3151 };
3152 }
3153
3154 // VIEW TRACKING
3155
3156 // These objects are used to represent the visible (currently drawn)
3157 // part of the document. A LineView may correspond to multiple
3158 // logical lines, if those are connected by collapsed ranges.
3159 function LineView(doc, line, lineN) {
3160 // The starting line
3161 this.line = line;
3162 // Continuing lines, if any
3163 this.rest = visualLineContinued(line);
3164 // Number of logical lines in this visual line
3165 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
3166 this.node = this.text = null;
3167 this.hidden = lineIsHidden(doc, line);
3168 }
3169
3170 // Create a range of LineView objects for the given lines.
3171 function buildViewArray(cm, from, to) {
3172 var array = [], nextPos;
3173 for (var pos = from; pos < to; pos = nextPos) {
3174 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
3175 nextPos = pos + view.size;
3176 array.push(view);
3177 }
3178 return array;
3179 }
3180
3181 // Updates the display.view data structure for a given change to the
3182 // document. From and to are in pre-change coordinates. Lendiff is
3183 // the amount of lines added or subtracted by the change. This is
3184 // used for changes that span multiple lines, or change the way
3185 // lines are divided into visual lines. regLineChange (below)
3186 // registers single-line changes.
3187 function regChange(cm, from, to, lendiff) {
3188 if (from == null) from = cm.doc.first;
3189 if (to == null) to = cm.doc.first + cm.doc.size;
3190 if (!lendiff) lendiff = 0;
3191
3192 var display = cm.display;
3193 if (lendiff && to < display.viewTo &&
3194 (display.updateLineNumbers == null || display.updateLineNumbers > from))
3195 display.updateLineNumbers = from;
3196
3197 cm.curOp.viewChanged = true;
3198
3199 if (from >= display.viewTo) { // Change after
3200 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
3201 resetView(cm);
3202 } else if (to <= display.viewFrom) { // Change before
3203 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
3204 resetView(cm);
3205 } else {
3206 display.viewFrom += lendiff;
3207 display.viewTo += lendiff;
3208 }
3209 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
3210 resetView(cm);
3211 } else if (from <= display.viewFrom) { // Top overlap
3212 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
3213 if (cut) {
3214 display.view = display.view.slice(cut.index);
3215 display.viewFrom = cut.lineN;
3216 display.viewTo += lendiff;
3217 } else {
3218 resetView(cm);
3219 }
3220 } else if (to >= display.viewTo) { // Bottom overlap
3221 var cut = viewCuttingPoint(cm, from, from, -1);
3222 if (cut) {
3223 display.view = display.view.slice(0, cut.index);
3224 display.viewTo = cut.lineN;
3225 } else {
3226 resetView(cm);
3227 }
3228 } else { // Gap in the middle
3229 var cutTop = viewCuttingPoint(cm, from, from, -1);
3230 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
3231 if (cutTop && cutBot) {
3232 display.view = display.view.slice(0, cutTop.index)
3233 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
3234 .concat(display.view.slice(cutBot.index));
3235 display.viewTo += lendiff;
3236 } else {
3237 resetView(cm);
3238 }
3239 }
3240
3241 var ext = display.externalMeasured;
3242 if (ext) {
3243 if (to < ext.lineN)
3244 ext.lineN += lendiff;
3245 else if (from < ext.lineN + ext.size)
3246 display.externalMeasured = null;
3247 }
3248 }
3249
3250 // Register a change to a single line. Type must be one of "text",
3251 // "gutter", "class", "widget"
3252 function regLineChange(cm, line, type) {
3253 cm.curOp.viewChanged = true;
3254 var display = cm.display, ext = cm.display.externalMeasured;
3255 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
3256 display.externalMeasured = null;
3257
3258 if (line < display.viewFrom || line >= display.viewTo) return;
3259 var lineView = display.view[findViewIndex(cm, line)];
3260 if (lineView.node == null) return;
3261 var arr = lineView.changes || (lineView.changes = []);
3262 if (indexOf(arr, type) == -1) arr.push(type);
3263 }
3264
3265 // Clear the view.
3266 function resetView(cm) {
3267 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
3268 cm.display.view = [];
3269 cm.display.viewOffset = 0;
3270 }
3271
3272 // Find the view element corresponding to a given line. Return null
3273 // when the line isn't visible.
3274 function findViewIndex(cm, n) {
3275 if (n >= cm.display.viewTo) return null;
3276 n -= cm.display.viewFrom;
3277 if (n < 0) return null;
3278 var view = cm.display.view;
3279 for (var i = 0; i < view.length; i++) {
3280 n -= view[i].size;
3281 if (n < 0) return i;
3282 }
3283 }
3284
3285 function viewCuttingPoint(cm, oldN, newN, dir) {
3286 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
3287 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
3288 return {index: index, lineN: newN};
3289 for (var i = 0, n = cm.display.viewFrom; i < index; i++)
3290 n += view[i].size;
3291 if (n != oldN) {
3292 if (dir > 0) {
3293 if (index == view.length - 1) return null;
3294 diff = (n + view[index].size) - oldN;
3295 index++;
3296 } else {
3297 diff = n - oldN;
3298 }
3299 oldN += diff; newN += diff;
3300 }
3301 while (visualLineNo(cm.doc, newN) != newN) {
3302 if (index == (dir < 0 ? 0 : view.length - 1)) return null;
3303 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
3304 index += dir;
3305 }
3306 return {index: index, lineN: newN};
3307 }
3308
3309 // Force the view to cover a given range, adding empty view element
3310 // or clipping off existing ones as needed.
3311 function adjustView(cm, from, to) {
3312 var display = cm.display, view = display.view;
3313 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
3314 display.view = buildViewArray(cm, from, to);
3315 display.viewFrom = from;
3316 } else {
3317 if (display.viewFrom > from)
3318 display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
3319 else if (display.viewFrom < from)
3320 display.view = display.view.slice(findViewIndex(cm, from));
3321 display.viewFrom = from;
3322 if (display.viewTo < to)
3323 display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
3324 else if (display.viewTo > to)
3325 display.view = display.view.slice(0, findViewIndex(cm, to));
3326 }
3327 display.viewTo = to;
3328 }
3329
3330 // Count the number of lines in the view whose DOM representation is
3331 // out of date (or nonexistent).
3332 function countDirtyView(cm) {
3333 var view = cm.display.view, dirty = 0;
3334 for (var i = 0; i < view.length; i++) {
3335 var lineView = view[i];
3336 if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
3337 }
3338 return dirty;
3339 }
3340
3341 // EVENT HANDLERS
3342
3343 // Attach the necessary event handlers when initializing the editor
3344 function registerEventHandlers(cm) {
3345 var d = cm.display;
3346 on(d.scroller, "mousedown", operation(cm, onMouseDown));
3347 // Older IE's will not fire a second mousedown for a double click
3348 if (ie && ie_version < 11)
3349 on(d.scroller, "dblclick", operation(cm, function(e) {
3350 if (signalDOMEvent(cm, e)) return;
3351 var pos = posFromMouse(cm, e);
3352 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
3353 e_preventDefault(e);
3354 var word = cm.findWordAt(pos);
3355 extendSelection(cm.doc, word.anchor, word.head);
3356 }));
3357 else
3358 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
3359 // Some browsers fire contextmenu *after* opening the menu, at
3360 // which point we can't mess with it anymore. Context menu is
3361 // handled in onMouseDown for these browsers.
3362 if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
3363
3364 // Used to suppress mouse event handling when a touch happens
3365 var touchFinished, prevTouch = {end: 0};
3366 function finishTouch() {
3367 if (d.activeTouch) {
3368 touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
3369 prevTouch = d.activeTouch;
3370 prevTouch.end = +new Date;
3371 }
3372 };
3373 function isMouseLikeTouchEvent(e) {
3374 if (e.touches.length != 1) return false;
3375 var touch = e.touches[0];
3376 return touch.radiusX <= 1 && touch.radiusY <= 1;
3377 }
3378 function farAway(touch, other) {
3379 if (other.left == null) return true;
3380 var dx = other.left - touch.left, dy = other.top - touch.top;
3381 return dx * dx + dy * dy > 20 * 20;
3382 }
3383 on(d.scroller, "touchstart", function(e) {
3384 if (!isMouseLikeTouchEvent(e)) {
3385 clearTimeout(touchFinished);
3386 var now = +new Date;
3387 d.activeTouch = {start: now, moved: false,
3388 prev: now - prevTouch.end <= 300 ? prevTouch : null};
3389 if (e.touches.length == 1) {
3390 d.activeTouch.left = e.touches[0].pageX;
3391 d.activeTouch.top = e.touches[0].pageY;
3392 }
3393 }
3394 });
3395 on(d.scroller, "touchmove", function() {
3396 if (d.activeTouch) d.activeTouch.moved = true;
3397 });
3398 on(d.scroller, "touchend", function(e) {
3399 var touch = d.activeTouch;
3400 if (touch && !eventInWidget(d, e) && touch.left != null &&
3401 !touch.moved && new Date - touch.start < 300) {
3402 var pos = cm.coordsChar(d.activeTouch, "page"), range;
3403 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
3404 range = new Range(pos, pos);
3405 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
3406 range = cm.findWordAt(pos);
3407 else // Triple tap
3408 range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
3409 cm.setSelection(range.anchor, range.head);
3410 cm.focus();
3411 e_preventDefault(e);
3412 }
3413 finishTouch();
3414 });
3415 on(d.scroller, "touchcancel", finishTouch);
3416
3417 // Sync scrolling between fake scrollbars and real scrollable
3418 // area, ensure viewport is updated when scrolling.
3419 on(d.scroller, "scroll", function() {
3420 if (d.scroller.clientHeight) {
3421 setScrollTop(cm, d.scroller.scrollTop);
3422 setScrollLeft(cm, d.scroller.scrollLeft, true);
3423 signal(cm, "scroll", cm);
3424 }
3425 });
3426
3427 // Listen to wheel events in order to try and update the viewport on time.
3428 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
3429 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
3430
3431 // Prevent wrapper from ever scrolling
3432 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
3433
3434 d.dragFunctions = {
3435 simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
3436 start: function(e){onDragStart(cm, e);},
3437 drop: operation(cm, onDrop)
3438 };
3439
3440 var inp = d.input.getField();
3441 on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
3442 on(inp, "keydown", operation(cm, onKeyDown));
3443 on(inp, "keypress", operation(cm, onKeyPress));
3444 on(inp, "focus", bind(onFocus, cm));
3445 on(inp, "blur", bind(onBlur, cm));
3446 }
3447
3448 function dragDropChanged(cm, value, old) {
3449 var wasOn = old && old != CodeMirror.Init;
3450 if (!value != !wasOn) {
3451 var funcs = cm.display.dragFunctions;
3452 var toggle = value ? on : off;
3453 toggle(cm.display.scroller, "dragstart", funcs.start);
3454 toggle(cm.display.scroller, "dragenter", funcs.simple);
3455 toggle(cm.display.scroller, "dragover", funcs.simple);
3456 toggle(cm.display.scroller, "drop", funcs.drop);
3457 }
3458 }
3459
3460 // Called when the window resizes
3461 function onResize(cm) {
3462 var d = cm.display;
3463 if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
3464 return;
3465 // Might be a text scaling operation, clear size caches.
3466 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
3467 d.scrollbarsClipped = false;
3468 cm.setSize();
3469 }
3470
3471 // MOUSE EVENTS
3472
3473 // Return true when the given mouse event happened in a widget
3474 function eventInWidget(display, e) {
3475 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
3476 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
3477 (n.parentNode == display.sizer && n != display.mover))
3478 return true;
3479 }
3480 }
3481
3482 // Given a mouse event, find the corresponding position. If liberal
3483 // is false, it checks whether a gutter or scrollbar was clicked,
3484 // and returns null if it was. forRect is used by rectangular
3485 // selections, and tries to estimate a character position even for
3486 // coordinates beyond the right of the text.
3487 function posFromMouse(cm, e, liberal, forRect) {
3488 var display = cm.display;
3489 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
3490
3491 var x, y, space = display.lineSpace.getBoundingClientRect();
3492 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
3493 try { x = e.clientX - space.left; y = e.clientY - space.top; }
3494 catch (e) { return null; }
3495 var coords = coordsChar(cm, x, y), line;
3496 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
3497 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
3498 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
3499 }
3500 return coords;
3501 }
3502
3503 // A mouse down can be a single click, double click, triple click,
3504 // start of selection drag, start of text drag, new cursor
3505 // (ctrl-click), rectangle drag (alt-drag), or xwin
3506 // middle-click-paste. Or it might be a click on something we should
3507 // not interfere with, such as a scrollbar or widget.
3508 function onMouseDown(e) {
3509 var cm = this, display = cm.display;
3510 if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
3511 display.shift = e.shiftKey;
3512
3513 if (eventInWidget(display, e)) {
3514 if (!webkit) {
3515 // Briefly turn off draggability, to allow widgets to do
3516 // normal dragging things.
3517 display.scroller.draggable = false;
3518 setTimeout(function(){display.scroller.draggable = true;}, 100);
3519 }
3520 return;
3521 }
3522 if (clickInGutter(cm, e)) return;
3523 var start = posFromMouse(cm, e);
3524 window.focus();
3525
3526 switch (e_button(e)) {
3527 case 1:
3528 if (start)
3529 leftButtonDown(cm, e, start);
3530 else if (e_target(e) == display.scroller)
3531 e_preventDefault(e);
3532 break;
3533 case 2:
3534 if (webkit) cm.state.lastMiddleDown = +new Date;
3535 if (start) extendSelection(cm.doc, start);
3536 setTimeout(function() {display.input.focus();}, 20);
3537 e_preventDefault(e);
3538 break;
3539 case 3:
3540 if (captureRightClick) onContextMenu(cm, e);
3541 else delayBlurEvent(cm);
3542 break;
3543 }
3544 }
3545
3546 var lastClick, lastDoubleClick;
3547 function leftButtonDown(cm, e, start) {
3548 if (ie) setTimeout(bind(ensureFocus, cm), 0);
3549 else cm.curOp.focus = activeElt();
3550
3551 var now = +new Date, type;
3552 if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
3553 type = "triple";
3554 } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
3555 type = "double";
3556 lastDoubleClick = {time: now, pos: start};
3557 } else {
3558 type = "single";
3559 lastClick = {time: now, pos: start};
3560 }
3561
3562 var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
3563 if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
3564 type == "single" && (contained = sel.contains(start)) > -1 &&
3565 !sel.ranges[contained].empty())
3566 leftButtonStartDrag(cm, e, start, modifier);
3567 else
3568 leftButtonSelect(cm, e, start, type, modifier);
3569 }
3570
3571 // Start a text drag. When it ends, see if any dragging actually
3572 // happen, and treat as a click if it didn't.
3573 function leftButtonStartDrag(cm, e, start, modifier) {
3574 var display = cm.display, startTime = +new Date;
3575 var dragEnd = operation(cm, function(e2) {
3576 if (webkit) display.scroller.draggable = false;
3577 cm.state.draggingText = false;
3578 off(document, "mouseup", dragEnd);
3579 off(display.scroller, "drop", dragEnd);
3580 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
3581 e_preventDefault(e2);
3582 if (!modifier && +new Date - 200 < startTime)
3583 extendSelection(cm.doc, start);
3584 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
3585 if (webkit || ie && ie_version == 9)
3586 setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
3587 else
3588 display.input.focus();
3589 }
3590 });
3591 // Let the drag handler handle this.
3592 if (webkit) display.scroller.draggable = true;
3593 cm.state.draggingText = dragEnd;
3594 // IE's approach to draggable
3595 if (display.scroller.dragDrop) display.scroller.dragDrop();
3596 on(document, "mouseup", dragEnd);
3597 on(display.scroller, "drop", dragEnd);
3598 }
3599
3600 // Normal selection, as opposed to text dragging.
3601 function leftButtonSelect(cm, e, start, type, addNew) {
3602 var display = cm.display, doc = cm.doc;
3603 e_preventDefault(e);
3604
3605 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
3606 if (addNew && !e.shiftKey) {
3607 ourIndex = doc.sel.contains(start);
3608 if (ourIndex > -1)
3609 ourRange = ranges[ourIndex];
3610 else
3611 ourRange = new Range(start, start);
3612 } else {
3613 ourRange = doc.sel.primary();
3614 ourIndex = doc.sel.primIndex;
3615 }
3616
3617 if (e.altKey) {
3618 type = "rect";
3619 if (!addNew) ourRange = new Range(start, start);
3620 start = posFromMouse(cm, e, true, true);
3621 ourIndex = -1;
3622 } else if (type == "double") {
3623 var word = cm.findWordAt(start);
3624 if (cm.display.shift || doc.extend)
3625 ourRange = extendRange(doc, ourRange, word.anchor, word.head);
3626 else
3627 ourRange = word;
3628 } else if (type == "triple") {
3629 var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
3630 if (cm.display.shift || doc.extend)
3631 ourRange = extendRange(doc, ourRange, line.anchor, line.head);
3632 else
3633 ourRange = line;
3634 } else {
3635 ourRange = extendRange(doc, ourRange, start);
3636 }
3637
3638 if (!addNew) {
3639 ourIndex = 0;
3640 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
3641 startSel = doc.sel;
3642 } else if (ourIndex == -1) {
3643 ourIndex = ranges.length;
3644 setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
3645 {scroll: false, origin: "*mouse"});
3646 } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
3647 setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
3648 startSel = doc.sel;
3649 } else {
3650 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
3651 }
3652
3653 var lastPos = start;
3654 function extendTo(pos) {
3655 if (cmp(lastPos, pos) == 0) return;
3656 lastPos = pos;
3657
3658 if (type == "rect") {
3659 var ranges = [], tabSize = cm.options.tabSize;
3660 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
3661 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
3662 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
3663 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
3664 line <= end; line++) {
3665 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
3666 if (left == right)
3667 ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
3668 else if (text.length > leftPos)
3669 ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
3670 }
3671 if (!ranges.length) ranges.push(new Range(start, start));
3672 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
3673 {origin: "*mouse", scroll: false});
3674 cm.scrollIntoView(pos);
3675 } else {
3676 var oldRange = ourRange;
3677 var anchor = oldRange.anchor, head = pos;
3678 if (type != "single") {
3679 if (type == "double")
3680 var range = cm.findWordAt(pos);
3681 else
3682 var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
3683 if (cmp(range.anchor, anchor) > 0) {
3684 head = range.head;
3685 anchor = minPos(oldRange.from(), range.anchor);
3686 } else {
3687 head = range.anchor;
3688 anchor = maxPos(oldRange.to(), range.head);
3689 }
3690 }
3691 var ranges = startSel.ranges.slice(0);
3692 ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
3693 setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
3694 }
3695 }
3696
3697 var editorSize = display.wrapper.getBoundingClientRect();
3698 // Used to ensure timeout re-tries don't fire when another extend
3699 // happened in the meantime (clearTimeout isn't reliable -- at
3700 // least on Chrome, the timeouts still happen even when cleared,
3701 // if the clear happens after their scheduled firing time).
3702 var counter = 0;
3703
3704 function extend(e) {
3705 var curCount = ++counter;
3706 var cur = posFromMouse(cm, e, true, type == "rect");
3707 if (!cur) return;
3708 if (cmp(cur, lastPos) != 0) {
3709 cm.curOp.focus = activeElt();
3710 extendTo(cur);
3711 var visible = visibleLines(display, doc);
3712 if (cur.line >= visible.to || cur.line < visible.from)
3713 setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
3714 } else {
3715 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
3716 if (outside) setTimeout(operation(cm, function() {
3717 if (counter != curCount) return;
3718 display.scroller.scrollTop += outside;
3719 extend(e);
3720 }), 50);
3721 }
3722 }
3723
3724 function done(e) {
3725 counter = Infinity;
3726 e_preventDefault(e);
3727 display.input.focus();
3728 off(document, "mousemove", move);
3729 off(document, "mouseup", up);
3730 doc.history.lastSelOrigin = null;
3731 }
3732
3733 var move = operation(cm, function(e) {
3734 if (!e_button(e)) done(e);
3735 else extend(e);
3736 });
3737 var up = operation(cm, done);
3738 on(document, "mousemove", move);
3739 on(document, "mouseup", up);
3740 }
3741
3742 // Determines whether an event happened in the gutter, and fires the
3743 // handlers for the corresponding event.
3744 function gutterEvent(cm, e, type, prevent, signalfn) {
3745 try { var mX = e.clientX, mY = e.clientY; }
3746 catch(e) { return false; }
3747 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
3748 if (prevent) e_preventDefault(e);
3749
3750 var display = cm.display;
3751 var lineBox = display.lineDiv.getBoundingClientRect();
3752
3753 if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
3754 mY -= lineBox.top - display.viewOffset;
3755
3756 for (var i = 0; i < cm.options.gutters.length; ++i) {
3757 var g = display.gutters.childNodes[i];
3758 if (g && g.getBoundingClientRect().right >= mX) {
3759 var line = lineAtHeight(cm.doc, mY);
3760 var gutter = cm.options.gutters[i];
3761 signalfn(cm, type, cm, line, gutter, e);
3762 return e_defaultPrevented(e);
3763 }
3764 }
3765 }
3766
3767 function clickInGutter(cm, e) {
3768 return gutterEvent(cm, e, "gutterClick", true, signalLater);
3769 }
3770
3771 // Kludge to work around strange IE behavior where it'll sometimes
3772 // re-fire a series of drag-related events right after the drop (#1551)
3773 var lastDrop = 0;
3774
3775 function onDrop(e) {
3776 var cm = this;
3777 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
3778 return;
3779 e_preventDefault(e);
3780 if (ie) lastDrop = +new Date;
3781 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
3782 if (!pos || isReadOnly(cm)) return;
3783 // Might be a file drop, in which case we simply extract the text
3784 // and insert it.
3785 if (files && files.length && window.FileReader && window.File) {
3786 var n = files.length, text = Array(n), read = 0;
3787 var loadFile = function(file, i) {
3788 var reader = new FileReader;
3789 reader.onload = operation(cm, function() {
3790 text[i] = reader.result;
3791 if (++read == n) {
3792 pos = clipPos(cm.doc, pos);
3793 var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
3794 makeChange(cm.doc, change);
3795 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
3796 }
3797 });
3798 reader.readAsText(file);
3799 };
3800 for (var i = 0; i < n; ++i) loadFile(files[i], i);
3801 } else { // Normal drop
3802 // Don't do a replace if the drop happened inside of the selected text.
3803 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
3804 cm.state.draggingText(e);
3805 // Ensure the editor is re-focused
3806 setTimeout(function() {cm.display.input.focus();}, 20);
3807 return;
3808 }
3809 try {
3810 var text = e.dataTransfer.getData("Text");
3811 if (text) {
3812 if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
3813 var selected = cm.listSelections();
3814 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
3815 if (selected) for (var i = 0; i < selected.length; ++i)
3816 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
3817 cm.replaceSelection(text, "around", "paste");
3818 cm.display.input.focus();
3819 }
3820 }
3821 catch(e){}
3822 }
3823 }
3824
3825 function onDragStart(cm, e) {
3826 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
3827 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
3828
3829 e.dataTransfer.setData("Text", cm.getSelection());
3830
3831 // Use dummy image instead of default browsers image.
3832 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
3833 if (e.dataTransfer.setDragImage && !safari) {
3834 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
3835 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
3836 if (presto) {
3837 img.width = img.height = 1;
3838 cm.display.wrapper.appendChild(img);
3839 // Force a relayout, or Opera won't use our image for some obscure reason
3840 img._top = img.offsetTop;
3841 }
3842 e.dataTransfer.setDragImage(img, 0, 0);
3843 if (presto) img.parentNode.removeChild(img);
3844 }
3845 }
3846
3847 // SCROLL EVENTS
3848
3849 // Sync the scrollable area and scrollbars, ensure the viewport
3850 // covers the visible area.
3851 function setScrollTop(cm, val) {
3852 if (Math.abs(cm.doc.scrollTop - val) < 2) return;
3853 cm.doc.scrollTop = val;
3854 if (!gecko) updateDisplaySimple(cm, {top: val});
3855 if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
3856 cm.display.scrollbars.setScrollTop(val);
3857 if (gecko) updateDisplaySimple(cm);
3858 startWorker(cm, 100);
3859 }
3860 // Sync scroller and scrollbar, ensure the gutter elements are
3861 // aligned.
3862 function setScrollLeft(cm, val, isScroller) {
3863 if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
3864 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
3865 cm.doc.scrollLeft = val;
3866 alignHorizontally(cm);
3867 if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
3868 cm.display.scrollbars.setScrollLeft(val);
3869 }
3870
3871 // Since the delta values reported on mouse wheel events are
3872 // unstandardized between browsers and even browser versions, and
3873 // generally horribly unpredictable, this code starts by measuring
3874 // the scroll effect that the first few mouse wheel events have,
3875 // and, from that, detects the way it can convert deltas to pixel
3876 // offsets afterwards.
3877 //
3878 // The reason we want to know the amount a wheel event will scroll
3879 // is that it gives us a chance to update the display before the
3880 // actual scrolling happens, reducing flickering.
3881
3882 var wheelSamples = 0, wheelPixelsPerUnit = null;
3883 // Fill in a browser-detected starting value on browsers where we
3884 // know one. These don't have to be accurate -- the result of them
3885 // being wrong would just be a slight flicker on the first wheel
3886 // scroll (if it is large enough).
3887 if (ie) wheelPixelsPerUnit = -.53;
3888 else if (gecko) wheelPixelsPerUnit = 15;
3889 else if (chrome) wheelPixelsPerUnit = -.7;
3890 else if (safari) wheelPixelsPerUnit = -1/3;
3891
3892 var wheelEventDelta = function(e) {
3893 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
3894 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
3895 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
3896 else if (dy == null) dy = e.wheelDelta;
3897 return {x: dx, y: dy};
3898 };
3899 CodeMirror.wheelEventPixels = function(e) {
3900 var delta = wheelEventDelta(e);
3901 delta.x *= wheelPixelsPerUnit;
3902 delta.y *= wheelPixelsPerUnit;
3903 return delta;
3904 };
3905
3906 function onScrollWheel(cm, e) {
3907 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
3908
3909 var display = cm.display, scroll = display.scroller;
3910 // Quit if there's nothing to scroll here
3911 if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
3912 dy && scroll.scrollHeight > scroll.clientHeight)) return;
3913
3914 // Webkit browsers on OS X abort momentum scrolls when the target
3915 // of the scroll event is removed from the scrollable element.
3916 // This hack (see related code in patchDisplay) makes sure the
3917 // element is kept around.
3918 if (dy && mac && webkit) {
3919 outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
3920 for (var i = 0; i < view.length; i++) {
3921 if (view[i].node == cur) {
3922 cm.display.currentWheelTarget = cur;
3923 break outer;
3924 }
3925 }
3926 }
3927 }
3928
3929 // On some browsers, horizontal scrolling will cause redraws to
3930 // happen before the gutter has been realigned, causing it to
3931 // wriggle around in a most unseemly way. When we have an
3932 // estimated pixels/delta value, we just handle horizontal
3933 // scrolling entirely here. It'll be slightly off from native, but
3934 // better than glitching out.
3935 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
3936 if (dy)
3937 setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
3938 setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
3939 e_preventDefault(e);
3940 display.wheelStartX = null; // Abort measurement, if in progress
3941 return;
3942 }
3943
3944 // 'Project' the visible viewport to cover the area that is being
3945 // scrolled into view (if we know enough to estimate it).
3946 if (dy && wheelPixelsPerUnit != null) {
3947 var pixels = dy * wheelPixelsPerUnit;
3948 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
3949 if (pixels < 0) top = Math.max(0, top + pixels - 50);
3950 else bot = Math.min(cm.doc.height, bot + pixels + 50);
3951 updateDisplaySimple(cm, {top: top, bottom: bot});
3952 }
3953
3954 if (wheelSamples < 20) {
3955 if (display.wheelStartX == null) {
3956 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
3957 display.wheelDX = dx; display.wheelDY = dy;
3958 setTimeout(function() {
3959 if (display.wheelStartX == null) return;
3960 var movedX = scroll.scrollLeft - display.wheelStartX;
3961 var movedY = scroll.scrollTop - display.wheelStartY;
3962 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
3963 (movedX && display.wheelDX && movedX / display.wheelDX);
3964 display.wheelStartX = display.wheelStartY = null;
3965 if (!sample) return;
3966 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
3967 ++wheelSamples;
3968 }, 200);
3969 } else {
3970 display.wheelDX += dx; display.wheelDY += dy;
3971 }
3972 }
3973 }
3974
3975 // KEY EVENTS
3976
3977 // Run a handler that was bound to a key.
3978 function doHandleBinding(cm, bound, dropShift) {
3979 if (typeof bound == "string") {
3980 bound = commands[bound];
3981 if (!bound) return false;
3982 }
3983 // Ensure previous input has been read, so that the handler sees a
3984 // consistent view of the document
3985 cm.display.input.ensurePolled();
3986 var prevShift = cm.display.shift, done = false;
3987 try {
3988 if (isReadOnly(cm)) cm.state.suppressEdits = true;
3989 if (dropShift) cm.display.shift = false;
3990 done = bound(cm) != Pass;
3991 } finally {
3992 cm.display.shift = prevShift;
3993 cm.state.suppressEdits = false;
3994 }
3995 return done;
3996 }
3997
3998 function lookupKeyForEditor(cm, name, handle) {
3999 for (var i = 0; i < cm.state.keyMaps.length; i++) {
4000 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
4001 if (result) return result;
4002 }
4003 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
4004 || lookupKey(name, cm.options.keyMap, handle, cm);
4005 }
4006
4007 var stopSeq = new Delayed;
4008 function dispatchKey(cm, name, e, handle) {
4009 var seq = cm.state.keySeq;
4010 if (seq) {
4011 if (isModifierKey(name)) return "handled";
4012 stopSeq.set(50, function() {
4013 if (cm.state.keySeq == seq) {
4014 cm.state.keySeq = null;
4015 cm.display.input.reset();
4016 }
4017 });
4018 name = seq + " " + name;
4019 }
4020 var result = lookupKeyForEditor(cm, name, handle);
4021
4022 if (result == "multi")
4023 cm.state.keySeq = name;
4024 if (result == "handled")
4025 signalLater(cm, "keyHandled", cm, name, e);
4026
4027 if (result == "handled" || result == "multi") {
4028 e_preventDefault(e);
4029 restartBlink(cm);
4030 }
4031
4032 if (seq && !result && /\'$/.test(name)) {
4033 e_preventDefault(e);
4034 return true;
4035 }
4036 return !!result;
4037 }
4038
4039 // Handle a key from the keydown event.
4040 function handleKeyBinding(cm, e) {
4041 var name = keyName(e, true);
4042 if (!name) return false;
4043
4044 if (e.shiftKey && !cm.state.keySeq) {
4045 // First try to resolve full name (including 'Shift-'). Failing
4046 // that, see if there is a cursor-motion command (starting with
4047 // 'go') bound to the keyname without 'Shift-'.
4048 return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
4049 || dispatchKey(cm, name, e, function(b) {
4050 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
4051 return doHandleBinding(cm, b);
4052 });
4053 } else {
4054 return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
4055 }
4056 }
4057
4058 // Handle a key from the keypress event
4059 function handleCharBinding(cm, e, ch) {
4060 return dispatchKey(cm, "'" + ch + "'", e,
4061 function(b) { return doHandleBinding(cm, b, true); });
4062 }
4063
4064 var lastStoppedKey = null;
4065 function onKeyDown(e) {
4066 var cm = this;
4067 cm.curOp.focus = activeElt();
4068 if (signalDOMEvent(cm, e)) return;
4069 // IE does strange things with escape.
4070 if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
4071 var code = e.keyCode;
4072 cm.display.shift = code == 16 || e.shiftKey;
4073 var handled = handleKeyBinding(cm, e);
4074 if (presto) {
4075 lastStoppedKey = handled ? code : null;
4076 // Opera has no cut event... we try to at least catch the key combo
4077 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
4078 cm.replaceSelection("", null, "cut");
4079 }
4080
4081 // Turn mouse into crosshair when Alt is held on Mac.
4082 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
4083 showCrossHair(cm);
4084 }
4085
4086 function showCrossHair(cm) {
4087 var lineDiv = cm.display.lineDiv;
4088 addClass(lineDiv, "CodeMirror-crosshair");
4089
4090 function up(e) {
4091 if (e.keyCode == 18 || !e.altKey) {
4092 rmClass(lineDiv, "CodeMirror-crosshair");
4093 off(document, "keyup", up);
4094 off(document, "mouseover", up);
4095 }
4096 }
4097 on(document, "keyup", up);
4098 on(document, "mouseover", up);
4099 }
4100
4101 function onKeyUp(e) {
4102 if (e.keyCode == 16) this.doc.sel.shift = false;
4103 signalDOMEvent(this, e);
4104 }
4105
4106 function onKeyPress(e) {
4107 var cm = this;
4108 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
4109 var keyCode = e.keyCode, charCode = e.charCode;
4110 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
4111 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
4112 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
4113 if (handleCharBinding(cm, e, ch)) return;
4114 cm.display.input.onKeyPress(e);
4115 }
4116
4117 // FOCUS/BLUR EVENTS
4118
4119 function delayBlurEvent(cm) {
4120 cm.state.delayingBlurEvent = true;
4121 setTimeout(function() {
4122 if (cm.state.delayingBlurEvent) {
4123 cm.state.delayingBlurEvent = false;
4124 onBlur(cm);
4125 }
4126 }, 100);
4127 }
4128
4129 function onFocus(cm) {
4130 if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
4131
4132 if (cm.options.readOnly == "nocursor") return;
4133 if (!cm.state.focused) {
4134 signal(cm, "focus", cm);
4135 cm.state.focused = true;
4136 addClass(cm.display.wrapper, "CodeMirror-focused");
4137 // This test prevents this from firing when a context
4138 // menu is closed (since the input reset would kill the
4139 // select-all detection hack)
4140 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
4141 cm.display.input.reset();
4142 if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
4143 }
4144 cm.display.input.receivedFocus();
4145 }
4146 restartBlink(cm);
4147 }
4148 function onBlur(cm) {
4149 if (cm.state.delayingBlurEvent) return;
4150
4151 if (cm.state.focused) {
4152 signal(cm, "blur", cm);
4153 cm.state.focused = false;
4154 rmClass(cm.display.wrapper, "CodeMirror-focused");
4155 }
4156 clearInterval(cm.display.blinker);
4157 setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
4158 }
4159
4160 // CONTEXT MENU HANDLING
4161
4162 // To make the context menu work, we need to briefly unhide the
4163 // textarea (making it as unobtrusive as possible) to let the
4164 // right-click take effect on it.
4165 function onContextMenu(cm, e) {
4166 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
4167 cm.display.input.onContextMenu(e);
4168 }
4169
4170 function contextMenuInGutter(cm, e) {
4171 if (!hasHandler(cm, "gutterContextMenu")) return false;
4172 return gutterEvent(cm, e, "gutterContextMenu", false, signal);
4173 }
4174
4175 // UPDATING
4176
4177 // Compute the position of the end of a change (its 'to' property
4178 // refers to the pre-change end).
4179 var changeEnd = CodeMirror.changeEnd = function(change) {
4180 if (!change.text) return change.to;
4181 return Pos(change.from.line + change.text.length - 1,
4182 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
4183 };
4184
4185 // Adjust a position to refer to the post-change position of the
4186 // same text, or the end of the change if the change covers it.
4187 function adjustForChange(pos, change) {
4188 if (cmp(pos, change.from) < 0) return pos;
4189 if (cmp(pos, change.to) <= 0) return changeEnd(change);
4190
4191 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
4192 if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
4193 return Pos(line, ch);
4194 }
4195
4196 function computeSelAfterChange(doc, change) {
4197 var out = [];
4198 for (var i = 0; i < doc.sel.ranges.length; i++) {
4199 var range = doc.sel.ranges[i];
4200 out.push(new Range(adjustForChange(range.anchor, change),
4201 adjustForChange(range.head, change)));
4202 }
4203 return normalizeSelection(out, doc.sel.primIndex);
4204 }
4205
4206 function offsetPos(pos, old, nw) {
4207 if (pos.line == old.line)
4208 return Pos(nw.line, pos.ch - old.ch + nw.ch);
4209 else
4210 return Pos(nw.line + (pos.line - old.line), pos.ch);
4211 }
4212
4213 // Used by replaceSelections to allow moving the selection to the
4214 // start or around the replaced test. Hint may be "start" or "around".
4215 function computeReplacedSel(doc, changes, hint) {
4216 var out = [];
4217 var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
4218 for (var i = 0; i < changes.length; i++) {
4219 var change = changes[i];
4220 var from = offsetPos(change.from, oldPrev, newPrev);
4221 var to = offsetPos(changeEnd(change), oldPrev, newPrev);
4222 oldPrev = change.to;
4223 newPrev = to;
4224 if (hint == "around") {
4225 var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
4226 out[i] = new Range(inv ? to : from, inv ? from : to);
4227 } else {
4228 out[i] = new Range(from, from);
4229 }
4230 }
4231 return new Selection(out, doc.sel.primIndex);
4232 }
4233
4234 // Allow "beforeChange" event handlers to influence a change
4235 function filterChange(doc, change, update) {
4236 var obj = {
4237 canceled: false,
4238 from: change.from,
4239 to: change.to,
4240 text: change.text,
4241 origin: change.origin,
4242 cancel: function() { this.canceled = true; }
4243 };
4244 if (update) obj.update = function(from, to, text, origin) {
4245 if (from) this.from = clipPos(doc, from);
4246 if (to) this.to = clipPos(doc, to);
4247 if (text) this.text = text;
4248 if (origin !== undefined) this.origin = origin;
4249 };
4250 signal(doc, "beforeChange", doc, obj);
4251 if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
4252
4253 if (obj.canceled) return null;
4254 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
4255 }
4256
4257 // Apply a change to a document, and add it to the document's
4258 // history, and propagating it to all linked documents.
4259 function makeChange(doc, change, ignoreReadOnly) {
4260 if (doc.cm) {
4261 if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
4262 if (doc.cm.state.suppressEdits) return;
4263 }
4264
4265 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
4266 change = filterChange(doc, change, true);
4267 if (!change) return;
4268 }
4269
4270 // Possibly split or suppress the update based on the presence
4271 // of read-only spans in its range.
4272 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
4273 if (split) {
4274 for (var i = split.length - 1; i >= 0; --i)
4275 makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
4276 } else {
4277 makeChangeInner(doc, change);
4278 }
4279 }
4280
4281 function makeChangeInner(doc, change) {
4282 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
4283 var selAfter = computeSelAfterChange(doc, change);
4284 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
4285
4286 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
4287 var rebased = [];
4288
4289 linkedDocs(doc, function(doc, sharedHist) {
4290 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
4291 rebaseHist(doc.history, change);
4292 rebased.push(doc.history);
4293 }
4294 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
4295 });
4296 }
4297
4298 // Revert a change stored in a document's history.
4299 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
4300 if (doc.cm && doc.cm.state.suppressEdits) return;
4301
4302 var hist = doc.history, event, selAfter = doc.sel;
4303 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
4304
4305 // Verify that there is a useable event (so that ctrl-z won't
4306 // needlessly clear selection events)
4307 for (var i = 0; i < source.length; i++) {
4308 event = source[i];
4309 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
4310 break;
4311 }
4312 if (i == source.length) return;
4313 hist.lastOrigin = hist.lastSelOrigin = null;
4314
4315 for (;;) {
4316 event = source.pop();
4317 if (event.ranges) {
4318 pushSelectionToHistory(event, dest);
4319 if (allowSelectionOnly && !event.equals(doc.sel)) {
4320 setSelection(doc, event, {clearRedo: false});
4321 return;
4322 }
4323 selAfter = event;
4324 }
4325 else break;
4326 }
4327
4328 // Build up a reverse change object to add to the opposite history
4329 // stack (redo when undoing, and vice versa).
4330 var antiChanges = [];
4331 pushSelectionToHistory(selAfter, dest);
4332 dest.push({changes: antiChanges, generation: hist.generation});
4333 hist.generation = event.generation || ++hist.maxGeneration;
4334
4335 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
4336
4337 for (var i = event.changes.length - 1; i >= 0; --i) {
4338 var change = event.changes[i];
4339 change.origin = type;
4340 if (filter && !filterChange(doc, change, false)) {
4341 source.length = 0;
4342 return;
4343 }
4344
4345 antiChanges.push(historyChangeFromChange(doc, change));
4346
4347 var after = i ? computeSelAfterChange(doc, change) : lst(source);
4348 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
4349 if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
4350 var rebased = [];
4351
4352 // Propagate to the linked documents
4353 linkedDocs(doc, function(doc, sharedHist) {
4354 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
4355 rebaseHist(doc.history, change);
4356 rebased.push(doc.history);
4357 }
4358 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
4359 });
4360 }
4361 }
4362
4363 // Sub-views need their line numbers shifted when text is added
4364 // above or below them in the parent document.
4365 function shiftDoc(doc, distance) {
4366 if (distance == 0) return;
4367 doc.first += distance;
4368 doc.sel = new Selection(map(doc.sel.ranges, function(range) {
4369 return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
4370 Pos(range.head.line + distance, range.head.ch));
4371 }), doc.sel.primIndex);
4372 if (doc.cm) {
4373 regChange(doc.cm, doc.first, doc.first - distance, distance);
4374 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
4375 regLineChange(doc.cm, l, "gutter");
4376 }
4377 }
4378
4379 // More lower-level change function, handling only a single document
4380 // (not linked ones).
4381 function makeChangeSingleDoc(doc, change, selAfter, spans) {
4382 if (doc.cm && !doc.cm.curOp)
4383 return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
4384
4385 if (change.to.line < doc.first) {
4386 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
4387 return;
4388 }
4389 if (change.from.line > doc.lastLine()) return;
4390
4391 // Clip the change to the size of this doc
4392 if (change.from.line < doc.first) {
4393 var shift = change.text.length - 1 - (doc.first - change.from.line);
4394 shiftDoc(doc, shift);
4395 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
4396 text: [lst(change.text)], origin: change.origin};
4397 }
4398 var last = doc.lastLine();
4399 if (change.to.line > last) {
4400 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
4401 text: [change.text[0]], origin: change.origin};
4402 }
4403
4404 change.removed = getBetween(doc, change.from, change.to);
4405
4406 if (!selAfter) selAfter = computeSelAfterChange(doc, change);
4407 if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
4408 else updateDoc(doc, change, spans);
4409 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
4410 }
4411
4412 // Handle the interaction of a change to a document with the editor
4413 // that this document is part of.
4414 function makeChangeSingleDocInEditor(cm, change, spans) {
4415 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
4416
4417 var recomputeMaxLength = false, checkWidthStart = from.line;
4418 if (!cm.options.lineWrapping) {
4419 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
4420 doc.iter(checkWidthStart, to.line + 1, function(line) {
4421 if (line == display.maxLine) {
4422 recomputeMaxLength = true;
4423 return true;
4424 }
4425 });
4426 }
4427
4428 if (doc.sel.contains(change.from, change.to) > -1)
4429 signalCursorActivity(cm);
4430
4431 updateDoc(doc, change, spans, estimateHeight(cm));
4432
4433 if (!cm.options.lineWrapping) {
4434 doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
4435 var len = lineLength(line);
4436 if (len > display.maxLineLength) {
4437 display.maxLine = line;
4438 display.maxLineLength = len;
4439 display.maxLineChanged = true;
4440 recomputeMaxLength = false;
4441 }
4442 });
4443 if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
4444 }
4445
4446 // Adjust frontier, schedule worker
4447 doc.frontier = Math.min(doc.frontier, from.line);
4448 startWorker(cm, 400);
4449
4450 var lendiff = change.text.length - (to.line - from.line) - 1;
4451 // Remember that these lines changed, for updating the display
4452 if (change.full)
4453 regChange(cm);
4454 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
4455 regLineChange(cm, from.line, "text");
4456 else
4457 regChange(cm, from.line, to.line + 1, lendiff);
4458
4459 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
4460 if (changeHandler || changesHandler) {
4461 var obj = {
4462 from: from, to: to,
4463 text: change.text,
4464 removed: change.removed,
4465 origin: change.origin
4466 };
4467 if (changeHandler) signalLater(cm, "change", cm, obj);
4468 if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
4469 }
4470 cm.display.selForContextMenu = null;
4471 }
4472
4473 function replaceRange(doc, code, from, to, origin) {
4474 if (!to) to = from;
4475 if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
4476 if (typeof code == "string") code = splitLines(code);
4477 makeChange(doc, {from: from, to: to, text: code, origin: origin});
4478 }
4479
4480 // SCROLLING THINGS INTO VIEW
4481
4482 // If an editor sits on the top or bottom of the window, partially
4483 // scrolled out of view, this ensures that the cursor is visible.
4484 function maybeScrollWindow(cm, coords) {
4485 if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
4486
4487 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
4488 if (coords.top + box.top < 0) doScroll = true;
4489 else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
4490 if (doScroll != null && !phantom) {
4491 var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
4492 (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
4493 (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
4494 coords.left + "px; width: 2px;");
4495 cm.display.lineSpace.appendChild(scrollNode);
4496 scrollNode.scrollIntoView(doScroll);
4497 cm.display.lineSpace.removeChild(scrollNode);
4498 }
4499 }
4500
4501 // Scroll a given position into view (immediately), verifying that
4502 // it actually became visible (as line heights are accurately
4503 // measured, the position of something may 'drift' during drawing).
4504 function scrollPosIntoView(cm, pos, end, margin) {
4505 if (margin == null) margin = 0;
4506 for (var limit = 0; limit < 5; limit++) {
4507 var changed = false, coords = cursorCoords(cm, pos);
4508 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
4509 var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
4510 Math.min(coords.top, endCoords.top) - margin,
4511 Math.max(coords.left, endCoords.left),
4512 Math.max(coords.bottom, endCoords.bottom) + margin);
4513 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
4514 if (scrollPos.scrollTop != null) {
4515 setScrollTop(cm, scrollPos.scrollTop);
4516 if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
4517 }
4518 if (scrollPos.scrollLeft != null) {
4519 setScrollLeft(cm, scrollPos.scrollLeft);
4520 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
4521 }
4522 if (!changed) break;
4523 }
4524 return coords;
4525 }
4526
4527 // Scroll a given set of coordinates into view (immediately).
4528 function scrollIntoView(cm, x1, y1, x2, y2) {
4529 var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
4530 if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
4531 if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
4532 }
4533
4534 // Calculate a new scroll position needed to scroll the given
4535 // rectangle into view. Returns an object with scrollTop and
4536 // scrollLeft properties. When these are undefined, the
4537 // vertical/horizontal position does not need to be adjusted.
4538 function calculateScrollPos(cm, x1, y1, x2, y2) {
4539 var display = cm.display, snapMargin = textHeight(cm.display);
4540 if (y1 < 0) y1 = 0;
4541 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
4542 var screen = displayHeight(cm), result = {};
4543 if (y2 - y1 > screen) y2 = y1 + screen;
4544 var docBottom = cm.doc.height + paddingVert(display);
4545 var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
4546 if (y1 < screentop) {
4547 result.scrollTop = atTop ? 0 : y1;
4548 } else if (y2 > screentop + screen) {
4549 var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
4550 if (newTop != screentop) result.scrollTop = newTop;
4551 }
4552
4553 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
4554 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
4555 var tooWide = x2 - x1 > screenw;
4556 if (tooWide) x2 = x1 + screenw;
4557 if (x1 < 10)
4558 result.scrollLeft = 0;
4559 else if (x1 < screenleft)
4560 result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
4561 else if (x2 > screenw + screenleft - 3)
4562 result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
4563 return result;
4564 }
4565
4566 // Store a relative adjustment to the scroll position in the current
4567 // operation (to be applied when the operation finishes).
4568 function addToScrollPos(cm, left, top) {
4569 if (left != null || top != null) resolveScrollToPos(cm);
4570 if (left != null)
4571 cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
4572 if (top != null)
4573 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
4574 }
4575
4576 // Make sure that at the end of the operation the current cursor is
4577 // shown.
4578 function ensureCursorVisible(cm) {
4579 resolveScrollToPos(cm);
4580 var cur = cm.getCursor(), from = cur, to = cur;
4581 if (!cm.options.lineWrapping) {
4582 from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
4583 to = Pos(cur.line, cur.ch + 1);
4584 }
4585 cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
4586 }
4587
4588 // When an operation has its scrollToPos property set, and another
4589 // scroll action is applied before the end of the operation, this
4590 // 'simulates' scrolling that position into view in a cheap way, so
4591 // that the effect of intermediate scroll commands is not ignored.
4592 function resolveScrollToPos(cm) {
4593 var range = cm.curOp.scrollToPos;
4594 if (range) {
4595 cm.curOp.scrollToPos = null;
4596 var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
4597 var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
4598 Math.min(from.top, to.top) - range.margin,
4599 Math.max(from.right, to.right),
4600 Math.max(from.bottom, to.bottom) + range.margin);
4601 cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
4602 }
4603 }
4604
4605 // API UTILITIES
4606
4607 // Indent the given line. The how parameter can be "smart",
4608 // "add"/null, "subtract", or "prev". When aggressive is false
4609 // (typically set to true for forced single-line indents), empty
4610 // lines are not indented, and places where the mode returns Pass
4611 // are left alone.
4612 function indentLine(cm, n, how, aggressive) {
4613 var doc = cm.doc, state;
4614 if (how == null) how = "add";
4615 if (how == "smart") {
4616 // Fall back to "prev" when the mode doesn't have an indentation
4617 // method.
4618 if (!doc.mode.indent) how = "prev";
4619 else state = getStateBefore(cm, n);
4620 }
4621
4622 var tabSize = cm.options.tabSize;
4623 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
4624 if (line.stateAfter) line.stateAfter = null;
4625 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
4626 if (!aggressive && !/\S/.test(line.text)) {
4627 indentation = 0;
4628 how = "not";
4629 } else if (how == "smart") {
4630 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
4631 if (indentation == Pass || indentation > 150) {
4632 if (!aggressive) return;
4633 how = "prev";
4634 }
4635 }
4636 if (how == "prev") {
4637 if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
4638 else indentation = 0;
4639 } else if (how == "add") {
4640 indentation = curSpace + cm.options.indentUnit;
4641 } else if (how == "subtract") {
4642 indentation = curSpace - cm.options.indentUnit;
4643 } else if (typeof how == "number") {
4644 indentation = curSpace + how;
4645 }
4646 indentation = Math.max(0, indentation);
4647
4648 var indentString = "", pos = 0;
4649 if (cm.options.indentWithTabs)
4650 for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
4651 if (pos < indentation) indentString += spaceStr(indentation - pos);
4652
4653 if (indentString != curSpaceString) {
4654 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
4655 line.stateAfter = null;
4656 return true;
4657 } else {
4658 // Ensure that, if the cursor was in the whitespace at the start
4659 // of the line, it is moved to the end of that space.
4660 for (var i = 0; i < doc.sel.ranges.length; i++) {
4661 var range = doc.sel.ranges[i];
4662 if (range.head.line == n && range.head.ch < curSpaceString.length) {
4663 var pos = Pos(n, curSpaceString.length);
4664 replaceOneSelection(doc, i, new Range(pos, pos));
4665 break;
4666 }
4667 }
4668 }
4669 }
4670
4671 // Utility for applying a change to a line by handle or number,
4672 // returning the number and optionally registering the line as
4673 // changed.
4674 function changeLine(doc, handle, changeType, op) {
4675 var no = handle, line = handle;
4676 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
4677 else no = lineNo(handle);
4678 if (no == null) return null;
4679 if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
4680 return line;
4681 }
4682
4683 // Helper for deleting text near the selection(s), used to implement
4684 // backspace, delete, and similar functionality.
4685 function deleteNearSelection(cm, compute) {
4686 var ranges = cm.doc.sel.ranges, kill = [];
4687 // Build up a set of ranges to kill first, merging overlapping
4688 // ranges.
4689 for (var i = 0; i < ranges.length; i++) {
4690 var toKill = compute(ranges[i]);
4691 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
4692 var replaced = kill.pop();
4693 if (cmp(replaced.from, toKill.from) < 0) {
4694 toKill.from = replaced.from;
4695 break;
4696 }
4697 }
4698 kill.push(toKill);
4699 }
4700 // Next, remove those actual ranges.
4701 runInOp(cm, function() {
4702 for (var i = kill.length - 1; i >= 0; i--)
4703 replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
4704 ensureCursorVisible(cm);
4705 });
4706 }
4707
4708 // Used for horizontal relative motion. Dir is -1 or 1 (left or
4709 // right), unit can be "char", "column" (like char, but doesn't
4710 // cross line boundaries), "word" (across next word), or "group" (to
4711 // the start of next group of word or non-word-non-whitespace
4712 // chars). The visually param controls whether, in right-to-left
4713 // text, direction 1 means to move towards the next index in the
4714 // string, or towards the character to the right of the current
4715 // position. The resulting position will have a hitSide=true
4716 // property if it reached the end of the document.
4717 function findPosH(doc, pos, dir, unit, visually) {
4718 var line = pos.line, ch = pos.ch, origDir = dir;
4719 var lineObj = getLine(doc, line);
4720 var possible = true;
4721 function findNextLine() {
4722 var l = line + dir;
4723 if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
4724 line = l;
4725 return lineObj = getLine(doc, l);
4726 }
4727 function moveOnce(boundToLine) {
4728 var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
4729 if (next == null) {
4730 if (!boundToLine && findNextLine()) {
4731 if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
4732 else ch = dir < 0 ? lineObj.text.length : 0;
4733 } else return (possible = false);
4734 } else ch = next;
4735 return true;
4736 }
4737
4738 if (unit == "char") moveOnce();
4739 else if (unit == "column") moveOnce(true);
4740 else if (unit == "word" || unit == "group") {
4741 var sawType = null, group = unit == "group";
4742 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
4743 for (var first = true;; first = false) {
4744 if (dir < 0 && !moveOnce(!first)) break;
4745 var cur = lineObj.text.charAt(ch) || "\n";
4746 var type = isWordChar(cur, helper) ? "w"
4747 : group && cur == "\n" ? "n"
4748 : !group || /\s/.test(cur) ? null
4749 : "p";
4750 if (group && !first && !type) type = "s";
4751 if (sawType && sawType != type) {
4752 if (dir < 0) {dir = 1; moveOnce();}
4753 break;
4754 }
4755
4756 if (type) sawType = type;
4757 if (dir > 0 && !moveOnce(!first)) break;
4758 }
4759 }
4760 var result = skipAtomic(doc, Pos(line, ch), origDir, true);
4761 if (!possible) result.hitSide = true;
4762 return result;
4763 }
4764
4765 // For relative vertical movement. Dir may be -1 or 1. Unit can be
4766 // "page" or "line". The resulting position will have a hitSide=true
4767 // property if it reached the end of the document.
4768 function findPosV(cm, pos, dir, unit) {
4769 var doc = cm.doc, x = pos.left, y;
4770 if (unit == "page") {
4771 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
4772 y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
4773 } else if (unit == "line") {
4774 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
4775 }
4776 for (;;) {
4777 var target = coordsChar(cm, x, y);
4778 if (!target.outside) break;
4779 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
4780 y += dir * 5;
4781 }
4782 return target;
4783 }
4784
4785 // EDITOR METHODS
4786
4787 // The publicly visible API. Note that methodOp(f) means
4788 // 'wrap f in an operation, performed on its `this` parameter'.
4789
4790 // This is not the complete set of editor methods. Most of the
4791 // methods defined on the Doc type are also injected into
4792 // CodeMirror.prototype, for backwards compatibility and
4793 // convenience.
4794
4795 CodeMirror.prototype = {
4796 constructor: CodeMirror,
4797 focus: function(){window.focus(); this.display.input.focus();},
4798
4799 setOption: function(option, value) {
4800 var options = this.options, old = options[option];
4801 if (options[option] == value && option != "mode") return;
4802 options[option] = value;
4803 if (optionHandlers.hasOwnProperty(option))
4804 operation(this, optionHandlers[option])(this, value, old);
4805 },
4806
4807 getOption: function(option) {return this.options[option];},
4808 getDoc: function() {return this.doc;},
4809
4810 addKeyMap: function(map, bottom) {
4811 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
4812 },
4813 removeKeyMap: function(map) {
4814 var maps = this.state.keyMaps;
4815 for (var i = 0; i < maps.length; ++i)
4816 if (maps[i] == map || maps[i].name == map) {
4817 maps.splice(i, 1);
4818 return true;
4819 }
4820 },
4821
4822 addOverlay: methodOp(function(spec, options) {
4823 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
4824 if (mode.startState) throw new Error("Overlays may not be stateful.");
4825 this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
4826 this.state.modeGen++;
4827 regChange(this);
4828 }),
4829 removeOverlay: methodOp(function(spec) {
4830 var overlays = this.state.overlays;
4831 for (var i = 0; i < overlays.length; ++i) {
4832 var cur = overlays[i].modeSpec;
4833 if (cur == spec || typeof spec == "string" && cur.name == spec) {
4834 overlays.splice(i, 1);
4835 this.state.modeGen++;
4836 regChange(this);
4837 return;
4838 }
4839 }
4840 }),
4841
4842 indentLine: methodOp(function(n, dir, aggressive) {
4843 if (typeof dir != "string" && typeof dir != "number") {
4844 if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
4845 else dir = dir ? "add" : "subtract";
4846 }
4847 if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
4848 }),
4849 indentSelection: methodOp(function(how) {
4850 var ranges = this.doc.sel.ranges, end = -1;
4851 for (var i = 0; i < ranges.length; i++) {
4852 var range = ranges[i];
4853 if (!range.empty()) {
4854 var from = range.from(), to = range.to();
4855 var start = Math.max(end, from.line);
4856 end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
4857 for (var j = start; j < end; ++j)
4858 indentLine(this, j, how);
4859 var newRanges = this.doc.sel.ranges;
4860 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
4861 replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
4862 } else if (range.head.line > end) {
4863 indentLine(this, range.head.line, how, true);
4864 end = range.head.line;
4865 if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
4866 }
4867 }
4868 }),
4869
4870 // Fetch the parser token for a given character. Useful for hacks
4871 // that want to inspect the mode state (say, for completion).
4872 getTokenAt: function(pos, precise) {
4873 return takeToken(this, pos, precise);
4874 },
4875
4876 getLineTokens: function(line, precise) {
4877 return takeToken(this, Pos(line), precise, true);
4878 },
4879
4880 getTokenTypeAt: function(pos) {
4881 pos = clipPos(this.doc, pos);
4882 var styles = getLineStyles(this, getLine(this.doc, pos.line));
4883 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
4884 var type;
4885 if (ch == 0) type = styles[2];
4886 else for (;;) {
4887 var mid = (before + after) >> 1;
4888 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
4889 else if (styles[mid * 2 + 1] < ch) before = mid + 1;
4890 else { type = styles[mid * 2 + 2]; break; }
4891 }
4892 var cut = type ? type.indexOf("cm-overlay ") : -1;
4893 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
4894 },
4895
4896 getModeAt: function(pos) {
4897 var mode = this.doc.mode;
4898 if (!mode.innerMode) return mode;
4899 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
4900 },
4901
4902 getHelper: function(pos, type) {
4903 return this.getHelpers(pos, type)[0];
4904 },
4905
4906 getHelpers: function(pos, type) {
4907 var found = [];
4908 if (!helpers.hasOwnProperty(type)) return found;
4909 var help = helpers[type], mode = this.getModeAt(pos);
4910 if (typeof mode[type] == "string") {
4911 if (help[mode[type]]) found.push(help[mode[type]]);
4912 } else if (mode[type]) {
4913 for (var i = 0; i < mode[type].length; i++) {
4914 var val = help[mode[type][i]];
4915 if (val) found.push(val);
4916 }
4917 } else if (mode.helperType && help[mode.helperType]) {
4918 found.push(help[mode.helperType]);
4919 } else if (help[mode.name]) {
4920 found.push(help[mode.name]);
4921 }
4922 for (var i = 0; i < help._global.length; i++) {
4923 var cur = help._global[i];
4924 if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
4925 found.push(cur.val);
4926 }
4927 return found;
4928 },
4929
4930 getStateAfter: function(line, precise) {
4931 var doc = this.doc;
4932 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
4933 return getStateBefore(this, line + 1, precise);
4934 },
4935
4936 cursorCoords: function(start, mode) {
4937 var pos, range = this.doc.sel.primary();
4938 if (start == null) pos = range.head;
4939 else if (typeof start == "object") pos = clipPos(this.doc, start);
4940 else pos = start ? range.from() : range.to();
4941 return cursorCoords(this, pos, mode || "page");
4942 },
4943
4944 charCoords: function(pos, mode) {
4945 return charCoords(this, clipPos(this.doc, pos), mode || "page");
4946 },
4947
4948 coordsChar: function(coords, mode) {
4949 coords = fromCoordSystem(this, coords, mode || "page");
4950 return coordsChar(this, coords.left, coords.top);
4951 },
4952
4953 lineAtHeight: function(height, mode) {
4954 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
4955 return lineAtHeight(this.doc, height + this.display.viewOffset);
4956 },
4957 heightAtLine: function(line, mode) {
4958 var end = false, lineObj;
4959 if (typeof line == "number") {
4960 var last = this.doc.first + this.doc.size - 1;
4961 if (line < this.doc.first) line = this.doc.first;
4962 else if (line > last) { line = last; end = true; }
4963 lineObj = getLine(this.doc, line);
4964 } else {
4965 lineObj = line;
4966 }
4967 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
4968 (end ? this.doc.height - heightAtLine(lineObj) : 0);
4969 },
4970
4971 defaultTextHeight: function() { return textHeight(this.display); },
4972 defaultCharWidth: function() { return charWidth(this.display); },
4973
4974 setGutterMarker: methodOp(function(line, gutterID, value) {
4975 return changeLine(this.doc, line, "gutter", function(line) {
4976 var markers = line.gutterMarkers || (line.gutterMarkers = {});
4977 markers[gutterID] = value;
4978 if (!value && isEmpty(markers)) line.gutterMarkers = null;
4979 return true;
4980 });
4981 }),
4982
4983 clearGutter: methodOp(function(gutterID) {
4984 var cm = this, doc = cm.doc, i = doc.first;
4985 doc.iter(function(line) {
4986 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
4987 line.gutterMarkers[gutterID] = null;
4988 regLineChange(cm, i, "gutter");
4989 if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
4990 }
4991 ++i;
4992 });
4993 }),
4994
4995 lineInfo: function(line) {
4996 if (typeof line == "number") {
4997 if (!isLine(this.doc, line)) return null;
4998 var n = line;
4999 line = getLine(this.doc, line);
5000 if (!line) return null;
5001 } else {
5002 var n = lineNo(line);
5003 if (n == null) return null;
5004 }
5005 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
5006 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
5007 widgets: line.widgets};
5008 },
5009
5010 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
5011
5012 addWidget: function(pos, node, scroll, vert, horiz) {
5013 var display = this.display;
5014 pos = cursorCoords(this, clipPos(this.doc, pos));
5015 var top = pos.bottom, left = pos.left;
5016 node.style.position = "absolute";
5017 node.setAttribute("cm-ignore-events", "true");
5018 this.display.input.setUneditable(node);
5019 display.sizer.appendChild(node);
5020 if (vert == "over") {
5021 top = pos.top;
5022 } else if (vert == "above" || vert == "near") {
5023 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
5024 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
5025 // Default to positioning above (if specified and possible); otherwise default to positioning below
5026 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
5027 top = pos.top - node.offsetHeight;
5028 else if (pos.bottom + node.offsetHeight <= vspace)
5029 top = pos.bottom;
5030 if (left + node.offsetWidth > hspace)
5031 left = hspace - node.offsetWidth;
5032 }
5033 node.style.top = top + "px";
5034 node.style.left = node.style.right = "";
5035 if (horiz == "right") {
5036 left = display.sizer.clientWidth - node.offsetWidth;
5037 node.style.right = "0px";
5038 } else {
5039 if (horiz == "left") left = 0;
5040 else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
5041 node.style.left = left + "px";
5042 }
5043 if (scroll)
5044 scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
5045 },
5046
5047 triggerOnKeyDown: methodOp(onKeyDown),
5048 triggerOnKeyPress: methodOp(onKeyPress),
5049 triggerOnKeyUp: onKeyUp,
5050
5051 execCommand: function(cmd) {
5052 if (commands.hasOwnProperty(cmd))
5053 return commands[cmd](this);
5054 },
5055
5056 findPosH: function(from, amount, unit, visually) {
5057 var dir = 1;
5058 if (amount < 0) { dir = -1; amount = -amount; }
5059 for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
5060 cur = findPosH(this.doc, cur, dir, unit, visually);
5061 if (cur.hitSide) break;
5062 }
5063 return cur;
5064 },
5065
5066 moveH: methodOp(function(dir, unit) {
5067 var cm = this;
5068 cm.extendSelectionsBy(function(range) {
5069 if (cm.display.shift || cm.doc.extend || range.empty())
5070 return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
5071 else
5072 return dir < 0 ? range.from() : range.to();
5073 }, sel_move);
5074 }),
5075
5076 deleteH: methodOp(function(dir, unit) {
5077 var sel = this.doc.sel, doc = this.doc;
5078 if (sel.somethingSelected())
5079 doc.replaceSelection("", null, "+delete");
5080 else
5081 deleteNearSelection(this, function(range) {
5082 var other = findPosH(doc, range.head, dir, unit, false);
5083 return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
5084 });
5085 }),
5086
5087 findPosV: function(from, amount, unit, goalColumn) {
5088 var dir = 1, x = goalColumn;
5089 if (amount < 0) { dir = -1; amount = -amount; }
5090 for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
5091 var coords = cursorCoords(this, cur, "div");
5092 if (x == null) x = coords.left;
5093 else coords.left = x;
5094 cur = findPosV(this, coords, dir, unit);
5095 if (cur.hitSide) break;
5096 }
5097 return cur;
5098 },
5099
5100 moveV: methodOp(function(dir, unit) {
5101 var cm = this, doc = this.doc, goals = [];
5102 var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
5103 doc.extendSelectionsBy(function(range) {
5104 if (collapse)
5105 return dir < 0 ? range.from() : range.to();
5106 var headPos = cursorCoords(cm, range.head, "div");
5107 if (range.goalColumn != null) headPos.left = range.goalColumn;
5108 goals.push(headPos.left);
5109 var pos = findPosV(cm, headPos, dir, unit);
5110 if (unit == "page" && range == doc.sel.primary())
5111 addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
5112 return pos;
5113 }, sel_move);
5114 if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
5115 doc.sel.ranges[i].goalColumn = goals[i];
5116 }),
5117
5118 // Find the word at the given position (as returned by coordsChar).
5119 findWordAt: function(pos) {
5120 var doc = this.doc, line = getLine(doc, pos.line).text;
5121 var start = pos.ch, end = pos.ch;
5122 if (line) {
5123 var helper = this.getHelper(pos, "wordChars");
5124 if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
5125 var startChar = line.charAt(start);
5126 var check = isWordChar(startChar, helper)
5127 ? function(ch) { return isWordChar(ch, helper); }
5128 : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
5129 : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
5130 while (start > 0 && check(line.charAt(start - 1))) --start;
5131 while (end < line.length && check(line.charAt(end))) ++end;
5132 }
5133 return new Range(Pos(pos.line, start), Pos(pos.line, end));
5134 },
5135
5136 toggleOverwrite: function(value) {
5137 if (value != null && value == this.state.overwrite) return;
5138 if (this.state.overwrite = !this.state.overwrite)
5139 addClass(this.display.cursorDiv, "CodeMirror-overwrite");
5140 else
5141 rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
5142
5143 signal(this, "overwriteToggle", this, this.state.overwrite);
5144 },
5145 hasFocus: function() { return this.display.input.getField() == activeElt(); },
5146
5147 scrollTo: methodOp(function(x, y) {
5148 if (x != null || y != null) resolveScrollToPos(this);
5149 if (x != null) this.curOp.scrollLeft = x;
5150 if (y != null) this.curOp.scrollTop = y;
5151 }),
5152 getScrollInfo: function() {
5153 var scroller = this.display.scroller;
5154 return {left: scroller.scrollLeft, top: scroller.scrollTop,
5155 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
5156 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
5157 clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
5158 },
5159
5160 scrollIntoView: methodOp(function(range, margin) {
5161 if (range == null) {
5162 range = {from: this.doc.sel.primary().head, to: null};
5163 if (margin == null) margin = this.options.cursorScrollMargin;
5164 } else if (typeof range == "number") {
5165 range = {from: Pos(range, 0), to: null};
5166 } else if (range.from == null) {
5167 range = {from: range, to: null};
5168 }
5169 if (!range.to) range.to = range.from;
5170 range.margin = margin || 0;
5171
5172 if (range.from.line != null) {
5173 resolveScrollToPos(this);
5174 this.curOp.scrollToPos = range;
5175 } else {
5176 var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
5177 Math.min(range.from.top, range.to.top) - range.margin,
5178 Math.max(range.from.right, range.to.right),
5179 Math.max(range.from.bottom, range.to.bottom) + range.margin);
5180 this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
5181 }
5182 }),
5183
5184 setSize: methodOp(function(width, height) {
5185 var cm = this;
5186 function interpret(val) {
5187 return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
5188 }
5189 if (width != null) cm.display.wrapper.style.width = interpret(width);
5190 if (height != null) cm.display.wrapper.style.height = interpret(height);
5191 if (cm.options.lineWrapping) clearLineMeasurementCache(this);
5192 var lineNo = cm.display.viewFrom;
5193 cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
5194 if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
5195 if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
5196 ++lineNo;
5197 });
5198 cm.curOp.forceUpdate = true;
5199 signal(cm, "refresh", this);
5200 }),
5201
5202 operation: function(f){return runInOp(this, f);},
5203
5204 refresh: methodOp(function() {
5205 var oldHeight = this.display.cachedTextHeight;
5206 regChange(this);
5207 this.curOp.forceUpdate = true;
5208 clearCaches(this);
5209 this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
5210 updateGutterSpace(this);
5211 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
5212 estimateLineHeights(this);
5213 signal(this, "refresh", this);
5214 }),
5215
5216 swapDoc: methodOp(function(doc) {
5217 var old = this.doc;
5218 old.cm = null;
5219 attachDoc(this, doc);
5220 clearCaches(this);
5221 this.display.input.reset();
5222 this.scrollTo(doc.scrollLeft, doc.scrollTop);
5223 this.curOp.forceScroll = true;
5224 signalLater(this, "swapDoc", this, old);
5225 return old;
5226 }),
5227
5228 getInputField: function(){return this.display.input.getField();},
5229 getWrapperElement: function(){return this.display.wrapper;},
5230 getScrollerElement: function(){return this.display.scroller;},
5231 getGutterElement: function(){return this.display.gutters;}
5232 };
5233 eventMixin(CodeMirror);
5234
5235 // OPTION DEFAULTS
5236
5237 // The default configuration options.
5238 var defaults = CodeMirror.defaults = {};
5239 // Functions to run when options are changed.
5240 var optionHandlers = CodeMirror.optionHandlers = {};
5241
5242 function option(name, deflt, handle, notOnInit) {
5243 CodeMirror.defaults[name] = deflt;
5244 if (handle) optionHandlers[name] =
5245 notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
5246 }
5247
5248 // Passed to option handlers when there is no old value.
5249 var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
5250
5251 // These two are, on init, called from the constructor because they
5252 // have to be initialized before the editor can start at all.
5253 option("value", "", function(cm, val) {
5254 cm.setValue(val);
5255 }, true);
5256 option("mode", null, function(cm, val) {
5257 cm.doc.modeOption = val;
5258 loadMode(cm);
5259 }, true);
5260
5261 option("indentUnit", 2, loadMode, true);
5262 option("indentWithTabs", false);
5263 option("smartIndent", true);
5264 option("tabSize", 4, function(cm) {
5265 resetModeState(cm);
5266 clearCaches(cm);
5267 regChange(cm);
5268 }, true);
5269 option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
5270 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
5271 if (old != CodeMirror.Init) cm.refresh();
5272 });
5273 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
5274 option("electricChars", true);
5275 option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
5276 throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
5277 }, true);
5278 option("rtlMoveVisually", !windows);
5279 option("wholeLineUpdateBefore", true);
5280
5281 option("theme", "default", function(cm) {
5282 themeChanged(cm);
5283 guttersChanged(cm);
5284 }, true);
5285 option("keyMap", "default", function(cm, val, old) {
5286 var next = getKeyMap(val);
5287 var prev = old != CodeMirror.Init && getKeyMap(old);
5288 if (prev && prev.detach) prev.detach(cm, next);
5289 if (next.attach) next.attach(cm, prev || null);
5290 });
5291 option("extraKeys", null);
5292
5293 option("lineWrapping", false, wrappingChanged, true);
5294 option("gutters", [], function(cm) {
5295 setGuttersForLineNumbers(cm.options);
5296 guttersChanged(cm);
5297 }, true);
5298 option("fixedGutter", true, function(cm, val) {
5299 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
5300 cm.refresh();
5301 }, true);
5302 option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
5303 option("scrollbarStyle", "native", function(cm) {
5304 initScrollbars(cm);
5305 updateScrollbars(cm);
5306 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
5307 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
5308 }, true);
5309 option("lineNumbers", false, function(cm) {
5310 setGuttersForLineNumbers(cm.options);
5311 guttersChanged(cm);
5312 }, true);
5313 option("firstLineNumber", 1, guttersChanged, true);
5314 option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
5315 option("showCursorWhenSelecting", false, updateSelection, true);
5316
5317 option("resetSelectionOnContextMenu", true);
5318 option("lineWiseCopyCut", true);
5319
5320 option("readOnly", false, function(cm, val) {
5321 if (val == "nocursor") {
5322 onBlur(cm);
5323 cm.display.input.blur();
5324 cm.display.disabled = true;
5325 } else {
5326 cm.display.disabled = false;
5327 if (!val) cm.display.input.reset();
5328 }
5329 });
5330 option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
5331 option("dragDrop", true, dragDropChanged);
5332
5333 option("cursorBlinkRate", 530);
5334 option("cursorScrollMargin", 0);
5335 option("cursorHeight", 1, updateSelection, true);
5336 option("singleCursorHeightPerLine", true, updateSelection, true);
5337 option("workTime", 100);
5338 option("workDelay", 100);
5339 option("flattenSpans", true, resetModeState, true);
5340 option("addModeClass", false, resetModeState, true);
5341 option("pollInterval", 100);
5342 option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
5343 option("historyEventDelay", 1250);
5344 option("viewportMargin", 10, function(cm){cm.refresh();}, true);
5345 option("maxHighlightLength", 10000, resetModeState, true);
5346 option("moveInputWithCursor", true, function(cm, val) {
5347 if (!val) cm.display.input.resetPosition();
5348 });
5349
5350 option("tabindex", null, function(cm, val) {
5351 cm.display.input.getField().tabIndex = val || "";
5352 });
5353 option("autofocus", null);
5354
5355 // MODE DEFINITION AND QUERYING
5356
5357 // Known modes, by name and by MIME
5358 var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
5359
5360 // Extra arguments are stored as the mode's dependencies, which is
5361 // used by (legacy) mechanisms like loadmode.js to automatically
5362 // load a mode. (Preferred mechanism is the require/define calls.)
5363 CodeMirror.defineMode = function(name, mode) {
5364 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
5365 if (arguments.length > 2)
5366 mode.dependencies = Array.prototype.slice.call(arguments, 2);
5367 modes[name] = mode;
5368 };
5369
5370 CodeMirror.defineMIME = function(mime, spec) {
5371 mimeModes[mime] = spec;
5372 };
5373
5374 // Given a MIME type, a {name, ...options} config object, or a name
5375 // string, return a mode config object.
5376 CodeMirror.resolveMode = function(spec) {
5377 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
5378 spec = mimeModes[spec];
5379 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
5380 var found = mimeModes[spec.name];
5381 if (typeof found == "string") found = {name: found};
5382 spec = createObj(found, spec);
5383 spec.name = found.name;
5384 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
5385 return CodeMirror.resolveMode("application/xml");
5386 }
5387 if (typeof spec == "string") return {name: spec};
5388 else return spec || {name: "null"};
5389 };
5390
5391 // Given a mode spec (anything that resolveMode accepts), find and
5392 // initialize an actual mode object.
5393 CodeMirror.getMode = function(options, spec) {
5394 var spec = CodeMirror.resolveMode(spec);
5395 var mfactory = modes[spec.name];
5396 if (!mfactory) return CodeMirror.getMode(options, "text/plain");
5397 var modeObj = mfactory(options, spec);
5398 if (modeExtensions.hasOwnProperty(spec.name)) {
5399 var exts = modeExtensions[spec.name];
5400 for (var prop in exts) {
5401 if (!exts.hasOwnProperty(prop)) continue;
5402 if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
5403 modeObj[prop] = exts[prop];
5404 }
5405 }
5406 modeObj.name = spec.name;
5407 if (spec.helperType) modeObj.helperType = spec.helperType;
5408 if (spec.modeProps) for (var prop in spec.modeProps)
5409 modeObj[prop] = spec.modeProps[prop];
5410
5411 return modeObj;
5412 };
5413
5414 // Minimal default mode.
5415 CodeMirror.defineMode("null", function() {
5416 return {token: function(stream) {stream.skipToEnd();}};
5417 });
5418 CodeMirror.defineMIME("text/plain", "null");
5419
5420 // This can be used to attach properties to mode objects from
5421 // outside the actual mode definition.
5422 var modeExtensions = CodeMirror.modeExtensions = {};
5423 CodeMirror.extendMode = function(mode, properties) {
5424 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
5425 copyObj(properties, exts);
5426 };
5427
5428 // EXTENSIONS
5429
5430 CodeMirror.defineExtension = function(name, func) {
5431 CodeMirror.prototype[name] = func;
5432 };
5433 CodeMirror.defineDocExtension = function(name, func) {
5434 Doc.prototype[name] = func;
5435 };
5436 CodeMirror.defineOption = option;
5437
5438 var initHooks = [];
5439 CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
5440
5441 var helpers = CodeMirror.helpers = {};
5442 CodeMirror.registerHelper = function(type, name, value) {
5443 if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
5444 helpers[type][name] = value;
5445 };
5446 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
5447 CodeMirror.registerHelper(type, name, value);
5448 helpers[type]._global.push({pred: predicate, val: value});
5449 };
5450
5451 // MODE STATE HANDLING
5452
5453 // Utility functions for working with state. Exported because nested
5454 // modes need to do this for their inner modes.
5455
5456 var copyState = CodeMirror.copyState = function(mode, state) {
5457 if (state === true) return state;
5458 if (mode.copyState) return mode.copyState(state);
5459 var nstate = {};
5460 for (var n in state) {
5461 var val = state[n];
5462 if (val instanceof Array) val = val.concat([]);
5463 nstate[n] = val;
5464 }
5465 return nstate;
5466 };
5467
5468 var startState = CodeMirror.startState = function(mode, a1, a2) {
5469 return mode.startState ? mode.startState(a1, a2) : true;
5470 };
5471
5472 // Given a mode and a state (for that mode), find the inner mode and
5473 // state at the position that the state refers to.
5474 CodeMirror.innerMode = function(mode, state) {
5475 while (mode.innerMode) {
5476 var info = mode.innerMode(state);
5477 if (!info || info.mode == mode) break;
5478 state = info.state;
5479 mode = info.mode;
5480 }
5481 return info || {mode: mode, state: state};
5482 };
5483
5484 // STANDARD COMMANDS
5485
5486 // Commands are parameter-less actions that can be performed on an
5487 // editor, mostly used for keybindings.
5488 var commands = CodeMirror.commands = {
5489 selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
5490 singleSelection: function(cm) {
5491 cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
5492 },
5493 killLine: function(cm) {
5494 deleteNearSelection(cm, function(range) {
5495 if (range.empty()) {
5496 var len = getLine(cm.doc, range.head.line).text.length;
5497 if (range.head.ch == len && range.head.line < cm.lastLine())
5498 return {from: range.head, to: Pos(range.head.line + 1, 0)};
5499 else
5500 return {from: range.head, to: Pos(range.head.line, len)};
5501 } else {
5502 return {from: range.from(), to: range.to()};
5503 }
5504 });
5505 },
5506 deleteLine: function(cm) {
5507 deleteNearSelection(cm, function(range) {
5508 return {from: Pos(range.from().line, 0),
5509 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
5510 });
5511 },
5512 delLineLeft: function(cm) {
5513 deleteNearSelection(cm, function(range) {
5514 return {from: Pos(range.from().line, 0), to: range.from()};
5515 });
5516 },
5517 delWrappedLineLeft: function(cm) {
5518 deleteNearSelection(cm, function(range) {
5519 var top = cm.charCoords(range.head, "div").top + 5;
5520 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
5521 return {from: leftPos, to: range.from()};
5522 });
5523 },
5524 delWrappedLineRight: function(cm) {
5525 deleteNearSelection(cm, function(range) {
5526 var top = cm.charCoords(range.head, "div").top + 5;
5527 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
5528 return {from: range.from(), to: rightPos };
5529 });
5530 },
5531 undo: function(cm) {cm.undo();},
5532 redo: function(cm) {cm.redo();},
5533 undoSelection: function(cm) {cm.undoSelection();},
5534 redoSelection: function(cm) {cm.redoSelection();},
5535 goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
5536 goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
5537 goLineStart: function(cm) {
5538 cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
5539 {origin: "+move", bias: 1});
5540 },
5541 goLineStartSmart: function(cm) {
5542 cm.extendSelectionsBy(function(range) {
5543 return lineStartSmart(cm, range.head);
5544 }, {origin: "+move", bias: 1});
5545 },
5546 goLineEnd: function(cm) {
5547 cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
5548 {origin: "+move", bias: -1});
5549 },
5550 goLineRight: function(cm) {
5551 cm.extendSelectionsBy(function(range) {
5552 var top = cm.charCoords(range.head, "div").top + 5;
5553 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
5554 }, sel_move);
5555 },
5556 goLineLeft: function(cm) {
5557 cm.extendSelectionsBy(function(range) {
5558 var top = cm.charCoords(range.head, "div").top + 5;
5559 return cm.coordsChar({left: 0, top: top}, "div");
5560 }, sel_move);
5561 },
5562 goLineLeftSmart: function(cm) {
5563 cm.extendSelectionsBy(function(range) {
5564 var top = cm.charCoords(range.head, "div").top + 5;
5565 var pos = cm.coordsChar({left: 0, top: top}, "div");
5566 if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
5567 return pos;
5568 }, sel_move);
5569 },
5570 goLineUp: function(cm) {cm.moveV(-1, "line");},
5571 goLineDown: function(cm) {cm.moveV(1, "line");},
5572 goPageUp: function(cm) {cm.moveV(-1, "page");},
5573 goPageDown: function(cm) {cm.moveV(1, "page");},
5574 goCharLeft: function(cm) {cm.moveH(-1, "char");},
5575 goCharRight: function(cm) {cm.moveH(1, "char");},
5576 goColumnLeft: function(cm) {cm.moveH(-1, "column");},
5577 goColumnRight: function(cm) {cm.moveH(1, "column");},
5578 goWordLeft: function(cm) {cm.moveH(-1, "word");},
5579 goGroupRight: function(cm) {cm.moveH(1, "group");},
5580 goGroupLeft: function(cm) {cm.moveH(-1, "group");},
5581 goWordRight: function(cm) {cm.moveH(1, "word");},
5582 delCharBefore: function(cm) {cm.deleteH(-1, "char");},
5583 delCharAfter: function(cm) {cm.deleteH(1, "char");},
5584 delWordBefore: function(cm) {cm.deleteH(-1, "word");},
5585 delWordAfter: function(cm) {cm.deleteH(1, "word");},
5586 delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
5587 delGroupAfter: function(cm) {cm.deleteH(1, "group");},
5588 indentAuto: function(cm) {cm.indentSelection("smart");},
5589 indentMore: function(cm) {cm.indentSelection("add");},
5590 indentLess: function(cm) {cm.indentSelection("subtract");},
5591 insertTab: function(cm) {cm.replaceSelection("\t");},
5592 insertSoftTab: function(cm) {
5593 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
5594 for (var i = 0; i < ranges.length; i++) {
5595 var pos = ranges[i].from();
5596 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
5597 spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
5598 }
5599 cm.replaceSelections(spaces);
5600 },
5601 defaultTab: function(cm) {
5602 if (cm.somethingSelected()) cm.indentSelection("add");
5603 else cm.execCommand("insertTab");
5604 },
5605 transposeChars: function(cm) {
5606 runInOp(cm, function() {
5607 var ranges = cm.listSelections(), newSel = [];
5608 for (var i = 0; i < ranges.length; i++) {
5609 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
5610 if (line) {
5611 if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
5612 if (cur.ch > 0) {
5613 cur = new Pos(cur.line, cur.ch + 1);
5614 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
5615 Pos(cur.line, cur.ch - 2), cur, "+transpose");
5616 } else if (cur.line > cm.doc.first) {
5617 var prev = getLine(cm.doc, cur.line - 1).text;
5618 if (prev)
5619 cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
5620 Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
5621 }
5622 }
5623 newSel.push(new Range(cur, cur));
5624 }
5625 cm.setSelections(newSel);
5626 });
5627 },
5628 newlineAndIndent: function(cm) {
5629 runInOp(cm, function() {
5630 var len = cm.listSelections().length;
5631 for (var i = 0; i < len; i++) {
5632 var range = cm.listSelections()[i];
5633 cm.replaceRange("\n", range.anchor, range.head, "+input");
5634 cm.indentLine(range.from().line + 1, null, true);
5635 ensureCursorVisible(cm);
5636 }
5637 });
5638 },
5639 toggleOverwrite: function(cm) {cm.toggleOverwrite();}
5640 };
5641
5642
5643 // STANDARD KEYMAPS
5644
5645 var keyMap = CodeMirror.keyMap = {};
5646
5647 keyMap.basic = {
5648 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
5649 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
5650 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
5651 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
5652 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
5653 "Esc": "singleSelection"
5654 };
5655 // Note that the save and find-related commands aren't defined by
5656 // default. User code or addons can define them. Unknown commands
5657 // are simply ignored.
5658 keyMap.pcDefault = {
5659 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
5660 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
5661 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
5662 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
5663 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
5664 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
5665 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
5666 fallthrough: "basic"
5667 };
5668 // Very basic readline/emacs-style bindings, which are standard on Mac.
5669 keyMap.emacsy = {
5670 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
5671 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
5672 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
5673 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
5674 };
5675 keyMap.macDefault = {
5676 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
5677 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
5678 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
5679 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
5680 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
5681 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
5682 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
5683 fallthrough: ["basic", "emacsy"]
5684 };
5685 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
5686
5687 // KEYMAP DISPATCH
5688
5689 function normalizeKeyName(name) {
5690 var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
5691 var alt, ctrl, shift, cmd;
5692 for (var i = 0; i < parts.length - 1; i++) {
5693 var mod = parts[i];
5694 if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
5695 else if (/^a(lt)?$/i.test(mod)) alt = true;
5696 else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
5697 else if (/^s(hift)$/i.test(mod)) shift = true;
5698 else throw new Error("Unrecognized modifier name: " + mod);
5699 }
5700 if (alt) name = "Alt-" + name;
5701 if (ctrl) name = "Ctrl-" + name;
5702 if (cmd) name = "Cmd-" + name;
5703 if (shift) name = "Shift-" + name;
5704 return name;
5705 }
5706
5707 // This is a kludge to keep keymaps mostly working as raw objects
5708 // (backwards compatibility) while at the same time support features
5709 // like normalization and multi-stroke key bindings. It compiles a
5710 // new normalized keymap, and then updates the old object to reflect
5711 // this.
5712 CodeMirror.normalizeKeyMap = function(keymap) {
5713 var copy = {};
5714 for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
5715 var value = keymap[keyname];
5716 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
5717 if (value == "...") { delete keymap[keyname]; continue; }
5718
5719 var keys = map(keyname.split(" "), normalizeKeyName);
5720 for (var i = 0; i < keys.length; i++) {
5721 var val, name;
5722 if (i == keys.length - 1) {
5723 name = keyname;
5724 val = value;
5725 } else {
5726 name = keys.slice(0, i + 1).join(" ");
5727 val = "...";
5728 }
5729 var prev = copy[name];
5730 if (!prev) copy[name] = val;
5731 else if (prev != val) throw new Error("Inconsistent bindings for " + name);
5732 }
5733 delete keymap[keyname];
5734 }
5735 for (var prop in copy) keymap[prop] = copy[prop];
5736 return keymap;
5737 };
5738
5739 var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
5740 map = getKeyMap(map);
5741 var found = map.call ? map.call(key, context) : map[key];
5742 if (found === false) return "nothing";
5743 if (found === "...") return "multi";
5744 if (found != null && handle(found)) return "handled";
5745
5746 if (map.fallthrough) {
5747 if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
5748 return lookupKey(key, map.fallthrough, handle, context);
5749 for (var i = 0; i < map.fallthrough.length; i++) {
5750 var result = lookupKey(key, map.fallthrough[i], handle, context);
5751 if (result) return result;
5752 }
5753 }
5754 };
5755
5756 // Modifier key presses don't count as 'real' key presses for the
5757 // purpose of keymap fallthrough.
5758 var isModifierKey = CodeMirror.isModifierKey = function(value) {
5759 var name = typeof value == "string" ? value : keyNames[value.keyCode];
5760 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
5761 };
5762
5763 // Look up the name of a key as indicated by an event object.
5764 var keyName = CodeMirror.keyName = function(event, noShift) {
5765 if (presto && event.keyCode == 34 && event["char"]) return false;
5766 var base = keyNames[event.keyCode], name = base;
5767 if (name == null || event.altGraphKey) return false;
5768 if (event.altKey && base != "Alt") name = "Alt-" + name;
5769 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
5770 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
5771 if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
5772 return name;
5773 };
5774
5775 function getKeyMap(val) {
5776 return typeof val == "string" ? keyMap[val] : val;
5777 }
5778
5779 // FROMTEXTAREA
5780
5781 CodeMirror.fromTextArea = function(textarea, options) {
5782 options = options ? copyObj(options) : {};
5783 options.value = textarea.value;
5784 if (!options.tabindex && textarea.tabIndex)
5785 options.tabindex = textarea.tabIndex;
5786 if (!options.placeholder && textarea.placeholder)
5787 options.placeholder = textarea.placeholder;
5788 // Set autofocus to true if this textarea is focused, or if it has
5789 // autofocus and no other element is focused.
5790 if (options.autofocus == null) {
5791 var hasFocus = activeElt();
5792 options.autofocus = hasFocus == textarea ||
5793 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
5794 }
5795
5796 function save() {textarea.value = cm.getValue();}
5797 if (textarea.form) {
5798 on(textarea.form, "submit", save);
5799 // Deplorable hack to make the submit method do the right thing.
5800 if (!options.leaveSubmitMethodAlone) {
5801 var form = textarea.form, realSubmit = form.submit;
5802 try {
5803 var wrappedSubmit = form.submit = function() {
5804 save();
5805 form.submit = realSubmit;
5806 form.submit();
5807 form.submit = wrappedSubmit;
5808 };
5809 } catch(e) {}
5810 }
5811 }
5812
5813 options.finishInit = function(cm) {
5814 cm.save = save;
5815 cm.getTextArea = function() { return textarea; };
5816 cm.toTextArea = function() {
5817 cm.toTextArea = isNaN; // Prevent this from being ran twice
5818 save();
5819 textarea.parentNode.removeChild(cm.getWrapperElement());
5820 textarea.style.display = "";
5821 if (textarea.form) {
5822 off(textarea.form, "submit", save);
5823 if (typeof textarea.form.submit == "function")
5824 textarea.form.submit = realSubmit;
5825 }
5826 };
5827 };
5828
5829 textarea.style.display = "none";
5830 var cm = CodeMirror(function(node) {
5831 textarea.parentNode.insertBefore(node, textarea.nextSibling);
5832 }, options);
5833 return cm;
5834 };
5835
5836 // STRING STREAM
5837
5838 // Fed to the mode parsers, provides helper functions to make
5839 // parsers more succinct.
5840
5841 var StringStream = CodeMirror.StringStream = function(string, tabSize) {
5842 this.pos = this.start = 0;
5843 this.string = string;
5844 this.tabSize = tabSize || 8;
5845 this.lastColumnPos = this.lastColumnValue = 0;
5846 this.lineStart = 0;
5847 };
5848
5849 StringStream.prototype = {
5850 eol: function() {return this.pos >= this.string.length;},
5851 sol: function() {return this.pos == this.lineStart;},
5852 peek: function() {return this.string.charAt(this.pos) || undefined;},
5853 next: function() {
5854 if (this.pos < this.string.length)
5855 return this.string.charAt(this.pos++);
5856 },
5857 eat: function(match) {
5858 var ch = this.string.charAt(this.pos);
5859 if (typeof match == "string") var ok = ch == match;
5860 else var ok = ch && (match.test ? match.test(ch) : match(ch));
5861 if (ok) {++this.pos; return ch;}
5862 },
5863 eatWhile: function(match) {
5864 var start = this.pos;
5865 while (this.eat(match)){}
5866 return this.pos > start;
5867 },
5868 eatSpace: function() {
5869 var start = this.pos;
5870 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
5871 return this.pos > start;
5872 },
5873 skipToEnd: function() {this.pos = this.string.length;},
5874 skipTo: function(ch) {
5875 var found = this.string.indexOf(ch, this.pos);
5876 if (found > -1) {this.pos = found; return true;}
5877 },
5878 backUp: function(n) {this.pos -= n;},
5879 column: function() {
5880 if (this.lastColumnPos < this.start) {
5881 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
5882 this.lastColumnPos = this.start;
5883 }
5884 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
5885 },
5886 indentation: function() {
5887 return countColumn(this.string, null, this.tabSize) -
5888 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
5889 },
5890 match: function(pattern, consume, caseInsensitive) {
5891 if (typeof pattern == "string") {
5892 var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
5893 var substr = this.string.substr(this.pos, pattern.length);
5894 if (cased(substr) == cased(pattern)) {
5895 if (consume !== false) this.pos += pattern.length;
5896 return true;
5897 }
5898 } else {
5899 var match = this.string.slice(this.pos).match(pattern);
5900 if (match && match.index > 0) return null;
5901 if (match && consume !== false) this.pos += match[0].length;
5902 return match;
5903 }
5904 },
5905 current: function(){return this.string.slice(this.start, this.pos);},
5906 hideFirstChars: function(n, inner) {
5907 this.lineStart += n;
5908 try { return inner(); }
5909 finally { this.lineStart -= n; }
5910 }
5911 };
5912
5913 // TEXTMARKERS
5914
5915 // Created with markText and setBookmark methods. A TextMarker is a
5916 // handle that can be used to clear or find a marked position in the
5917 // document. Line objects hold arrays (markedSpans) containing
5918 // {from, to, marker} object pointing to such marker objects, and
5919 // indicating that such a marker is present on that line. Multiple
5920 // lines may point to the same marker when it spans across lines.
5921 // The spans will have null for their from/to properties when the
5922 // marker continues beyond the start/end of the line. Markers have
5923 // links back to the lines they currently touch.
5924
5925 var nextMarkerId = 0;
5926
5927 var TextMarker = CodeMirror.TextMarker = function(doc, type) {
5928 this.lines = [];
5929 this.type = type;
5930 this.doc = doc;
5931 this.id = ++nextMarkerId;
5932 };
5933 eventMixin(TextMarker);
5934
5935 // Clear the marker.
5936 TextMarker.prototype.clear = function() {
5937 if (this.explicitlyCleared) return;
5938 var cm = this.doc.cm, withOp = cm && !cm.curOp;
5939 if (withOp) startOperation(cm);
5940 if (hasHandler(this, "clear")) {
5941 var found = this.find();
5942 if (found) signalLater(this, "clear", found.from, found.to);
5943 }
5944 var min = null, max = null;
5945 for (var i = 0; i < this.lines.length; ++i) {
5946 var line = this.lines[i];
5947 var span = getMarkedSpanFor(line.markedSpans, this);
5948 if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
5949 else if (cm) {
5950 if (span.to != null) max = lineNo(line);
5951 if (span.from != null) min = lineNo(line);
5952 }
5953 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
5954 if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
5955 updateLineHeight(line, textHeight(cm.display));
5956 }
5957 if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
5958 var visual = visualLine(this.lines[i]), len = lineLength(visual);
5959 if (len > cm.display.maxLineLength) {
5960 cm.display.maxLine = visual;
5961 cm.display.maxLineLength = len;
5962 cm.display.maxLineChanged = true;
5963 }
5964 }
5965
5966 if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
5967 this.lines.length = 0;
5968 this.explicitlyCleared = true;
5969 if (this.atomic && this.doc.cantEdit) {
5970 this.doc.cantEdit = false;
5971 if (cm) reCheckSelection(cm.doc);
5972 }
5973 if (cm) signalLater(cm, "markerCleared", cm, this);
5974 if (withOp) endOperation(cm);
5975 if (this.parent) this.parent.clear();
5976 };
5977
5978 // Find the position of the marker in the document. Returns a {from,
5979 // to} object by default. Side can be passed to get a specific side
5980 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
5981 // Pos objects returned contain a line object, rather than a line
5982 // number (used to prevent looking up the same line twice).
5983 TextMarker.prototype.find = function(side, lineObj) {
5984 if (side == null && this.type == "bookmark") side = 1;
5985 var from, to;
5986 for (var i = 0; i < this.lines.length; ++i) {
5987 var line = this.lines[i];
5988 var span = getMarkedSpanFor(line.markedSpans, this);
5989 if (span.from != null) {
5990 from = Pos(lineObj ? line : lineNo(line), span.from);
5991 if (side == -1) return from;
5992 }
5993 if (span.to != null) {
5994 to = Pos(lineObj ? line : lineNo(line), span.to);
5995 if (side == 1) return to;
5996 }
5997 }
5998 return from && {from: from, to: to};
5999 };
6000
6001 // Signals that the marker's widget changed, and surrounding layout
6002 // should be recomputed.
6003 TextMarker.prototype.changed = function() {
6004 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
6005 if (!pos || !cm) return;
6006 runInOp(cm, function() {
6007 var line = pos.line, lineN = lineNo(pos.line);
6008 var view = findViewForLine(cm, lineN);
6009 if (view) {
6010 clearLineMeasurementCacheFor(view);
6011 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
6012 }
6013 cm.curOp.updateMaxLine = true;
6014 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
6015 var oldHeight = widget.height;
6016 widget.height = null;
6017 var dHeight = widgetHeight(widget) - oldHeight;
6018 if (dHeight)
6019 updateLineHeight(line, line.height + dHeight);
6020 }
6021 });
6022 };
6023
6024 TextMarker.prototype.attachLine = function(line) {
6025 if (!this.lines.length && this.doc.cm) {
6026 var op = this.doc.cm.curOp;
6027 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
6028 (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
6029 }
6030 this.lines.push(line);
6031 };
6032 TextMarker.prototype.detachLine = function(line) {
6033 this.lines.splice(indexOf(this.lines, line), 1);
6034 if (!this.lines.length && this.doc.cm) {
6035 var op = this.doc.cm.curOp;
6036 (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
6037 }
6038 };
6039
6040 // Collapsed markers have unique ids, in order to be able to order
6041 // them, which is needed for uniquely determining an outer marker
6042 // when they overlap (they may nest, but not partially overlap).
6043 var nextMarkerId = 0;
6044
6045 // Create a marker, wire it up to the right lines, and
6046 function markText(doc, from, to, options, type) {
6047 // Shared markers (across linked documents) are handled separately
6048 // (markTextShared will call out to this again, once per
6049 // document).
6050 if (options && options.shared) return markTextShared(doc, from, to, options, type);
6051 // Ensure we are in an operation.
6052 if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
6053
6054 var marker = new TextMarker(doc, type), diff = cmp(from, to);
6055 if (options) copyObj(options, marker, false);
6056 // Don't connect empty markers unless clearWhenEmpty is false
6057 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
6058 return marker;
6059 if (marker.replacedWith) {
6060 // Showing up as a widget implies collapsed (widget replaces text)
6061 marker.collapsed = true;
6062 marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
6063 if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
6064 if (options.insertLeft) marker.widgetNode.insertLeft = true;
6065 }
6066 if (marker.collapsed) {
6067 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
6068 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
6069 throw new Error("Inserting collapsed marker partially overlapping an existing one");
6070 sawCollapsedSpans = true;
6071 }
6072
6073 if (marker.addToHistory)
6074 addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
6075
6076 var curLine = from.line, cm = doc.cm, updateMaxLine;
6077 doc.iter(curLine, to.line + 1, function(line) {
6078 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
6079 updateMaxLine = true;
6080 if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
6081 addMarkedSpan(line, new MarkedSpan(marker,
6082 curLine == from.line ? from.ch : null,
6083 curLine == to.line ? to.ch : null));
6084 ++curLine;
6085 });
6086 // lineIsHidden depends on the presence of the spans, so needs a second pass
6087 if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
6088 if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
6089 });
6090
6091 if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
6092
6093 if (marker.readOnly) {
6094 sawReadOnlySpans = true;
6095 if (doc.history.done.length || doc.history.undone.length)
6096 doc.clearHistory();
6097 }
6098 if (marker.collapsed) {
6099 marker.id = ++nextMarkerId;
6100 marker.atomic = true;
6101 }
6102 if (cm) {
6103 // Sync editor state
6104 if (updateMaxLine) cm.curOp.updateMaxLine = true;
6105 if (marker.collapsed)
6106 regChange(cm, from.line, to.line + 1);
6107 else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
6108 for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
6109 if (marker.atomic) reCheckSelection(cm.doc);
6110 signalLater(cm, "markerAdded", cm, marker);
6111 }
6112 return marker;
6113 }
6114
6115 // SHARED TEXTMARKERS
6116
6117 // A shared marker spans multiple linked documents. It is
6118 // implemented as a meta-marker-object controlling multiple normal
6119 // markers.
6120 var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
6121 this.markers = markers;
6122 this.primary = primary;
6123 for (var i = 0; i < markers.length; ++i)
6124 markers[i].parent = this;
6125 };
6126 eventMixin(SharedTextMarker);
6127
6128 SharedTextMarker.prototype.clear = function() {
6129 if (this.explicitlyCleared) return;
6130 this.explicitlyCleared = true;
6131 for (var i = 0; i < this.markers.length; ++i)
6132 this.markers[i].clear();
6133 signalLater(this, "clear");
6134 };
6135 SharedTextMarker.prototype.find = function(side, lineObj) {
6136 return this.primary.find(side, lineObj);
6137 };
6138
6139 function markTextShared(doc, from, to, options, type) {
6140 options = copyObj(options);
6141 options.shared = false;
6142 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
6143 var widget = options.widgetNode;
6144 linkedDocs(doc, function(doc) {
6145 if (widget) options.widgetNode = widget.cloneNode(true);
6146 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
6147 for (var i = 0; i < doc.linked.length; ++i)
6148 if (doc.linked[i].isParent) return;
6149 primary = lst(markers);
6150 });
6151 return new SharedTextMarker(markers, primary);
6152 }
6153
6154 function findSharedMarkers(doc) {
6155 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
6156 function(m) { return m.parent; });
6157 }
6158
6159 function copySharedMarkers(doc, markers) {
6160 for (var i = 0; i < markers.length; i++) {
6161 var marker = markers[i], pos = marker.find();
6162 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
6163 if (cmp(mFrom, mTo)) {
6164 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
6165 marker.markers.push(subMark);
6166 subMark.parent = marker;
6167 }
6168 }
6169 }
6170
6171 function detachSharedMarkers(markers) {
6172 for (var i = 0; i < markers.length; i++) {
6173 var marker = markers[i], linked = [marker.primary.doc];;
6174 linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
6175 for (var j = 0; j < marker.markers.length; j++) {
6176 var subMarker = marker.markers[j];
6177 if (indexOf(linked, subMarker.doc) == -1) {
6178 subMarker.parent = null;
6179 marker.markers.splice(j--, 1);
6180 }
6181 }
6182 }
6183 }
6184
6185 // TEXTMARKER SPANS
6186
6187 function MarkedSpan(marker, from, to) {
6188 this.marker = marker;
6189 this.from = from; this.to = to;
6190 }
6191
6192 // Search an array of spans for a span matching the given marker.
6193 function getMarkedSpanFor(spans, marker) {
6194 if (spans) for (var i = 0; i < spans.length; ++i) {
6195 var span = spans[i];
6196 if (span.marker == marker) return span;
6197 }
6198 }
6199 // Remove a span from an array, returning undefined if no spans are
6200 // left (we don't store arrays for lines without spans).
6201 function removeMarkedSpan(spans, span) {
6202 for (var r, i = 0; i < spans.length; ++i)
6203 if (spans[i] != span) (r || (r = [])).push(spans[i]);
6204 return r;
6205 }
6206 // Add a span to a line.
6207 function addMarkedSpan(line, span) {
6208 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
6209 span.marker.attachLine(line);
6210 }
6211
6212 // Used for the algorithm that adjusts markers for a change in the
6213 // document. These functions cut an array of spans at a given
6214 // character position, returning an array of remaining chunks (or
6215 // undefined if nothing remains).
6216 function markedSpansBefore(old, startCh, isInsert) {
6217 if (old) for (var i = 0, nw; i < old.length; ++i) {
6218 var span = old[i], marker = span.marker;
6219 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
6220 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
6221 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
6222 (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
6223 }
6224 }
6225 return nw;
6226 }
6227 function markedSpansAfter(old, endCh, isInsert) {
6228 if (old) for (var i = 0, nw; i < old.length; ++i) {
6229 var span = old[i], marker = span.marker;
6230 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
6231 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
6232 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
6233 (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
6234 span.to == null ? null : span.to - endCh));
6235 }
6236 }
6237 return nw;
6238 }
6239
6240 // Given a change object, compute the new set of marker spans that
6241 // cover the line in which the change took place. Removes spans
6242 // entirely within the change, reconnects spans belonging to the
6243 // same marker that appear on both sides of the change, and cuts off
6244 // spans partially within the change. Returns an array of span
6245 // arrays with one element for each line in (after) the change.
6246 function stretchSpansOverChange(doc, change) {
6247 if (change.full) return null;
6248 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
6249 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
6250 if (!oldFirst && !oldLast) return null;
6251
6252 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
6253 // Get the spans that 'stick out' on both sides
6254 var first = markedSpansBefore(oldFirst, startCh, isInsert);
6255 var last = markedSpansAfter(oldLast, endCh, isInsert);
6256
6257 // Next, merge those two ends
6258 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
6259 if (first) {
6260 // Fix up .to properties of first
6261 for (var i = 0; i < first.length; ++i) {
6262 var span = first[i];
6263 if (span.to == null) {
6264 var found = getMarkedSpanFor(last, span.marker);
6265 if (!found) span.to = startCh;
6266 else if (sameLine) span.to = found.to == null ? null : found.to + offset;
6267 }
6268 }
6269 }
6270 if (last) {
6271 // Fix up .from in last (or move them into first in case of sameLine)
6272 for (var i = 0; i < last.length; ++i) {
6273 var span = last[i];
6274 if (span.to != null) span.to += offset;
6275 if (span.from == null) {
6276 var found = getMarkedSpanFor(first, span.marker);
6277 if (!found) {
6278 span.from = offset;
6279 if (sameLine) (first || (first = [])).push(span);
6280 }
6281 } else {
6282 span.from += offset;
6283 if (sameLine) (first || (first = [])).push(span);
6284 }
6285 }
6286 }
6287 // Make sure we didn't create any zero-length spans
6288 if (first) first = clearEmptySpans(first);
6289 if (last && last != first) last = clearEmptySpans(last);
6290
6291 var newMarkers = [first];
6292 if (!sameLine) {
6293 // Fill gap with whole-line-spans
6294 var gap = change.text.length - 2, gapMarkers;
6295 if (gap > 0 && first)
6296 for (var i = 0; i < first.length; ++i)
6297 if (first[i].to == null)
6298 (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
6299 for (var i = 0; i < gap; ++i)
6300 newMarkers.push(gapMarkers);
6301 newMarkers.push(last);
6302 }
6303 return newMarkers;
6304 }
6305
6306 // Remove spans that are empty and don't have a clearWhenEmpty
6307 // option of false.
6308 function clearEmptySpans(spans) {
6309 for (var i = 0; i < spans.length; ++i) {
6310 var span = spans[i];
6311 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
6312 spans.splice(i--, 1);
6313 }
6314 if (!spans.length) return null;
6315 return spans;
6316 }
6317
6318 // Used for un/re-doing changes from the history. Combines the
6319 // result of computing the existing spans with the set of spans that
6320 // existed in the history (so that deleting around a span and then
6321 // undoing brings back the span).
6322 function mergeOldSpans(doc, change) {
6323 var old = getOldSpans(doc, change);
6324 var stretched = stretchSpansOverChange(doc, change);
6325 if (!old) return stretched;
6326 if (!stretched) return old;
6327
6328 for (var i = 0; i < old.length; ++i) {
6329 var oldCur = old[i], stretchCur = stretched[i];
6330 if (oldCur && stretchCur) {
6331 spans: for (var j = 0; j < stretchCur.length; ++j) {
6332 var span = stretchCur[j];
6333 for (var k = 0; k < oldCur.length; ++k)
6334 if (oldCur[k].marker == span.marker) continue spans;
6335 oldCur.push(span);
6336 }
6337 } else if (stretchCur) {
6338 old[i] = stretchCur;
6339 }
6340 }
6341 return old;
6342 }
6343
6344 // Used to 'clip' out readOnly ranges when making a change.
6345 function removeReadOnlyRanges(doc, from, to) {
6346 var markers = null;
6347 doc.iter(from.line, to.line + 1, function(line) {
6348 if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
6349 var mark = line.markedSpans[i].marker;
6350 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
6351 (markers || (markers = [])).push(mark);
6352 }
6353 });
6354 if (!markers) return null;
6355 var parts = [{from: from, to: to}];
6356 for (var i = 0; i < markers.length; ++i) {
6357 var mk = markers[i], m = mk.find(0);
6358 for (var j = 0; j < parts.length; ++j) {
6359 var p = parts[j];
6360 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
6361 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
6362 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
6363 newParts.push({from: p.from, to: m.from});
6364 if (dto > 0 || !mk.inclusiveRight && !dto)
6365 newParts.push({from: m.to, to: p.to});
6366 parts.splice.apply(parts, newParts);
6367 j += newParts.length - 1;
6368 }
6369 }
6370 return parts;
6371 }
6372
6373 // Connect or disconnect spans from a line.
6374 function detachMarkedSpans(line) {
6375 var spans = line.markedSpans;
6376 if (!spans) return;
6377 for (var i = 0; i < spans.length; ++i)
6378 spans[i].marker.detachLine(line);
6379 line.markedSpans = null;
6380 }
6381 function attachMarkedSpans(line, spans) {
6382 if (!spans) return;
6383 for (var i = 0; i < spans.length; ++i)
6384 spans[i].marker.attachLine(line);
6385 line.markedSpans = spans;
6386 }
6387
6388 // Helpers used when computing which overlapping collapsed span
6389 // counts as the larger one.
6390 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
6391 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
6392
6393 // Returns a number indicating which of two overlapping collapsed
6394 // spans is larger (and thus includes the other). Falls back to
6395 // comparing ids when the spans cover exactly the same range.
6396 function compareCollapsedMarkers(a, b) {
6397 var lenDiff = a.lines.length - b.lines.length;
6398 if (lenDiff != 0) return lenDiff;
6399 var aPos = a.find(), bPos = b.find();
6400 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
6401 if (fromCmp) return -fromCmp;
6402 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
6403 if (toCmp) return toCmp;
6404 return b.id - a.id;
6405 }
6406
6407 // Find out whether a line ends or starts in a collapsed span. If
6408 // so, return the marker for that span.
6409 function collapsedSpanAtSide(line, start) {
6410 var sps = sawCollapsedSpans && line.markedSpans, found;
6411 if (sps) for (var sp, i = 0; i < sps.length; ++i) {
6412 sp = sps[i];
6413 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
6414 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
6415 found = sp.marker;
6416 }
6417 return found;
6418 }
6419 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
6420 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
6421
6422 // Test whether there exists a collapsed span that partially
6423 // overlaps (covers the start or end, but not both) of a new span.
6424 // Such overlap is not allowed.
6425 function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
6426 var line = getLine(doc, lineNo);
6427 var sps = sawCollapsedSpans && line.markedSpans;
6428 if (sps) for (var i = 0; i < sps.length; ++i) {
6429 var sp = sps[i];
6430 if (!sp.marker.collapsed) continue;
6431 var found = sp.marker.find(0);
6432 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
6433 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
6434 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
6435 if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
6436 fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
6437 return true;
6438 }
6439 }
6440
6441 // A visual line is a line as drawn on the screen. Folding, for
6442 // example, can cause multiple logical lines to appear on the same
6443 // visual line. This finds the start of the visual line that the
6444 // given line is part of (usually that is the line itself).
6445 function visualLine(line) {
6446 var merged;
6447 while (merged = collapsedSpanAtStart(line))
6448 line = merged.find(-1, true).line;
6449 return line;
6450 }
6451
6452 // Returns an array of logical lines that continue the visual line
6453 // started by the argument, or undefined if there are no such lines.
6454 function visualLineContinued(line) {
6455 var merged, lines;
6456 while (merged = collapsedSpanAtEnd(line)) {
6457 line = merged.find(1, true).line;
6458 (lines || (lines = [])).push(line);
6459 }
6460 return lines;
6461 }
6462
6463 // Get the line number of the start of the visual line that the
6464 // given line number is part of.
6465 function visualLineNo(doc, lineN) {
6466 var line = getLine(doc, lineN), vis = visualLine(line);
6467 if (line == vis) return lineN;
6468 return lineNo(vis);
6469 }
6470 // Get the line number of the start of the next visual line after
6471 // the given line.
6472 function visualLineEndNo(doc, lineN) {
6473 if (lineN > doc.lastLine()) return lineN;
6474 var line = getLine(doc, lineN), merged;
6475 if (!lineIsHidden(doc, line)) return lineN;
6476 while (merged = collapsedSpanAtEnd(line))
6477 line = merged.find(1, true).line;
6478 return lineNo(line) + 1;
6479 }
6480
6481 // Compute whether a line is hidden. Lines count as hidden when they
6482 // are part of a visual line that starts with another line, or when
6483 // they are entirely covered by collapsed, non-widget span.
6484 function lineIsHidden(doc, line) {
6485 var sps = sawCollapsedSpans && line.markedSpans;
6486 if (sps) for (var sp, i = 0; i < sps.length; ++i) {
6487 sp = sps[i];
6488 if (!sp.marker.collapsed) continue;
6489 if (sp.from == null) return true;
6490 if (sp.marker.widgetNode) continue;
6491 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
6492 return true;
6493 }
6494 }
6495 function lineIsHiddenInner(doc, line, span) {
6496 if (span.to == null) {
6497 var end = span.marker.find(1, true);
6498 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
6499 }
6500 if (span.marker.inclusiveRight && span.to == line.text.length)
6501 return true;
6502 for (var sp, i = 0; i < line.markedSpans.length; ++i) {
6503 sp = line.markedSpans[i];
6504 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
6505 (sp.to == null || sp.to != span.from) &&
6506 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
6507 lineIsHiddenInner(doc, line, sp)) return true;
6508 }
6509 }
6510
6511 // LINE WIDGETS
6512
6513 // Line widgets are block elements displayed above or below a line.
6514
6515 var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
6516 if (options) for (var opt in options) if (options.hasOwnProperty(opt))
6517 this[opt] = options[opt];
6518 this.doc = doc;
6519 this.node = node;
6520 };
6521 eventMixin(LineWidget);
6522
6523 function adjustScrollWhenAboveVisible(cm, line, diff) {
6524 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
6525 addToScrollPos(cm, null, diff);
6526 }
6527
6528 LineWidget.prototype.clear = function() {
6529 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
6530 if (no == null || !ws) return;
6531 for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
6532 if (!ws.length) line.widgets = null;
6533 var height = widgetHeight(this);
6534 updateLineHeight(line, Math.max(0, line.height - height));
6535 if (cm) runInOp(cm, function() {
6536 adjustScrollWhenAboveVisible(cm, line, -height);
6537 regLineChange(cm, no, "widget");
6538 });
6539 };
6540 LineWidget.prototype.changed = function() {
6541 var oldH = this.height, cm = this.doc.cm, line = this.line;
6542 this.height = null;
6543 var diff = widgetHeight(this) - oldH;
6544 if (!diff) return;
6545 updateLineHeight(line, line.height + diff);
6546 if (cm) runInOp(cm, function() {
6547 cm.curOp.forceUpdate = true;
6548 adjustScrollWhenAboveVisible(cm, line, diff);
6549 });
6550 };
6551
6552 function widgetHeight(widget) {
6553 if (widget.height != null) return widget.height;
6554 var cm = widget.doc.cm;
6555 if (!cm) return 0;
6556 if (!contains(document.body, widget.node)) {
6557 var parentStyle = "position: relative;";
6558 if (widget.coverGutter)
6559 parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
6560 if (widget.noHScroll)
6561 parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
6562 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
6563 }
6564 return widget.height = widget.node.offsetHeight;
6565 }
6566
6567 function addLineWidget(doc, handle, node, options) {
6568 var widget = new LineWidget(doc, node, options);
6569 var cm = doc.cm;
6570 if (cm && widget.noHScroll) cm.display.alignWidgets = true;
6571 changeLine(doc, handle, "widget", function(line) {
6572 var widgets = line.widgets || (line.widgets = []);
6573 if (widget.insertAt == null) widgets.push(widget);
6574 else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
6575 widget.line = line;
6576 if (cm && !lineIsHidden(doc, line)) {
6577 var aboveVisible = heightAtLine(line) < doc.scrollTop;
6578 updateLineHeight(line, line.height + widgetHeight(widget));
6579 if (aboveVisible) addToScrollPos(cm, null, widget.height);
6580 cm.curOp.forceUpdate = true;
6581 }
6582 return true;
6583 });
6584 return widget;
6585 }
6586
6587 // LINE DATA STRUCTURE
6588
6589 // Line objects. These hold state related to a line, including
6590 // highlighting info (the styles array).
6591 var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
6592 this.text = text;
6593 attachMarkedSpans(this, markedSpans);
6594 this.height = estimateHeight ? estimateHeight(this) : 1;
6595 };
6596 eventMixin(Line);
6597 Line.prototype.lineNo = function() { return lineNo(this); };
6598
6599 // Change the content (text, markers) of a line. Automatically
6600 // invalidates cached information and tries to re-estimate the
6601 // line's height.
6602 function updateLine(line, text, markedSpans, estimateHeight) {
6603 line.text = text;
6604 if (line.stateAfter) line.stateAfter = null;
6605 if (line.styles) line.styles = null;
6606 if (line.order != null) line.order = null;
6607 detachMarkedSpans(line);
6608 attachMarkedSpans(line, markedSpans);
6609 var estHeight = estimateHeight ? estimateHeight(line) : 1;
6610 if (estHeight != line.height) updateLineHeight(line, estHeight);
6611 }
6612
6613 // Detach a line from the document tree and its markers.
6614 function cleanUpLine(line) {
6615 line.parent = null;
6616 detachMarkedSpans(line);
6617 }
6618
6619 function extractLineClasses(type, output) {
6620 if (type) for (;;) {
6621 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
6622 if (!lineClass) break;
6623 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
6624 var prop = lineClass[1] ? "bgClass" : "textClass";
6625 if (output[prop] == null)
6626 output[prop] = lineClass[2];
6627 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
6628 output[prop] += " " + lineClass[2];
6629 }
6630 return type;
6631 }
6632
6633 function callBlankLine(mode, state) {
6634 if (mode.blankLine) return mode.blankLine(state);
6635 if (!mode.innerMode) return;
6636 var inner = CodeMirror.innerMode(mode, state);
6637 if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
6638 }
6639
6640 function readToken(mode, stream, state, inner) {
6641 for (var i = 0; i < 10; i++) {
6642 if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
6643 var style = mode.token(stream, state);
6644 if (stream.pos > stream.start) return style;
6645 }
6646 throw new Error("Mode " + mode.name + " failed to advance stream.");
6647 }
6648
6649 // Utility for getTokenAt and getLineTokens
6650 function takeToken(cm, pos, precise, asArray) {
6651 function getObj(copy) {
6652 return {start: stream.start, end: stream.pos,
6653 string: stream.current(),
6654 type: style || null,
6655 state: copy ? copyState(doc.mode, state) : state};
6656 }
6657
6658 var doc = cm.doc, mode = doc.mode, style;
6659 pos = clipPos(doc, pos);
6660 var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
6661 var stream = new StringStream(line.text, cm.options.tabSize), tokens;
6662 if (asArray) tokens = [];
6663 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
6664 stream.start = stream.pos;
6665 style = readToken(mode, stream, state);
6666 if (asArray) tokens.push(getObj(true));
6667 }
6668 return asArray ? tokens : getObj();
6669 }
6670
6671 // Run the given mode's parser over a line, calling f for each token.
6672 function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
6673 var flattenSpans = mode.flattenSpans;
6674 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
6675 var curStart = 0, curStyle = null;
6676 var stream = new StringStream(text, cm.options.tabSize), style;
6677 var inner = cm.options.addModeClass && [null];
6678 if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
6679 while (!stream.eol()) {
6680 if (stream.pos > cm.options.maxHighlightLength) {
6681 flattenSpans = false;
6682 if (forceToEnd) processLine(cm, text, state, stream.pos);
6683 stream.pos = text.length;
6684 style = null;
6685 } else {
6686 style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
6687 }
6688 if (inner) {
6689 var mName = inner[0].name;
6690 if (mName) style = "m-" + (style ? mName + " " + style : mName);
6691 }
6692 if (!flattenSpans || curStyle != style) {
6693 while (curStart < stream.start) {
6694 curStart = Math.min(stream.start, curStart + 50000);
6695 f(curStart, curStyle);
6696 }
6697 curStyle = style;
6698 }
6699 stream.start = stream.pos;
6700 }
6701 while (curStart < stream.pos) {
6702 // Webkit seems to refuse to render text nodes longer than 57444 characters
6703 var pos = Math.min(stream.pos, curStart + 50000);
6704 f(pos, curStyle);
6705 curStart = pos;
6706 }
6707 }
6708
6709 // Compute a style array (an array starting with a mode generation
6710 // -- for invalidation -- followed by pairs of end positions and
6711 // style strings), which is used to highlight the tokens on the
6712 // line.
6713 function highlightLine(cm, line, state, forceToEnd) {
6714 // A styles array always starts with a number identifying the
6715 // mode/overlays that it is based on (for easy invalidation).
6716 var st = [cm.state.modeGen], lineClasses = {};
6717 // Compute the base array of styles
6718 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
6719 st.push(end, style);
6720 }, lineClasses, forceToEnd);
6721
6722 // Run overlays, adjust style array.
6723 for (var o = 0; o < cm.state.overlays.length; ++o) {
6724 var overlay = cm.state.overlays[o], i = 1, at = 0;
6725 runMode(cm, line.text, overlay.mode, true, function(end, style) {
6726 var start = i;
6727 // Ensure there's a token end at the current position, and that i points at it
6728 while (at < end) {
6729 var i_end = st[i];
6730 if (i_end > end)
6731 st.splice(i, 1, end, st[i+1], i_end);
6732 i += 2;
6733 at = Math.min(end, i_end);
6734 }
6735 if (!style) return;
6736 if (overlay.opaque) {
6737 st.splice(start, i - start, end, "cm-overlay " + style);
6738 i = start + 2;
6739 } else {
6740 for (; start < i; start += 2) {
6741 var cur = st[start+1];
6742 st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
6743 }
6744 }
6745 }, lineClasses);
6746 }
6747
6748 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
6749 }
6750
6751 function getLineStyles(cm, line, updateFrontier) {
6752 if (!line.styles || line.styles[0] != cm.state.modeGen) {
6753 var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
6754 line.styles = result.styles;
6755 if (result.classes) line.styleClasses = result.classes;
6756 else if (line.styleClasses) line.styleClasses = null;
6757 if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
6758 }
6759 return line.styles;
6760 }
6761
6762 // Lightweight form of highlight -- proceed over this line and
6763 // update state, but don't save a style array. Used for lines that
6764 // aren't currently visible.
6765 function processLine(cm, text, state, startAt) {
6766 var mode = cm.doc.mode;
6767 var stream = new StringStream(text, cm.options.tabSize);
6768 stream.start = stream.pos = startAt || 0;
6769 if (text == "") callBlankLine(mode, state);
6770 while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
6771 readToken(mode, stream, state);
6772 stream.start = stream.pos;
6773 }
6774 }
6775
6776 // Convert a style as returned by a mode (either null, or a string
6777 // containing one or more styles) to a CSS style. This is cached,
6778 // and also looks for line-wide styles.
6779 var styleToClassCache = {}, styleToClassCacheWithMode = {};
6780 function interpretTokenStyle(style, options) {
6781 if (!style || /^\s*$/.test(style)) return null;
6782 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
6783 return cache[style] ||
6784 (cache[style] = style.replace(/\S+/g, "cm-$&"));
6785 }
6786
6787 // Render the DOM representation of the text of a line. Also builds
6788 // up a 'line map', which points at the DOM nodes that represent
6789 // specific stretches of text, and is used by the measuring code.
6790 // The returned object contains the DOM node, this map, and
6791 // information about line-wide styles that were set by the mode.
6792 function buildLineContent(cm, lineView) {
6793 // The padding-right forces the element to have a 'border', which
6794 // is needed on Webkit to be able to get line-level bounding
6795 // rectangles for it (in measureChar).
6796 var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
6797 var builder = {pre: elt("pre", [content]), content: content,
6798 col: 0, pos: 0, cm: cm,
6799 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
6800 lineView.measure = {};
6801
6802 // Iterate over the logical lines that make up this visual line.
6803 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
6804 var line = i ? lineView.rest[i - 1] : lineView.line, order;
6805 builder.pos = 0;
6806 builder.addToken = buildToken;
6807 // Optionally wire in some hacks into the token-rendering
6808 // algorithm, to deal with browser quirks.
6809 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
6810 builder.addToken = buildTokenBadBidi(builder.addToken, order);
6811 builder.map = [];
6812 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
6813 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
6814 if (line.styleClasses) {
6815 if (line.styleClasses.bgClass)
6816 builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
6817 if (line.styleClasses.textClass)
6818 builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
6819 }
6820
6821 // Ensure at least a single node is present, for measuring.
6822 if (builder.map.length == 0)
6823 builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
6824
6825 // Store the map and a cache object for the current logical line
6826 if (i == 0) {
6827 lineView.measure.map = builder.map;
6828 lineView.measure.cache = {};
6829 } else {
6830 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
6831 (lineView.measure.caches || (lineView.measure.caches = [])).push({});
6832 }
6833 }
6834
6835 // See issue #2901
6836 if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
6837 builder.content.className = "cm-tab-wrap-hack";
6838
6839 signal(cm, "renderLine", cm, lineView.line, builder.pre);
6840 if (builder.pre.className)
6841 builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
6842
6843 return builder;
6844 }
6845
6846 function defaultSpecialCharPlaceholder(ch) {
6847 var token = elt("span", "\u2022", "cm-invalidchar");
6848 token.title = "\\u" + ch.charCodeAt(0).toString(16);
6849 token.setAttribute("aria-label", token.title);
6850 return token;
6851 }
6852
6853 // Build up the DOM representation for a single token, and add it to
6854 // the line map. Takes care to render special characters separately.
6855 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
6856 if (!text) return;
6857 var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
6858 var special = builder.cm.state.specialChars, mustWrap = false;
6859 if (!special.test(text)) {
6860 builder.col += text.length;
6861 var content = document.createTextNode(displayText);
6862 builder.map.push(builder.pos, builder.pos + text.length, content);
6863 if (ie && ie_version < 9) mustWrap = true;
6864 builder.pos += text.length;
6865 } else {
6866 var content = document.createDocumentFragment(), pos = 0;
6867 while (true) {
6868 special.lastIndex = pos;
6869 var m = special.exec(text);
6870 var skipped = m ? m.index - pos : text.length - pos;
6871 if (skipped) {
6872 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
6873 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
6874 else content.appendChild(txt);
6875 builder.map.push(builder.pos, builder.pos + skipped, txt);
6876 builder.col += skipped;
6877 builder.pos += skipped;
6878 }
6879 if (!m) break;
6880 pos += skipped + 1;
6881 if (m[0] == "\t") {
6882 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
6883 var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
6884 txt.setAttribute("role", "presentation");
6885 txt.setAttribute("cm-text", "\t");
6886 builder.col += tabWidth;
6887 } else {
6888 var txt = builder.cm.options.specialCharPlaceholder(m[0]);
6889 txt.setAttribute("cm-text", m[0]);
6890 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
6891 else content.appendChild(txt);
6892 builder.col += 1;
6893 }
6894 builder.map.push(builder.pos, builder.pos + 1, txt);
6895 builder.pos++;
6896 }
6897 }
6898 if (style || startStyle || endStyle || mustWrap || css) {
6899 var fullStyle = style || "";
6900 if (startStyle) fullStyle += startStyle;
6901 if (endStyle) fullStyle += endStyle;
6902 var token = elt("span", [content], fullStyle, css);
6903 if (title) token.title = title;
6904 return builder.content.appendChild(token);
6905 }
6906 builder.content.appendChild(content);
6907 }
6908
6909 function splitSpaces(old) {
6910 var out = " ";
6911 for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
6912 out += " ";
6913 return out;
6914 }
6915
6916 // Work around nonsense dimensions being reported for stretches of
6917 // right-to-left text.
6918 function buildTokenBadBidi(inner, order) {
6919 return function(builder, text, style, startStyle, endStyle, title, css) {
6920 style = style ? style + " cm-force-border" : "cm-force-border";
6921 var start = builder.pos, end = start + text.length;
6922 for (;;) {
6923 // Find the part that overlaps with the start of this text
6924 for (var i = 0; i < order.length; i++) {
6925 var part = order[i];
6926 if (part.to > start && part.from <= start) break;
6927 }
6928 if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
6929 inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
6930 startStyle = null;
6931 text = text.slice(part.to - start);
6932 start = part.to;
6933 }
6934 };
6935 }
6936
6937 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
6938 var widget = !ignoreWidget && marker.widgetNode;
6939 if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
6940 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
6941 if (!widget)
6942 widget = builder.content.appendChild(document.createElement("span"));
6943 widget.setAttribute("cm-marker", marker.id);
6944 }
6945 if (widget) {
6946 builder.cm.display.input.setUneditable(widget);
6947 builder.content.appendChild(widget);
6948 }
6949 builder.pos += size;
6950 }
6951
6952 // Outputs a number of spans to make up a line, taking highlighting
6953 // and marked text into account.
6954 function insertLineContent(line, builder, styles) {
6955 var spans = line.markedSpans, allText = line.text, at = 0;
6956 if (!spans) {
6957 for (var i = 1; i < styles.length; i+=2)
6958 builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
6959 return;
6960 }
6961
6962 var len = allText.length, pos = 0, i = 1, text = "", style, css;
6963 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
6964 for (;;) {
6965 if (nextChange == pos) { // Update current marker set
6966 spanStyle = spanEndStyle = spanStartStyle = title = css = "";
6967 collapsed = null; nextChange = Infinity;
6968 var foundBookmarks = [];
6969 for (var j = 0; j < spans.length; ++j) {
6970 var sp = spans[j], m = sp.marker;
6971 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
6972 foundBookmarks.push(m);
6973 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
6974 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
6975 nextChange = sp.to;
6976 spanEndStyle = "";
6977 }
6978 if (m.className) spanStyle += " " + m.className;
6979 if (m.css) css = m.css;
6980 if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
6981 if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
6982 if (m.title && !title) title = m.title;
6983 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
6984 collapsed = sp;
6985 } else if (sp.from > pos && nextChange > sp.from) {
6986 nextChange = sp.from;
6987 }
6988 }
6989 if (collapsed && (collapsed.from || 0) == pos) {
6990 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
6991 collapsed.marker, collapsed.from == null);
6992 if (collapsed.to == null) return;
6993 if (collapsed.to == pos) collapsed = false;
6994 }
6995 if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
6996 buildCollapsedSpan(builder, 0, foundBookmarks[j]);
6997 }
6998 if (pos >= len) break;
6999
7000 var upto = Math.min(len, nextChange);
7001 while (true) {
7002 if (text) {
7003 var end = pos + text.length;
7004 if (!collapsed) {
7005 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
7006 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
7007 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
7008 }
7009 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
7010 pos = end;
7011 spanStartStyle = "";
7012 }
7013 text = allText.slice(at, at = styles[i++]);
7014 style = interpretTokenStyle(styles[i++], builder.cm.options);
7015 }
7016 }
7017 }
7018
7019 // DOCUMENT DATA STRUCTURE
7020
7021 // By default, updates that start and end at the beginning of a line
7022 // are treated specially, in order to make the association of line
7023 // widgets and marker elements with the text behave more intuitive.
7024 function isWholeLineUpdate(doc, change) {
7025 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
7026 (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
7027 }
7028
7029 // Perform a change on the document data structure.
7030 function updateDoc(doc, change, markedSpans, estimateHeight) {
7031 function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
7032 function update(line, text, spans) {
7033 updateLine(line, text, spans, estimateHeight);
7034 signalLater(line, "change", line, change);
7035 }
7036 function linesFor(start, end) {
7037 for (var i = start, result = []; i < end; ++i)
7038 result.push(new Line(text[i], spansFor(i), estimateHeight));
7039 return result;
7040 }
7041
7042 var from = change.from, to = change.to, text = change.text;
7043 var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
7044 var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
7045
7046 // Adjust the line structure
7047 if (change.full) {
7048 doc.insert(0, linesFor(0, text.length));
7049 doc.remove(text.length, doc.size - text.length);
7050 } else if (isWholeLineUpdate(doc, change)) {
7051 // This is a whole-line replace. Treated specially to make
7052 // sure line objects move the way they are supposed to.
7053 var added = linesFor(0, text.length - 1);
7054 update(lastLine, lastLine.text, lastSpans);
7055 if (nlines) doc.remove(from.line, nlines);
7056 if (added.length) doc.insert(from.line, added);
7057 } else if (firstLine == lastLine) {
7058 if (text.length == 1) {
7059 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
7060 } else {
7061 var added = linesFor(1, text.length - 1);
7062 added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
7063 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
7064 doc.insert(from.line + 1, added);
7065 }
7066 } else if (text.length == 1) {
7067 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
7068 doc.remove(from.line + 1, nlines);
7069 } else {
7070 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
7071 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
7072 var added = linesFor(1, text.length - 1);
7073 if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
7074 doc.insert(from.line + 1, added);
7075 }
7076
7077 signalLater(doc, "change", doc, change);
7078 }
7079
7080 // The document is represented as a BTree consisting of leaves, with
7081 // chunk of lines in them, and branches, with up to ten leaves or
7082 // other branch nodes below them. The top node is always a branch
7083 // node, and is the document object itself (meaning it has
7084 // additional methods and properties).
7085 //
7086 // All nodes have parent links. The tree is used both to go from
7087 // line numbers to line objects, and to go from objects to numbers.
7088 // It also indexes by height, and is used to convert between height
7089 // and line object, and to find the total height of the document.
7090 //
7091 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
7092
7093 function LeafChunk(lines) {
7094 this.lines = lines;
7095 this.parent = null;
7096 for (var i = 0, height = 0; i < lines.length; ++i) {
7097 lines[i].parent = this;
7098 height += lines[i].height;
7099 }
7100 this.height = height;
7101 }
7102
7103 LeafChunk.prototype = {
7104 chunkSize: function() { return this.lines.length; },
7105 // Remove the n lines at offset 'at'.
7106 removeInner: function(at, n) {
7107 for (var i = at, e = at + n; i < e; ++i) {
7108 var line = this.lines[i];
7109 this.height -= line.height;
7110 cleanUpLine(line);
7111 signalLater(line, "delete");
7112 }
7113 this.lines.splice(at, n);
7114 },
7115 // Helper used to collapse a small branch into a single leaf.
7116 collapse: function(lines) {
7117 lines.push.apply(lines, this.lines);
7118 },
7119 // Insert the given array of lines at offset 'at', count them as
7120 // having the given height.
7121 insertInner: function(at, lines, height) {
7122 this.height += height;
7123 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
7124 for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
7125 },
7126 // Used to iterate over a part of the tree.
7127 iterN: function(at, n, op) {
7128 for (var e = at + n; at < e; ++at)
7129 if (op(this.lines[at])) return true;
7130 }
7131 };
7132
7133 function BranchChunk(children) {
7134 this.children = children;
7135 var size = 0, height = 0;
7136 for (var i = 0; i < children.length; ++i) {
7137 var ch = children[i];
7138 size += ch.chunkSize(); height += ch.height;
7139 ch.parent = this;
7140 }
7141 this.size = size;
7142 this.height = height;
7143 this.parent = null;
7144 }
7145
7146 BranchChunk.prototype = {
7147 chunkSize: function() { return this.size; },
7148 removeInner: function(at, n) {
7149 this.size -= n;
7150 for (var i = 0; i < this.children.length; ++i) {
7151 var child = this.children[i], sz = child.chunkSize();
7152 if (at < sz) {
7153 var rm = Math.min(n, sz - at), oldHeight = child.height;
7154 child.removeInner(at, rm);
7155 this.height -= oldHeight - child.height;
7156 if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
7157 if ((n -= rm) == 0) break;
7158 at = 0;
7159 } else at -= sz;
7160 }
7161 // If the result is smaller than 25 lines, ensure that it is a
7162 // single leaf node.
7163 if (this.size - n < 25 &&
7164 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
7165 var lines = [];
7166 this.collapse(lines);
7167 this.children = [new LeafChunk(lines)];
7168 this.children[0].parent = this;
7169 }
7170 },
7171 collapse: function(lines) {
7172 for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
7173 },
7174 insertInner: function(at, lines, height) {
7175 this.size += lines.length;
7176 this.height += height;
7177 for (var i = 0; i < this.children.length; ++i) {
7178 var child = this.children[i], sz = child.chunkSize();
7179 if (at <= sz) {
7180 child.insertInner(at, lines, height);
7181 if (child.lines && child.lines.length > 50) {
7182 while (child.lines.length > 50) {
7183 var spilled = child.lines.splice(child.lines.length - 25, 25);
7184 var newleaf = new LeafChunk(spilled);
7185 child.height -= newleaf.height;
7186 this.children.splice(i + 1, 0, newleaf);
7187 newleaf.parent = this;
7188 }
7189 this.maybeSpill();
7190 }
7191 break;
7192 }
7193 at -= sz;
7194 }
7195 },
7196 // When a node has grown, check whether it should be split.
7197 maybeSpill: function() {
7198 if (this.children.length <= 10) return;
7199 var me = this;
7200 do {
7201 var spilled = me.children.splice(me.children.length - 5, 5);
7202 var sibling = new BranchChunk(spilled);
7203 if (!me.parent) { // Become the parent node
7204 var copy = new BranchChunk(me.children);
7205 copy.parent = me;
7206 me.children = [copy, sibling];
7207 me = copy;
7208 } else {
7209 me.size -= sibling.size;
7210 me.height -= sibling.height;
7211 var myIndex = indexOf(me.parent.children, me);
7212 me.parent.children.splice(myIndex + 1, 0, sibling);
7213 }
7214 sibling.parent = me.parent;
7215 } while (me.children.length > 10);
7216 me.parent.maybeSpill();
7217 },
7218 iterN: function(at, n, op) {
7219 for (var i = 0; i < this.children.length; ++i) {
7220 var child = this.children[i], sz = child.chunkSize();
7221 if (at < sz) {
7222 var used = Math.min(n, sz - at);
7223 if (child.iterN(at, used, op)) return true;
7224 if ((n -= used) == 0) break;
7225 at = 0;
7226 } else at -= sz;
7227 }
7228 }
7229 };
7230
7231 var nextDocId = 0;
7232 var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
7233 if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
7234 if (firstLine == null) firstLine = 0;
7235
7236 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
7237 this.first = firstLine;
7238 this.scrollTop = this.scrollLeft = 0;
7239 this.cantEdit = false;
7240 this.cleanGeneration = 1;
7241 this.frontier = firstLine;
7242 var start = Pos(firstLine, 0);
7243 this.sel = simpleSelection(start);
7244 this.history = new History(null);
7245 this.id = ++nextDocId;
7246 this.modeOption = mode;
7247
7248 if (typeof text == "string") text = splitLines(text);
7249 updateDoc(this, {from: start, to: start, text: text});
7250 setSelection(this, simpleSelection(start), sel_dontScroll);
7251 };
7252
7253 Doc.prototype = createObj(BranchChunk.prototype, {
7254 constructor: Doc,
7255 // Iterate over the document. Supports two forms -- with only one
7256 // argument, it calls that for each line in the document. With
7257 // three, it iterates over the range given by the first two (with
7258 // the second being non-inclusive).
7259 iter: function(from, to, op) {
7260 if (op) this.iterN(from - this.first, to - from, op);
7261 else this.iterN(this.first, this.first + this.size, from);
7262 },
7263
7264 // Non-public interface for adding and removing lines.
7265 insert: function(at, lines) {
7266 var height = 0;
7267 for (var i = 0; i < lines.length; ++i) height += lines[i].height;
7268 this.insertInner(at - this.first, lines, height);
7269 },
7270 remove: function(at, n) { this.removeInner(at - this.first, n); },
7271
7272 // From here, the methods are part of the public interface. Most
7273 // are also available from CodeMirror (editor) instances.
7274
7275 getValue: function(lineSep) {
7276 var lines = getLines(this, this.first, this.first + this.size);
7277 if (lineSep === false) return lines;
7278 return lines.join(lineSep || "\n");
7279 },
7280 setValue: docMethodOp(function(code) {
7281 var top = Pos(this.first, 0), last = this.first + this.size - 1;
7282 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
7283 text: splitLines(code), origin: "setValue", full: true}, true);
7284 setSelection(this, simpleSelection(top));
7285 }),
7286 replaceRange: function(code, from, to, origin) {
7287 from = clipPos(this, from);
7288 to = to ? clipPos(this, to) : from;
7289 replaceRange(this, code, from, to, origin);
7290 },
7291 getRange: function(from, to, lineSep) {
7292 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
7293 if (lineSep === false) return lines;
7294 return lines.join(lineSep || "\n");
7295 },
7296
7297 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
7298
7299 getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
7300 getLineNumber: function(line) {return lineNo(line);},
7301
7302 getLineHandleVisualStart: function(line) {
7303 if (typeof line == "number") line = getLine(this, line);
7304 return visualLine(line);
7305 },
7306
7307 lineCount: function() {return this.size;},
7308 firstLine: function() {return this.first;},
7309 lastLine: function() {return this.first + this.size - 1;},
7310
7311 clipPos: function(pos) {return clipPos(this, pos);},
7312
7313 getCursor: function(start) {
7314 var range = this.sel.primary(), pos;
7315 if (start == null || start == "head") pos = range.head;
7316 else if (start == "anchor") pos = range.anchor;
7317 else if (start == "end" || start == "to" || start === false) pos = range.to();
7318 else pos = range.from();
7319 return pos;
7320 },
7321 listSelections: function() { return this.sel.ranges; },
7322 somethingSelected: function() {return this.sel.somethingSelected();},
7323
7324 setCursor: docMethodOp(function(line, ch, options) {
7325 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
7326 }),
7327 setSelection: docMethodOp(function(anchor, head, options) {
7328 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
7329 }),
7330 extendSelection: docMethodOp(function(head, other, options) {
7331 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7332 }),
7333 extendSelections: docMethodOp(function(heads, options) {
7334 extendSelections(this, clipPosArray(this, heads, options));
7335 }),
7336 extendSelectionsBy: docMethodOp(function(f, options) {
7337 extendSelections(this, map(this.sel.ranges, f), options);
7338 }),
7339 setSelections: docMethodOp(function(ranges, primary, options) {
7340 if (!ranges.length) return;
7341 for (var i = 0, out = []; i < ranges.length; i++)
7342 out[i] = new Range(clipPos(this, ranges[i].anchor),
7343 clipPos(this, ranges[i].head));
7344 if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
7345 setSelection(this, normalizeSelection(out, primary), options);
7346 }),
7347 addSelection: docMethodOp(function(anchor, head, options) {
7348 var ranges = this.sel.ranges.slice(0);
7349 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
7350 setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
7351 }),
7352
7353 getSelection: function(lineSep) {
7354 var ranges = this.sel.ranges, lines;
7355 for (var i = 0; i < ranges.length; i++) {
7356 var sel = getBetween(this, ranges[i].from(), ranges[i].to());
7357 lines = lines ? lines.concat(sel) : sel;
7358 }
7359 if (lineSep === false) return lines;
7360 else return lines.join(lineSep || "\n");
7361 },
7362 getSelections: function(lineSep) {
7363 var parts = [], ranges = this.sel.ranges;
7364 for (var i = 0; i < ranges.length; i++) {
7365 var sel = getBetween(this, ranges[i].from(), ranges[i].to());
7366 if (lineSep !== false) sel = sel.join(lineSep || "\n");
7367 parts[i] = sel;
7368 }
7369 return parts;
7370 },
7371 replaceSelection: function(code, collapse, origin) {
7372 var dup = [];
7373 for (var i = 0; i < this.sel.ranges.length; i++)
7374 dup[i] = code;
7375 this.replaceSelections(dup, collapse, origin || "+input");
7376 },
7377 replaceSelections: docMethodOp(function(code, collapse, origin) {
7378 var changes = [], sel = this.sel;
7379 for (var i = 0; i < sel.ranges.length; i++) {
7380 var range = sel.ranges[i];
7381 changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
7382 }
7383 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
7384 for (var i = changes.length - 1; i >= 0; i--)
7385 makeChange(this, changes[i]);
7386 if (newSel) setSelectionReplaceHistory(this, newSel);
7387 else if (this.cm) ensureCursorVisible(this.cm);
7388 }),
7389 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
7390 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
7391 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
7392 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
7393
7394 setExtending: function(val) {this.extend = val;},
7395 getExtending: function() {return this.extend;},
7396
7397 historySize: function() {
7398 var hist = this.history, done = 0, undone = 0;
7399 for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
7400 for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
7401 return {undo: done, redo: undone};
7402 },
7403 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
7404
7405 markClean: function() {
7406 this.cleanGeneration = this.changeGeneration(true);
7407 },
7408 changeGeneration: function(forceSplit) {
7409 if (forceSplit)
7410 this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
7411 return this.history.generation;
7412 },
7413 isClean: function (gen) {
7414 return this.history.generation == (gen || this.cleanGeneration);
7415 },
7416
7417 getHistory: function() {
7418 return {done: copyHistoryArray(this.history.done),
7419 undone: copyHistoryArray(this.history.undone)};
7420 },
7421 setHistory: function(histData) {
7422 var hist = this.history = new History(this.history.maxGeneration);
7423 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
7424 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
7425 },
7426
7427 addLineClass: docMethodOp(function(handle, where, cls) {
7428 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
7429 var prop = where == "text" ? "textClass"
7430 : where == "background" ? "bgClass"
7431 : where == "gutter" ? "gutterClass" : "wrapClass";
7432 if (!line[prop]) line[prop] = cls;
7433 else if (classTest(cls).test(line[prop])) return false;
7434 else line[prop] += " " + cls;
7435 return true;
7436 });
7437 }),
7438 removeLineClass: docMethodOp(function(handle, where, cls) {
7439 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
7440 var prop = where == "text" ? "textClass"
7441 : where == "background" ? "bgClass"
7442 : where == "gutter" ? "gutterClass" : "wrapClass";
7443 var cur = line[prop];
7444 if (!cur) return false;
7445 else if (cls == null) line[prop] = null;
7446 else {
7447 var found = cur.match(classTest(cls));
7448 if (!found) return false;
7449 var end = found.index + found[0].length;
7450 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
7451 }
7452 return true;
7453 });
7454 }),
7455
7456 addLineWidget: docMethodOp(function(handle, node, options) {
7457 return addLineWidget(this, handle, node, options);
7458 }),
7459 removeLineWidget: function(widget) { widget.clear(); },
7460
7461 markText: function(from, to, options) {
7462 return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
7463 },
7464 setBookmark: function(pos, options) {
7465 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
7466 insertLeft: options && options.insertLeft,
7467 clearWhenEmpty: false, shared: options && options.shared,
7468 handleMouseEvents: options && options.handleMouseEvents};
7469 pos = clipPos(this, pos);
7470 return markText(this, pos, pos, realOpts, "bookmark");
7471 },
7472 findMarksAt: function(pos) {
7473 pos = clipPos(this, pos);
7474 var markers = [], spans = getLine(this, pos.line).markedSpans;
7475 if (spans) for (var i = 0; i < spans.length; ++i) {
7476 var span = spans[i];
7477 if ((span.from == null || span.from <= pos.ch) &&
7478 (span.to == null || span.to >= pos.ch))
7479 markers.push(span.marker.parent || span.marker);
7480 }
7481 return markers;
7482 },
7483 findMarks: function(from, to, filter) {
7484 from = clipPos(this, from); to = clipPos(this, to);
7485 var found = [], lineNo = from.line;
7486 this.iter(from.line, to.line + 1, function(line) {
7487 var spans = line.markedSpans;
7488 if (spans) for (var i = 0; i < spans.length; i++) {
7489 var span = spans[i];
7490 if (!(lineNo == from.line && from.ch > span.to ||
7491 span.from == null && lineNo != from.line||
7492 lineNo == to.line && span.from > to.ch) &&
7493 (!filter || filter(span.marker)))
7494 found.push(span.marker.parent || span.marker);
7495 }
7496 ++lineNo;
7497 });
7498 return found;
7499 },
7500 getAllMarks: function() {
7501 var markers = [];
7502 this.iter(function(line) {
7503 var sps = line.markedSpans;
7504 if (sps) for (var i = 0; i < sps.length; ++i)
7505 if (sps[i].from != null) markers.push(sps[i].marker);
7506 });
7507 return markers;
7508 },
7509
7510 posFromIndex: function(off) {
7511 var ch, lineNo = this.first;
7512 this.iter(function(line) {
7513 var sz = line.text.length + 1;
7514 if (sz > off) { ch = off; return true; }
7515 off -= sz;
7516 ++lineNo;
7517 });
7518 return clipPos(this, Pos(lineNo, ch));
7519 },
7520 indexFromPos: function (coords) {
7521 coords = clipPos(this, coords);
7522 var index = coords.ch;
7523 if (coords.line < this.first || coords.ch < 0) return 0;
7524 this.iter(this.first, coords.line, function (line) {
7525 index += line.text.length + 1;
7526 });
7527 return index;
7528 },
7529
7530 copy: function(copyHistory) {
7531 var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
7532 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
7533 doc.sel = this.sel;
7534 doc.extend = false;
7535 if (copyHistory) {
7536 doc.history.undoDepth = this.history.undoDepth;
7537 doc.setHistory(this.getHistory());
7538 }
7539 return doc;
7540 },
7541
7542 linkedDoc: function(options) {
7543 if (!options) options = {};
7544 var from = this.first, to = this.first + this.size;
7545 if (options.from != null && options.from > from) from = options.from;
7546 if (options.to != null && options.to < to) to = options.to;
7547 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
7548 if (options.sharedHist) copy.history = this.history;
7549 (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
7550 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
7551 copySharedMarkers(copy, findSharedMarkers(this));
7552 return copy;
7553 },
7554 unlinkDoc: function(other) {
7555 if (other instanceof CodeMirror) other = other.doc;
7556 if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
7557 var link = this.linked[i];
7558 if (link.doc != other) continue;
7559 this.linked.splice(i, 1);
7560 other.unlinkDoc(this);
7561 detachSharedMarkers(findSharedMarkers(this));
7562 break;
7563 }
7564 // If the histories were shared, split them again
7565 if (other.history == this.history) {
7566 var splitIds = [other.id];
7567 linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
7568 other.history = new History(null);
7569 other.history.done = copyHistoryArray(this.history.done, splitIds);
7570 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
7571 }
7572 },
7573 iterLinkedDocs: function(f) {linkedDocs(this, f);},
7574
7575 getMode: function() {return this.mode;},
7576 getEditor: function() {return this.cm;}
7577 });
7578
7579 // Public alias.
7580 Doc.prototype.eachLine = Doc.prototype.iter;
7581
7582 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
7583 var dontDelegate = "iter insert remove copy getEditor".split(" ");
7584 for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
7585 CodeMirror.prototype[prop] = (function(method) {
7586 return function() {return method.apply(this.doc, arguments);};
7587 })(Doc.prototype[prop]);
7588
7589 eventMixin(Doc);
7590
7591 // Call f for all linked documents.
7592 function linkedDocs(doc, f, sharedHistOnly) {
7593 function propagate(doc, skip, sharedHist) {
7594 if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
7595 var rel = doc.linked[i];
7596 if (rel.doc == skip) continue;
7597 var shared = sharedHist && rel.sharedHist;
7598 if (sharedHistOnly && !shared) continue;
7599 f(rel.doc, shared);
7600 propagate(rel.doc, doc, shared);
7601 }
7602 }
7603 propagate(doc, null, true);
7604 }
7605
7606 // Attach a document to an editor.
7607 function attachDoc(cm, doc) {
7608 if (doc.cm) throw new Error("This document is already in use.");
7609 cm.doc = doc;
7610 doc.cm = cm;
7611 estimateLineHeights(cm);
7612 loadMode(cm);
7613 if (!cm.options.lineWrapping) findMaxLine(cm);
7614 cm.options.mode = doc.modeOption;
7615 regChange(cm);
7616 }
7617
7618 // LINE UTILITIES
7619
7620 // Find the line object corresponding to the given line number.
7621 function getLine(doc, n) {
7622 n -= doc.first;
7623 if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
7624 for (var chunk = doc; !chunk.lines;) {
7625 for (var i = 0;; ++i) {
7626 var child = chunk.children[i], sz = child.chunkSize();
7627 if (n < sz) { chunk = child; break; }
7628 n -= sz;
7629 }
7630 }
7631 return chunk.lines[n];
7632 }
7633
7634 // Get the part of a document between two positions, as an array of
7635 // strings.
7636 function getBetween(doc, start, end) {
7637 var out = [], n = start.line;
7638 doc.iter(start.line, end.line + 1, function(line) {
7639 var text = line.text;
7640 if (n == end.line) text = text.slice(0, end.ch);
7641 if (n == start.line) text = text.slice(start.ch);
7642 out.push(text);
7643 ++n;
7644 });
7645 return out;
7646 }
7647 // Get the lines between from and to, as array of strings.
7648 function getLines(doc, from, to) {
7649 var out = [];
7650 doc.iter(from, to, function(line) { out.push(line.text); });
7651 return out;
7652 }
7653
7654 // Update the height of a line, propagating the height change
7655 // upwards to parent nodes.
7656 function updateLineHeight(line, height) {
7657 var diff = height - line.height;
7658 if (diff) for (var n = line; n; n = n.parent) n.height += diff;
7659 }
7660
7661 // Given a line object, find its line number by walking up through
7662 // its parent links.
7663 function lineNo(line) {
7664 if (line.parent == null) return null;
7665 var cur = line.parent, no = indexOf(cur.lines, line);
7666 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
7667 for (var i = 0;; ++i) {
7668 if (chunk.children[i] == cur) break;
7669 no += chunk.children[i].chunkSize();
7670 }
7671 }
7672 return no + cur.first;
7673 }
7674
7675 // Find the line at the given vertical position, using the height
7676 // information in the document tree.
7677 function lineAtHeight(chunk, h) {
7678 var n = chunk.first;
7679 outer: do {
7680 for (var i = 0; i < chunk.children.length; ++i) {
7681 var child = chunk.children[i], ch = child.height;
7682 if (h < ch) { chunk = child; continue outer; }
7683 h -= ch;
7684 n += child.chunkSize();
7685 }
7686 return n;
7687 } while (!chunk.lines);
7688 for (var i = 0; i < chunk.lines.length; ++i) {
7689 var line = chunk.lines[i], lh = line.height;
7690 if (h < lh) break;
7691 h -= lh;
7692 }
7693 return n + i;
7694 }
7695
7696
7697 // Find the height above the given line.
7698 function heightAtLine(lineObj) {
7699 lineObj = visualLine(lineObj);
7700
7701 var h = 0, chunk = lineObj.parent;
7702 for (var i = 0; i < chunk.lines.length; ++i) {
7703 var line = chunk.lines[i];
7704 if (line == lineObj) break;
7705 else h += line.height;
7706 }
7707 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
7708 for (var i = 0; i < p.children.length; ++i) {
7709 var cur = p.children[i];
7710 if (cur == chunk) break;
7711 else h += cur.height;
7712 }
7713 }
7714 return h;
7715 }
7716
7717 // Get the bidi ordering for the given line (and cache it). Returns
7718 // false for lines that are fully left-to-right, and an array of
7719 // BidiSpan objects otherwise.
7720 function getOrder(line) {
7721 var order = line.order;
7722 if (order == null) order = line.order = bidiOrdering(line.text);
7723 return order;
7724 }
7725
7726 // HISTORY
7727
7728 function History(startGen) {
7729 // Arrays of change events and selections. Doing something adds an
7730 // event to done and clears undo. Undoing moves events from done
7731 // to undone, redoing moves them in the other direction.
7732 this.done = []; this.undone = [];
7733 this.undoDepth = Infinity;
7734 // Used to track when changes can be merged into a single undo
7735 // event
7736 this.lastModTime = this.lastSelTime = 0;
7737 this.lastOp = this.lastSelOp = null;
7738 this.lastOrigin = this.lastSelOrigin = null;
7739 // Used by the isClean() method
7740 this.generation = this.maxGeneration = startGen || 1;
7741 }
7742
7743 // Create a history change event from an updateDoc-style change
7744 // object.
7745 function historyChangeFromChange(doc, change) {
7746 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
7747 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
7748 linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
7749 return histChange;
7750 }
7751
7752 // Pop all selection events off the end of a history array. Stop at
7753 // a change event.
7754 function clearSelectionEvents(array) {
7755 while (array.length) {
7756 var last = lst(array);
7757 if (last.ranges) array.pop();
7758 else break;
7759 }
7760 }
7761
7762 // Find the top change event in the history. Pop off selection
7763 // events that are in the way.
7764 function lastChangeEvent(hist, force) {
7765 if (force) {
7766 clearSelectionEvents(hist.done);
7767 return lst(hist.done);
7768 } else if (hist.done.length && !lst(hist.done).ranges) {
7769 return lst(hist.done);
7770 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
7771 hist.done.pop();
7772 return lst(hist.done);
7773 }
7774 }
7775
7776 // Register a change in the history. Merges changes that are within
7777 // a single operation, ore are close together with an origin that
7778 // allows merging (starting with "+") into a single event.
7779 function addChangeToHistory(doc, change, selAfter, opId) {
7780 var hist = doc.history;
7781 hist.undone.length = 0;
7782 var time = +new Date, cur;
7783
7784 if ((hist.lastOp == opId ||
7785 hist.lastOrigin == change.origin && change.origin &&
7786 ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
7787 change.origin.charAt(0) == "*")) &&
7788 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
7789 // Merge this change into the last event
7790 var last = lst(cur.changes);
7791 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
7792 // Optimized case for simple insertion -- don't want to add
7793 // new changesets for every character typed
7794 last.to = changeEnd(change);
7795 } else {
7796 // Add new sub-event
7797 cur.changes.push(historyChangeFromChange(doc, change));
7798 }
7799 } else {
7800 // Can not be merged, start a new event.
7801 var before = lst(hist.done);
7802 if (!before || !before.ranges)
7803 pushSelectionToHistory(doc.sel, hist.done);
7804 cur = {changes: [historyChangeFromChange(doc, change)],
7805 generation: hist.generation};
7806 hist.done.push(cur);
7807 while (hist.done.length > hist.undoDepth) {
7808 hist.done.shift();
7809 if (!hist.done[0].ranges) hist.done.shift();
7810 }
7811 }
7812 hist.done.push(selAfter);
7813 hist.generation = ++hist.maxGeneration;
7814 hist.lastModTime = hist.lastSelTime = time;
7815 hist.lastOp = hist.lastSelOp = opId;
7816 hist.lastOrigin = hist.lastSelOrigin = change.origin;
7817
7818 if (!last) signal(doc, "historyAdded");
7819 }
7820
7821 function selectionEventCanBeMerged(doc, origin, prev, sel) {
7822 var ch = origin.charAt(0);
7823 return ch == "*" ||
7824 ch == "+" &&
7825 prev.ranges.length == sel.ranges.length &&
7826 prev.somethingSelected() == sel.somethingSelected() &&
7827 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
7828 }
7829
7830 // Called whenever the selection changes, sets the new selection as
7831 // the pending selection in the history, and pushes the old pending
7832 // selection into the 'done' array when it was significantly
7833 // different (in number of selected ranges, emptiness, or time).
7834 function addSelectionToHistory(doc, sel, opId, options) {
7835 var hist = doc.history, origin = options && options.origin;
7836
7837 // A new event is started when the previous origin does not match
7838 // the current, or the origins don't allow matching. Origins
7839 // starting with * are always merged, those starting with + are
7840 // merged when similar and close together in time.
7841 if (opId == hist.lastSelOp ||
7842 (origin && hist.lastSelOrigin == origin &&
7843 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
7844 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
7845 hist.done[hist.done.length - 1] = sel;
7846 else
7847 pushSelectionToHistory(sel, hist.done);
7848
7849 hist.lastSelTime = +new Date;
7850 hist.lastSelOrigin = origin;
7851 hist.lastSelOp = opId;
7852 if (options && options.clearRedo !== false)
7853 clearSelectionEvents(hist.undone);
7854 }
7855
7856 function pushSelectionToHistory(sel, dest) {
7857 var top = lst(dest);
7858 if (!(top && top.ranges && top.equals(sel)))
7859 dest.push(sel);
7860 }
7861
7862 // Used to store marked span information in the history.
7863 function attachLocalSpans(doc, change, from, to) {
7864 var existing = change["spans_" + doc.id], n = 0;
7865 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
7866 if (line.markedSpans)
7867 (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
7868 ++n;
7869 });
7870 }
7871
7872 // When un/re-doing restores text containing marked spans, those
7873 // that have been explicitly cleared should not be restored.
7874 function removeClearedSpans(spans) {
7875 if (!spans) return null;
7876 for (var i = 0, out; i < spans.length; ++i) {
7877 if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
7878 else if (out) out.push(spans[i]);
7879 }
7880 return !out ? spans : out.length ? out : null;
7881 }
7882
7883 // Retrieve and filter the old marked spans stored in a change event.
7884 function getOldSpans(doc, change) {
7885 var found = change["spans_" + doc.id];
7886 if (!found) return null;
7887 for (var i = 0, nw = []; i < change.text.length; ++i)
7888 nw.push(removeClearedSpans(found[i]));
7889 return nw;
7890 }
7891
7892 // Used both to provide a JSON-safe object in .getHistory, and, when
7893 // detaching a document, to split the history in two
7894 function copyHistoryArray(events, newGroup, instantiateSel) {
7895 for (var i = 0, copy = []; i < events.length; ++i) {
7896 var event = events[i];
7897 if (event.ranges) {
7898 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
7899 continue;
7900 }
7901 var changes = event.changes, newChanges = [];
7902 copy.push({changes: newChanges});
7903 for (var j = 0; j < changes.length; ++j) {
7904 var change = changes[j], m;
7905 newChanges.push({from: change.from, to: change.to, text: change.text});
7906 if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
7907 if (indexOf(newGroup, Number(m[1])) > -1) {
7908 lst(newChanges)[prop] = change[prop];
7909 delete change[prop];
7910 }
7911 }
7912 }
7913 }
7914 return copy;
7915 }
7916
7917 // Rebasing/resetting history to deal with externally-sourced changes
7918
7919 function rebaseHistSelSingle(pos, from, to, diff) {
7920 if (to < pos.line) {
7921 pos.line += diff;
7922 } else if (from < pos.line) {
7923 pos.line = from;
7924 pos.ch = 0;
7925 }
7926 }
7927
7928 // Tries to rebase an array of history events given a change in the
7929 // document. If the change touches the same lines as the event, the
7930 // event, and everything 'behind' it, is discarded. If the change is
7931 // before the event, the event's positions are updated. Uses a
7932 // copy-on-write scheme for the positions, to avoid having to
7933 // reallocate them all on every rebase, but also avoid problems with
7934 // shared position objects being unsafely updated.
7935 function rebaseHistArray(array, from, to, diff) {
7936 for (var i = 0; i < array.length; ++i) {
7937 var sub = array[i], ok = true;
7938 if (sub.ranges) {
7939 if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
7940 for (var j = 0; j < sub.ranges.length; j++) {
7941 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
7942 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
7943 }
7944 continue;
7945 }
7946 for (var j = 0; j < sub.changes.length; ++j) {
7947 var cur = sub.changes[j];
7948 if (to < cur.from.line) {
7949 cur.from = Pos(cur.from.line + diff, cur.from.ch);
7950 cur.to = Pos(cur.to.line + diff, cur.to.ch);
7951 } else if (from <= cur.to.line) {
7952 ok = false;
7953 break;
7954 }
7955 }
7956 if (!ok) {
7957 array.splice(0, i + 1);
7958 i = 0;
7959 }
7960 }
7961 }
7962
7963 function rebaseHist(hist, change) {
7964 var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
7965 rebaseHistArray(hist.done, from, to, diff);
7966 rebaseHistArray(hist.undone, from, to, diff);
7967 }
7968
7969 // EVENT UTILITIES
7970
7971 // Due to the fact that we still support jurassic IE versions, some
7972 // compatibility wrappers are needed.
7973
7974 var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
7975 if (e.preventDefault) e.preventDefault();
7976 else e.returnValue = false;
7977 };
7978 var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
7979 if (e.stopPropagation) e.stopPropagation();
7980 else e.cancelBubble = true;
7981 };
7982 function e_defaultPrevented(e) {
7983 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
7984 }
7985 var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
7986
7987 function e_target(e) {return e.target || e.srcElement;}
7988 function e_button(e) {
7989 var b = e.which;
7990 if (b == null) {
7991 if (e.button & 1) b = 1;
7992 else if (e.button & 2) b = 3;
7993 else if (e.button & 4) b = 2;
7994 }
7995 if (mac && e.ctrlKey && b == 1) b = 3;
7996 return b;
7997 }
7998
7999 // EVENT HANDLING
8000
8001 // Lightweight event framework. on/off also work on DOM nodes,
8002 // registering native DOM handlers.
8003
8004 var on = CodeMirror.on = function(emitter, type, f) {
8005 if (emitter.addEventListener)
8006 emitter.addEventListener(type, f, false);
8007 else if (emitter.attachEvent)
8008 emitter.attachEvent("on" + type, f);
8009 else {
8010 var map = emitter._handlers || (emitter._handlers = {});
8011 var arr = map[type] || (map[type] = []);
8012 arr.push(f);
8013 }
8014 };
8015
8016 var off = CodeMirror.off = function(emitter, type, f) {
8017 if (emitter.removeEventListener)
8018 emitter.removeEventListener(type, f, false);
8019 else if (emitter.detachEvent)
8020 emitter.detachEvent("on" + type, f);
8021 else {
8022 var arr = emitter._handlers && emitter._handlers[type];
8023 if (!arr) return;
8024 for (var i = 0; i < arr.length; ++i)
8025 if (arr[i] == f) { arr.splice(i, 1); break; }
8026 }
8027 };
8028
8029 var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
8030 var arr = emitter._handlers && emitter._handlers[type];
8031 if (!arr) return;
8032 var args = Array.prototype.slice.call(arguments, 2);
8033 for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
8034 };
8035
8036 var orphanDelayedCallbacks = null;
8037
8038 // Often, we want to signal events at a point where we are in the
8039 // middle of some work, but don't want the handler to start calling
8040 // other methods on the editor, which might be in an inconsistent
8041 // state or simply not expect any other events to happen.
8042 // signalLater looks whether there are any handlers, and schedules
8043 // them to be executed when the last operation ends, or, if no
8044 // operation is active, when a timeout fires.
8045 function signalLater(emitter, type /*, values...*/) {
8046 var arr = emitter._handlers && emitter._handlers[type];
8047 if (!arr) return;
8048 var args = Array.prototype.slice.call(arguments, 2), list;
8049 if (operationGroup) {
8050 list = operationGroup.delayedCallbacks;
8051 } else if (orphanDelayedCallbacks) {
8052 list = orphanDelayedCallbacks;
8053 } else {
8054 list = orphanDelayedCallbacks = [];
8055 setTimeout(fireOrphanDelayed, 0);
8056 }
8057 function bnd(f) {return function(){f.apply(null, args);};};
8058 for (var i = 0; i < arr.length; ++i)
8059 list.push(bnd(arr[i]));
8060 }
8061
8062 function fireOrphanDelayed() {
8063 var delayed = orphanDelayedCallbacks;
8064 orphanDelayedCallbacks = null;
8065 for (var i = 0; i < delayed.length; ++i) delayed[i]();
8066 }
8067
8068 // The DOM events that CodeMirror handles can be overridden by
8069 // registering a (non-DOM) handler on the editor for the event name,
8070 // and preventDefault-ing the event in that handler.
8071 function signalDOMEvent(cm, e, override) {
8072 if (typeof e == "string")
8073 e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
8074 signal(cm, override || e.type, cm, e);
8075 return e_defaultPrevented(e) || e.codemirrorIgnore;
8076 }
8077
8078 function signalCursorActivity(cm) {
8079 var arr = cm._handlers && cm._handlers.cursorActivity;
8080 if (!arr) return;
8081 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
8082 for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
8083 set.push(arr[i]);
8084 }
8085
8086 function hasHandler(emitter, type) {
8087 var arr = emitter._handlers && emitter._handlers[type];
8088 return arr && arr.length > 0;
8089 }
8090
8091 // Add on and off methods to a constructor's prototype, to make
8092 // registering events on such objects more convenient.
8093 function eventMixin(ctor) {
8094 ctor.prototype.on = function(type, f) {on(this, type, f);};
8095 ctor.prototype.off = function(type, f) {off(this, type, f);};
8096 }
8097
8098 // MISC UTILITIES
8099
8100 // Number of pixels added to scroller and sizer to hide scrollbar
8101 var scrollerGap = 30;
8102
8103 // Returned or thrown by various protocols to signal 'I'm not
8104 // handling this'.
8105 var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
8106
8107 // Reused option objects for setSelection & friends
8108 var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
8109
8110 function Delayed() {this.id = null;}
8111 Delayed.prototype.set = function(ms, f) {
8112 clearTimeout(this.id);
8113 this.id = setTimeout(f, ms);
8114 };
8115
8116 // Counts the column offset in a string, taking tabs into account.
8117 // Used mostly to find indentation.
8118 var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
8119 if (end == null) {
8120 end = string.search(/[^\s\u00a0]/);
8121 if (end == -1) end = string.length;
8122 }
8123 for (var i = startIndex || 0, n = startValue || 0;;) {
8124 var nextTab = string.indexOf("\t", i);
8125 if (nextTab < 0 || nextTab >= end)
8126 return n + (end - i);
8127 n += nextTab - i;
8128 n += tabSize - (n % tabSize);
8129 i = nextTab + 1;
8130 }
8131 };
8132
8133 // The inverse of countColumn -- find the offset that corresponds to
8134 // a particular column.
8135 function findColumn(string, goal, tabSize) {
8136 for (var pos = 0, col = 0;;) {
8137 var nextTab = string.indexOf("\t", pos);
8138 if (nextTab == -1) nextTab = string.length;
8139 var skipped = nextTab - pos;
8140 if (nextTab == string.length || col + skipped >= goal)
8141 return pos + Math.min(skipped, goal - col);
8142 col += nextTab - pos;
8143 col += tabSize - (col % tabSize);
8144 pos = nextTab + 1;
8145 if (col >= goal) return pos;
8146 }
8147 }
8148
8149 var spaceStrs = [""];
8150 function spaceStr(n) {
8151 while (spaceStrs.length <= n)
8152 spaceStrs.push(lst(spaceStrs) + " ");
8153 return spaceStrs[n];
8154 }
8155
8156 function lst(arr) { return arr[arr.length-1]; }
8157
8158 var selectInput = function(node) { node.select(); };
8159 if (ios) // Mobile Safari apparently has a bug where select() is broken.
8160 selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
8161 else if (ie) // Suppress mysterious IE10 errors
8162 selectInput = function(node) { try { node.select(); } catch(_e) {} };
8163
8164 function indexOf(array, elt) {
8165 for (var i = 0; i < array.length; ++i)
8166 if (array[i] == elt) return i;
8167 return -1;
8168 }
8169 function map(array, f) {
8170 var out = [];
8171 for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
8172 return out;
8173 }
8174
8175 function nothing() {}
8176
8177 function createObj(base, props) {
8178 var inst;
8179 if (Object.create) {
8180 inst = Object.create(base);
8181 } else {
8182 nothing.prototype = base;
8183 inst = new nothing();
8184 }
8185 if (props) copyObj(props, inst);
8186 return inst;
8187 };
8188
8189 function copyObj(obj, target, overwrite) {
8190 if (!target) target = {};
8191 for (var prop in obj)
8192 if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
8193 target[prop] = obj[prop];
8194 return target;
8195 }
8196
8197 function bind(f) {
8198 var args = Array.prototype.slice.call(arguments, 1);
8199 return function(){return f.apply(null, args);};
8200 }
8201
8202 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
8203 var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
8204 return /\w/.test(ch) || ch > "\x80" &&
8205 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
8206 };
8207 function isWordChar(ch, helper) {
8208 if (!helper) return isWordCharBasic(ch);
8209 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
8210 return helper.test(ch);
8211 }
8212
8213 function isEmpty(obj) {
8214 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
8215 return true;
8216 }
8217
8218 // Extending unicode characters. A series of a non-extending char +
8219 // any number of extending chars is treated as a single unit as far
8220 // as editing and measuring is concerned. This is not fully correct,
8221 // since some scripts/fonts/browsers also treat other configurations
8222 // of code points as a group.
8223 var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
8224 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
8225
8226 // DOM UTILITIES
8227
8228 function elt(tag, content, className, style) {
8229 var e = document.createElement(tag);
8230 if (className) e.className = className;
8231 if (style) e.style.cssText = style;
8232 if (typeof content == "string") e.appendChild(document.createTextNode(content));
8233 else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
8234 return e;
8235 }
8236
8237 var range;
8238 if (document.createRange) range = function(node, start, end, endNode) {
8239 var r = document.createRange();
8240 r.setEnd(endNode || node, end);
8241 r.setStart(node, start);
8242 return r;
8243 };
8244 else range = function(node, start, end) {
8245 var r = document.body.createTextRange();
8246 try { r.moveToElementText(node.parentNode); }
8247 catch(e) { return r; }
8248 r.collapse(true);
8249 r.moveEnd("character", end);
8250 r.moveStart("character", start);
8251 return r;
8252 };
8253
8254 function removeChildren(e) {
8255 for (var count = e.childNodes.length; count > 0; --count)
8256 e.removeChild(e.firstChild);
8257 return e;
8258 }
8259
8260 function removeChildrenAndAdd(parent, e) {
8261 return removeChildren(parent).appendChild(e);
8262 }
8263
8264 var contains = CodeMirror.contains = function(parent, child) {
8265 if (child.nodeType == 3) // Android browser always returns false when child is a textnode
8266 child = child.parentNode;
8267 if (parent.contains)
8268 return parent.contains(child);
8269 do {
8270 if (child.nodeType == 11) child = child.host;
8271 if (child == parent) return true;
8272 } while (child = child.parentNode);
8273 };
8274
8275 function activeElt() { return document.activeElement; }
8276 // Older versions of IE throws unspecified error when touching
8277 // document.activeElement in some cases (during loading, in iframe)
8278 if (ie && ie_version < 11) activeElt = function() {
8279 try { return document.activeElement; }
8280 catch(e) { return document.body; }
8281 };
8282
8283 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
8284 var rmClass = CodeMirror.rmClass = function(node, cls) {
8285 var current = node.className;
8286 var match = classTest(cls).exec(current);
8287 if (match) {
8288 var after = current.slice(match.index + match[0].length);
8289 node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
8290 }
8291 };
8292 var addClass = CodeMirror.addClass = function(node, cls) {
8293 var current = node.className;
8294 if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
8295 };
8296 function joinClasses(a, b) {
8297 var as = a.split(" ");
8298 for (var i = 0; i < as.length; i++)
8299 if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
8300 return b;
8301 }
8302
8303 // WINDOW-WIDE EVENTS
8304
8305 // These must be handled carefully, because naively registering a
8306 // handler for each editor will cause the editors to never be
8307 // garbage collected.
8308
8309 function forEachCodeMirror(f) {
8310 if (!document.body.getElementsByClassName) return;
8311 var byClass = document.body.getElementsByClassName("CodeMirror");
8312 for (var i = 0; i < byClass.length; i++) {
8313 var cm = byClass[i].CodeMirror;
8314 if (cm) f(cm);
8315 }
8316 }
8317
8318 var globalsRegistered = false;
8319 function ensureGlobalHandlers() {
8320 if (globalsRegistered) return;
8321 registerGlobalHandlers();
8322 globalsRegistered = true;
8323 }
8324 function registerGlobalHandlers() {
8325 // When the window resizes, we need to refresh active editors.
8326 var resizeTimer;
8327 on(window, "resize", function() {
8328 if (resizeTimer == null) resizeTimer = setTimeout(function() {
8329 resizeTimer = null;
8330 forEachCodeMirror(onResize);
8331 }, 100);
8332 });
8333 // When the window loses focus, we want to show the editor as blurred
8334 on(window, "blur", function() {
8335 forEachCodeMirror(onBlur);
8336 });
8337 }
8338
8339 // FEATURE DETECTION
8340
8341 // Detect drag-and-drop
8342 var dragAndDrop = function() {
8343 // There is *some* kind of drag-and-drop support in IE6-8, but I
8344 // couldn't get it to work yet.
8345 if (ie && ie_version < 9) return false;
8346 var div = elt('div');
8347 return "draggable" in div || "dragDrop" in div;
8348 }();
8349
8350 var zwspSupported;
8351 function zeroWidthElement(measure) {
8352 if (zwspSupported == null) {
8353 var test = elt("span", "\u200b");
8354 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
8355 if (measure.firstChild.offsetHeight != 0)
8356 zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
8357 }
8358 var node = zwspSupported ? elt("span", "\u200b") :
8359 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
8360 node.setAttribute("cm-text", "");
8361 return node;
8362 }
8363
8364 // Feature-detect IE's crummy client rect reporting for bidi text
8365 var badBidiRects;
8366 function hasBadBidiRects(measure) {
8367 if (badBidiRects != null) return badBidiRects;
8368 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
8369 var r0 = range(txt, 0, 1).getBoundingClientRect();
8370 if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
8371 var r1 = range(txt, 1, 2).getBoundingClientRect();
8372 return badBidiRects = (r1.right - r0.right < 3);
8373 }
8374
8375 // See if "".split is the broken IE version, if so, provide an
8376 // alternative way to split lines.
8377 var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
8378 var pos = 0, result = [], l = string.length;
8379 while (pos <= l) {
8380 var nl = string.indexOf("\n", pos);
8381 if (nl == -1) nl = string.length;
8382 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
8383 var rt = line.indexOf("\r");
8384 if (rt != -1) {
8385 result.push(line.slice(0, rt));
8386 pos += rt + 1;
8387 } else {
8388 result.push(line);
8389 pos = nl + 1;
8390 }
8391 }
8392 return result;
8393 } : function(string){return string.split(/\r\n?|\n/);};
8394
8395 var hasSelection = window.getSelection ? function(te) {
8396 try { return te.selectionStart != te.selectionEnd; }
8397 catch(e) { return false; }
8398 } : function(te) {
8399 try {var range = te.ownerDocument.selection.createRange();}
8400 catch(e) {}
8401 if (!range || range.parentElement() != te) return false;
8402 return range.compareEndPoints("StartToEnd", range) != 0;
8403 };
8404
8405 var hasCopyEvent = (function() {
8406 var e = elt("div");
8407 if ("oncopy" in e) return true;
8408 e.setAttribute("oncopy", "return;");
8409 return typeof e.oncopy == "function";
8410 })();
8411
8412 var badZoomedRects = null;
8413 function hasBadZoomedRects(measure) {
8414 if (badZoomedRects != null) return badZoomedRects;
8415 var node = removeChildrenAndAdd(measure, elt("span", "x"));
8416 var normal = node.getBoundingClientRect();
8417 var fromRange = range(node, 0, 1).getBoundingClientRect();
8418 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
8419 }
8420
8421 // KEY NAMES
8422
8423 var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
8424 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
8425 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
8426 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
8427 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
8428 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
8429 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
8430 CodeMirror.keyNames = keyNames;
8431 (function() {
8432 // Number keys
8433 for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
8434 // Alphabetic keys
8435 for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
8436 // Function keys
8437 for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
8438 })();
8439
8440 // BIDI HELPERS
8441
8442 function iterateBidiSections(order, from, to, f) {
8443 if (!order) return f(from, to, "ltr");
8444 var found = false;
8445 for (var i = 0; i < order.length; ++i) {
8446 var part = order[i];
8447 if (part.from < to && part.to > from || from == to && part.to == from) {
8448 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
8449 found = true;
8450 }
8451 }
8452 if (!found) f(from, to, "ltr");
8453 }
8454
8455 function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
8456 function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
8457
8458 function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
8459 function lineRight(line) {
8460 var order = getOrder(line);
8461 if (!order) return line.text.length;
8462 return bidiRight(lst(order));
8463 }
8464
8465 function lineStart(cm, lineN) {
8466 var line = getLine(cm.doc, lineN);
8467 var visual = visualLine(line);
8468 if (visual != line) lineN = lineNo(visual);
8469 var order = getOrder(visual);
8470 var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
8471 return Pos(lineN, ch);
8472 }
8473 function lineEnd(cm, lineN) {
8474 var merged, line = getLine(cm.doc, lineN);
8475 while (merged = collapsedSpanAtEnd(line)) {
8476 line = merged.find(1, true).line;
8477 lineN = null;
8478 }
8479 var order = getOrder(line);
8480 var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
8481 return Pos(lineN == null ? lineNo(line) : lineN, ch);
8482 }
8483 function lineStartSmart(cm, pos) {
8484 var start = lineStart(cm, pos.line);
8485 var line = getLine(cm.doc, start.line);
8486 var order = getOrder(line);
8487 if (!order || order[0].level == 0) {
8488 var firstNonWS = Math.max(0, line.text.search(/\S/));
8489 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
8490 return Pos(start.line, inWS ? 0 : firstNonWS);
8491 }
8492 return start;
8493 }
8494
8495 function compareBidiLevel(order, a, b) {
8496 var linedir = order[0].level;
8497 if (a == linedir) return true;
8498 if (b == linedir) return false;
8499 return a < b;
8500 }
8501 var bidiOther;
8502 function getBidiPartAt(order, pos) {
8503 bidiOther = null;
8504 for (var i = 0, found; i < order.length; ++i) {
8505 var cur = order[i];
8506 if (cur.from < pos && cur.to > pos) return i;
8507 if ((cur.from == pos || cur.to == pos)) {
8508 if (found == null) {
8509 found = i;
8510 } else if (compareBidiLevel(order, cur.level, order[found].level)) {
8511 if (cur.from != cur.to) bidiOther = found;
8512 return i;
8513 } else {
8514 if (cur.from != cur.to) bidiOther = i;
8515 return found;
8516 }
8517 }
8518 }
8519 return found;
8520 }
8521
8522 function moveInLine(line, pos, dir, byUnit) {
8523 if (!byUnit) return pos + dir;
8524 do pos += dir;
8525 while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
8526 return pos;
8527 }
8528
8529 // This is needed in order to move 'visually' through bi-directional
8530 // text -- i.e., pressing left should make the cursor go left, even
8531 // when in RTL text. The tricky part is the 'jumps', where RTL and
8532 // LTR text touch each other. This often requires the cursor offset
8533 // to move more than one unit, in order to visually move one unit.
8534 function moveVisually(line, start, dir, byUnit) {
8535 var bidi = getOrder(line);
8536 if (!bidi) return moveLogically(line, start, dir, byUnit);
8537 var pos = getBidiPartAt(bidi, start), part = bidi[pos];
8538 var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
8539
8540 for (;;) {
8541 if (target > part.from && target < part.to) return target;
8542 if (target == part.from || target == part.to) {
8543 if (getBidiPartAt(bidi, target) == pos) return target;
8544 part = bidi[pos += dir];
8545 return (dir > 0) == part.level % 2 ? part.to : part.from;
8546 } else {
8547 part = bidi[pos += dir];
8548 if (!part) return null;
8549 if ((dir > 0) == part.level % 2)
8550 target = moveInLine(line, part.to, -1, byUnit);
8551 else
8552 target = moveInLine(line, part.from, 1, byUnit);
8553 }
8554 }
8555 }
8556
8557 function moveLogically(line, start, dir, byUnit) {
8558 var target = start + dir;
8559 if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
8560 return target < 0 || target > line.text.length ? null : target;
8561 }
8562
8563 // Bidirectional ordering algorithm
8564 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
8565 // that this (partially) implements.
8566
8567 // One-char codes used for character types:
8568 // L (L): Left-to-Right
8569 // R (R): Right-to-Left
8570 // r (AL): Right-to-Left Arabic
8571 // 1 (EN): European Number
8572 // + (ES): European Number Separator
8573 // % (ET): European Number Terminator
8574 // n (AN): Arabic Number
8575 // , (CS): Common Number Separator
8576 // m (NSM): Non-Spacing Mark
8577 // b (BN): Boundary Neutral
8578 // s (B): Paragraph Separator
8579 // t (S): Segment Separator
8580 // w (WS): Whitespace
8581 // N (ON): Other Neutrals
8582
8583 // Returns null if characters are ordered as they appear
8584 // (left-to-right), or an array of sections ({from, to, level}
8585 // objects) in the order in which they occur visually.
8586 var bidiOrdering = (function() {
8587 // Character types for codepoints 0 to 0xff
8588 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
8589 // Character types for codepoints 0x600 to 0x6ff
8590 var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
8591 function charType(code) {
8592 if (code <= 0xf7) return lowTypes.charAt(code);
8593 else if (0x590 <= code && code <= 0x5f4) return "R";
8594 else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
8595 else if (0x6ee <= code && code <= 0x8ac) return "r";
8596 else if (0x2000 <= code && code <= 0x200b) return "w";
8597 else if (code == 0x200c) return "b";
8598 else return "L";
8599 }
8600
8601 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
8602 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
8603 // Browsers seem to always treat the boundaries of block elements as being L.
8604 var outerType = "L";
8605
8606 function BidiSpan(level, from, to) {
8607 this.level = level;
8608 this.from = from; this.to = to;
8609 }
8610
8611 return function(str) {
8612 if (!bidiRE.test(str)) return false;
8613 var len = str.length, types = [];
8614 for (var i = 0, type; i < len; ++i)
8615 types.push(type = charType(str.charCodeAt(i)));
8616
8617 // W1. Examine each non-spacing mark (NSM) in the level run, and
8618 // change the type of the NSM to the type of the previous
8619 // character. If the NSM is at the start of the level run, it will
8620 // get the type of sor.
8621 for (var i = 0, prev = outerType; i < len; ++i) {
8622 var type = types[i];
8623 if (type == "m") types[i] = prev;
8624 else prev = type;
8625 }
8626
8627 // W2. Search backwards from each instance of a European number
8628 // until the first strong type (R, L, AL, or sor) is found. If an
8629 // AL is found, change the type of the European number to Arabic
8630 // number.
8631 // W3. Change all ALs to R.
8632 for (var i = 0, cur = outerType; i < len; ++i) {
8633 var type = types[i];
8634 if (type == "1" && cur == "r") types[i] = "n";
8635 else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
8636 }
8637
8638 // W4. A single European separator between two European numbers
8639 // changes to a European number. A single common separator between
8640 // two numbers of the same type changes to that type.
8641 for (var i = 1, prev = types[0]; i < len - 1; ++i) {
8642 var type = types[i];
8643 if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
8644 else if (type == "," && prev == types[i+1] &&
8645 (prev == "1" || prev == "n")) types[i] = prev;
8646 prev = type;
8647 }
8648
8649 // W5. A sequence of European terminators adjacent to European
8650 // numbers changes to all European numbers.
8651 // W6. Otherwise, separators and terminators change to Other
8652 // Neutral.
8653 for (var i = 0; i < len; ++i) {
8654 var type = types[i];
8655 if (type == ",") types[i] = "N";
8656 else if (type == "%") {
8657 for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
8658 var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
8659 for (var j = i; j < end; ++j) types[j] = replace;
8660 i = end - 1;
8661 }
8662 }
8663
8664 // W7. Search backwards from each instance of a European number
8665 // until the first strong type (R, L, or sor) is found. If an L is
8666 // found, then change the type of the European number to L.
8667 for (var i = 0, cur = outerType; i < len; ++i) {
8668 var type = types[i];
8669 if (cur == "L" && type == "1") types[i] = "L";
8670 else if (isStrong.test(type)) cur = type;
8671 }
8672
8673 // N1. A sequence of neutrals takes the direction of the
8674 // surrounding strong text if the text on both sides has the same
8675 // direction. European and Arabic numbers act as if they were R in
8676 // terms of their influence on neutrals. Start-of-level-run (sor)
8677 // and end-of-level-run (eor) are used at level run boundaries.
8678 // N2. Any remaining neutrals take the embedding direction.
8679 for (var i = 0; i < len; ++i) {
8680 if (isNeutral.test(types[i])) {
8681 for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
8682 var before = (i ? types[i-1] : outerType) == "L";
8683 var after = (end < len ? types[end] : outerType) == "L";
8684 var replace = before || after ? "L" : "R";
8685 for (var j = i; j < end; ++j) types[j] = replace;
8686 i = end - 1;
8687 }
8688 }
8689
8690 // Here we depart from the documented algorithm, in order to avoid
8691 // building up an actual levels array. Since there are only three
8692 // levels (0, 1, 2) in an implementation that doesn't take
8693 // explicit embedding into account, we can build up the order on
8694 // the fly, without following the level-based algorithm.
8695 var order = [], m;
8696 for (var i = 0; i < len;) {
8697 if (countsAsLeft.test(types[i])) {
8698 var start = i;
8699 for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
8700 order.push(new BidiSpan(0, start, i));
8701 } else {
8702 var pos = i, at = order.length;
8703 for (++i; i < len && types[i] != "L"; ++i) {}
8704 for (var j = pos; j < i;) {
8705 if (countsAsNum.test(types[j])) {
8706 if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
8707 var nstart = j;
8708 for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
8709 order.splice(at, 0, new BidiSpan(2, nstart, j));
8710 pos = j;
8711 } else ++j;
8712 }
8713 if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
8714 }
8715 }
8716 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
8717 order[0].from = m[0].length;
8718 order.unshift(new BidiSpan(0, 0, m[0].length));
8719 }
8720 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
8721 lst(order).to -= m[0].length;
8722 order.push(new BidiSpan(0, len - m[0].length, len));
8723 }
8724 if (order[0].level == 2)
8725 order.unshift(new BidiSpan(1, order[0].to, order[0].to));
8726 if (order[0].level != lst(order).level)
8727 order.push(new BidiSpan(order[0].level, len, len));
8728
8729 return order;
8730 };
8731 })();
8732
8733 // THE END
8734
8735 CodeMirror.version = "5.2.0";
8736
8737 return CodeMirror;
8738});
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js b/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js
new file mode 100644
index 0000000..ef01847
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/javascript.js
@@ -0,0 +1,701 @@
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4// TODO actually recognize syntax of TypeScript constructs
5
6(function(mod) {
7 if (typeof exports == "object" && typeof module == "object") // CommonJS
8 mod(require("../../lib/codemirror"));
9 else if (typeof define == "function" && define.amd) // AMD
10 define(["../../lib/codemirror"], mod);
11 else // Plain browser env
12 mod(CodeMirror);
13})(function(CodeMirror) {
14"use strict";
15
16CodeMirror.defineMode("javascript", function(config, parserConfig) {
17 var indentUnit = config.indentUnit;
18 var statementIndent = parserConfig.statementIndent;
19 var jsonldMode = parserConfig.jsonld;
20 var jsonMode = parserConfig.json || jsonldMode;
21 var isTS = parserConfig.typescript;
22 var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
23
24 // Tokenizer
25
26 var keywords = function(){
27 function kw(type) {return {type: type, style: "keyword"};}
28 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
29 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
30
31 var jsKeywords = {
32 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
33 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
34 "var": kw("var"), "const": kw("var"), "let": kw("var"),
35 "function": kw("function"), "catch": kw("catch"),
36 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
37 "in": operator, "typeof": operator, "instanceof": operator,
38 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
39 "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
40 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
41 };
42
43 // Extend the 'normal' keywords with the TypeScript language extensions
44 if (isTS) {
45 var type = {type: "variable", style: "variable-3"};
46 var tsKeywords = {
47 // object-like things
48 "interface": kw("interface"),
49 "extends": kw("extends"),
50 "constructor": kw("constructor"),
51
52 // scope modifiers
53 "public": kw("public"),
54 "private": kw("private"),
55 "protected": kw("protected"),
56 "static": kw("static"),
57
58 // types
59 "string": type, "number": type, "bool": type, "any": type
60 };
61
62 for (var attr in tsKeywords) {
63 jsKeywords[attr] = tsKeywords[attr];
64 }
65 }
66
67 return jsKeywords;
68 }();
69
70 var isOperatorChar = /[+\-*&%=<>!?|~^]/;
71 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
72
73 function readRegexp(stream) {
74 var escaped = false, next, inSet = false;
75 while ((next = stream.next()) != null) {
76 if (!escaped) {
77 if (next == "/" && !inSet) return;
78 if (next == "[") inSet = true;
79 else if (inSet && next == "]") inSet = false;
80 }
81 escaped = !escaped && next == "\\";
82 }
83 }
84
85 // Used as scratch variables to communicate multiple values without
86 // consing up tons of objects.
87 var type, content;
88 function ret(tp, style, cont) {
89 type = tp; content = cont;
90 return style;
91 }
92 function tokenBase(stream, state) {
93 var ch = stream.next();
94 if (ch == '"' || ch == "'") {
95 state.tokenize = tokenString(ch);
96 return state.tokenize(stream, state);
97 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
98 return ret("number", "number");
99 } else if (ch == "." && stream.match("..")) {
100 return ret("spread", "meta");
101 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
102 return ret(ch);
103 } else if (ch == "=" && stream.eat(">")) {
104 return ret("=>", "operator");
105 } else if (ch == "0" && stream.eat(/x/i)) {
106 stream.eatWhile(/[\da-f]/i);
107 return ret("number", "number");
108 } else if (/\d/.test(ch)) {
109 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
110 return ret("number", "number");
111 } else if (ch == "/") {
112 if (stream.eat("*")) {
113 state.tokenize = tokenComment;
114 return tokenComment(stream, state);
115 } else if (stream.eat("/")) {
116 stream.skipToEnd();
117 return ret("comment", "comment");
118 } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
119 state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
120 readRegexp(stream);
121 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
122 return ret("regexp", "string-2");
123 } else {
124 stream.eatWhile(isOperatorChar);
125 return ret("operator", "operator", stream.current());
126 }
127 } else if (ch == "`") {
128 state.tokenize = tokenQuasi;
129 return tokenQuasi(stream, state);
130 } else if (ch == "#") {
131 stream.skipToEnd();
132 return ret("error", "error");
133 } else if (isOperatorChar.test(ch)) {
134 stream.eatWhile(isOperatorChar);
135 return ret("operator", "operator", stream.current());
136 } else if (wordRE.test(ch)) {
137 stream.eatWhile(wordRE);
138 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
139 return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
140 ret("variable", "variable", word);
141 }
142 }
143
144 function tokenString(quote) {
145 return function(stream, state) {
146 var escaped = false, next;
147 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
148 state.tokenize = tokenBase;
149 return ret("jsonld-keyword", "meta");
150 }
151 while ((next = stream.next()) != null) {
152 if (next == quote && !escaped) break;
153 escaped = !escaped && next == "\\";
154 }
155 if (!escaped) state.tokenize = tokenBase;
156 return ret("string", "string");
157 };
158 }
159
160 function tokenComment(stream, state) {
161 var maybeEnd = false, ch;
162 while (ch = stream.next()) {
163 if (ch == "/" && maybeEnd) {
164 state.tokenize = tokenBase;
165 break;
166 }
167 maybeEnd = (ch == "*");
168 }
169 return ret("comment", "comment");
170 }
171
172 function tokenQuasi(stream, state) {
173 var escaped = false, next;
174 while ((next = stream.next()) != null) {
175 if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
176 state.tokenize = tokenBase;
177 break;
178 }
179 escaped = !escaped && next == "\\";
180 }
181 return ret("quasi", "string-2", stream.current());
182 }
183
184 var brackets = "([{}])";
185 // This is a crude lookahead trick to try and notice that we're
186 // parsing the argument patterns for a fat-arrow function before we
187 // actually hit the arrow token. It only works if the arrow is on
188 // the same line as the arguments and there's no strange noise
189 // (comments) in between. Fallback is to only notice when we hit the
190 // arrow, and not declare the arguments as locals for the arrow
191 // body.
192 function findFatArrow(stream, state) {
193 if (state.fatArrowAt) state.fatArrowAt = null;
194 var arrow = stream.string.indexOf("=>", stream.start);
195 if (arrow < 0) return;
196
197 var depth = 0, sawSomething = false;
198 for (var pos = arrow - 1; pos >= 0; --pos) {
199 var ch = stream.string.charAt(pos);
200 var bracket = brackets.indexOf(ch);
201 if (bracket >= 0 && bracket < 3) {
202 if (!depth) { ++pos; break; }
203 if (--depth == 0) break;
204 } else if (bracket >= 3 && bracket < 6) {
205 ++depth;
206 } else if (wordRE.test(ch)) {
207 sawSomething = true;
208 } else if (/["'\/]/.test(ch)) {
209 return;
210 } else if (sawSomething && !depth) {
211 ++pos;
212 break;
213 }
214 }
215 if (sawSomething && !depth) state.fatArrowAt = pos;
216 }
217
218 // Parser
219
220 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
221
222 function JSLexical(indented, column, type, align, prev, info) {
223 this.indented = indented;
224 this.column = column;
225 this.type = type;
226 this.prev = prev;
227 this.info = info;
228 if (align != null) this.align = align;
229 }
230
231 function inScope(state, varname) {
232 for (var v = state.localVars; v; v = v.next)
233 if (v.name == varname) return true;
234 for (var cx = state.context; cx; cx = cx.prev) {
235 for (var v = cx.vars; v; v = v.next)
236 if (v.name == varname) return true;
237 }
238 }
239
240 function parseJS(state, style, type, content, stream) {
241 var cc = state.cc;
242 // Communicate our context to the combinators.
243 // (Less wasteful than consing up a hundred closures on every call.)
244 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
245
246 if (!state.lexical.hasOwnProperty("align"))
247 state.lexical.align = true;
248
249 while(true) {
250 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
251 if (combinator(type, content)) {
252 while(cc.length && cc[cc.length - 1].lex)
253 cc.pop()();
254 if (cx.marked) return cx.marked;
255 if (type == "variable" && inScope(state, content)) return "variable-2";
256 return style;
257 }
258 }
259 }
260
261 // Combinator utils
262
263 var cx = {state: null, column: null, marked: null, cc: null};
264 function pass() {
265 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
266 }
267 function cont() {
268 pass.apply(null, arguments);
269 return true;
270 }
271 function register(varname) {
272 function inList(list) {
273 for (var v = list; v; v = v.next)
274 if (v.name == varname) return true;
275 return false;
276 }
277 var state = cx.state;
278 if (state.context) {
279 cx.marked = "def";
280 if (inList(state.localVars)) return;
281 state.localVars = {name: varname, next: state.localVars};
282 } else {
283 if (inList(state.globalVars)) return;
284 if (parserConfig.globalVars)
285 state.globalVars = {name: varname, next: state.globalVars};
286 }
287 }
288
289 // Combinators
290
291 var defaultVars = {name: "this", next: {name: "arguments"}};
292 function pushcontext() {
293 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
294 cx.state.localVars = defaultVars;
295 }
296 function popcontext() {
297 cx.state.localVars = cx.state.context.vars;
298 cx.state.context = cx.state.context.prev;
299 }
300 function pushlex(type, info) {
301 var result = function() {
302 var state = cx.state, indent = state.indented;
303 if (state.lexical.type == "stat") indent = state.lexical.indented;
304 else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
305 indent = outer.indented;
306 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
307 };
308 result.lex = true;
309 return result;
310 }
311 function poplex() {
312 var state = cx.state;
313 if (state.lexical.prev) {
314 if (state.lexical.type == ")")
315 state.indented = state.lexical.indented;
316 state.lexical = state.lexical.prev;
317 }
318 }
319 poplex.lex = true;
320
321 function expect(wanted) {
322 function exp(type) {
323 if (type == wanted) return cont();
324 else if (wanted == ";") return pass();
325 else return cont(exp);
326 };
327 return exp;
328 }
329
330 function statement(type, value) {
331 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
332 if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
333 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
334 if (type == "{") return cont(pushlex("}"), block, poplex);
335 if (type == ";") return cont();
336 if (type == "if") {
337 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
338 cx.state.cc.pop()();
339 return cont(pushlex("form"), expression, statement, poplex, maybeelse);
340 }
341 if (type == "function") return cont(functiondef);
342 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
343 if (type == "variable") return cont(pushlex("stat"), maybelabel);
344 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
345 block, poplex, poplex);
346 if (type == "case") return cont(expression, expect(":"));
347 if (type == "default") return cont(expect(":"));
348 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
349 statement, poplex, popcontext);
350 if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
351 if (type == "class") return cont(pushlex("form"), className, poplex);
352 if (type == "export") return cont(pushlex("form"), afterExport, poplex);
353 if (type == "import") return cont(pushlex("form"), afterImport, poplex);
354 return pass(pushlex("stat"), expression, expect(";"), poplex);
355 }
356 function expression(type) {
357 return expressionInner(type, false);
358 }
359 function expressionNoComma(type) {
360 return expressionInner(type, true);
361 }
362 function expressionInner(type, noComma) {
363 if (cx.state.fatArrowAt == cx.stream.start) {
364 var body = noComma ? arrowBodyNoComma : arrowBody;
365 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
366 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
367 }
368
369 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
370 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
371 if (type == "function") return cont(functiondef, maybeop);
372 if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
373 if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
374 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
375 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
376 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
377 if (type == "quasi") { return pass(quasi, maybeop); }
378 return cont();
379 }
380 function maybeexpression(type) {
381 if (type.match(/[;\}\)\],]/)) return pass();
382 return pass(expression);
383 }
384 function maybeexpressionNoComma(type) {
385 if (type.match(/[;\}\)\],]/)) return pass();
386 return pass(expressionNoComma);
387 }
388
389 function maybeoperatorComma(type, value) {
390 if (type == ",") return cont(expression);
391 return maybeoperatorNoComma(type, value, false);
392 }
393 function maybeoperatorNoComma(type, value, noComma) {
394 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
395 var expr = noComma == false ? expression : expressionNoComma;
396 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
397 if (type == "operator") {
398 if (/\+\+|--/.test(value)) return cont(me);
399 if (value == "?") return cont(expression, expect(":"), expr);
400 return cont(expr);
401 }
402 if (type == "quasi") { return pass(quasi, me); }
403 if (type == ";") return;
404 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
405 if (type == ".") return cont(property, me);
406 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
407 }
408 function quasi(type, value) {
409 if (type != "quasi") return pass();
410 if (value.slice(value.length - 2) != "${") return cont(quasi);
411 return cont(expression, continueQuasi);
412 }
413 function continueQuasi(type) {
414 if (type == "}") {
415 cx.marked = "string-2";
416 cx.state.tokenize = tokenQuasi;
417 return cont(quasi);
418 }
419 }
420 function arrowBody(type) {
421 findFatArrow(cx.stream, cx.state);
422 return pass(type == "{" ? statement : expression);
423 }
424 function arrowBodyNoComma(type) {
425 findFatArrow(cx.stream, cx.state);
426 return pass(type == "{" ? statement : expressionNoComma);
427 }
428 function maybelabel(type) {
429 if (type == ":") return cont(poplex, statement);
430 return pass(maybeoperatorComma, expect(";"), poplex);
431 }
432 function property(type) {
433 if (type == "variable") {cx.marked = "property"; return cont();}
434 }
435 function objprop(type, value) {
436 if (type == "variable" || cx.style == "keyword") {
437 cx.marked = "property";
438 if (value == "get" || value == "set") return cont(getterSetter);
439 return cont(afterprop);
440 } else if (type == "number" || type == "string") {
441 cx.marked = jsonldMode ? "property" : (cx.style + " property");
442 return cont(afterprop);
443 } else if (type == "jsonld-keyword") {
444 return cont(afterprop);
445 } else if (type == "[") {
446 return cont(expression, expect("]"), afterprop);
447 }
448 }
449 function getterSetter(type) {
450 if (type != "variable") return pass(afterprop);
451 cx.marked = "property";
452 return cont(functiondef);
453 }
454 function afterprop(type) {
455 if (type == ":") return cont(expressionNoComma);
456 if (type == "(") return pass(functiondef);
457 }
458 function commasep(what, end) {
459 function proceed(type) {
460 if (type == ",") {
461 var lex = cx.state.lexical;
462 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
463 return cont(what, proceed);
464 }
465 if (type == end) return cont();
466 return cont(expect(end));
467 }
468 return function(type) {
469 if (type == end) return cont();
470 return pass(what, proceed);
471 };
472 }
473 function contCommasep(what, end, info) {
474 for (var i = 3; i < arguments.length; i++)
475 cx.cc.push(arguments[i]);
476 return cont(pushlex(end, info), commasep(what, end), poplex);
477 }
478 function block(type) {
479 if (type == "}") return cont();
480 return pass(statement, block);
481 }
482 function maybetype(type) {
483 if (isTS && type == ":") return cont(typedef);
484 }
485 function typedef(type) {
486 if (type == "variable"){cx.marked = "variable-3"; return cont();}
487 }
488 function vardef() {
489 return pass(pattern, maybetype, maybeAssign, vardefCont);
490 }
491 function pattern(type, value) {
492 if (type == "variable") { register(value); return cont(); }
493 if (type == "[") return contCommasep(pattern, "]");
494 if (type == "{") return contCommasep(proppattern, "}");
495 }
496 function proppattern(type, value) {
497 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
498 register(value);
499 return cont(maybeAssign);
500 }
501 if (type == "variable") cx.marked = "property";
502 return cont(expect(":"), pattern, maybeAssign);
503 }
504 function maybeAssign(_type, value) {
505 if (value == "=") return cont(expressionNoComma);
506 }
507 function vardefCont(type) {
508 if (type == ",") return cont(vardef);
509 }
510 function maybeelse(type, value) {
511 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
512 }
513 function forspec(type) {
514 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
515 }
516 function forspec1(type) {
517 if (type == "var") return cont(vardef, expect(";"), forspec2);
518 if (type == ";") return cont(forspec2);
519 if (type == "variable") return cont(formaybeinof);
520 return pass(expression, expect(";"), forspec2);
521 }
522 function formaybeinof(_type, value) {
523 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
524 return cont(maybeoperatorComma, forspec2);
525 }
526 function forspec2(type, value) {
527 if (type == ";") return cont(forspec3);
528 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
529 return pass(expression, expect(";"), forspec3);
530 }
531 function forspec3(type) {
532 if (type != ")") cont(expression);
533 }
534 function functiondef(type, value) {
535 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
536 if (type == "variable") {register(value); return cont(functiondef);}
537 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
538 }
539 function funarg(type) {
540 if (type == "spread") return cont(funarg);
541 return pass(pattern, maybetype);
542 }
543 function className(type, value) {
544 if (type == "variable") {register(value); return cont(classNameAfter);}
545 }
546 function classNameAfter(type, value) {
547 if (value == "extends") return cont(expression, classNameAfter);
548 if (type == "{") return cont(pushlex("}"), classBody, poplex);
549 }
550 function classBody(type, value) {
551 if (type == "variable" || cx.style == "keyword") {
552 if (value == "static") {
553 cx.marked = "keyword";
554 return cont(classBody);
555 }
556 cx.marked = "property";
557 if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
558 return cont(functiondef, classBody);
559 }
560 if (value == "*") {
561 cx.marked = "keyword";
562 return cont(classBody);
563 }
564 if (type == ";") return cont(classBody);
565 if (type == "}") return cont();
566 }
567 function classGetterSetter(type) {
568 if (type != "variable") return pass();
569 cx.marked = "property";
570 return cont();
571 }
572 function afterModule(type, value) {
573 if (type == "string") return cont(statement);
574 if (type == "variable") { register(value); return cont(maybeFrom); }
575 }
576 function afterExport(_type, value) {
577 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
578 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
579 return pass(statement);
580 }
581 function afterImport(type) {
582 if (type == "string") return cont();
583 return pass(importSpec, maybeFrom);
584 }
585 function importSpec(type, value) {
586 if (type == "{") return contCommasep(importSpec, "}");
587 if (type == "variable") register(value);
588 if (value == "*") cx.marked = "keyword";
589 return cont(maybeAs);
590 }
591 function maybeAs(_type, value) {
592 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
593 }
594 function maybeFrom(_type, value) {
595 if (value == "from") { cx.marked = "keyword"; return cont(expression); }
596 }
597 function arrayLiteral(type) {
598 if (type == "]") return cont();
599 return pass(expressionNoComma, maybeArrayComprehension);
600 }
601 function maybeArrayComprehension(type) {
602 if (type == "for") return pass(comprehension, expect("]"));
603 if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
604 return pass(commasep(expressionNoComma, "]"));
605 }
606 function comprehension(type) {
607 if (type == "for") return cont(forspec, comprehension);
608 if (type == "if") return cont(expression, comprehension);
609 }
610
611 function isContinuedStatement(state, textAfter) {
612 return state.lastType == "operator" || state.lastType == "," ||
613 isOperatorChar.test(textAfter.charAt(0)) ||
614 /[,.]/.test(textAfter.charAt(0));
615 }
616
617 // Interface
618
619 return {
620 startState: function(basecolumn) {
621 var state = {
622 tokenize: tokenBase,
623 lastType: "sof",
624 cc: [],
625 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
626 localVars: parserConfig.localVars,
627 context: parserConfig.localVars && {vars: parserConfig.localVars},
628 indented: 0
629 };
630 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
631 state.globalVars = parserConfig.globalVars;
632 return state;
633 },
634
635 token: function(stream, state) {
636 if (stream.sol()) {
637 if (!state.lexical.hasOwnProperty("align"))
638 state.lexical.align = false;
639 state.indented = stream.indentation();
640 findFatArrow(stream, state);
641 }
642 if (state.tokenize != tokenComment && stream.eatSpace()) return null;
643 var style = state.tokenize(stream, state);
644 if (type == "comment") return style;
645 state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
646 return parseJS(state, style, type, content, stream);
647 },
648
649 indent: function(state, textAfter) {
650 if (state.tokenize == tokenComment) return CodeMirror.Pass;
651 if (state.tokenize != tokenBase) return 0;
652 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
653 // Kludge to prevent 'maybelse' from blocking lexical scope pops
654 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
655 var c = state.cc[i];
656 if (c == poplex) lexical = lexical.prev;
657 else if (c != maybeelse) break;
658 }
659 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
660 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
661 lexical = lexical.prev;
662 var type = lexical.type, closing = firstChar == type;
663
664 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
665 else if (type == "form" && firstChar == "{") return lexical.indented;
666 else if (type == "form") return lexical.indented + indentUnit;
667 else if (type == "stat")
668 return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
669 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
670 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
671 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
672 else return lexical.indented + (closing ? 0 : indentUnit);
673 },
674
675 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
676 blockCommentStart: jsonMode ? null : "/*",
677 blockCommentEnd: jsonMode ? null : "*/",
678 lineComment: jsonMode ? null : "//",
679 fold: "brace",
680 closeBrackets: "()[]{}''\"\"``",
681
682 helperType: jsonMode ? "json" : "javascript",
683 jsonldMode: jsonldMode,
684 jsonMode: jsonMode
685 };
686});
687
688CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
689
690CodeMirror.defineMIME("text/javascript", "javascript");
691CodeMirror.defineMIME("text/ecmascript", "javascript");
692CodeMirror.defineMIME("application/javascript", "javascript");
693CodeMirror.defineMIME("application/x-javascript", "javascript");
694CodeMirror.defineMIME("application/ecmascript", "javascript");
695CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
696CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
697CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
698CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
699CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
700
701});
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/neo.css b/sources/samples/toolbarconfigurator/lib/codemirror/neo.css
new file mode 100644
index 0000000..d019aab
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/neo.css
@@ -0,0 +1,36 @@
1/* neo theme for codemirror */
2
3/* Color scheme */
4
5.cm-s-neo.CodeMirror {
6 background-color:#ffffff;
7 color:#2e383c;
8 line-height:1.4375;
9}
10.cm-s-neo .cm-comment {color:#75787b}
11.cm-s-neo .cm-keyword, .cm-s-neo .cm-property {color:#1d75b3}
12.cm-s-neo .cm-atom,.cm-s-neo .cm-number {color:#75438a}
13.cm-s-neo .cm-node,.cm-s-neo .cm-tag {color:#9c3328}
14.cm-s-neo .cm-string {color:#b35e14}
15.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier {color:#047d65}
16
17
18/* Editor styling */
19
20.cm-s-neo pre {
21 padding:0;
22}
23
24.cm-s-neo .CodeMirror-gutters {
25 border:none;
26 border-right:10px solid transparent;
27 background-color:transparent;
28}
29
30.cm-s-neo .CodeMirror-linenumber {
31 padding:0;
32 color:#e0e2e5;
33}
34
35.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; }
36.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; }
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.css b/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.css
new file mode 100644
index 0000000..924e638
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.css
@@ -0,0 +1,38 @@
1.CodeMirror-hints {
2 position: absolute;
3 z-index: 10;
4 overflow: hidden;
5 list-style: none;
6
7 margin: 0;
8 padding: 2px;
9
10 -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
11 -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
12 box-shadow: 2px 3px 5px rgba(0,0,0,.2);
13 border-radius: 3px;
14 border: 1px solid silver;
15
16 background: white;
17 font-size: 90%;
18 font-family: monospace;
19
20 max-height: 20em;
21 overflow-y: auto;
22}
23
24.CodeMirror-hint {
25 margin: 0;
26 padding: 0 4px;
27 border-radius: 2px;
28 max-width: 19em;
29 overflow: hidden;
30 white-space: pre;
31 color: black;
32 cursor: pointer;
33}
34
35li.CodeMirror-hint-active {
36 background: #08f;
37 color: white;
38}
diff --git a/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.js b/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.js
new file mode 100644
index 0000000..539181f
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/lib/codemirror/show-hint.js
@@ -0,0 +1,392 @@
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4(function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11})(function(CodeMirror) {
12 "use strict";
13
14 var HINT_ELEMENT_CLASS = "CodeMirror-hint";
15 var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
16
17 // This is the old interface, kept around for now to stay
18 // backwards-compatible.
19 CodeMirror.showHint = function(cm, getHints, options) {
20 if (!getHints) return cm.showHint(options);
21 if (options && options.async) getHints.async = true;
22 var newOpts = {hint: getHints};
23 if (options) for (var prop in options) newOpts[prop] = options[prop];
24 return cm.showHint(newOpts);
25 };
26
27 CodeMirror.defineExtension("showHint", function(options) {
28 // We want a single cursor position.
29 if (this.listSelections().length > 1 || this.somethingSelected()) return;
30
31 if (this.state.completionActive) this.state.completionActive.close();
32 var completion = this.state.completionActive = new Completion(this, options);
33 if (!completion.options.hint) return;
34
35 CodeMirror.signal(this, "startCompletion", this);
36 completion.update();
37 });
38
39 function Completion(cm, options) {
40 this.cm = cm;
41 this.options = this.buildOptions(options);
42 this.widget = null;
43 this.debounce = 0;
44 this.tick = 0;
45 this.startPos = this.cm.getCursor();
46 this.startLen = this.cm.getLine(this.startPos.line).length;
47
48 var self = this;
49 cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
50 }
51
52 var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
53 return setTimeout(fn, 1000/60);
54 };
55 var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
56
57 Completion.prototype = {
58 close: function() {
59 if (!this.active()) return;
60 this.cm.state.completionActive = null;
61 this.tick = null;
62 this.cm.off("cursorActivity", this.activityFunc);
63
64 if (this.widget) this.widget.close();
65 CodeMirror.signal(this.cm, "endCompletion", this.cm);
66 },
67
68 active: function() {
69 return this.cm.state.completionActive == this;
70 },
71
72 pick: function(data, i) {
73 var completion = data.list[i];
74 if (completion.hint) completion.hint(this.cm, data, completion);
75 else this.cm.replaceRange(getText(completion), completion.from || data.from,
76 completion.to || data.to, "complete");
77 CodeMirror.signal(data, "pick", completion);
78 this.close();
79 },
80
81 showHints: function(data) {
82 if (!data || !data.list.length || !this.active()) return this.close();
83
84 if (this.options.completeSingle && data.list.length == 1)
85 this.pick(data, 0);
86 else
87 this.showWidget(data);
88 },
89
90 cursorActivity: function() {
91 if (this.debounce) {
92 cancelAnimationFrame(this.debounce);
93 this.debounce = 0;
94 }
95
96 var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
97 if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
98 pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
99 (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
100 this.close();
101 } else {
102 var self = this;
103 this.debounce = requestAnimationFrame(function() {self.update();});
104 if (this.widget) this.widget.disable();
105 }
106 },
107
108 update: function() {
109 if (this.tick == null) return;
110 if (this.data) CodeMirror.signal(this.data, "update");
111 if (!this.options.hint.async) {
112 this.finishUpdate(this.options.hint(this.cm, this.options), myTick);
113 } else {
114 var myTick = ++this.tick, self = this;
115 this.options.hint(this.cm, function(data) {
116 if (self.tick == myTick) self.finishUpdate(data);
117 }, this.options);
118 }
119 },
120
121 finishUpdate: function(data) {
122 this.data = data;
123 var picked = this.widget && this.widget.picked;
124 if (this.widget) this.widget.close();
125 if (data && data.list.length) {
126 if (picked && data.list.length == 1) this.pick(data, 0);
127 else this.widget = new Widget(this, data);
128 }
129 },
130
131 showWidget: function(data) {
132 this.data = data;
133 this.widget = new Widget(this, data);
134 CodeMirror.signal(data, "shown");
135 },
136
137 buildOptions: function(options) {
138 var editor = this.cm.options.hintOptions;
139 var out = {};
140 for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
141 if (editor) for (var prop in editor)
142 if (editor[prop] !== undefined) out[prop] = editor[prop];
143 if (options) for (var prop in options)
144 if (options[prop] !== undefined) out[prop] = options[prop];
145 return out;
146 }
147 };
148
149 function getText(completion) {
150 if (typeof completion == "string") return completion;
151 else return completion.text;
152 }
153
154 function buildKeyMap(completion, handle) {
155 var baseMap = {
156 Up: function() {handle.moveFocus(-1);},
157 Down: function() {handle.moveFocus(1);},
158 PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
159 PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
160 Home: function() {handle.setFocus(0);},
161 End: function() {handle.setFocus(handle.length - 1);},
162 Enter: handle.pick,
163 Tab: handle.pick,
164 Esc: handle.close
165 };
166 var custom = completion.options.customKeys;
167 var ourMap = custom ? {} : baseMap;
168 function addBinding(key, val) {
169 var bound;
170 if (typeof val != "string")
171 bound = function(cm) { return val(cm, handle); };
172 // This mechanism is deprecated
173 else if (baseMap.hasOwnProperty(val))
174 bound = baseMap[val];
175 else
176 bound = val;
177 ourMap[key] = bound;
178 }
179 if (custom)
180 for (var key in custom) if (custom.hasOwnProperty(key))
181 addBinding(key, custom[key]);
182 var extra = completion.options.extraKeys;
183 if (extra)
184 for (var key in extra) if (extra.hasOwnProperty(key))
185 addBinding(key, extra[key]);
186 return ourMap;
187 }
188
189 function getHintElement(hintsElement, el) {
190 while (el && el != hintsElement) {
191 if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
192 el = el.parentNode;
193 }
194 }
195
196 function Widget(completion, data) {
197 this.completion = completion;
198 this.data = data;
199 this.picked = false;
200 var widget = this, cm = completion.cm;
201
202 var hints = this.hints = document.createElement("ul");
203 hints.className = "CodeMirror-hints";
204 this.selectedHint = data.selectedHint || 0;
205
206 var completions = data.list;
207 for (var i = 0; i < completions.length; ++i) {
208 var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
209 var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
210 if (cur.className != null) className = cur.className + " " + className;
211 elt.className = className;
212 if (cur.render) cur.render(elt, data, cur);
213 else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
214 elt.hintId = i;
215 }
216
217 var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
218 var left = pos.left, top = pos.bottom, below = true;
219 hints.style.left = left + "px";
220 hints.style.top = top + "px";
221 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
222 var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
223 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
224 (completion.options.container || document.body).appendChild(hints);
225 var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
226 if (overlapY > 0) {
227 var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
228 if (curTop - height > 0) { // Fits above cursor
229 hints.style.top = (top = pos.top - height) + "px";
230 below = false;
231 } else if (height > winH) {
232 hints.style.height = (winH - 5) + "px";
233 hints.style.top = (top = pos.bottom - box.top) + "px";
234 var cursor = cm.getCursor();
235 if (data.from.ch != cursor.ch) {
236 pos = cm.cursorCoords(cursor);
237 hints.style.left = (left = pos.left) + "px";
238 box = hints.getBoundingClientRect();
239 }
240 }
241 }
242 var overlapX = box.right - winW;
243 if (overlapX > 0) {
244 if (box.right - box.left > winW) {
245 hints.style.width = (winW - 5) + "px";
246 overlapX -= (box.right - box.left) - winW;
247 }
248 hints.style.left = (left = pos.left - overlapX) + "px";
249 }
250
251 cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
252 moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
253 setFocus: function(n) { widget.changeActive(n); },
254 menuSize: function() { return widget.screenAmount(); },
255 length: completions.length,
256 close: function() { completion.close(); },
257 pick: function() { widget.pick(); },
258 data: data
259 }));
260
261 if (completion.options.closeOnUnfocus) {
262 var closingOnBlur;
263 cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
264 cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
265 }
266
267 var startScroll = cm.getScrollInfo();
268 cm.on("scroll", this.onScroll = function() {
269 var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
270 var newTop = top + startScroll.top - curScroll.top;
271 var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
272 if (!below) point += hints.offsetHeight;
273 if (point <= editor.top || point >= editor.bottom) return completion.close();
274 hints.style.top = newTop + "px";
275 hints.style.left = (left + startScroll.left - curScroll.left) + "px";
276 });
277
278 CodeMirror.on(hints, "dblclick", function(e) {
279 var t = getHintElement(hints, e.target || e.srcElement);
280 if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
281 });
282
283 CodeMirror.on(hints, "click", function(e) {
284 var t = getHintElement(hints, e.target || e.srcElement);
285 if (t && t.hintId != null) {
286 widget.changeActive(t.hintId);
287 if (completion.options.completeOnSingleClick) widget.pick();
288 }
289 });
290
291 CodeMirror.on(hints, "mousedown", function() {
292 setTimeout(function(){cm.focus();}, 20);
293 });
294
295 CodeMirror.signal(data, "select", completions[0], hints.firstChild);
296 return true;
297 }
298
299 Widget.prototype = {
300 close: function() {
301 if (this.completion.widget != this) return;
302 this.completion.widget = null;
303 this.hints.parentNode.removeChild(this.hints);
304 this.completion.cm.removeKeyMap(this.keyMap);
305
306 var cm = this.completion.cm;
307 if (this.completion.options.closeOnUnfocus) {
308 cm.off("blur", this.onBlur);
309 cm.off("focus", this.onFocus);
310 }
311 cm.off("scroll", this.onScroll);
312 },
313
314 disable: function() {
315 this.completion.cm.removeKeyMap(this.keyMap);
316 var widget = this;
317 this.keyMap = {Enter: function() { widget.picked = true; }};
318 this.completion.cm.addKeyMap(this.keyMap);
319 },
320
321 pick: function() {
322 this.completion.pick(this.data, this.selectedHint);
323 },
324
325 changeActive: function(i, avoidWrap) {
326 if (i >= this.data.list.length)
327 i = avoidWrap ? this.data.list.length - 1 : 0;
328 else if (i < 0)
329 i = avoidWrap ? 0 : this.data.list.length - 1;
330 if (this.selectedHint == i) return;
331 var node = this.hints.childNodes[this.selectedHint];
332 node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
333 node = this.hints.childNodes[this.selectedHint = i];
334 node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
335 if (node.offsetTop < this.hints.scrollTop)
336 this.hints.scrollTop = node.offsetTop - 3;
337 else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
338 this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
339 CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
340 },
341
342 screenAmount: function() {
343 return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
344 }
345 };
346
347 CodeMirror.registerHelper("hint", "auto", function(cm, options) {
348 var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
349 if (helpers.length) {
350 for (var i = 0; i < helpers.length; i++) {
351 var cur = helpers[i](cm, options);
352 if (cur && cur.list.length) return cur;
353 }
354 } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
355 if (words) return CodeMirror.hint.fromList(cm, {words: words});
356 } else if (CodeMirror.hint.anyword) {
357 return CodeMirror.hint.anyword(cm, options);
358 }
359 });
360
361 CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
362 var cur = cm.getCursor(), token = cm.getTokenAt(cur);
363 var found = [];
364 for (var i = 0; i < options.words.length; i++) {
365 var word = options.words[i];
366 if (word.slice(0, token.string.length) == token.string)
367 found.push(word);
368 }
369
370 if (found.length) return {
371 list: found,
372 from: CodeMirror.Pos(cur.line, token.start),
373 to: CodeMirror.Pos(cur.line, token.end)
374 };
375 });
376
377 CodeMirror.commands.autocomplete = CodeMirror.showHint;
378
379 var defaultOptions = {
380 hint: CodeMirror.hint.auto,
381 completeSingle: true,
382 alignWithWord: true,
383 closeCharacters: /[\s()\[\]{};:>,]/,
384 closeOnUnfocus: true,
385 completeOnSingleClick: false,
386 container: null,
387 customKeys: null,
388 extraKeys: null
389 };
390
391 CodeMirror.defineOption("hintOptions", null);
392});
diff --git a/sources/samples/toolbarconfigurator/package.json b/sources/samples/toolbarconfigurator/package.json
new file mode 100644
index 0000000..1fceff9
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/package.json
@@ -0,0 +1,12 @@
1{
2 "name": "ckeditor-toolbarconfigurator",
3 "version": "0.0.0",
4 "description": "",
5 "author": "CKSource (http://cksource.com/)",
6 "license": "For licensing, see LICENSE.md or http://ckeditor.com/license.",
7 "devDependencies": {
8 "benderjs": "~0.2.1",
9 "benderjs-chai": "~0.2.0",
10 "benderjs-mocha": "~0.1.2"
11 }
12}
diff --git a/sources/samples/toolbarconfigurator/tests/one.js b/sources/samples/toolbarconfigurator/tests/one.js
new file mode 100644
index 0000000..1d3837f
--- /dev/null
+++ b/sources/samples/toolbarconfigurator/tests/one.js
@@ -0,0 +1,9 @@
1/* global describe, it, expect, ToolbarConfigurator */
2
3describe( 'Full toolbar configurator', function() {
4 var FTE = ToolbarConfigurator.FullToolbarEditor;
5
6 it( 'exists', function() {
7 expect( FTE ).to.be.a( 'function' );
8 } );
9} );
diff --git a/sources/skins/moono/colorpanel.css b/sources/skins/moono/colorpanel.css
new file mode 100644
index 0000000..efad9d9
--- /dev/null
+++ b/sources/skins/moono/colorpanel.css
@@ -0,0 +1,127 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7colorpanel.css (part of editor.css)
8=====================================
9
10The color panel is related to the contents part of the panels that are
11displayed when clicking the color buttons of the toolbar. See panels.css for
12styles related to the outer part of panels.
13
14The following is the visual representation of the color panel contents:
15
16+-- .cke_panel_block.cke_colorblock --+
17| +-- a.cke_colorauto --------------+ |
18| | | |
19| | AUTOMATIC COLOR | |
20| | | |
21| +---------------------------------+ |
22| +-- table ------------------------+ |
23| | | |
24| | COLOR PALETTE | |
25| | | |
26| |---------------------------------| |
27| | "More Colors" | |
28| +---------------------------------+ |
29+-------------------------------------+
30
31The AUTOMATIC COLOR section is an <a> containing a table with two cells with
32the following contents:
33
34+-- TD -----------------+ +-- TD -----------------+
35| +-- .cke_colorbox --+ | | |
36| | | | | "Automatic" |
37| +-------------------+ | | |
38+-----------------------+ +-----------------------+
39
40The COLOR PALETTE section instead is a table with a variable number of cells
41(by default 8). Each cell represents a color box, with the following structure:
42
43+-- A.cke_colorbox ---------+
44| +-- SPAN.cke_colorbox --+ |
45| | | |
46| +-----------------------+ |
47+---------------------------+
48*/
49
50/* The container of the color palette. */
51.cke_colorblock
52{
53 padding: 3px;
54 font-size: 11px;
55 font-family: 'Microsoft Sans Serif', Tahoma, Arial, Verdana, Sans-Serif;
56}
57
58.cke_colorblock,
59.cke_colorblock a
60{
61 text-decoration: none;
62 color: #000;
63}
64
65/* The box which is to represent a single color on the color palette.
66 It is a small, square-shaped element which can be selected from the palette. */
67span.cke_colorbox
68{
69 width: 10px;
70 height: 10px;
71 border: #808080 1px solid;
72 float: left;
73}
74
75.cke_rtl span.cke_colorbox
76{
77 float: right;
78}
79
80/* The wrapper of the span.cke_colorbox. It provides an extra border and padding. */
81a.cke_colorbox
82{
83 border: #fff 1px solid;
84 padding: 2px;
85 float: left;
86 width: 12px;
87 height: 12px;
88}
89
90.cke_rtl a.cke_colorbox
91{
92 float: right;
93}
94
95/* Different states of the a.cke_colorbox wrapper. */
96a:hover.cke_colorbox,
97a:focus.cke_colorbox,
98a:active.cke_colorbox
99{
100 border: #b6b6b6 1px solid;
101 background-color: #e5e5e5;
102}
103
104/* Buttons which are visible at the top/bottom of the color palette:
105 - cke_colorauto (TOP) applies the automatic color.
106 - cke_colormore (BOTTOM) executes the color dialog.
107*/
108a.cke_colorauto,
109a.cke_colormore
110{
111 border: #fff 1px solid;
112 padding: 2px;
113 display: block;
114 cursor: pointer;
115}
116
117/* Different states of cke_colorauto/cke_colormore buttons. */
118a:hover.cke_colorauto,
119a:hover.cke_colormore,
120a:focus.cke_colorauto,
121a:focus.cke_colormore,
122a:active.cke_colorauto,
123a:active.cke_colormore
124{
125 border: #b6b6b6 1px solid;
126 background-color: #e5e5e5;
127}
diff --git a/sources/skins/moono/dev/icons16.png b/sources/skins/moono/dev/icons16.png
new file mode 100644
index 0000000..a919742
--- /dev/null
+++ b/sources/skins/moono/dev/icons16.png
Binary files differ
diff --git a/sources/skins/moono/dev/icons16.svg b/sources/skins/moono/dev/icons16.svg
new file mode 100644
index 0000000..5719d3e
--- /dev/null
+++ b/sources/skins/moono/dev/icons16.svg
@@ -0,0 +1,2374 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:xlink="http://www.w3.org/1999/xlink"
11 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13 version="1.1"
14 id="Layer_1"
15 x="0px"
16 y="0px"
17 width="496.00443"
18 height="368.00006"
19 viewBox="0 0 496.00443 368.00004"
20 enable-background="new 0 0 612 792"
21 xml:space="preserve"
22 inkscape:version="0.48.3.1 r9886"
23 sodipodi:docname="icons16.svg"
24 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/skins/moono/dev/icons16.png"
25 inkscape:export-xdpi="90"
26 inkscape:export-ydpi="90"><metadata
27 id="metadata9"><rdf:RDF><cc:Work
28 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
29 rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
30 id="defs7"><marker
31 inkscape:stockid="DiamondLstart"
32 orient="auto"
33 refY="0.0"
34 refX="0.0"
35 id="DiamondLstart"
36 style="overflow:visible"><path
37 id="path4964"
38 d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z "
39 style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
40 transform="scale(0.8) translate(7,0)" /></marker><linearGradient
41 inkscape:collect="always"
42 id="linearGradient4352"><stop
43 style="stop-color:#ff4141;stop-opacity:0"
44 offset="0"
45 id="stop4354" /><stop
46 id="stop4362"
47 offset="0.24227905"
48 style="stop-color:#ff4141;stop-opacity:0.78823529;" /><stop
49 id="stop4360"
50 offset="0.73632693"
51 style="stop-color:#ff4141;stop-opacity:0" /><stop
52 style="stop-color:#ff4141;stop-opacity:1"
53 offset="1"
54 id="stop4356" /></linearGradient><linearGradient
55 id="linearGradient4392"><stop
56 style="stop-color:#666666;stop-opacity:1;"
57 offset="0"
58 id="stop4394" /><stop
59 style="stop-color:#424242;stop-opacity:1;"
60 offset="1"
61 id="stop4396" /></linearGradient><linearGradient
62 id="linearGradient4392-45"><stop
63 style="stop-color:#666666;stop-opacity:1;"
64 offset="0"
65 id="stop4394-8" /><stop
66 style="stop-color:#424242;stop-opacity:1;"
67 offset="1"
68 id="stop4396-68" /></linearGradient><linearGradient
69 id="linearGradient4392-7-7"><stop
70 style="stop-color:#666666;stop-opacity:1;"
71 offset="0"
72 id="stop4394-2-8" /><stop
73 style="stop-color:#424242;stop-opacity:1;"
74 offset="1"
75 id="stop4396-7-9" /></linearGradient><filter
76 id="filter3224-1-7-1"
77 inkscape:label="Inner Shadow"
78 inkscape:menu="Shadows and Glows"
79 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
80 color-interpolation-filters="sRGB"
81 width="1"
82 height="1"
83 y="0"
84 x="0"><feOffset
85 id="feOffset3228-5-5-5"
86 dx="0"
87 dy="1.2"
88 result="result11" /><feComposite
89 id="feComposite3230-2-4-1"
90 in2="result11"
91 result="result6"
92 in="SourceGraphic"
93 operator="in" /><feFlood
94 id="feFlood3232-7-3-4"
95 result="result10"
96 in="result6"
97 flood-opacity="1"
98 flood-color="rgb(34,34,34)" /><feBlend
99 id="feBlend3234-6-3-5"
100 in2="result10"
101 mode="normal"
102 in="result6"
103 result="result12" /><feComposite
104 id="feComposite3236-1-3-5"
105 in2="SourceGraphic"
106 result="result2"
107 operator="in" /></filter><filter
108 id="filter3224-1-7-1-3"
109 inkscape:label="Inner Shadow"
110 inkscape:menu="Shadows and Glows"
111 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
112 color-interpolation-filters="sRGB"
113 width="1"
114 height="1"
115 y="0"
116 x="0"><feOffset
117 id="feOffset3228-5-5-5-70"
118 dx="0"
119 dy="1.2"
120 result="result11" /><feComposite
121 id="feComposite3230-2-4-1-9"
122 in2="result11"
123 result="result6"
124 in="SourceGraphic"
125 operator="in" /><feFlood
126 id="feFlood3232-7-3-4-91"
127 result="result10"
128 in="result6"
129 flood-opacity="1"
130 flood-color="rgb(34,34,34)" /><feBlend
131 id="feBlend3234-6-3-5-53"
132 in2="result10"
133 mode="normal"
134 in="result6"
135 result="result12" /><feComposite
136 id="feComposite3236-1-3-5-3"
137 in2="SourceGraphic"
138 result="result2"
139 operator="in" /></filter><linearGradient
140 inkscape:collect="always"
141 xlink:href="#linearGradient4392-45"
142 id="linearGradient4838"
143 gradientUnits="userSpaceOnUse"
144 gradientTransform="matrix(1.33333,0,0,1.33333,48.36541,-271.81697)"
145 x1="91"
146 y1="204"
147 x2="91"
148 y2="216" /><linearGradient
149 inkscape:collect="always"
150 xlink:href="#linearGradient4392-45"
151 id="linearGradient4840"
152 gradientUnits="userSpaceOnUse"
153 gradientTransform="matrix(-1,0,0,-1,511,96.250061)"
154 x1="472"
155 y1="17"
156 x2="472"
157 y2="31" /><linearGradient
158 inkscape:collect="always"
159 xlink:href="#linearGradient4392-45"
160 id="linearGradient4842"
161 gradientUnits="userSpaceOnUse"
162 gradientTransform="translate(47.88294,17.406131)"
163 x1="55"
164 y1="51"
165 x2="55"
166 y2="63" /><linearGradient
167 inkscape:collect="always"
168 xlink:href="#linearGradient4392-45"
169 id="linearGradient4844"
170 gradientUnits="userSpaceOnUse"
171 gradientTransform="translate(-95,49.250061)"
172 x1="136"
173 y1="50"
174 x2="136"
175 y2="62" /><linearGradient
176 inkscape:collect="always"
177 xlink:href="#linearGradient4392-45"
178 id="linearGradient4846"
179 gradientUnits="userSpaceOnUse"
180 gradientTransform="translate(-15,49.250061)"
181 x1="120"
182 y1="50"
183 x2="120"
184 y2="62" /><linearGradient
185 inkscape:collect="always"
186 xlink:href="#linearGradient4392-45"
187 id="linearGradient4848"
188 gradientUnits="userSpaceOnUse"
189 gradientTransform="translate(-79,49.250061)"
190 x1="88"
191 y1="50"
192 x2="88"
193 y2="63" /><linearGradient
194 inkscape:collect="always"
195 xlink:href="#linearGradient4392-45"
196 id="linearGradient4850"
197 gradientUnits="userSpaceOnUse"
198 gradientTransform="translate(-271,80.250061)"
199 x1="343"
200 y1="50"
201 x2="343"
202 y2="63" /><linearGradient
203 inkscape:collect="always"
204 xlink:href="#linearGradient4392-45"
205 id="linearGradient4852"
206 gradientUnits="userSpaceOnUse"
207 gradientTransform="translate(148,91.176371)"
208 x1="148"
209 y1="73.073685"
210 x2="148"
211 y2="84.073685" /><linearGradient
212 inkscape:collect="always"
213 xlink:href="#linearGradient4392-45"
214 id="linearGradient4856"
215 gradientUnits="userSpaceOnUse"
216 gradientTransform="translate(-367,176.25006)"
217 x1="407"
218 y1="113"
219 x2="407"
220 y2="127" /><linearGradient
221 inkscape:collect="always"
222 xlink:href="#linearGradient4392-45"
223 id="linearGradient4858"
224 gradientUnits="userSpaceOnUse"
225 gradientTransform="matrix(1.1649013,0,0,1.1649013,-385.36445,145.3613)"
226 x1="365"
227 y1="96.073685"
228 x2="365"
229 y2="108.07368" /><linearGradient
230 inkscape:collect="always"
231 xlink:href="#linearGradient4392-45"
232 id="linearGradient4860"
233 gradientUnits="userSpaceOnUse"
234 gradientTransform="matrix(1.33333,0,0,1.33333,-414.467,95.072771)"
235 x1="365"
236 y1="73.073685"
237 x2="365"
238 y2="84.073685" /><linearGradient
239 inkscape:collect="always"
240 xlink:href="#linearGradient4392-45"
241 id="linearGradient4862"
242 gradientUnits="userSpaceOnUse"
243 gradientTransform="matrix(1.1673123,0,0,1.1673123,-226.67995,74.209541)"
244 x1="366"
245 y1="48.073685"
246 x2="366"
247 y2="60.073685" /><linearGradient
248 inkscape:collect="always"
249 xlink:href="#linearGradient4392-45"
250 id="linearGradient4864"
251 gradientUnits="userSpaceOnUse"
252 gradientTransform="matrix(1.1111083,0,0,1.1111083,-186.99896,-192.59658)"
253 x1="378"
254 y1="205"
255 x2="378"
256 y2="214" /><linearGradient
257 inkscape:collect="always"
258 xlink:href="#linearGradient4392-45"
259 id="linearGradient4866"
260 gradientUnits="userSpaceOnUse"
261 gradientTransform="translate(178.99998,90.187541)"
262 x1="246"
263 y1="73.073685"
264 x2="246"
265 y2="84.073685" /><linearGradient
266 inkscape:collect="always"
267 xlink:href="#linearGradient4392-45"
268 id="linearGradient4868"
269 gradientUnits="userSpaceOnUse"
270 gradientTransform="translate(170.99998,90.187541)"
271 x1="222"
272 y1="73.073685"
273 x2="222"
274 y2="84.073685" /><linearGradient
275 inkscape:collect="always"
276 xlink:href="#linearGradient4392-45"
277 id="linearGradient4870"
278 gradientUnits="userSpaceOnUse"
279 gradientTransform="matrix(1.0131693,0,0,1.0131693,160.31347,89.185861)"
280 x1="197"
281 y1="73.073685"
282 x2="197"
283 y2="84.073685" /><linearGradient
284 inkscape:collect="always"
285 xlink:href="#linearGradient4392-45"
286 id="linearGradient4872"
287 gradientUnits="userSpaceOnUse"
288 gradientTransform="translate(154.99998,90.187541)"
289 x1="171"
290 y1="73.073685"
291 x2="171"
292 y2="84.073685" /><linearGradient
293 inkscape:collect="always"
294 xlink:href="#linearGradient4392-45"
295 id="linearGradient4874"
296 gradientUnits="userSpaceOnUse"
297 gradientTransform="matrix(1.2458722,0,0,1.1615489,-281.43958,-203.65157)"
298 x1="233"
299 y1="204"
300 x2="233"
301 y2="216" /><linearGradient
302 inkscape:collect="always"
303 xlink:href="#linearGradient4392-45"
304 id="linearGradient4876"
305 gradientUnits="userSpaceOnUse"
306 gradientTransform="matrix(1.1666672,0,0,1.1723864,-10.00007,112.59337)"
307 x1="126"
308 y1="96.073685"
309 x2="126"
310 y2="108.07368" /><linearGradient
311 inkscape:collect="always"
312 xlink:href="#linearGradient4392-45"
313 id="linearGradient4878"
314 gradientUnits="userSpaceOnUse"
315 gradientTransform="matrix(1.33333,0,0,1.1621519,95.65429,77.66723)"
316 x1="124"
317 y1="74.073685"
318 x2="124"
319 y2="82.073685" /><linearGradient
320 inkscape:collect="always"
321 xlink:href="#linearGradient4392-45"
322 id="linearGradient4880"
323 gradientUnits="userSpaceOnUse"
324 gradientTransform="matrix(1.1666666,0,0,1.1666669,-22,113.17048)"
325 x1="54"
326 y1="96.073685"
327 x2="54"
328 y2="108.07368" /><linearGradient
329 inkscape:collect="always"
330 xlink:href="#linearGradient4392-45"
331 id="linearGradient4882"
332 gradientUnits="userSpaceOnUse"
333 gradientTransform="matrix(1.33333,0,0,1.33333,-111.63459,-272.81697)"
334 x1="91"
335 y1="204"
336 x2="91"
337 y2="216" /><linearGradient
338 inkscape:collect="always"
339 xlink:href="#linearGradient4392-45"
340 id="linearGradient4884"
341 gradientUnits="userSpaceOnUse"
342 gradientTransform="matrix(1.33333,0,0,1.33333,-111.63459,-272.81697)"
343 x1="91"
344 y1="204"
345 x2="91"
346 y2="216" /><linearGradient
347 inkscape:collect="always"
348 xlink:href="#linearGradient4392-45"
349 id="linearGradient4886"
350 gradientUnits="userSpaceOnUse"
351 gradientTransform="matrix(1.1458395,0,0,1.1458395,-24.974994,183.6777)"
352 x1="30"
353 y1="120.07368"
354 x2="30"
355 y2="132.07368" /><linearGradient
356 inkscape:collect="always"
357 xlink:href="#linearGradient4392-45"
358 id="linearGradient4888"
359 gradientUnits="userSpaceOnUse"
360 gradientTransform="matrix(1.2584059,0,0,1.2584059,-26.9426,202.63781)"
361 x1="54"
362 y1="122.07368"
363 x2="54"
364 y2="130.07368" /><linearGradient
365 inkscape:collect="always"
366 xlink:href="#linearGradient4392-45"
367 id="linearGradient4890"
368 gradientUnits="userSpaceOnUse"
369 gradientTransform="matrix(1.1739937,0,0,1.1739937,-39.36396,212.27908)"
370 x1="150"
371 y1="120.07368"
372 x2="150"
373 y2="132.07368" /><linearGradient
374 inkscape:collect="always"
375 xlink:href="#linearGradient4392-45"
376 id="linearGradient4892"
377 gradientUnits="userSpaceOnUse"
378 gradientTransform="matrix(1.33333,0,0,1.33333,-30.36848,96.482511)"
379 x1="150"
380 y1="97.073685"
381 x2="150"
382 y2="107.07368" /><linearGradient
383 inkscape:collect="always"
384 xlink:href="#linearGradient4392-45"
385 id="linearGradient4894"
386 gradientUnits="userSpaceOnUse"
387 gradientTransform="matrix(1.1666648,0,0,1.1666669,34.00037,113.17712)"
388 x1="198"
389 y1="96.073685"
390 x2="198"
391 y2="108.07368" /><linearGradient
392 inkscape:collect="always"
393 xlink:href="#linearGradient4392-45"
394 id="linearGradient4898"
395 gradientUnits="userSpaceOnUse"
396 gradientTransform="translate(97,-203.74994)"
397 x1="136"
398 y1="204"
399 x2="136"
400 y2="220" /><linearGradient
401 inkscape:collect="always"
402 xlink:href="#linearGradient4392-45"
403 id="linearGradient4900"
404 gradientUnits="userSpaceOnUse"
405 gradientTransform="translate(-111,48.250061)"
406 x1="184"
407 y1="50"
408 x2="184"
409 y2="62" /><linearGradient
410 inkscape:collect="always"
411 xlink:href="#linearGradient4392-45"
412 id="linearGradient4904"
413 gradientUnits="userSpaceOnUse"
414 gradientTransform="translate(81,48.250061)"
415 x1="216"
416 y1="51.999996"
417 x2="216"
418 y2="59.999996" /><linearGradient
419 inkscape:collect="always"
420 xlink:href="#linearGradient4392-45"
421 id="linearGradient4906"
422 gradientUnits="userSpaceOnUse"
423 gradientTransform="translate(-271,79.250061)"
424 x1="407"
425 y1="51"
426 x2="407"
427 y2="62" /><linearGradient
428 inkscape:collect="always"
429 xlink:href="#linearGradient4392-45"
430 id="linearGradient4908"
431 gradientUnits="userSpaceOnUse"
432 gradientTransform="translate(-239,78.250061)"
433 x1="407"
434 y1="51"
435 x2="407"
436 y2="62" /><linearGradient
437 inkscape:collect="always"
438 xlink:href="#linearGradient4392-45"
439 id="linearGradient4910"
440 gradientUnits="userSpaceOnUse"
441 gradientTransform="translate(-79,48.250061)"
442 x1="87"
443 y1="16.999994"
444 x2="87"
445 y2="30.999994" /><linearGradient
446 inkscape:collect="always"
447 xlink:href="#linearGradient4392-45"
448 id="linearGradient4912"
449 gradientUnits="userSpaceOnUse"
450 gradientTransform="matrix(-1.1111083,0,0,1.1111083,716.999,-192.59658)"
451 x1="378"
452 y1="205"
453 x2="378"
454 y2="214" /><linearGradient
455 inkscape:collect="always"
456 xlink:href="#linearGradient4392-45"
457 id="linearGradient4914"
458 gradientUnits="userSpaceOnUse"
459 gradientTransform="translate(17,80.250061)"
460 x1="57"
461 y1="83"
462 x2="57"
463 y2="94" /><linearGradient
464 inkscape:collect="always"
465 xlink:href="#linearGradient4392-45"
466 id="linearGradient4916"
467 gradientUnits="userSpaceOnUse"
468 gradientTransform="translate(49,80.250061)"
469 x1="87"
470 y1="82"
471 x2="87"
472 y2="95" /><linearGradient
473 inkscape:collect="always"
474 xlink:href="#linearGradient4392-45"
475 id="linearGradient4918"
476 gradientUnits="userSpaceOnUse"
477 gradientTransform="matrix(-1,0,0,1,321,80.250061)"
478 x1="87"
479 y1="82"
480 x2="87"
481 y2="95" /><linearGradient
482 inkscape:collect="always"
483 xlink:href="#linearGradient4392-45"
484 id="linearGradient4920"
485 gradientUnits="userSpaceOnUse"
486 gradientTransform="translate(113,81.250061)"
487 x1="344"
488 y1="82"
489 x2="344"
490 y2="93" /><linearGradient
491 inkscape:collect="always"
492 xlink:href="#linearGradient4392-45"
493 id="linearGradient4922"
494 gradientUnits="userSpaceOnUse"
495 gradientTransform="translate(113,81.250061)"
496 x1="375"
497 y1="82"
498 x2="375"
499 y2="93" /><linearGradient
500 inkscape:collect="always"
501 xlink:href="#linearGradient4392-45"
502 id="linearGradient4924"
503 gradientUnits="userSpaceOnUse"
504 gradientTransform="matrix(1.2587978,0,0,1.2587978,-390.22595,101.39303)"
505 x1="340"
506 y1="75.073685"
507 x2="340"
508 y2="84.073685" /><linearGradient
509 inkscape:collect="always"
510 xlink:href="#linearGradient4392-45"
511 id="linearGradient4926"
512 gradientUnits="userSpaceOnUse"
513 gradientTransform="translate(49,80.250061)"
514 x1="87"
515 y1="82"
516 x2="87"
517 y2="95" /><linearGradient
518 inkscape:collect="always"
519 xlink:href="#linearGradient4392-45"
520 id="linearGradient4928"
521 gradientUnits="userSpaceOnUse"
522 gradientTransform="translate(81.11142,80.250041)"
523 x1="87"
524 y1="82"
525 x2="87"
526 y2="95" /><linearGradient
527 inkscape:collect="always"
528 xlink:href="#linearGradient4392-45"
529 id="linearGradient4930"
530 gradientUnits="userSpaceOnUse"
531 gradientTransform="matrix(-1,0,0,1,289,80.250051)"
532 x1="87"
533 y1="82"
534 x2="87"
535 y2="95" /><linearGradient
536 inkscape:collect="always"
537 xlink:href="#linearGradient4392-45"
538 id="linearGradient4932"
539 gradientUnits="userSpaceOnUse"
540 gradientTransform="translate(-15,112.25006)"
541 x1="24"
542 y1="114"
543 x2="24"
544 y2="126" /><linearGradient
545 inkscape:collect="always"
546 xlink:href="#linearGradient4392-45"
547 id="linearGradient4934"
548 gradientUnits="userSpaceOnUse"
549 gradientTransform="translate(-15,112.25006)"
550 x1="216"
551 y1="115"
552 x2="216"
553 y2="126" /><linearGradient
554 inkscape:collect="always"
555 xlink:href="#linearGradient4392-45"
556 id="linearGradient4936"
557 gradientUnits="userSpaceOnUse"
558 gradientTransform="translate(207,48.250051)"
559 x1="120"
560 y1="50"
561 x2="120"
562 y2="62" /><linearGradient
563 inkscape:collect="always"
564 xlink:href="#linearGradient4392-45"
565 id="linearGradient4938"
566 gradientUnits="userSpaceOnUse"
567 gradientTransform="translate(16,48.250051)"
568 x1="120"
569 y1="50"
570 x2="120"
571 y2="62" /><linearGradient
572 inkscape:collect="always"
573 xlink:href="#linearGradient4392-45"
574 id="linearGradient4940"
575 gradientUnits="userSpaceOnUse"
576 gradientTransform="translate(81.18519,49.361171)"
577 x1="120"
578 y1="50"
579 x2="120"
580 y2="62" /><linearGradient
581 inkscape:collect="always"
582 xlink:href="#linearGradient4392-45"
583 id="linearGradient4944"
584 gradientUnits="userSpaceOnUse"
585 gradientTransform="matrix(0.95906074,0,0,0.83983765,-245.54139,86.680785)"
586 x1="263.14438"
587 y1="53.202732"
588 x2="263.14438"
589 y2="65.97139" /><linearGradient
590 inkscape:collect="always"
591 xlink:href="#linearGradient4392-45"
592 id="linearGradient4946"
593 gradientUnits="userSpaceOnUse"
594 x1="324.89481"
595 y1="49.999996"
596 x2="327.98953"
597 y2="61.999996" /><linearGradient
598 inkscape:collect="always"
599 xlink:href="#linearGradient4392-45"
600 id="linearGradient4948"
601 gradientUnits="userSpaceOnUse"
602 x1="324.89481"
603 y1="49.999996"
604 x2="327.98953"
605 y2="61.999996" /><linearGradient
606 inkscape:collect="always"
607 xlink:href="#linearGradient4392-45"
608 id="linearGradient4950"
609 gradientUnits="userSpaceOnUse"
610 x1="263.14438"
611 y1="53.202732"
612 x2="263.14438"
613 y2="65.97139" /><linearGradient
614 inkscape:collect="always"
615 xlink:href="#linearGradient4392-45"
616 id="linearGradient4952"
617 gradientUnits="userSpaceOnUse"
618 x1="263.14438"
619 y1="53.202732"
620 x2="263.14438"
621 y2="65.97139" /><linearGradient
622 inkscape:collect="always"
623 xlink:href="#linearGradient4392-45"
624 id="linearGradient4954"
625 gradientUnits="userSpaceOnUse"
626 gradientTransform="matrix(-1.1111083,0,0,1.1111083,684.999,-192.59658)"
627 x1="378"
628 y1="205"
629 x2="378"
630 y2="214" /><linearGradient
631 inkscape:collect="always"
632 xlink:href="#linearGradient4392-45"
633 id="linearGradient4956"
634 gradientUnits="userSpaceOnUse"
635 gradientTransform="matrix(1.1111083,0,0,1.1111083,-90.99896,-192.59658)"
636 x1="378"
637 y1="205"
638 x2="378"
639 y2="214" /><linearGradient
640 inkscape:collect="always"
641 xlink:href="#linearGradient4392-45"
642 id="linearGradient4958"
643 gradientUnits="userSpaceOnUse"
644 gradientTransform="matrix(-1,0,0,1,352.81481,49.361171)"
645 x1="120"
646 y1="50"
647 x2="120"
648 y2="62" /><linearGradient
649 inkscape:collect="always"
650 xlink:href="#linearGradient4392-45"
651 id="linearGradient4960"
652 gradientUnits="userSpaceOnUse"
653 gradientTransform="matrix(-1.33333,0,0,1.33333,593.467,95.072771)"
654 x1="365"
655 y1="73.073685"
656 x2="365"
657 y2="84.073685" /><linearGradient
658 inkscape:collect="always"
659 xlink:href="#linearGradient4392-45"
660 id="linearGradient4962"
661 gradientUnits="userSpaceOnUse"
662 gradientTransform="matrix(-1,0,0,1,481,176.25006)"
663 x1="407"
664 y1="113"
665 x2="407"
666 y2="127" /><linearGradient
667 inkscape:collect="always"
668 xlink:href="#linearGradient4392-7-7"
669 id="linearGradient4964"
670 gradientUnits="userSpaceOnUse"
671 gradientTransform="translate(-207,-111.74995)"
672 x1="280"
673 y1="112"
674 x2="280"
675 y2="128" /><linearGradient
676 inkscape:collect="always"
677 xlink:href="#linearGradient4392-45"
678 id="linearGradient4966"
679 gradientUnits="userSpaceOnUse"
680 gradientTransform="translate(57,80.250061)"
681 x1="57"
682 y1="83"
683 x2="57"
684 y2="94" /><linearGradient
685 inkscape:collect="always"
686 xlink:href="#linearGradient4392-45"
687 id="linearGradient4968"
688 gradientUnits="userSpaceOnUse"
689 gradientTransform="matrix(-1,0,0,1,449,112.25006)"
690 x1="216"
691 y1="115"
692 x2="216"
693 y2="126" /><linearGradient
694 inkscape:collect="always"
695 xlink:href="#linearGradient4392-45"
696 id="linearGradient4970"
697 gradientUnits="userSpaceOnUse"
698 gradientTransform="matrix(1.1666672,0,0,1.1723864,-106.00007,208.59337)"
699 x1="126"
700 y1="96.073685"
701 x2="126"
702 y2="108.07368" /><linearGradient
703 inkscape:collect="always"
704 xlink:href="#linearGradient4392"
705 id="linearGradient4972"
706 gradientUnits="userSpaceOnUse"
707 x1="104"
708 y1="230.99998"
709 x2="104"
710 y2="232.99998"
711 gradientTransform="translate(1.0000001,0.25006141)" /><linearGradient
712 inkscape:collect="always"
713 xlink:href="#linearGradient4392-45"
714 id="linearGradient4974"
715 gradientUnits="userSpaceOnUse"
716 gradientTransform="translate(47,47.99999)"
717 x1="120"
718 y1="50"
719 x2="120"
720 y2="62" /><linearGradient
721 inkscape:collect="always"
722 xlink:href="#linearGradient4392-45"
723 id="linearGradient4980"
724 gradientUnits="userSpaceOnUse"
725 gradientTransform="matrix(1.33333,0,0,1.33333,144.36541,-271.81697)"
726 x1="91"
727 y1="204"
728 x2="91"
729 y2="216" /><linearGradient
730 inkscape:collect="always"
731 xlink:href="#linearGradient4392-45"
732 id="linearGradient4982"
733 gradientUnits="userSpaceOnUse"
734 gradientTransform="matrix(1.33333,0,0,1.33333,-111.63459,-271.81697)"
735 x1="91"
736 y1="204"
737 x2="91"
738 y2="216" /><linearGradient
739 inkscape:collect="always"
740 xlink:href="#linearGradient4392-45"
741 id="linearGradient4984"
742 gradientUnits="userSpaceOnUse"
743 gradientTransform="matrix(1.33333,0,0,1.33333,-80.63459,-273.06703)"
744 x1="91"
745 y1="204"
746 x2="91"
747 y2="216" /><linearGradient
748 inkscape:collect="always"
749 xlink:href="#linearGradient4392-45"
750 id="linearGradient4986"
751 gradientUnits="userSpaceOnUse"
752 gradientTransform="matrix(1.33333,0,0,1.33333,-80.63459,-273.06703)"
753 x1="91"
754 y1="204"
755 x2="91"
756 y2="216" /><linearGradient
757 inkscape:collect="always"
758 xlink:href="#linearGradient4392-45"
759 id="linearGradient4988"
760 gradientUnits="userSpaceOnUse"
761 gradientTransform="matrix(1.33333,0,0,1.33333,-79.63459,-272.06703)"
762 x1="91"
763 y1="204"
764 x2="91"
765 y2="216" /><linearGradient
766 inkscape:collect="always"
767 xlink:href="#linearGradient4392-45"
768 id="linearGradient4990"
769 gradientUnits="userSpaceOnUse"
770 gradientTransform="matrix(1.33333,0,0,1.33333,-15.63459,-271.81697)"
771 x1="91"
772 y1="204"
773 x2="91"
774 y2="216" /><linearGradient
775 inkscape:collect="always"
776 xlink:href="#linearGradient4392-45"
777 id="linearGradient4992"
778 gradientUnits="userSpaceOnUse"
779 gradientTransform="matrix(1.33333,0,0,1.33333,16.36541,-272.06703)"
780 x1="91"
781 y1="204"
782 x2="91"
783 y2="216" /><linearGradient
784 inkscape:collect="always"
785 xlink:href="#linearGradient4392-45"
786 id="linearGradient4994"
787 gradientUnits="userSpaceOnUse"
788 gradientTransform="matrix(1.33333,0,0,1.33333,176.36541,-271.81697)"
789 x1="91"
790 y1="204"
791 x2="91"
792 y2="216" /><linearGradient
793 inkscape:collect="always"
794 xlink:href="#linearGradient4392-45"
795 id="linearGradient4996"
796 gradientUnits="userSpaceOnUse"
797 gradientTransform="matrix(1.33333,0,0,1.33333,-80.63459,-244.81697)"
798 x1="91"
799 y1="204"
800 x2="91"
801 y2="216" /><linearGradient
802 inkscape:collect="always"
803 xlink:href="#linearGradient4392-45"
804 id="linearGradient5002"
805 gradientUnits="userSpaceOnUse"
806 gradientTransform="matrix(1.33333,0,0,1.33333,67.36541,-272.06703)"
807 x1="91"
808 y1="204"
809 x2="91"
810 y2="216" /><linearGradient
811 inkscape:collect="always"
812 xlink:href="#linearGradient4392-45"
813 id="linearGradient5004"
814 gradientUnits="userSpaceOnUse"
815 gradientTransform="matrix(1.33333,0,0,1.33333,208.36541,-272.06703)"
816 x1="91"
817 y1="204"
818 x2="91"
819 y2="216" /><linearGradient
820 inkscape:collect="always"
821 xlink:href="#linearGradient4392"
822 id="linearGradient6476"
823 gradientUnits="userSpaceOnUse"
824 gradientTransform="translate(17,-2.7499485)"
825 x1="56"
826 y1="225"
827 x2="56"
828 y2="239" /><linearGradient
829 id="linearGradient4392-45-3"><stop
830 style="stop-color:#666666;stop-opacity:1;"
831 offset="0"
832 id="stop4394-8-2" /><stop
833 style="stop-color:#424242;stop-opacity:1;"
834 offset="1"
835 id="stop4396-68-9" /></linearGradient><filter
836 id="filter3224-1-7-1-2"
837 inkscape:label="Inner Shadow"
838 inkscape:menu="Shadows and Glows"
839 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
840 color-interpolation-filters="sRGB"
841 width="1"
842 height="1"
843 y="0"
844 x="0"><feOffset
845 id="feOffset3228-5-5-5-0"
846 dx="0"
847 dy="1.2"
848 result="result11" /><feComposite
849 id="feComposite3230-2-4-1-5"
850 in2="result11"
851 result="result6"
852 in="SourceGraphic"
853 operator="in" /><feFlood
854 id="feFlood3232-7-3-4-1"
855 result="result10"
856 in="result6"
857 flood-opacity="1"
858 flood-color="rgb(34,34,34)" /><feBlend
859 id="feBlend3234-6-3-5-8"
860 in2="result10"
861 mode="normal"
862 in="result6"
863 result="result12" /><feComposite
864 id="feComposite3236-1-3-5-5"
865 in2="SourceGraphic"
866 result="result2"
867 operator="in" /></filter><linearGradient
868 y2="108.07368"
869 x2="342"
870 y1="97.073685"
871 x1="342"
872 gradientTransform="matrix(1.2681238,0,0,1.2681238,-424.35773,135.21343)"
873 gradientUnits="userSpaceOnUse"
874 id="linearGradient7390"
875 xlink:href="#linearGradient4392-45-3"
876 inkscape:collect="always" /><linearGradient
877 inkscape:collect="always"
878 xlink:href="#linearGradient4392"
879 id="linearGradient3645"
880 gradientUnits="userSpaceOnUse"
881 gradientTransform="translate(33,0.25005141)"
882 x1="72"
883 y1="32"
884 x2="72"
885 y2="47" /><linearGradient
886 inkscape:collect="always"
887 xlink:href="#linearGradient4392"
888 id="linearGradient3667"
889 gradientUnits="userSpaceOnUse"
890 gradientTransform="matrix(-1,0,0,1,209,0.25005141)"
891 x1="72"
892 y1="32"
893 x2="72"
894 y2="47" /><linearGradient
895 inkscape:collect="always"
896 xlink:href="#linearGradient4392"
897 id="linearGradient3726"
898 gradientUnits="userSpaceOnUse"
899 x1="72"
900 y1="32"
901 x2="72"
902 y2="47"
903 gradientTransform="translate(1.0000001,0.25005141)" /><linearGradient
904 inkscape:collect="always"
905 xlink:href="#linearGradient4392"
906 id="linearGradient3809"
907 x1="264"
908 y1="114"
909 x2="264"
910 y2="121"
911 gradientUnits="userSpaceOnUse"
912 gradientTransform="translate(1.0000001,-13.749949)" /><linearGradient
913 inkscape:collect="always"
914 xlink:href="#linearGradient4392-45"
915 id="linearGradient3576"
916 gradientUnits="userSpaceOnUse"
917 gradientTransform="matrix(1.33333,0,0,1.33333,-478.467,255.07277)"
918 x1="365"
919 y1="73.073685"
920 x2="365"
921 y2="84.073685" /><linearGradient
922 inkscape:collect="always"
923 xlink:href="#linearGradient4352"
924 id="linearGradient4358"
925 x1="366.95544"
926 y1="335.06354"
927 x2="356.00427"
928 y2="335.08957"
929 gradientUnits="userSpaceOnUse"
930 gradientTransform="matrix(0.90909091,0,0,1,-318.63636,23.250061)" /><linearGradient
931 inkscape:collect="always"
932 xlink:href="#linearGradient4392-45"
933 id="linearGradient3629"
934 gradientUnits="userSpaceOnUse"
935 gradientTransform="matrix(1.33333,0,0,1.33333,-127.467,242.82272)"
936 x1="365"
937 y1="73.073685"
938 x2="365"
939 y2="84.073685" /><linearGradient
940 inkscape:collect="always"
941 xlink:href="#linearGradient4352"
942 id="linearGradient3631"
943 gradientUnits="userSpaceOnUse"
944 gradientTransform="matrix(0.90909091,0,0,1,32.363636,11)"
945 x1="366.95544"
946 y1="335.06354"
947 x2="356.00427"
948 y2="335.08957" /><linearGradient
949 inkscape:collect="always"
950 xlink:href="#linearGradient4392-45"
951 id="linearGradient3633"
952 gradientUnits="userSpaceOnUse"
953 gradientTransform="matrix(1.33333,0,0,1.33333,-127.467,242.82271)"
954 x1="365"
955 y1="73.073685"
956 x2="365"
957 y2="84.073685" /><linearGradient
958 inkscape:collect="always"
959 xlink:href="#linearGradient4352"
960 id="linearGradient3635"
961 gradientUnits="userSpaceOnUse"
962 gradientTransform="matrix(0.90909091,0,0,1,32.363636,11)"
963 x1="366.95544"
964 y1="335.06354"
965 x2="356.00427"
966 y2="335.08957" /><linearGradient
967 inkscape:collect="always"
968 xlink:href="#linearGradient4392-45"
969 id="linearGradient4406"
970 gradientUnits="userSpaceOnUse"
971 gradientTransform="matrix(1.33333,0,0,1.33333,-478.467,255.07277)"
972 x1="365"
973 y1="73.073685"
974 x2="365"
975 y2="84.073685" /><linearGradient
976 inkscape:collect="always"
977 xlink:href="#linearGradient4392"
978 id="linearGradient4386"
979 x1="73"
980 y1="321"
981 x2="73"
982 y2="335"
983 gradientUnits="userSpaceOnUse"
984 gradientTransform="translate(1.0000001,0.25005141)" /><linearGradient
985 inkscape:collect="always"
986 xlink:href="#linearGradient4392"
987 id="linearGradient4388"
988 x1="69"
989 y1="323"
990 x2="69"
991 y2="333"
992 gradientUnits="userSpaceOnUse" /><linearGradient
993 inkscape:collect="always"
994 xlink:href="#linearGradient4392-3"
995 id="linearGradient4386-0"
996 x1="73"
997 y1="321"
998 x2="73"
999 y2="335"
1000 gradientUnits="userSpaceOnUse" /><linearGradient
1001 id="linearGradient4392-3"><stop
1002 style="stop-color:#666666;stop-opacity:1;"
1003 offset="0"
1004 id="stop4394-6" /><stop
1005 style="stop-color:#424242;stop-opacity:1;"
1006 offset="1"
1007 id="stop4396-8" /></linearGradient><filter
1008 id="filter3224-1-7-1-2-7"
1009 inkscape:label="Inner Shadow"
1010 inkscape:menu="Shadows and Glows"
1011 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1012 color-interpolation-filters="sRGB"
1013 width="1"
1014 height="1"
1015 y="0"
1016 x="0"><feOffset
1017 id="feOffset3228-5-5-5-0-0"
1018 dx="0"
1019 dy="1.2"
1020 result="result11" /><feComposite
1021 id="feComposite3230-2-4-1-5-5"
1022 in2="result11"
1023 result="result6"
1024 in="SourceGraphic"
1025 operator="in" /><feFlood
1026 id="feFlood3232-7-3-4-1-0"
1027 result="result10"
1028 in="result6"
1029 flood-opacity="1"
1030 flood-color="rgb(34,34,34)" /><feBlend
1031 id="feBlend3234-6-3-5-8-2"
1032 in2="result10"
1033 mode="normal"
1034 in="result6"
1035 result="result12" /><feComposite
1036 id="feComposite3236-1-3-5-5-1"
1037 in2="SourceGraphic"
1038 result="result2"
1039 operator="in" /></filter><linearGradient
1040 inkscape:collect="always"
1041 xlink:href="#linearGradient4392-45"
1042 id="linearGradient3947"
1043 gradientUnits="userSpaceOnUse"
1044 gradientTransform="matrix(1.33333,0,0,1.33333,-478.467,255.07277)"
1045 x1="365"
1046 y1="73.073685"
1047 x2="365"
1048 y2="84.073685" /><linearGradient
1049 inkscape:collect="always"
1050 xlink:href="#linearGradient4352"
1051 id="linearGradient3949"
1052 gradientUnits="userSpaceOnUse"
1053 gradientTransform="matrix(0.90909091,0,0,1,-318.63636,23.250061)"
1054 x1="366.95544"
1055 y1="335.06354"
1056 x2="356.00427"
1057 y2="335.08957" /><linearGradient
1058 inkscape:collect="always"
1059 xlink:href="#linearGradient4392"
1060 id="linearGradient3951"
1061 gradientUnits="userSpaceOnUse"
1062 x1="69"
1063 y1="323"
1064 x2="69"
1065 y2="333" /><linearGradient
1066 inkscape:collect="always"
1067 xlink:href="#linearGradient4392"
1068 id="linearGradient3287"
1069 x1="39.452351"
1070 y1="196.14122"
1071 x2="39.452351"
1072 y2="202.77057"
1073 gradientUnits="userSpaceOnUse"
1074 gradientTransform="translate(1.0000001,0.25006141)" /><linearGradient
1075 inkscape:collect="always"
1076 xlink:href="#linearGradient4392"
1077 id="linearGradient3289"
1078 x1="7.0987959"
1079 y1="196.14124"
1080 x2="7.0987959"
1081 y2="202.87701"
1082 gradientUnits="userSpaceOnUse"
1083 gradientTransform="translate(1.0000001,0.25006141)" /><linearGradient
1084 inkscape:collect="always"
1085 xlink:href="#linearGradient4392"
1086 id="linearGradient3291"
1087 x1="38.596195"
1088 y1="163.43153"
1089 x2="38.596195"
1090 y2="174.78519"
1091 gradientUnits="userSpaceOnUse"
1092 gradientTransform="translate(1.0000001,0.25006141)" /><linearGradient
1093 inkscape:collect="always"
1094 xlink:href="#linearGradient4392"
1095 id="linearGradient3293"
1096 x1="9.2478447"
1097 y1="162.9012"
1098 x2="9.2478447"
1099 y2="174.65788"
1100 gradientUnits="userSpaceOnUse"
1101 gradientTransform="translate(1.0000001,0.25006141)" /><linearGradient
1102 inkscape:collect="always"
1103 xlink:href="#linearGradient4392"
1104 id="linearGradient3295"
1105 x1="329"
1106 y1="96.25"
1107 x2="329"
1108 y2="112.25"
1109 gradientUnits="userSpaceOnUse" /><linearGradient
1110 id="linearGradient4392-4"><stop
1111 style="stop-color:#666666;stop-opacity:1;"
1112 offset="0"
1113 id="stop4394-86" /><stop
1114 style="stop-color:#424242;stop-opacity:1;"
1115 offset="1"
1116 id="stop4396-6" /></linearGradient><filter
1117 id="filter3224-1-7-1-3-6"
1118 inkscape:label="Inner Shadow"
1119 inkscape:menu="Shadows and Glows"
1120 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1121 color-interpolation-filters="sRGB"
1122 width="1"
1123 height="1"
1124 y="0"
1125 x="0"><feOffset
1126 id="feOffset3228-5-5-5-70-8"
1127 dx="0"
1128 dy="1.2"
1129 result="result11" /><feComposite
1130 id="feComposite3230-2-4-1-9-3"
1131 in2="result11"
1132 result="result6"
1133 in="SourceGraphic"
1134 operator="in" /><feFlood
1135 id="feFlood3232-7-3-4-91-9"
1136 result="result10"
1137 in="result6"
1138 flood-opacity="1"
1139 flood-color="rgb(34,34,34)" /><feBlend
1140 id="feBlend3234-6-3-5-53-7"
1141 in2="result10"
1142 mode="normal"
1143 in="result6"
1144 result="result12" /><feComposite
1145 id="feComposite3236-1-3-5-3-6"
1146 in2="SourceGraphic"
1147 result="result2"
1148 operator="in" /></filter><linearGradient
1149 inkscape:collect="always"
1150 xlink:href="#linearGradient4392-4"
1151 id="linearGradient6173"
1152 gradientUnits="userSpaceOnUse"
1153 gradientTransform="matrix(2,0,0,2,-32,386.0001)"
1154 x1="88"
1155 y1="161"
1156 x2="88"
1157 y2="174" /><linearGradient
1158 id="linearGradient6287"><stop
1159 style="stop-color:#666666;stop-opacity:1;"
1160 offset="0"
1161 id="stop6289" /><stop
1162 style="stop-color:#424242;stop-opacity:1;"
1163 offset="1"
1164 id="stop6291" /></linearGradient><filter
1165 id="filter6293"
1166 inkscape:label="Inner Shadow"
1167 inkscape:menu="Shadows and Glows"
1168 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1169 color-interpolation-filters="sRGB"
1170 width="1"
1171 height="1"
1172 y="0"
1173 x="0"><feOffset
1174 id="feOffset6295"
1175 dx="0"
1176 dy="1.2"
1177 result="result11" /><feComposite
1178 id="feComposite6297"
1179 in2="result11"
1180 result="result6"
1181 in="SourceGraphic"
1182 operator="in" /><feFlood
1183 id="feFlood6299"
1184 result="result10"
1185 in="result6"
1186 flood-opacity="1"
1187 flood-color="rgb(34,34,34)" /><feBlend
1188 id="feBlend6301"
1189 in2="result10"
1190 mode="normal"
1191 in="result6"
1192 result="result12" /><feComposite
1193 id="feComposite6303"
1194 in2="SourceGraphic"
1195 result="result2"
1196 operator="in" /></filter><linearGradient
1197 inkscape:collect="always"
1198 xlink:href="#linearGradient4392-45"
1199 id="linearGradient3348"
1200 gradientUnits="userSpaceOnUse"
1201 gradientTransform="translate(-15,193.25005)"
1202 x1="88"
1203 y1="161"
1204 x2="88"
1205 y2="174" /><linearGradient
1206 inkscape:collect="always"
1207 xlink:href="#linearGradient4392-45"
1208 id="linearGradient3350"
1209 gradientUnits="userSpaceOnUse"
1210 gradientTransform="translate(17,193.25005)"
1211 x1="88"
1212 y1="161"
1213 x2="88"
1214 y2="174" /><linearGradient
1215 inkscape:collect="always"
1216 xlink:href="#linearGradient4392-45-36"
1217 id="linearGradient4840-7"
1218 gradientUnits="userSpaceOnUse"
1219 gradientTransform="matrix(-1,0,0,-1,511,96.250061)"
1220 x1="472"
1221 y1="17"
1222 x2="472"
1223 y2="31" /><linearGradient
1224 id="linearGradient4392-45-36"><stop
1225 style="stop-color:#666666;stop-opacity:1;"
1226 offset="0"
1227 id="stop4394-8-4" /><stop
1228 style="stop-color:#424242;stop-opacity:1;"
1229 offset="1"
1230 id="stop4396-68-0" /></linearGradient><filter
1231 id="filter3224-1-7-1-21"
1232 inkscape:label="Inner Shadow"
1233 inkscape:menu="Shadows and Glows"
1234 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1235 color-interpolation-filters="sRGB"
1236 width="1"
1237 height="1"
1238 y="0"
1239 x="0"><feOffset
1240 id="feOffset3228-5-5-5-2"
1241 dx="0"
1242 dy="1.2"
1243 result="result11" /><feComposite
1244 id="feComposite3230-2-4-1-2"
1245 in2="result11"
1246 result="result6"
1247 in="SourceGraphic"
1248 operator="in" /><feFlood
1249 id="feFlood3232-7-3-4-3"
1250 result="result10"
1251 in="result6"
1252 flood-opacity="1"
1253 flood-color="rgb(34,34,34)" /><feBlend
1254 id="feBlend3234-6-3-5-4"
1255 in2="result10"
1256 mode="normal"
1257 in="result6"
1258 result="result12" /><feComposite
1259 id="feComposite3236-1-3-5-1"
1260 in2="SourceGraphic"
1261 result="result2"
1262 operator="in" /></filter><linearGradient
1263 inkscape:collect="always"
1264 xlink:href="#linearGradient4392-45-1"
1265 id="linearGradient4563-7"
1266 gradientUnits="userSpaceOnUse"
1267 gradientTransform="matrix(1.1649013,0,0,1.1649013,-321.36445,209.3613)"
1268 x1="365"
1269 y1="96.073685"
1270 x2="365"
1271 y2="108.07368" /><linearGradient
1272 id="linearGradient4392-45-1"><stop
1273 style="stop-color:#666666;stop-opacity:1;"
1274 offset="0"
1275 id="stop4394-8-21" /><stop
1276 style="stop-color:#424242;stop-opacity:1;"
1277 offset="1"
1278 id="stop4396-68-2" /></linearGradient><filter
1279 id="filter3224-1-7-1-5"
1280 inkscape:label="Inner Shadow"
1281 inkscape:menu="Shadows and Glows"
1282 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1283 color-interpolation-filters="sRGB"
1284 width="1"
1285 height="1"
1286 y="0"
1287 x="0"><feOffset
1288 id="feOffset3228-5-5-5-6"
1289 dx="0"
1290 dy="1.2"
1291 result="result11" /><feComposite
1292 id="feComposite3230-2-4-1-0"
1293 in2="result11"
1294 result="result6"
1295 in="SourceGraphic"
1296 operator="in" /><feFlood
1297 id="feFlood3232-7-3-4-6"
1298 result="result10"
1299 in="result6"
1300 flood-opacity="1"
1301 flood-color="rgb(34,34,34)" /><feBlend
1302 id="feBlend3234-6-3-5-6"
1303 in2="result10"
1304 mode="normal"
1305 in="result6"
1306 result="result12" /><feComposite
1307 id="feComposite3236-1-3-5-55"
1308 in2="SourceGraphic"
1309 result="result2"
1310 operator="in" /></filter><linearGradient
1311 y2="108.07368"
1312 x2="365"
1313 y1="96.073685"
1314 x1="365"
1315 gradientTransform="matrix(1.1649013,0,0,1.1649013,-328.36445,204.3613)"
1316 gradientUnits="userSpaceOnUse"
1317 id="linearGradient4604-8"
1318 xlink:href="#linearGradient4392-45-1-0"
1319 inkscape:collect="always" /><linearGradient
1320 id="linearGradient4392-45-1-0"><stop
1321 style="stop-color:#666666;stop-opacity:1;"
1322 offset="0"
1323 id="stop4394-8-21-2" /><stop
1324 style="stop-color:#424242;stop-opacity:1;"
1325 offset="1"
1326 id="stop4396-68-2-2" /></linearGradient><filter
1327 id="filter3224-1-7-1-5-0"
1328 inkscape:label="Inner Shadow"
1329 inkscape:menu="Shadows and Glows"
1330 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1331 color-interpolation-filters="sRGB"
1332 width="1"
1333 height="1"
1334 y="0"
1335 x="0"><feOffset
1336 id="feOffset3228-5-5-5-6-7"
1337 dx="0"
1338 dy="1.2"
1339 result="result11" /><feComposite
1340 id="feComposite3230-2-4-1-0-9"
1341 in2="result11"
1342 result="result6"
1343 in="SourceGraphic"
1344 operator="in" /><feFlood
1345 id="feFlood3232-7-3-4-6-7"
1346 result="result10"
1347 in="result6"
1348 flood-opacity="1"
1349 flood-color="rgb(34,34,34)" /><feBlend
1350 id="feBlend3234-6-3-5-6-4"
1351 in2="result10"
1352 mode="normal"
1353 in="result6"
1354 result="result12" /><feComposite
1355 id="feComposite3236-1-3-5-55-7"
1356 in2="SourceGraphic"
1357 result="result2"
1358 operator="in" /></filter><filter
1359 id="filter3224-1-7-1-5-0-8"
1360 inkscape:label="Inner Shadow"
1361 inkscape:menu="Shadows and Glows"
1362 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1363 color-interpolation-filters="sRGB"
1364 width="1"
1365 height="1"
1366 y="0"
1367 x="0"><feOffset
1368 id="feOffset3228-5-5-5-6-7-6"
1369 dx="0"
1370 dy="1.2"
1371 result="result11" /><feComposite
1372 id="feComposite3230-2-4-1-0-9-3"
1373 in2="result11"
1374 result="result6"
1375 in="SourceGraphic"
1376 operator="in" /><feFlood
1377 id="feFlood3232-7-3-4-6-7-1"
1378 result="result10"
1379 in="result6"
1380 flood-opacity="1"
1381 flood-color="rgb(34,34,34)" /><feBlend
1382 id="feBlend3234-6-3-5-6-4-1"
1383 in2="result10"
1384 mode="normal"
1385 in="result6"
1386 result="result12" /><feComposite
1387 id="feComposite3236-1-3-5-55-7-6"
1388 in2="SourceGraphic"
1389 result="result2"
1390 operator="in" /></filter><filter
1391 id="filter3224-1-7-1-7"
1392 inkscape:label="Inner Shadow"
1393 inkscape:menu="Shadows and Glows"
1394 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1395 color-interpolation-filters="sRGB"
1396 width="1"
1397 height="1"
1398 y="0"
1399 x="0"><feOffset
1400 id="feOffset3228-5-5-5-5"
1401 dx="0"
1402 dy="1.2"
1403 result="result11" /><feComposite
1404 id="feComposite3230-2-4-1-56"
1405 in2="result11"
1406 result="result6"
1407 in="SourceGraphic"
1408 operator="in" /><feFlood
1409 id="feFlood3232-7-3-4-7"
1410 result="result10"
1411 in="result6"
1412 flood-opacity="1"
1413 flood-color="rgb(34,34,34)" /><feBlend
1414 id="feBlend3234-6-3-5-0"
1415 in2="result10"
1416 mode="normal"
1417 in="result6"
1418 result="result12" /><feComposite
1419 id="feComposite3236-1-3-5-9"
1420 in2="SourceGraphic"
1421 result="result2"
1422 operator="in" /></filter><filter
1423 id="filter3224-1-7-1-7-5"
1424 inkscape:label="Inner Shadow"
1425 inkscape:menu="Shadows and Glows"
1426 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1427 color-interpolation-filters="sRGB"
1428 width="1"
1429 height="1"
1430 y="0"
1431 x="0"><feOffset
1432 id="feOffset3228-5-5-5-5-8"
1433 dx="0"
1434 dy="1.2"
1435 result="result11" /><feComposite
1436 id="feComposite3230-2-4-1-56-0"
1437 in2="result11"
1438 result="result6"
1439 in="SourceGraphic"
1440 operator="in" /><feFlood
1441 id="feFlood3232-7-3-4-7-3"
1442 result="result10"
1443 in="result6"
1444 flood-opacity="1"
1445 flood-color="rgb(34,34,34)" /><feBlend
1446 id="feBlend3234-6-3-5-0-5"
1447 in2="result10"
1448 mode="normal"
1449 in="result6"
1450 result="result12" /><feComposite
1451 id="feComposite3236-1-3-5-9-5"
1452 in2="SourceGraphic"
1453 result="result2"
1454 operator="in" /></filter></defs><sodipodi:namedview
1455 pagecolor="#dddddd"
1456 bordercolor="#666666"
1457 borderopacity="1"
1458 objecttolerance="10"
1459 gridtolerance="10"
1460 guidetolerance="10"
1461 inkscape:pageopacity="0"
1462 inkscape:pageshadow="2"
1463 inkscape:window-width="1360"
1464 inkscape:window-height="898"
1465 id="namedview5"
1466 showgrid="true"
1467 inkscape:showpageshadow="false"
1468 inkscape:zoom="22.627417"
1469 inkscape:cx="133.501"
1470 inkscape:cy="41.601897"
1471 inkscape:window-x="363"
1472 inkscape:window-y="91"
1473 inkscape:window-maximized="0"
1474 inkscape:current-layer="layer1"
1475 fit-margin-top="1"
1476 fit-margin-left="0"
1477 fit-margin-bottom="0"
1478 fit-margin-right="2"
1479 showguides="false"
1480 inkscape:guide-bbox="true"><inkscape:grid
1481 type="xygrid"
1482 id="grid2986"
1483 units="px"
1484 empspacing="16"
1485 visible="true"
1486 enabled="true"
1487 snapvisiblegridlinesonly="true"
1488 spacingx="1px"
1489 spacingy="1px"
1490 dotted="false"
1491 originx="0px"
1492 originy="4.0855018e-05px" /></sodipodi:namedview>
1493
1494
1495<g
1496 inkscape:groupmode="layer"
1497 id="layer2"
1498 inkscape:label="Dark background"
1499 style="display:inline"
1500 transform="translate(-1,-0.25001385)"
1501 sodipodi:insensitive="true"><rect
1502 style="fill:#ffaaaa;fill-opacity:1;stroke:none"
1503 id="rect6406"
1504 width="496"
1505 height="368"
1506 x="1"
1507 y="0.25000146" /></g><g
1508 inkscape:groupmode="layer"
1509 id="layer1"
1510 inkscape:label="Shadow"
1511 style="display:inline"
1512 transform="translate(-1,-0.25001385)"
1513 sodipodi:insensitive="true"><path
1514 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1515 d="m 68,2.2664957 0,1 10,0 0,-1 z m 160.09375,1 c -0.0535,0.15448 -0.0937,0.32687 -0.0937,0.5 0,0.83099 0.669,1.5 1.5,1.5 l 7,0 c 0.831,0 1.5,-0.66901 1.5,-1.5 0,-0.17313 -0.0403,-0.34552 -0.0937,-0.5 -0.20326,0.58701 -0.74838,1 -1.40625,1 l -7,0 c -0.65787,0 -1.20299,-0.41299 -1.40625,-1 z m 1.90625,4 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,-0.55401 0.446,-1 1,-1 l 6,0 c 0.554,0 1,0.44599 1,1 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 z m 1.5,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.2769893 0.223,0.4999983 0.5,0.4999983 l 3,0 c 0.277,0 0.5,-0.223009 0.5,-0.4999983 0,-0.277 -0.223,-0.5 -0.5,-0.5 z M 69,10.266494 l 0,1 2,0 2,0 4,0 0,-1 z m 162.5,1 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m -165.5,0.9375 0,1 3,3.0625 9,0 c 1.108,0 2,-0.89201 2,-2 l 0,-1 c 0,1.10799 -0.892,2 -2,2 l -1,0 -4,0 -2,0 -2,0 z m 160,0.0625 0,1 c 0,0.554 0.446,1 1,1 l 2,0 0,-1 -2,0 c -0.554,0 -1,-0.446 -1,-1 z m 14,0 c 0,0.554 -0.446,1 -1,1 l -2,0 0,1 2,0 c 0.554,0 1,-0.446 1,-1 z m -10,3 0,1 6,0 0,-1 z M 5.09375,35.078994 c -0.0321,0.10941 -0.0625,0.22755 -0.0625,0.375 0,2.02126 1.30983,3.93782 2.84375,5.5 l 0.4375,-0.5625 c -1.55369,-1.47791 -2.95861,-3.3358 -3.21875,-5.3125 z m 9.875,0.09375 c -0.25301,1.93915 -1.65457,3.76438 -3.1875,5.21875 l 0.46875,0.53125 c 1.4966,-1.53303 2.75,-3.41075 2.75,-5.375 0,-0.13982 -0.0081,-0.26521 -0.03125,-0.375 z m 211.71875,5.59375 -0.6875,0.5 7,5 0,-1 z m 44.625,0 -6.3125,4.5 0,1 7,-5 z m 32,0 -6.3125,4.5 0,1 7,-5 z m 19.375,0 -0.6875,0.5 7,5 0,-1 z M 10.03125,41.860244 C 9.22019,42.486324 8.48091,42.963334 8,43.266494 c 0.22032,0.18121 0.39081,0.41214 0.53125,0.65625 0.43604,-0.28502 0.92578,-0.61924 1.5,-1.0625 0.60817,0.4711 1.13459,0.82096 1.59375,1.125 0.13177,-0.24582 0.28903,-0.46928 0.5,-0.65625 -0.50956,-0.32059 -1.26151,-0.82409 -2.09375,-1.46875 z M 233,41.922744 l 0,1 c 3.41666,0 5.61556,1.23041 7,3.34375 0,-0.37177 -0.024,-0.7269 -0.0625,-1.0625 -1.38712,-2.06828 -3.5607,-3.28125 -6.9375,-3.28125 z m 32,0 c -3.3768,0 -5.55038,1.21298 -6.9375,3.28125 -0.0385,0.3356 -0.0625,0.69073 -0.0625,1.0625 1.38444,-2.11333 3.58334,-3.34375 7,-3.34375 z m 32,0 c -3.3768,0 -5.55038,1.21298 -6.9375,3.28125 -0.0385,0.3356 -0.0625,0.69073 -0.0625,1.0625 1.38444,-2.11333 3.58334,-3.34375 7,-3.34375 z m 32,0 0,1 c 3.41666,0 5.61556,1.23041 7,3.34375 0,-0.37177 -0.024,-0.7269 -0.0625,-1.0625 -1.38712,-2.06828 -3.5607,-3.28125 -6.9375,-3.28125 z m -322.65625,1.9375 c -0.68772,0 -1.21875,0.51508 -1.21875,1.15625 0,0.18496 0.0456,0.34537 0.125,0.5 0.19583,-0.38143 0.60441,-0.65625 1.09375,-0.65625 0.48369,0 0.88614,0.28199 1.09375,0.65625 0.0876,-0.15786 0.15625,-0.30978 0.15625,-0.5 0,-0.64117 -0.56229,-1.15625 -1.25,-1.15625 z m 7.5,0 c -0.68772,0 -1.25,0.51508 -1.25,1.15625 0,0.19022 0.0687,0.34214 0.15625,0.5 0.2076,-0.37426 0.61005,-0.65625 1.09375,-0.65625 0.48934,0 0.89792,0.27482 1.09375,0.65625 0.0794,-0.15463 0.125,-0.31504 0.125,-0.5 0,-0.64117 -0.53104,-1.15625 -1.21875,-1.15625 z m -5.0625,1.65625 c -0.24632,1.04124 -1.24534,1.8125 -2.4375,1.8125 -1.18081,0 -2.15456,-0.75502 -2.40625,-1.78125 -0.0326,0.15175 -0.0625,0.30846 -0.0625,0.46875 0,1.28234 1.0933,2.3125 2.46875,2.3125 1.37545,0 2.5,-1.03016 2.5,-2.3125 0,-0.17336 -0.0239,-0.33674 -0.0625,-0.5 z m 2.625,0.03125 c -0.0359,0.15617 -0.0625,0.30294 -0.0625,0.46875 0,1.28234 1.12455,2.3125 2.5,2.3125 1.37545,0 2.46875,-1.03016 2.46875,-2.3125 0,-0.16029 -0.03,-0.31697 -0.0625,-0.46875 -0.25169,1.02623 -1.22544,1.78125 -2.40625,1.78125 -1.18081,0 -2.17929,-0.75502 -2.4375,-1.78125 z M 99,67.266494 l 0,1 2,0 0,-1 z m 5,0 0,1 2,0 0,-1 z m 5,0 0,1 3,0 0,-1 z m -101.5,0 c -1.933,0 -3.5,1.567 -3.5,3.5 0,0.16773 0.00805,0.33856 0.03125,0.5 0.24009,-1.699 1.70348,-3 3.46875,-3 1.73308,0 3.15841,1.25256 3.4375,2.90625 0.0156,-0.13448 0.0625,-0.26754 0.0625,-0.40625 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m 27.5,1 0,1 2,0 0,-1 z m 71,1 0,1 1,0 0,-1 z m 0,1 -2,0 0,1 2,0 z m -65.25,-1.5625 -0.75,0.5 3,2 0,-1 z m 2.25,0.1875 0,1 c 2.26799,8.7e-4 3.4435,1.45051 4,2.3125 -0.014,-0.50756 -0.142583,-0.99673 -0.34375,-1.4375 -0.01583,-0.0347 -0.04562,-0.05965 -0.0625,-0.09375 C 45.939623,69.851134 44.84378,68.892204 43,68.891494 z m 56,2.375 0,1 2,0 0,-1 z m -86.03125,-0.0625 c -0.0883,1.09275 -0.49087,2.08521 -1.125,2.90625 l 0.375,0.375 C 12.6919,73.678874 13,72.770744 13,71.766494 c 0,-0.18985 -0.01255,-0.37761 -0.03125,-0.5625 z M 37,71.266494 l 0,1 1,0 0,-1 z m 0,1 -2,0 -2,0 0,1 2,0 2,0 z m 69,0 0,1 1,0 0,-1 z m 0,1 -2,0 -1,0 0,1 1,0 2,0 z m 2,-1 0,0.84375 0,0.15625 0.25,0 0.75,-0.75 0,-0.25 z M 2.03125,71.328994 C 2.01985,71.473844 2,71.618704 2,71.766494 c 0,3.03756 2.46243,5.5 5.5,5.5 1.04725,0 2.01057,-0.30446 2.84375,-0.8125 l 3.53125,3.53125 c 0.39174,0.39173 1.01451,0.39173 1.40625,0 0.33125,-0.33125 0.35395,-0.82959 0.125,-1.21875 -0.0418,0.0711 -0.0645,0.15826 -0.125,0.21875 -0.39174,0.39173 -1.01451,0.39173 -1.40625,0 l -3.53125,-3.53125 c -0.83318,0.50804 -1.7965,0.8125 -2.84375,0.8125 -2.84772,0 -5.1871,-2.1641 -5.46875,-4.9375 z M 98,73.266494 l 0,1 1,0 0,-1 z m 3,0 0,1 1,0 0,-1 z m 9.21875,0 c 0.13749,0.14402 0.26979,0.29334 0.40625,0.4375 l -5.21875,5.25 -1.40625,1.40625 -1.40625,-1.40625 -1.625,-1.625 -0.5,0.5 2.125,2.125 1.40625,1.40625 1.40625,-1.40625 5.21875,-5.25 c -0.13646,-0.14416 -0.26876,-0.29348 -0.40625,-0.4375 l 1.375,0 0.40625,0 0,-1 -0.40625,0 -0.96875,0 z m -67.21875,0 0,1 3,0 0,-1 z m -9,2 c 0.056,2.03024 1.74134,3.6862 4,3.6875 l 0,-1 c -1.64956,-9.5e-4 -2.96714,-0.88894 -3.59375,-2.15625 -0.0253,-0.0318 -0.0386,-0.06245 -0.0625,-0.09375 -0.11831,-0.15487 -0.25718,-0.30341 -0.34375,-0.4375 z m 9,1 0,1 3,0 0,-1 z m -2.75,1.5 -2.25,1.4375 0,1 3,-1.9375 z m 1.75,1.5 0,1 1,0 0,-1 z m 1,1 0,1 3,0 2,0 0,-1 -2,0 z m 292.5,17 -0.5,1 0,1 1,-2 z m -0.5,2 -0.5,0 -4.5,9.000036 0.5,0 4,-8 0.5,0 z M 37,100.48529 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,-0.55401 0.446,-1 1,-1 l 8,0 c 0.554,0 1,0.44599 1,1 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 z m 36,-1.218796 c -0.207107,0 -0.423297,0.01085 -0.625,0.03125 -0.125778,0.0159 -0.252316,0.0374 -0.375,0.0625 -2.278414,0.46623 -4,2.490036 -4,4.906286 0,0.17259 0.01418,0.33191 0.03125,0.5 0.25605,-2.52128 2.379919,-4.5 4.96875,-4.5 2.588831,0 4.7127,1.97872 4.96875,4.5 0.01707,-0.16809 0.03125,-0.32741 0.03125,-0.5 0,-2.41625 -1.721586,-4.440056 -4,-4.906286 -0.122684,-0.0251 -0.249222,-0.0466 -0.375,-0.0625 -0.04024,-0.004 -0.08453,0.003 -0.125,0 -0.168085,-0.0171 -0.327411,-0.03125 -0.5,-0.03125 z m 58,0 c -0.554,0 -1,0.446002 -1,1.000036 l 0,1 c 0,-0.554 0.446,-1 1,-1 l 0.5,0 2,0 9.5,0 c 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554034 -0.446,-1.000036 -1,-1.000036 z m 32.03125,0 c -0.554,0 -1,0.446002 -1,1.000036 l 0,1 c 0,-0.554 0.446,-1 1,-1 l 9.5,0 2,0 0.5,0 c 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554034 -0.446,-1.000036 -1,-1.000036 z M 195,100.26653 c -0.554,0 -1,1 -1,1 l 0,1 c 0,-0.554 0.446,-1 1,-1 l 12,0 c 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554 -0.446,-1 -1,-1 z m 32,0 c -0.554,0 -1,1 -1,1 l 0,1 c 0,-0.554 0.446,-1 1,-1 l 12,0 c 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554 -0.446,-1 -1,-1 z m 96,-1.000036 c -0.554,0 -1,0.445992 -1,1.000036 l 0,1 c 0,-0.55401 0.446,-1 1,-1 l 0.5,0 3.5,0 0.5,0 3.5,0 1,0 0.5,-1.000036 -1.5,0 -4,0 z m 13,0.28125 0,0.718786 0.71875,0 C 336.5419,99.964166 336.30232,99.724594 336,99.547744 z M 99,100.26653 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,-0.55401 0.446,-1 1,-1 l 1.5,0 2,0 8.5,0 c 0.554,0 1,0.44599 1,1 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 z m -96,2.21876 0,1 1,0 3,0 2,0 5,0 1,0 0,7 0,-8 z m 128.5,-1.21876 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.0444,0.53446 0.5625,0.5 l 0.4375,0 0,-1 -0.4375,0 c -0.0257,0.002 -0.0391,-1.5e-4 -0.0625,0 z m 1.5,0 0,1 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 39.53125,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 0.5,0 0,-1 z m 1.5,0 0,1 0.4375,0 c 0.5181,0.0345 0.5625,-0.25763 0.5625,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 -0.0234,-1.5e-4 -0.0368,0.002 -0.0625,0 z m 117.96875,0 c -0.18612,0 -0.35468,0.0304 -0.53125,0.0625 -0.5068,0.14135 -0.92854,0.48982 -1.1875,0.9375 l 1.71875,0 10,0 1.71875,0 c -0.25896,-0.44768 -0.6807,-0.79615 -1.1875,-0.9375 -0.16893,-0.0471 -0.34578,-0.0625 -0.53125,-0.0625 z m 44,0 0,1 1,0 0,-1 z m -235.5,1 c -0.277,0 -0.5,0.22299 -0.5,0.5 0.0807,0.57703 0.3111,0.49624 1,0.5 l 0,-1 -0.4375,0 c -0.0263,-4.3e-4 -0.0385,10e-4 -0.0625,0 z m 1.5,0 0,1 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.777,-0.5 -0.5,-0.5 z m -57.5,1.71876 -4.5,4.5 -1.40625,-1.40625 -0.9375,-0.9375 -0.5,0.5 1.4375,1.4375 1.40625,1.40625 5,-5 z m -40.5,0.5 0,1 3,0 0,-1 z m 197,-0.21876 3,4 3,-4 -0.75,0 -2.25,3 -2.25,-3 z m 26,0 3,4 3,-4 -0.75,0 -2.25,3 -2.25,-3 z m 109,-1 0,1 1,0 0,-1 z m -327,2.21876 0,1 5,0 0,-1 z m 61.0625,-0.71876 c -0.02868,0.16658 -0.0625,0.32524 -0.0625,0.5 0,1.65685 1.34315,3 3,3 1.65685,0 3,-1.34315 3,-3 0,-0.17476 -0.03382,-0.33342 -0.0625,-0.5 -0.243216,1.41264 -1.455414,2.5 -2.9375,2.5 -1.482086,0 -2.694284,-1.08736 -2.9375,-2.5 z m -3.03125,0.125 C 67.02375,105.01412 67,105.14206 67,105.26653 c 0,3.3137 2.68629,6 6,6 3.31371,0 6,-2.6863 6,-6 0,-0.12447 -0.02378,-0.25241 -0.03125,-0.375 -0.273821,2.69627 -2.325104,4.84119 -4.96875,5.28125 -0.162744,0.0333 -0.331915,0.0454 -0.5,0.0625 -0.16239,0.0132 -0.334211,0.0312 -0.5,0.0312 -0.165789,0 -0.33761,-0.0182 -0.5,-0.0312 -0.04138,-0.004 -0.08393,0.005 -0.125,0 -0.127563,-0.013 -0.249927,-0.0417 -0.375,-0.0625 -2.643646,-0.44006 -4.694929,-2.58498 -4.96875,-5.28125 z m 189.96875,0.375 0,1 c 0,1.662 1.338,3 3,3 l 10,0 c 1.662,0 3,-1.338 3,-3 l 0,-1 c 0,1.662 -1.338,3 -3,3 l -10,0 c -1.662,0 -3,-1.338 -3,-3 z m 32,0 0,1 c 0,1.662 1.338,3 3,3 l 10,0 c 1.662,0 3,-1.338 3,-3 l 0,-1 c 0,1.662 -1.338,3 -3,3 l -10,0 c -1.662,0 -3,-1.338 -3,-3 z m 47,0 0,1 1,0 0,-1 z m -192,0.40625 -4.59375,4.59375 0.84375,0 c 0.0134,-0.0178 0.0149,-0.0462 0.0312,-0.0625 l 3.71875,-3.6875 0,-0.84375 z m 18.03125,0 0,0.84375 3.71875,3.6875 c 0.0163,0.0163 0.0179,0.0447 0.0312,0.0625 l 0.84375,0 -4.59375,-4.59375 z M 4,107.48529 l 0,1 3,0 0,-1 z m 321.65625,-0.25001 c -0.0517,0.018 -0.0982,0.0312 -0.15625,0.0312 l -0.5,0 -1,0 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0.5,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.1841 -0.16469,-0.4438 -0.3125,-0.53125 -0.007,-0.004 -0.0247,0.003 -0.0312,0 z M 9,108.48529 l 0,1 5,0 0,-1 z m 26,0 0,1 c 0,1.0907 0.9093,2 2,2 l 8,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 l -8,0 c -1.0907,0 -2,-0.9093 -2,-2 z m 96.5,-1.21876 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.12178,-0.5281 -0.5,-0.5 l -0.5,0 -1,0 z m 40.8125,0 c -0.19381,0.0717 -0.28125,0.29225 -0.28125,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -0.5,0 -1,0 -0.5,0 c -0.0945,-0.007 -0.15415,-0.0239 -0.21875,0 z m 20.6875,1 0,1 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 l -12,0 c -1.0907,0 -2,-0.9093 -2,-2 z m 32,0 0,1 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 l -12,0 c -1.0907,0 -2,-0.9093 -2,-2 z m 96,-1 0,1 c 0,1.09069 0.9093,2 2,2 l 4,0 0.5,-1 -4.5,0 c -1.0907,0 -2,-0.90931 -2,-2 z m 15,0 0,1 0.71875,0 0.28125,0 0,-1 z m -192,0.625 -2.34375,2.375 0.625,0 1.71875,-1.75 z m 18.03125,0 0,0.625 1.71875,1.75 0.625,0 z M 2,109.48529 l 0,1 c 0,0.55399 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44601 1,-1 l 0,-1 c 0,0.55399 -0.446,1 -1,1 l -12,0 c -0.554,0 -1,-0.44601 -1,-1 z m 95,-1.21876 0,1 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 l -12,0 c -1.0907,0 -2,-0.9093 -2,-2 z m 3.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.11921,-0.5 -0.5,-0.5 l -0.5,0 -1,0 z m 28.5,1 0,1 c 0,1.09069 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.90931 2,-2 l 0,-0.375 c 0.0328,-0.0893 0.0213,-0.17215 0,-0.25 l 0,-0.375 c 0,1.09069 -0.9093,2 -2,2 l -0.71875,0 -0.625,0 -1.40625,0 -0.84375,0 -3.375,0 -5.03125,0 c -1.0907,0 -2,-0.90931 -2,-2 z m 32.03125,0 0,0.375 c -0.0213,0.0779 -0.0328,0.1607 0,0.25 l 0,0.375 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 l -7.03125,0 -1.375,0 -0.84375,0 -1.40625,0 -0.625,0 -0.71875,0 c -1.0907,0 -2,-0.9093 -2,-2 z m 168.46875,0 -1.5,3 -1.5,0 -0.5,1 2,0 1.5,-3 1.5,0 0,-1 -1,0 z m 2.5,0 0,1 1,0 0,-1 z m 2,0 0,1 1,0 0,-1 z m 2,0 0,0.71875 c 0.30232,-0.17686 0.5419,-0.41643 0.71875,-0.71875 z m -195.5,22 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2.5,0 0,-1 z m 63.96875,0 -0.0937,0.34375 -3,0 -2.40625,8.65625 -2.71875,0 -0.28125,1 3,0 2.40625,-8.65625 3,0 0.3125,-1.34375 -0.21875,0 z m -159.1875,0.0312 -0.25,0.96875 -1.59375,0 -2.0625,8.03125 0.25,0 1.8125,-7.03125 1.59375,0 0.5,-1.96875 z m 150.3125,0.3125 -0.21875,1 2.71875,0 0.28125,-1 z M 8.5625,132.26653 c -0.21684,0.0127 -0.42028,0.0372 -0.59375,0.0625 l 0,1 c 0.17347,-0.0253 0.37691,-0.0498 0.59375,-0.0625 0.21684,-0.0126 0.42262,1e-5 0.625,0 0.24576,1e-5 0.48745,0.0245 0.71875,0.0625 0.23129,0.0253 0.42028,0.0862 0.59375,0.1875 0.17347,0.0886 0.30506,0.19778 0.40625,0.375 0.0253,0.0411 0.0431,0.10584 0.0625,0.15625 0.0553,-0.14566 0.09375,-0.29026 0.09375,-0.46875 0,-0.27849 -0.05499,-0.52292 -0.15625,-0.6875 -0.10119,-0.17722 -0.23278,-0.2864 -0.40625,-0.375 -0.17347,-0.1013 -0.36246,-0.1622 -0.59375,-0.1875 -0.2313,-0.038 -0.47299,-0.0625 -0.71875,-0.0625 -0.20238,1e-5 -0.40816,-0.0126 -0.625,0 z m 31.125,0 -0.25,1 1.34375,0 0.25,-1 z m 104.3125,0.5 c 0,0.277 -0.223,0.5 -0.5,0.5 l -0.5,0 -2,0 0,1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 z m -130.375,1.03125 c -0.063,0.36627 -0.21145,0.69408 -0.4375,1 -0.30358,0.43041 -0.69834,0.77808 -1.21875,1.03125 0.33848,0.10821 0.62371,0.23704 0.875,0.375 0.12273,-0.12465 0.24256,-0.26278 0.34375,-0.40625 0.31803,-0.4304 0.46874,-0.91175 0.46875,-1.46875 0,-0.18355 -6.9e-4,-0.34959 -0.03125,-0.53125 z m 149.46875,0.0937 c -0.19229,0.43111 -0.1321,0.96164 0.21875,1.3125 l 1.53125,1.53125 0.5,-0.5 -2.03125,-2.03125 c -0.0959,-0.0959 -0.16343,-0.1957 -0.21875,-0.3125 z m 7.78125,0 c -0.0553,0.1168 -0.12287,0.21661 -0.21875,0.3125 l -2.03125,2.0313 0.5,0.5 1.53125,-1.53125 c 0.35085,-0.35086 0.41104,-0.88139 0.21875,-1.3125 z m -30.875,0.875 0,1 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 -0.5,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 z m -8.90625,0.125 c -0.19229,0.43111 -0.1321,0.96164 0.21875,1.3125 l 1.53125,1.53125 0.5,-0.5 -2.03125,-2.03125 c -0.0959,-0.0959 -0.16343,-0.1957 -0.21875,-0.3125 z m 7.78125,0 c -0.0553,0.1168 -0.12287,0.21661 -0.21875,0.3125 l -2.03125,2.0313 0.5,0.5 1.53125,-1.53125 c 0.35085,-0.35086 0.41104,-0.88139 0.21875,-1.3125 z m -69.875,1.8438 0,1 c 0,0 0.0818,1.2882 0.21875,1.84375 0.13694,0.55554 0.35886,1.04609 0.6875,1.4375 0.32865,0.3914 0.76476,0.6916 1.3125,0.90625 0.56144,0.20201 1.24087,0.28125 2.0625,0.28125 0.8353,0 1.53231,-0.0792 2.09375,-0.28125 0.56143,-0.21465 1.03265,-0.51485 1.375,-0.90625 0.34233,-0.39141 0.5818,-0.88196 0.71875,-1.4375 0.13697,-0.55555 0.18749,-1.16195 0.1875,-1.84375 l 0,-1 c -1e-5,0.6818 -0.05053,1.2882 -0.1875,1.84375 -0.13695,0.55554 -0.37642,1.04609 -0.71875,1.4375 -0.34235,0.3914 -0.81357,0.6916 -1.375,0.90625 -0.56144,0.20205 -1.25845,0.28125 -2.09375,0.28125 -0.82163,0 -1.50106,-0.0792 -2.0625,-0.28125 -0.54774,-0.21465 -0.98385,-0.51485 -1.3125,-0.90625 -0.32864,-0.39141 -0.55056,-0.88196 -0.6875,-1.4375 C 69.0818,138.02348 69,137.41708 69,136.73528 z m -61.03125,0.21875 0,1 1.4375,0 c 0.69388,1e-5 1.220231,0.15308 1.625,0.40625 0.29273,0.16795 0.4753,0.42054 0.5625,0.75 0.0413,-0.15807 0.0625,-0.33102 0.0625,-0.53125 0,-0.56965 -0.20578,-0.97823 -0.625,-1.21875 -0.404769,-0.25317 -0.93112,-0.40624 -1.625,-0.40625 z M 167,137.89153 l -2.0625,2.03125 c -0.45327,0.45327 -1.17173,0.45327 -1.625,0 -0.10242,-0.10242 -0.16262,-0.2179 -0.21875,-0.34375 -0.20618,0.43535 -0.13864,0.98636 0.21875,1.34375 0.45327,0.45327 1.17173,0.45327 1.625,0 l 2.0625,-2.03125 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.35739,-0.35739 0.42493,-0.9084 0.21875,-1.34375 -0.0561,0.12585 -0.11633,0.24133 -0.21875,0.34375 -0.45327,0.45327 -1.17173,0.45327 -1.625,0 z m -32,1 -2.0625,2.03125 c -0.45327,0.45327 -1.17173,0.45327 -1.625,0 -0.10242,-0.10242 -0.16262,-0.2179 -0.21875,-0.34375 -0.20618,0.43535 -0.13864,0.98636 0.21875,1.34375 0.45327,0.45327 1.17173,0.45327 1.625,0 l 2.0625,-2.03125 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.35739,-0.35739 0.42493,-0.9084 0.21875,-1.34375 -0.0561,0.12585 -0.11633,0.24133 -0.21875,0.34375 -0.45327,0.45327 -1.17173,0.45327 -1.625,0 z m -120.75,0.28125 c -0.0559,0.448 -0.1825,0.85035 -0.375,1.1875 -0.27467,0.46838 -0.64796,0.83384 -1.125,1.125 -0.4626,0.2785 -1.00573,0.49841 -1.65625,0.625 -0.636069,0.11395 -1.32525,0.15625 -2.0625,0.15625 l -3.75,0 0,1 3.75,0 c 0.73725,0 1.426431,-0.0423 2.0625,-0.15625 0.65052,-0.12659 1.19365,-0.3465 1.65625,-0.625 0.47704,-0.29116 0.85033,-0.65662 1.125,-1.125 0.27465,-0.48104 0.40624,-1.07235 0.40625,-1.78125 0,-0.13608 -0.01035,-0.27282 -0.03125,-0.40625 z m 158.25,0.0937 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.24281,0.60287 0.5,0.5 l 2.5,0 0,-1 z m 29.75,0.65625 -0.5,0.46875 1.4375,1.46875 0.46875,-0.5 z m 4.8125,0 -1.4375,1.4375 0.5,0.5 1.4375,-1.46875 z M 176,140.76653 c 0,0.277 -0.223,0.5 -0.5,0.5 l -0.5,0 -2,0 0,1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 z m -133.28125,0.53125 -0.25,0.96875 -5.34375,0 -0.28125,1 5.625,0 0.5,-1.96875 z M 194.5,142.26653 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 10.125,0.0937 -1.90625,1.96875 -0.5,-0.5 -0.46875,0.5 0.96875,1 1.90625,-1.96875 1.96875,1.96875 0.96875,-1 -0.5,-0.5 -0.46875,0.5 z m -32.625,0.40625 0,1 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 -0.5,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 z m -103.5,0.5 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 10,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 224.5,19 0,1 2,0 0,-1 z m -288.5,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 0.5,0 0,-1 z m 4,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 27,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 10,0 c 0,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.599346,0.45353 0.5625,0.5 l 0.4375,0 0,-1 -0.4375,0 z m 28,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 25,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 361.5,0 0,1 1,0 0,-1 z m 27,0 0,1 1,0 0,-1 z m -354.5,1 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.20711 0.13304,0.39285 0.3125,0.46875 0.0598,0.0253 0.11847,0.0312 0.1875,0.0312 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.069,0 -0.12768,0.006 -0.1875,0.0312 -0.17946,0.0759 -0.3125,0.26164 -0.3125,0.46875 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 2,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 37,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -2,0 -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m -9,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m 41,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.777,0.46875 -0.5,0.46875 l -3,0 -2,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 27,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 2,0 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 -0.223,-0.46875 -0.5,-0.46875 z m 9,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 85.5,0 0,1 7,0 0,-1 z m 33.875,0 0,1 8.09375,0 0,-1 z m 35.125,0 0,1 7,0 0,-1 z m 27,0 0,1 12,0 0,-1 z m 43,0 0,1 1,0 0,-1 z m 27,0 0,1 1,0 0,-1 z m -421.9375,0.5 c -0.0411,0.15976 -0.0625,0.32741 -0.0625,0.5 0,1.10456 0.895431,2 2,2 1.104569,0 2,-0.89544 2,-2 0,-0.17259 -0.0214,-0.34024 -0.0625,-0.5 -0.221963,0.8627 -1.00552,1.5 -1.9375,1.5 -0.93198,0 -1.715537,-0.6373 -1.9375,-1.5 z m 40,0 c -0.0411,0.15976 -0.0625,0.32741 -0.0625,0.5 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-0.17259 -0.0214,-0.34024 -0.0625,-0.5 -0.22196,0.8627 -1.00552,1.5 -1.9375,1.5 -0.93198,0 -1.71554,-0.6373 -1.9375,-1.5 z m -98.5625,0.5 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 27,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 38,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 25,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 200.5,0 0,1 1,0 0,-1 z m 3,0 0,1 1,0 0,-1 z m 154.0625,0.5 c -0.0287,0.16658 -0.0625,0.32524 -0.0625,0.5 0,1.65685 1.34315,3 3,3 l 0,-1 c -1.48209,0 -2.69428,-1.08736 -2.9375,-2.5 z m 27,0 c -0.0287,0.16658 -0.0625,0.32524 -0.0625,0.5 0,1.65685 1.34315,3 3,3 l 0,-1 c -1.48209,0 -2.69428,-1.08736 -2.9375,-2.5 z m -224.125,0.0625 c -0.0395,0.16596 -0.0625,0.33 -0.0625,0.5 0,1.2454 1.11952,2.25457 2.53125,2.3125 0.11409,-0.35505 0.2024,-0.68476 0.25,-1 -0.0438,8.7e-4 -0.0797,0 -0.125,0 -1.27634,0 -2.33451,-0.77035 -2.59375,-1.8125 z m 8,0 c -0.0395,0.165 -0.0625,0.33 -0.0625,0.5 0,1.24541 1.11952,2.25457 2.53125,2.3125 0.11379,-0.35113 0.2024,-0.68899 0.25,-1 -0.0465,8.7e-4 -0.077,0 -0.125,0 -1.27634,0 -2.33451,-0.77035 -2.59375,-1.8125 z m -2.78125,0.34375 c -0.32899,3.04037 -2.38768,4.9421 -3.9375,5.71875 -0.35953,0.46482 -0.80193,0.93399 -1.34375,1.40625 1.33333,0 5.3125,-2.32015 5.3125,-6.96875 0,-0.0539 -0.0272,-0.10254 -0.0312,-0.15625 z m 8,0 c -0.32572,3.03782 -2.38152,4.9188 -3.9375,5.6875 -0.35966,0.46296 -0.80081,0.93301 -1.34375,1.40625 1.37466,0 5.3125,-2.28889 5.3125,-6.9375 0,-0.0539 -0.0272,-0.10264 -0.0312,-0.15625 z M 138.5,167.26653 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 35,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 26,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 29,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 -0.223,-0.46875 -0.5,-0.46875 z m 66.5,0 0,1 1,0 0,-1 z m 0,1 -2,0 -1,0 0,1 1,0 2,0 z m -290,-0.5 0,1 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-1 c 0,0.27699 -0.223,0.5 -0.5,0.5 -0.277,0 -0.5,-0.22301 -0.5,-0.5 z m 41,0 0,1 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-1 c 0,0.27699 -0.223,0.5 -0.5,0.5 -0.277,0 -0.5,-0.22301 -0.5,-0.5 z m 251,0.5 0,1 1,0 0,-1 z m 3,0 0,1 2,0 0,-1 z m 23,0 0,1 9,0 2,0 0,-1 z m 65,0 0,1 2,0 9,0 0,-1 z m 31,0 0,1 12,0 0,-1 z m -64.15625,0.0312 0,1 2.03125,0 8.09375,0 2.03125,0 0,-1 z m -224.21875,0.9688 -0.625,0.46875 0,0.0625 2,1.46875 0,-1 z m 1.375,1 2.5,0 c 0.0693,0 0.12764,-0.008 0.1875,-0.0312 0.17958,-0.0702 0.3125,-0.24018 0.3125,-0.4375 l 0,-0.0625 c 0,-0.0658 -0.006,-0.13122 -0.0312,-0.1875 -0.0757,-0.16883 -0.261,-0.28125 -0.46875,-0.28125 l -2.5,0 0,1 z m 6.5,-1 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 2,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 37,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -2,0 -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m -9.125,0 0.625,0.46875 0,0.0625 -2,1.46875 0,-1 z m -1.375,1 -2.5,0 c -0.27637,0 -0.5,-0.18037 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.22363,-0.46875 0.5,-0.46875 l 2.5,0 z m 42.59375,-1 c 0.28935,0 0.53125,0.20565 0.53125,0.46875 l 0,0.0625 c 0,0.43405 -0.2419,0.46875 -0.53125,0.46875 l -2.59375,0 0,-1 z m -2.59375,1 0,1 -2.09375,-1.46875 0,-0.0625 0.65625,-0.46875 z m -5.5,-1 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.777,0.46875 -0.5,0.46875 l -3,0 -2,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 27,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 2,0 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 -0.223,-0.46875 -0.5,-0.46875 z m 9,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 2.5,0 0,-1 z m 2.5,1 0,1 2,-1.46875 0,-0.0625 -0.625,-0.46875 z m 215.5,-0.5 -2.5,2.5 0,1 3,-3 z m 39,0 -0.5,0.5 3,3 0,-1 z m -193.3125,0.875 -2.09375,4.65625 -1.40625,0 -0.4375,1 1.84375,0 2.53125,-5.65625 z m -4.75,0.4375 -1.40625,1.375 0.5,0.5 1.40625,-1.375 z m 5.875,0 -0.5,0.5 1.375,1.375 0.5,-0.5 z M 3.5,171.26653 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,-1 z m 5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 27,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 9,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,-1 z m 29,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 25,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 40,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 35,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 26,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 29,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 -0.223,-0.46875 -0.5,-0.46875 z m 94.5,0 0,1 9,0 0,-1 z m 67,0 0,1 9,0 0,-1 z m 29,0 0,1 12,0 0,-1 z m -62.125,0.0625 0,1 8.09375,0 0,-1 z M 6,172.76653 c 0,0.0693 -0.00605,0.12755 -0.03125,0.1875 -0.0505,0.13912 -0.15407,0.24025 -0.28125,0.28125 -0.0599,0.0252 -0.1182,0.0312 -0.1875,0.0312 l -0.5,0 -1,0 0,1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 C 5.99395,173.89413 6,173.83578 6,173.76653 z m 41,0 c 0,0.0693 -0.0061,0.12755 -0.03125,0.1875 -0.05055,0.13912 -0.15407,0.24025 -0.28125,0.28125 -0.05986,0.0252 -0.1182,0.0312 -0.1875,0.0312 l -0.5,0 -1,0 0,1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 C 46.99395,173.89413 47,173.83578 47,173.76653 z m 20.0625,0 c -0.0411,0.15976 -0.0625,0.32741 -0.0625,0.5 0,1.10456 0.895431,2 2,2 1.104569,0 2,-0.89544 2,-2 0,-0.17259 -0.0214,-0.34024 -0.0625,-0.5 -0.221963,0.8627 -1.00552,1.5 -1.9375,1.5 -0.93198,0 -1.715537,-0.6373 -1.9375,-1.5 z m 40,0 c -0.0411,0.15976 -0.0625,0.32741 -0.0625,0.5 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-0.17259 -0.0214,-0.34024 -0.0625,-0.5 -0.22196,0.8627 -1.00552,1.5 -1.9375,1.5 -0.93198,0 -1.71554,-0.6373 -1.9375,-1.5 z m 184.5625,0.1875 -0.5,0.5 2.84375,2.84375 0.96875,-0.90625 -0.5,-0.53125 -0.46875,0.4375 z m 11.5,0 -2.34375,2.34375 -0.46875,-0.4375 -0.5,0.53125 0.96875,0.90625 2.84375,-2.84375 z M 8.5,173.26653 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 27,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 38,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 25,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 34,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.069,0 -0.12768,0.006 -0.1875,0.0312 -0.17946,0.0759 -0.3125,0.26164 -0.3125,0.46875 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 37,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m -9,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m 41,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 27,0 c -0.277,0 -0.5,0.20566 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 -0.223,-0.46875 -0.5,-0.46875 z m 9,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 221.5,0 0,1 1,0 0,-1 z m 2,0 0,1 1,0 0,-1 z m 25,0 0,1 1,0 0,-1 z m 2,0 0,1 1,0 0,-1 z m -165,1 0,1 12,0 0,-1 z m 64,0 0,1 12,0 0,-1 z m 32,0 0,1 12,0 0,-1 z m -64.15625,0.0937 0,1 12.15625,0 0,-1 z M 3,174.76653 l 0,1 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1.5,0 -0.5,0 c -0.277,0 -0.5,-0.22301 -0.5,-0.5 z m 41,0 0,1 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1.5,0 -0.5,0 c -0.277,0 -0.5,-0.22301 -0.5,-0.5 z m 92.0625,0 0,1 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 l 0,-1 c 0,0.277 -0.21154,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.223 -0.46875,-0.5 z m 32.9375,0 0,1 c 0,0.277 -0.21154,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.223 -0.46875,-0.5 l 0,-1 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 z m 32.9375,0 0,1 c 0,0.27699 -0.21154,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.22301 -0.46875,-0.5 l 0,-1 c 0,0.27699 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.22301 0.46875,-0.5 z m 31.0625,0 0,1 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25722,0 0.46875,-0.223 0.46875,-0.5 l 0,-1 c 0,0.277 -0.21153,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.223 -0.46875,-0.5 z m -228,22.5 c -0.1602,0 -0.31869,0.0256 -0.46875,0.0625 C 3.6596,197.54351 3,198.33602 3,199.26653 l 0,1 c 0,-1.09071 0.9093,-2 2,-2 l 3,0 0,-1 z m 5,0 0,1 3,0 c 1.0907,0 2,0.90929 2,2 l 0,-1 c 0,-0.93051 -0.6596,-1.72302 -1.53125,-1.9375 -0.0216,-0.004 -0.0407,-0.0283 -0.0625,-0.0312 -0.12925,-0.027 -0.26991,-0.0312 -0.40625,-0.0312 l -3,0 z m 27,0 c -0.1602,0 -0.31869,0.0256 -0.46875,0.0625 C 35.6596,197.54351 35,198.33602 35,199.26653 l 0,1 c 0,-1.09071 0.9093,-2 2,-2 l 3,0 0,-1 z m 5,0 0,1 3,0 c 1.0907,0 2,0.90929 2,2 l 0,0.4375 0.53125,0.53125 0.4375,0.4375 C 47.98778,201.5373 48,201.40693 48,201.26653 l 0,-1 c 0,0.1404 -0.01222,0.27077 -0.03125,0.40625 l -0.4375,-0.4375 L 47,199.70403 l 0,-0.4375 c 0,-0.93051 -0.659603,-1.72302 -1.53125,-1.9375 -0.02162,-0.004 -0.04073,-0.0283 -0.0625,-0.0312 -0.129247,-0.027 -0.269913,-0.0312 -0.40625,-0.0312 l -3,0 z m -36.5,2 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 7,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 -2,0 z m 32,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 4.3125,0 1.5,0 1.1875,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 -2,0 z m -35.5,1 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 1,-1 1,1 3,0 c 1.64649,0 3,-1.35351 3,-3 l 0,-1 c 0,1.48353 -1.10933,2.70546 -2.53125,2.9375 -0.0223,0.005 -0.0399,0.0265 -0.0625,0.0312 -0.13548,0.019 -0.26585,0.0312 -0.40625,0.0312 l -3,0 -1,-1 -1,1 -3,0 c -0.1404,0 -0.27077,-0.0122 -0.40625,-0.0312 -0.0226,-0.005 -0.0402,-0.0258 -0.0625,-0.0312 C 3.10933,202.97199 2,201.75006 2,200.26653 z m 2,0 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,-1 -2.5,0 -0.5,0 c -0.554,0 -1,-0.446 -1,-1 z m 10,0 c 0,0.554 -0.446,1 -1,1 l -0.5,0 -2.5,0 0,1 3,0 c 0.554,0 1,-0.446 1,-1 z m 20,0 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 0.6875,-0.6875 -0.5,-0.5 -0.1875,0.1875 -3,0 c -0.1404,0 -0.27077,-0.0122 -0.40625,-0.0312 -0.0226,-0.005 -0.0401,-0.0258 -0.0625,-0.0312 C 35.10933,202.97189 34,201.75006 34,200.26653 z m 2,0 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,-1 -2.5,0 -0.5,0 c -0.554,0 -1,-0.446 -1,-1 z m 10,0 c 0,0.0353 -0.02772,0.0594 -0.03125,0.0937 l -0.875,0.875 c -0.03434,0.004 -0.05845,0.0312 -0.09375,0.0312 l -0.5,0 -0.1875,0 -1,0 1,1 0.6875,0 c 0.0353,0 0.05941,-0.0277 0.09375,-0.0312 l 0.875,-0.875 C 45.97225,201.32598 46,201.30183 46,201.26653 z m 25.8125,0.65625 c -0.899959,-0.0141 -1.82217,0.32909 -2.8125,1.34375 l 0,1 c 3.96132,-4.05865 6.94268,2.81598 11,-1 l 0,-1 c -3.04299,2.86198 -5.487624,-0.30138 -8.1875,-0.34375 z m 35.375,0 c -2.69988,0.0424 -5.14451,3.20574 -8.1875,0.34375 l 0,1 c 4.05732,3.81599 7.03868,-3.05865 11,1 l 0,-1 c -0.99033,-1.01466 -1.91254,-1.35788 -2.8125,-1.34375 z m -66.34375,0.34375 -0.03125,0.0312 -0.65625,0.71875 0.46875,0.5 0.1875,-0.21875 1,-1.03125 -0.96875,0 z m 1.1875,1.21875 -0.5,0.5 1.59375,1.59375 0.5,-0.5 z m 5.3125,0 -1.59375,1.59375 0.5,0.5 1.59375,-1.59375 z m -2.65625,2.65625 -2.125,2.125 -0.53125,-0.5625 -0.5,0.5 1.03125,1.0625 2.125,-2.125 2.125,2.125 1.03125,-1.0625 -0.5,-0.5 -0.53125,0.5625 z m 22.3125,2.125 0,1 1,0 0,-1 z m 44,0 0,1 1,0 0,-1 z m 154,19 c -0.34628,0 -0.67165,0.0352 -1,0.0937 -0.98506,0.17561 -1.89451,0.59634 -2.65625,1.1875 0.13763,0.005 0.26821,0.0331 0.40625,0.0625 0.0582,0.0594 -0.12804,0.19841 -0.3125,0.34375 0.31668,-0.24446 0.66584,-0.3597 1.09375,-0.375 0.20293,-0.0412 0.41536,-0.0346 0.59375,0 0.16865,-0.0578 0.35611,-0.0825 0.53125,-0.125 -0.22012,-0.0629 0.0305,-0.20755 0.28125,-0.21875 0.0955,-0.004 0.16445,0.0179 0.21875,0.0625 0.11003,0.002 0.2574,-0.10843 0.1875,0.0312 0.12547,-0.0147 0.24703,-0.0248 0.375,-0.0312 -0.12874,-0.0406 0.003,-0.1019 0.125,-0.125 0.10685,-0.0202 0.16269,0.002 0.0312,0.0937 0.0427,-9.4e-4 0.0821,0 0.125,0 0.13861,0 0.27026,0.0205 0.40625,0.0312 0.0233,-0.0312 0.0578,-0.0728 0.125,-0.125 0.0886,-0.0585 0.113,-0.0756 0.125,-0.0625 0.027,0.0293 -0.0732,0.19992 -0.0312,0.1875 0.014,-0.004 0.0355,-0.0411 0.0937,-0.0937 0.27569,-0.0726 0.65041,0.0656 0.84375,0.28125 0.009,0.01 0.0231,0.0209 0.0312,0.0312 0.016,0.0203 0.0186,0.041 0.0312,0.0625 0.005,0.009 -0.005,0.0221 0,0.0312 0.0224,0.0438 0.0566,0.0778 0.0625,0.125 0.11394,-0.038 0.23099,-0.0536 0.34375,-0.0937 0.0491,0.0177 0.10773,0.0123 0.15625,0.0312 -0.057,0.0184 -0.10829,0.071 -0.15625,0.0625 -0.2431,0.18027 0.18715,0.11836 0.4375,0.21875 -0.0479,-0.17153 0.0692,-0.42292 0.15625,-0.46875 0.041,-0.0216 0.0545,0.0172 0.0625,0.125 -0.0128,0.0643 0.017,0.19499 0.0312,0.3125 1.80061,0.91451 3.06549,2.70374 3.25,4.8125 0.012,-0.15544 0.0312,-0.31017 0.0312,-0.46875 0,-2.36207 -1.35959,-4.39623 -3.34375,-5.375 0.0114,0.14518 0.0591,0.3475 -0.0312,0.3125 0.10838,-0.49625 -0.9425,-0.21013 -0.59375,-0.46875 0.048,0.009 0.0992,-0.0441 0.15625,-0.0625 -0.0485,-0.0189 -0.10715,-0.0137 -0.15625,-0.0312 -0.26917,0.0961 -0.54455,0.1962 -0.8125,0.25 -0.0958,-0.002 -0.2497,-0.019 -0.3125,-0.0312 0.0241,-0.006 0.0765,-0.0264 0.1875,-0.0312 0.0729,-0.099 0.0423,-0.0421 0.15625,-0.125 0.0599,-0.086 0.79642,-0.122 0.1875,-0.125 -0.0279,-0.003 -0.019,-0.0282 -0.0312,-0.0312 0.0509,-0.01 0.14162,-0.0192 0.25,-0.0312 -0.26349,-0.0756 -0.53626,-0.14391 -0.8125,-0.1875 -0.27624,-0.0436 -0.55593,-0.0625 -0.84375,-0.0625 z m 0.9375,0.34375 c 0.10941,-0.002 0.19002,0.0392 -0.0312,0.125 l -0.125,0 c -0.0956,-0.0755 0.047,-0.123 0.15625,-0.125 z m -0.34375,0.34375 c 0.0496,-0.007 0.1158,-0.01 0.1875,0.0312 0.23935,-0.0591 0.64214,0.0399 0.15625,0.0937 -0.0173,-0.0557 -0.1805,0.0348 -0.1875,-0.0312 -0.30815,0.0694 -0.3051,-0.0736 -0.15625,-0.0937 z m -96.375,0.125 c -2.01716,0.24966 -3.59375,2.35002 -3.59375,4.84375 0,0.18815 0.0135,0.38055 0.0312,0.5625 0.18622,-2.45446 1.88384,-4.40625 3.96875,-4.40625 2.08491,0 3.78253,1.95179 3.96875,4.40625 0.0174,-0.18193 0.0312,-0.37435 0.0312,-0.5625 0,-2.65998 -1.79067,-4.84375 -4,-4.84375 -0.13808,0 -0.27177,-0.0166 -0.40625,0 z m 95.96875,0.0625 c 0.14032,-0.0399 0.26801,0.0676 -0.0625,0.0937 -0.0249,0.0331 -0.039,0.001 -0.0625,0 0.0321,-0.0541 0.0782,-0.0805 0.125,-0.0937 z m -1.5625,0.0312 c 0.17989,-0.004 0.26434,0.0509 -0.0937,0.125 -0.11866,0.0154 -0.22739,0.165 -0.34375,0.125 -9e-5,-0.1727 0.25776,-0.246 0.4375,-0.25 z M 3,227.26653 l 0,1 2.5,0 9.5,0 0,-1 z m 40.46875,0.3125 c -1.88316,0.0897 -2.926,2.52114 -3.9375,4.78125 l -0.21875,0.5 c -0.80967,1.77098 -1.63642,3.3095 -2.96875,3.3125 0.3882,0.27003 0.75663,0.46625 1.09375,0.59375 0.74347,-0.56869 1.31215,-1.67512 1.875,-2.90625 l 0.21875,-0.5 c 1.0115,-2.26011 2.05434,-4.69152 3.9375,-4.78125 0.33166,-0.0157 0.67688,0.0457 1.0625,0.1875 0.33672,-0.25016 0.70547,-0.40625 1.125,-0.40625 -0.85371,-0.58916 -1.55978,-0.81105 -2.1875,-0.78125 z m 222.46875,0.0312 c -0.10926,0.002 -0.25181,0.0495 -0.15625,0.125 l 0.125,0 c 0.22132,-0.0858 0.14066,-0.12682 0.0312,-0.125 z m 0.5,0.15625 c -0.0203,0.0141 -0.0254,0.0267 -0.0312,0.0625 0.0724,-0.0194 0.14598,-0.0391 0.21875,-0.0625 -0.076,-0.0103 -0.15699,-0.0211 -0.1875,0 z m -0.84375,0.1875 c -0.12371,0.0168 -0.14134,0.131 0.0312,0.125 0.0351,-0.001 0.0729,-0.0196 0.125,-0.0312 0.007,0.066 0.1702,-0.0245 0.1875,0.0312 0.0875,-0.01 0.12024,-0.0198 0.15625,-0.0312 -0.007,-0.0318 -0.0413,-0.0395 -0.0625,-0.0625 -0.0797,-0.0105 -0.16296,-0.0215 -0.25,0 -0.0717,-0.0408 -0.13788,-0.038 -0.1875,-0.0312 z m 2.03125,0.15625 c 0.004,0.029 0.008,0.0565 0,0.0937 0.0384,0.0149 0.0606,-0.0143 0.0625,-0.0625 -0.0144,10e-4 -0.038,-0.0146 -0.0625,-0.0312 z m -2.4375,0.0312 c -0.0468,0.0133 -0.0929,0.0396 -0.125,0.0937 0.0235,0.001 0.0376,0.0331 0.0625,0 0.33051,-0.0263 0.20282,-0.13368 0.0625,-0.0937 z m -0.34375,0.0312 c -0.12212,0.0231 -0.25374,0.0844 -0.125,0.125 l 0.0312,0.0312 0.0937,-0.0312 c 0.22922,-0.13332 0.12212,-0.14807 0,-0.125 z m 1.0625,0.0312 c 0.065,0.0918 0.1072,0.21301 0.1875,0.21875 0.0987,-0.11602 0.1767,-0.13872 0.21875,-0.125 -0.1283,-0.0667 -0.26786,-0.0902 -0.40625,-0.0937 z m -1.5625,0.0315 c -0.0283,0.006 -0.0807,0.0189 -0.125,0.0312 -0.10641,0.0913 -0.14533,0.19131 -0.0625,0.28125 0.23141,-0.0322 0.39735,-0.0693 0.15625,-0.15625 0.0809,-0.1276 0.0749,-0.16495 0.0312,-0.15625 z M 265,228.36023 c -0.0243,-0.005 -0.0587,0.0139 -0.0937,0.0312 -0.0387,0.23854 -0.27092,0.27701 -0.53125,0.28125 0.18753,0.0603 0.34616,0.1219 0.34375,0.3125 0.34901,0.0214 0.0627,-0.2312 0.375,-0.1875 0.0374,-0.0477 0.0595,-0.10421 0.0937,-0.15625 -0.0739,-0.0575 -0.0798,-0.26094 -0.1875,-0.28125 z m 1.375,0 c 0.0343,0.11949 0.009,0.35008 0.0625,0.40625 0.0407,-0.0282 0.12377,-0.0215 0.25,0 -0.007,-0.16706 -0.14492,-0.29959 -0.3125,-0.40625 z m -5.96875,0.0625 c -0.87281,1.042 -1.40625,2.37815 -1.40625,3.84375 0,0.20711 0.0109,0.4233 0.0312,0.625 0.05,-0.77883 0.24163,-1.51871 0.5625,-2.1875 -0.0134,-0.002 -0.021,-0.0151 -0.0312,-0.0625 0.0384,-0.0679 0.0822,-0.1008 0.0937,-0.0937 0.20706,-0.40173 0.46215,-0.78135 0.75,-1.125 0.25655,-0.0158 0.56015,0.0785 0.6875,0.25 0.0297,-0.0169 0.0688,-0.0334 0.0937,-0.0312 0.042,-0.0985 0.08,-0.16987 0.125,-0.1875 -0.33344,-0.18836 -0.1679,-0.36609 -0.0937,-0.5625 -0.009,0.0116 -0.0318,0.0132 -0.0625,-0.0312 0.0243,-0.30945 -0.40794,-0.4586 -0.75,-0.4375 z m 4.25,0.0625 c -0.0294,0.007 -0.0677,0.0412 -0.0937,0.0937 0.23501,0.0305 0.18197,-0.11403 0.0937,-0.0937 z m 2.96875,0 c -0.1229,0.0647 -0.30864,0.56687 0,0.625 0.19641,0.13297 0.0343,-0.35877 0.0625,-0.5 -0.008,-0.10783 -0.0215,-0.14656 -0.0625,-0.125 z m -6.40625,0.15625 c -0.009,0.0326 -0.003,0.0919 0,0.15625 0.008,-0.04 0.0392,-0.0815 0.0312,-0.125 -0.001,-0.0172 -0.0254,-0.0171 -0.0312,-0.0312 z M 261,228.82903 c 0.0264,-0.019 0.0968,0.0763 0,0.0625 -0.007,-0.0415 -0.009,-0.0565 0,-0.0625 z m 4.875,0.34375 c -0.23735,-0.008 -0.70217,0.40793 -0.21875,0.15625 0.44403,-0.16004 -0.2027,0.70993 -0.125,0.125 l -0.0312,0.0625 c -0.0217,0.31005 -0.5469,0.5013 -0.5625,0.5625 -0.30778,0.0882 -0.38275,0.41405 -0.46875,0.34375 0.0688,0.4831 -0.87396,0.50311 -0.53125,1.09375 -0.0138,0.0154 -0.0211,0.21545 -0.0937,0.15625 -0.0109,-0.394 -0.37081,-0.61268 -0.71875,-0.4375 0.0163,0.0122 0.0242,0.0232 0.0312,0.0312 -0.10385,0.007 -0.5117,-0.077 -0.5625,0.125 -0.10172,0.1351 -0.1738,0.2411 -0.25,0.1875 0.0576,0.14242 0.0733,0.32522 0,0.4375 -0.005,0.23701 0.13149,0.33275 0.28125,0.34375 0.004,-0.007 0.0258,0.006 0.0312,0 0.0616,-0.0648 0.13539,-0.0965 0.25,-0.0937 0.0604,-0.0487 0.12526,-0.1103 0.15625,-0.1875 0.14196,-0.0234 0.16896,0.0402 0.15625,0.125 0.31377,-0.0921 0.61514,0.11241 0.625,0.46875 0.0727,0.0592 0.0799,-0.14085 0.0937,-0.15625 -0.12166,-0.20968 -0.0682,-0.3254 0.0312,-0.4375 -0.004,-0.002 0.004,-0.0297 0,-0.0312 -0.18038,-0.0735 -0.37537,-0.1227 -0.4375,-0.0937 0.0102,-0.029 0.024,-0.0525 0.0625,-0.0625 0.10213,-0.0253 0.27432,0.0391 0.4375,0.0937 0.19261,-0.16267 0.4762,-0.29076 0.4375,-0.5625 0.086,0.0703 0.16097,-0.25555 0.46875,-0.34375 0.0156,-0.0612 0.5408,-0.25245 0.5625,-0.5625 l 0.0312,-0.0625 c -0.0777,0.58493 0.56903,-0.28504 0.125,-0.125 -0.48342,0.25168 -0.0186,-0.16425 0.21875,-0.15625 0.2339,0.10315 1.13432,-0.3299 0.59375,-0.375 -0.0817,0.002 -0.0573,-0.25438 -0.0937,-0.40625 -0.002,-0.007 -0.0294,0.006 -0.0312,0 -0.0448,0.005 -0.0241,-0.019 0,-0.0625 -0.0396,-0.0514 -0.12172,-0.0571 -0.25,0.0937 -0.091,-0.007 -0.14021,-0.15128 -0.21875,-0.25 z m -4.84375,0.15625 c 0.0652,0.004 0.34053,0.29011 0.0312,0.125 -0.0557,-0.0851 -0.053,-0.126 -0.0312,-0.125 z m 4.875,0.1875 c 0.0553,0.002 0.006,0.0768 -0.0937,0.0312 0.0427,-0.0211 0.0754,-0.032 0.0937,-0.0312 z m 0.21875,0 c -0.0161,0.0169 -0.0897,0.0798 -0.25,0.15625 -0.098,0.0228 -0.17812,0.12482 -0.28125,0.125 0.054,-0.10979 0.30057,-0.2123 0.4375,-0.25 0.0685,-0.0188 0.10987,-0.0481 0.0937,-0.0312 z m 0.4375,0.59375 c -0.0981,0.006 -0.34815,0.29505 -0.21875,0.28125 0.13337,0.0266 0.64304,-0.01 0.25,-0.15625 0.021,-0.0859 8.5e-4,-0.12697 -0.0312,-0.125 z M 4.09375,230.26653 C 4.04015,230.42085 4,230.59394 4,230.76653 c 0,0.82842 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67158 1.5,-1.5 0,-0.17259 -0.04015,-0.34568 -0.09375,-0.5 -0.20384,0.58641 -0.75041,1 -1.40625,1 -0.65584,0 -1.20241,-0.41359 -1.40625,-1 z m 93.90625,3 0,1 14,0 0,-1 z m 101,-3 0,1 10,0 0,-1 z m 26,0 0,1 10,0 0,-1 z m 40.90625,0.25 c -0.0184,-7.1e-4 -0.051,0.0102 -0.0937,0.0312 0.0994,0.0455 0.14906,-0.0292 0.0937,-0.0312 z m 0.21875,0 c 0.0161,-0.0169 -0.0253,0.0124 -0.0937,0.0312 -0.13693,0.0377 -0.38348,0.14021 -0.4375,0.25 0.10313,-1.8e-4 0.18325,-0.1022 0.28125,-0.125 0.16025,-0.0764 0.23388,-0.1394 0.25,-0.15625 z m -5.28125,0.4375 c -0.11123,0.1825 -0.1956,0.40944 -0.1875,0.5625 -0.006,0.28224 0.15163,0.47561 0.375,0.5625 -0.16645,0.0629 -0.0795,0.49173 0.0937,0.625 0.234,0.59128 0.0786,-0.21992 -0.0625,-0.40625 0.1184,-0.41868 0.28654,0.49131 0.5,0.59375 0.0459,0.40021 0.30654,0.5924 0.6875,0.71875 0.1724,0.007 0.42696,0.0904 0.5625,0 -0.0572,0.0939 -0.0543,0.2011 0.0937,0.21875 0.0497,0.0166 0.18315,0.0719 0.21875,0 0.0368,0.0175 0.10148,0.0197 0.15625,-0.0312 0.0432,-0.0198 0.0361,0.0124 0.0625,0 -0.11865,0.0885 -0.24669,0.23155 0.0312,0.28125 0.18197,0.12198 0.21941,-0.59882 -0.0312,-0.46875 -0.27053,-0.0764 -0.31824,0.10185 -0.25,0.1875 -0.15746,0.0411 -0.11319,-0.12221 -0.0312,-0.28125 -0.0131,-0.0878 -0.1107,-0.0461 -0.1875,0.0312 0.0164,-0.0269 0.0254,-0.0521 0.0312,-0.0937 0.0937,-0.0718 0.12538,-0.11212 0.15625,-0.125 0.065,-0.0272 0.0304,0.0826 0,0.1875 0.11801,-0.22906 0.30468,-0.48768 0,-0.4375 -0.14636,0.36457 -0.72915,0.44313 -0.71875,-0.0625 0.0685,-0.10487 0.0484,-0.26871 0,-0.40625 -0.0319,-0.004 -0.0654,0.001 -0.0937,0 -0.38096,-0.12635 -0.6416,-0.31854 -0.6875,-0.71875 -0.21346,-0.10244 -0.3816,-1.01243 -0.5,-0.59375 0.1411,0.18633 0.2965,0.99753 0.0625,0.40625 -0.1732,-0.13327 -0.26025,-0.5621 -0.0937,-0.625 -0.0698,-0.0272 -0.13352,-0.0776 -0.1875,-0.125 z M 43.3125,231.29778 c -0.1816,0.31879 -0.35963,0.64171 -0.53125,1 l 1.5,0 c 0.0209,0 0.0427,-0.003 0.0625,0 l 0.375,-0.5 c 0,-0.26716 -0.17967,-0.5 -0.4375,-0.5 z m 216.34375,0.25 c -0.0116,-0.007 -0.0553,0.0258 -0.0937,0.0937 0.0414,0.1895 0.12859,-0.0729 0.0937,-0.0937 z M 163,232.32903 c -0.0205,0.19287 -0.0312,0.39628 -0.0312,0.59375 0,2.09778 1.19729,3.92576 3,5 l 1,0 0,-0.5 c -2.21887,-0.87849 -3.79699,-2.80631 -3.96875,-5.09375 z m 13.28125,0 c -0.17176,2.28744 -1.74988,4.21527 -3.96875,5.09375 l 0,0.5 1,0 c 1.80271,-1.07423 3,-2.90222 3,-5 0,-0.19747 -0.0105,-0.40088 -0.0312,-0.59375 z m -142.25,0.4375 c -0.0117,0.16523 -0.03125,0.33181 -0.03125,0.5 0,3.86518 3.13483,7 7,7 3.86633,0 7,-3.13482 7,-7 0,-0.16819 -0.01958,-0.33477 -0.03125,-0.5 -0.256502,3.63184 -3.27066,6.5 -6.96875,6.5 -3.69698,0 -6.71216,-2.86816 -6.96875,-6.5 z m 224,0 c -0.0117,0.16523 -0.0312,0.33181 -0.0312,0.5 0,3.86516 3.13484,7 7,7 3.86516,0 7,-3.13484 7,-7 0,-0.16819 -0.0197,-0.33477 -0.0312,-0.5 -0.23218,3.28629 -2.72453,5.92969 -5.9375,6.40625 -0.2472,0.0367 -0.49509,0.0837 -0.75,0.0937 -0.0934,0.004 -0.1869,0 -0.28125,0 -0.23901,0 -0.48704,-0.004 -0.71875,-0.0312 -0.17128,-0.0174 -0.33259,-0.0642 -0.5,-0.0937 -3.12189,-0.55073 -5.52238,-3.15326 -5.75,-6.375 z m 5.5625,0.1249 c -0.0385,0.01 -0.0523,0.0335 -0.0625,0.0625 0.0946,-0.044 0.49211,0.15054 0.6875,0.21875 0.0251,-0.024 0.0663,-0.0415 0.0937,-0.0625 -0.12035,-0.0982 -0.5371,-0.26382 -0.71875,-0.21875 z M 199,233.26653 l 0,1 3,0 0,-1 z m 4,0 0,1 3,0 0,-1 z m 4,0 0,1 2,0 0,-1 z m 18,0 0,1 2,0 0,-1 z m 3,0 0,1 3,0 0,-1 z m 4,0 0,1 3,0 0,-1 z m -34.5625,0.0625 -3.4375,2.9375 0,1 4,-3.4375 z m 39.125,0 -0.5625,0.5 4,3.4375 0,-1 z m 27.4375,0 c -0.008,0.003 -0.012,0.0122 0,0.0312 0.0896,0.0203 0.0878,0.008 0.0937,0 -0.003,-0.002 0.003,-0.0298 0,-0.0312 -0.021,-0.009 -0.0441,-10e-4 -0.0625,0 2.1e-4,0.004 -0.0269,-0.004 -0.0312,0 z m -0.71875,0.78125 c -0.0104,0.0169 0.0106,0.052 0.15625,0.15625 0.36178,0.0251 -0.12511,-0.20702 -0.15625,-0.15625 z m 0.34375,0.15625 c -0.0422,0.0167 -0.0392,0.0395 0.0312,0.0937 0.0399,0.0493 0.0896,0.0317 0.125,0 0.004,-0.0295 0.0211,-0.0628 0.0312,-0.0937 -0.0712,-0.007 -0.14694,-0.016 -0.1875,0 z m 0.34375,0.65625 c -0.10804,0.2558 -0.28337,0.47349 -0.125,0.65625 0.16253,-0.007 0.37406,0.005 0.59375,0.0625 -0.14762,-0.22531 -0.31541,-0.46286 -0.46875,-0.71875 z m 0.46875,0.71875 c 0.0531,0.0811 0.10775,0.1673 0.15625,0.25 0.13697,0.0174 0.23403,0.0459 0.40625,0.0625 -0.11265,-0.16775 -0.33219,-0.2521 -0.5625,-0.3125 z m 0.15625,0.25 c -0.35747,-0.0455 -0.56127,-0.0826 -0.71875,-0.125 0.18134,0.32397 0.38486,0.60386 0.5625,0.875 0.21419,0.0562 0.41301,0.13583 0.53125,0.28125 -10e-4,-0.0109 10e-4,-0.0203 0,-0.0312 -0.06,-0.39876 -0.20182,-0.7051 -0.375,-1 z m -0.15625,0.75 c -0.72058,-0.18902 -1.52571,0.0359 0.15625,0.25 -0.0485,-0.0827 -0.10312,-0.16891 -0.15625,-0.25 z m 0.15625,0.25 c 0.17318,0.2949 0.31495,0.60124 0.375,1 0.0174,0.13576 0.0395,0.24991 0.0625,0.375 0.0832,6.6e-4 0.16831,0.004 0.25,0 -0.11731,-0.35952 -0.24191,-0.79815 -0.3125,-1.3125 -0.14943,-0.0169 -0.24832,-0.0464 -0.375,-0.0625 z m 3,-1.5 c -0.0448,0.33467 0.0313,0.75539 -0.3125,0.875 -0.59418,0.0802 -0.30854,0.82256 -0.71875,1.15625 -0.0731,0.0783 -0.14495,-0.0104 -0.21875,-0.0312 -0.0534,-0.0219 -0.1027,-0.0513 -0.125,-0.0937 0.007,0.12666 0.0413,0.2432 0.1875,0.34375 -0.0237,0.28512 -0.4357,0.12709 -0.375,0.4375 -10e-4,0.0372 0.002,0.0587 0,0.0937 0.0652,-0.0112 0.12302,-0.0492 0.1875,-0.0625 0.0225,-0.12203 0.0832,-0.12133 0.0625,0 0.17042,-0.0369 0.33537,-0.10524 0.5,-0.15625 0.0746,-0.31626 0.11553,-0.6356 0.5,-0.6875 0.47136,-0.164 0.14359,-0.87555 0.4375,-1.1875 0.32681,-0.29111 0.15382,-0.54762 -0.125,-0.6875 z m -1.375,1.90625 c 0.15775,-0.34927 -0.0227,-0.40268 0,0 z M 2,238.26653 l 0,1 14,0 0,-1 -13,0 z m 197,0 0,1 10,0 0,-1 z m 26,0 0,1 10,0 0,-1 z m -62.03125,0.3125 0,1 c 0,0.36933 0.28692,0.65625 0.65625,0.65625 l 4,0 c 0.368,0 0.6875,-0.28825 0.6875,-0.65625 l 0,-0.78125 0,-0.21875 c 0,0.368 -0.3195,0.65625 -0.6875,0.65625 l -4,0 c -0.36933,0 -0.65625,-0.28692 -0.65625,-0.65625 z m 8,0 0,0.21875 0,0.78125 c 0,0.368 0.28825,0.65625 0.65625,0.65625 l 4,0 c 0.0924,0 0.17019,0.002 0.25,-0.0312 0.23926,-0.1012 0.4375,-0.349 0.4375,-0.625 l 0,-1 c 0,0.276 -0.19824,0.5238 -0.4375,0.625 -0.0798,0.0332 -0.1576,0.0312 -0.25,0.0312 l -4,0 c -0.368,0 -0.65625,-0.28825 -0.65625,-0.65625 z M 99,239.26653 l 0,1 12,0 0,-1 z m -58.875,20.34375 -0.15625,0.4375 -3.625,8.875 0.40625,0 3.21875,-7.875 0.15625,-0.4375 1.8125,0 0.09375,0.21875 3.25,8.09375 0.40625,0 -3.65625,-9.09375 -0.09375,-0.21875 z m -30.8330666,1.40537 -1,2.6875 0.375,0 0.625,-1.6875 0.5625,1.6875 0.3437496,0 z m -1.71875,4.71875 -0.90625,2.5 -2.09375,0 c -0.13585,0.33226 -0.27307,0.67472 -0.40625,1 l 2.5,0 0.90625,-2.5 3.3437496,0 0.8125,2.5 2.625,0 c -0.13156,-0.32951 -0.27229,-0.66624 -0.40625,-1 l -2.21875,0 -0.8125,-2.5 z m 32.5205666,-0.34287 -0.28125,0.53125 c 0,0.32152 0.27225,0.59375 0.59375,0.59375 l 1.15625,0 c 0.32151,0 0.59288,-0.27223 0.59375,-0.59375 L 41.875,265.39153 c -0.0948,0.0648 -0.19193,0.125 -0.3125,0.125 l -1.15625,0 c -0.12056,0 -0.21755,-0.0602 -0.3125,-0.125 z M 34,268.92278 l 0,1 c 0,1.28606 1.0577,2.34375 2.34375,2.34375 l 9.3125,0 c 1.28606,0 2.3125,-1.05769 2.3125,-2.34375 l 0,-1 c 0,1.28606 -1.02644,2.34375 -2.3125,2.34375 l -9.3125,0 C 35.0577,271.26653 34,270.20884 34,268.92278 z m -31.03125,2.34375 0,1 13.03125,0 0,-1 z m 3.09375,19 -0.5625,0.625 0.46875,0.46875 L 7,290.26653 z m 4.9375,0 1.03125,1.09375 0.46875,-0.46875 -0.5625,-0.625 z m 23.5,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 3.5,0 c -0.554,0 -1,0.446 -1,1 l 0,1 c 0,-0.554 0.446,-1 1,-1 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554 -0.446,-1 -1,-1 z m 22,0 c -0.554,0 -1,0.446 -1,1 l 0,1 c 0,-0.554 0.446,-1 1,-1 0.554,0 1,0.446 1,1 l 0,-1 c 0,-0.554 -0.446,-1 -1,-1 z m 3.5,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -45,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 29,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -76,0.625 -1.5,1.375 0,1 1.5,-1.375 2,2 2,0 0,-1 -2,0 z m 11,0 -2,2 -2,0 0,1 2,0 2,-2 1.5,1.375 0,-1 z m 20,1.375 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 29,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -45,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 29,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -45,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 29,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -72,1.375 -2,2 0.46875,0.53125 L 7.5,300.64153 z m 3,0 0,1 1.53125,1.53125 0.46875,-0.53125 z m 25.5,0.625 c -0.554,0 -1,0.446 -1,1 0,0.1879 0.0668,0.35013 0.15625,0.5 0.17423,-0.29199 0.47765,-0.5 0.84375,-0.5 l 5,0 c 0.3661,0 0.66952,0.20801 0.84375,0.5 0.0894,-0.14987 0.15625,-0.3121 0.15625,-0.5 0,-0.554 -0.446,-1 -1,-1 z m 37,0 c -0.554,0 -1,0.446 -1,1 0,0.1879 0.06682,0.35013 0.15625,0.5 0.174233,-0.29199 0.477651,-0.5 0.84375,-0.5 l 5,0 c 0.366099,0 0.669517,0.20801 0.84375,0.5 0.08943,-0.14987 0.15625,-0.3121 0.15625,-0.5 0,-0.554 -0.446,-1 -1,-1 z m -29,1 0,1 c 0,1.0907 0.9093,2 2,2 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 -1.0907,0 -2,-0.9093 -2,-2 z m 22,0 0,1 c 0,1.0907 0.9093,2 2,2 1.0907,0 2,-0.9093 2,-2 l 0,-1 c 0,1.0907 -0.9093,2 -2,2 -1.0907,0 -2,-0.9093 -2,-2 z m -31.9375,0.5 c -0.0416,0.15879 -0.0625,0.32958 -0.0625,0.5 0,1.0907 0.9093,2 2,2 l 5,0 c 1.0907,0 2,-0.9093 2,-2 0,-0.17042 -0.0209,-0.34121 -0.0625,-0.5 -0.22476,0.85745 -1.01722,1.5 -1.9375,1.5 l -5,0 c -0.92028,0 -1.71274,-0.64255 -1.9375,-1.5 z m 37,0 c -0.04162,0.15879 -0.0625,0.32958 -0.0625,0.5 0,1.0907 0.9093,2 2,2 l 5,0 c 1.0907,0 2,-0.9093 2,-2 0,-0.17042 -0.02088,-0.34121 -0.0625,-0.5 -0.224763,0.85745 -1.017222,1.5 -1.9375,1.5 l -5,0 c -0.920278,0 -1.712737,-0.64255 -1.9375,-1.5 z m -69.0625,1.5 0,1 5,0 -0.9375,-1 z m 9.9375,0 -0.9375,1 5,0 0,-1 z m -2.53125,20.28125 c -1.26501,0 -2.3125,1.04749 -2.3125,2.3125 l -2.15625,0 c -0.071,0.3201 -0.125,0.659 -0.125,1 l 2.28125,0 c 0,-1.26501 1.04749,-2.3125 2.3125,-2.3125 1.09686,0 2.02751,0.77849 2.25,1.8125 0.0343,-0.15805 0.03125,-0.33128 0.03125,-0.5 0,-1.26501 -1.01624,-2.3125 -2.28125,-2.3125 z m 4.53125,2.875 c -0.23194,1.88014 -1.607221,3.4109 -3.40625,3.875 l 0,0.125 c 0,0.6325 -0.4925,1.15625 -1.125,1.15625 -0.6325,0 -1.15625,-0.52375 -1.15625,-1.15625 l 0,0.875 0,0.125 c 0,0.41052 0.2347,0.76332 0.5625,0.96875 0.18372,-0.0736 0.3831,-0.125 0.59375,-0.125 0.21065,0 0.41003,0.0514 0.59375,0.125 0.31856,-0.20543 0.53125,-0.55823 0.53125,-0.96875 l 0,-0.125 c 1.976569,-0.5099 3.4375,-2.30281 3.4375,-4.4375 0,-0.14723 -0.01785,-0.29375 -0.03125,-0.4375 z m -6.03125,7.9375 c -0.0529,0.15899 -0.09375,0.32277 -0.09375,0.5 0,0.88308 0.71066,1.625 1.59375,1.625 0.88309,0 1.59375,-0.74192 1.59375,-1.625 0,-0.17723 -0.04095,-0.34101 -0.09375,-0.5 -0.21067,0.64123 -0.79413,1.125 -1.5,1.125 -0.70587,0 -1.28933,-0.48377 -1.5,-1.125 z"
1516 id="path5248"
1517 inkscape:connector-curvature="0"
1518 sodipodi:nodetypes="ccccccsssscssccsscsscsssssssssscccccccssssssscccsscsccccccssccsccsccsscccccccsccccccsccccccccccccccccccccccccccccccccccccccccccccccccsscscsssscscsscscsssccssscsccccccccccccccccsscscssccccccccccccccccccccccccccccccccccscccccccccccccccccccccccccccccccccsscssccscsccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccsscsscssssccscscscccssscsccscssssscsccscssssscsscssssscsscssssscsccccccccsccccsscsccscssscccccccccccscccccccssscsssccscccscccsccccccsscccccccccccccsssccccccccccccccccccccccccccccccccccccccccssscsccssscccscccccsssscssccsssscssccccccccccccccccccccccccccsccssscsscccccccccsssscsscssssscccscssssscccccsssscssccsssscssccssccsccccccccccccccccccsssscssccsssscsscssssssccscsssscccscccccsccccsssscscccccscccccccccccccccccccccccccsssccscccccccccccccccccccccccccccccccccccscccccccccccscccssccccccccccccscccccccccssssscscccccscccccccccccccsccccccccscccccccccscccccscsccsscsscccscsccsscsscccccsccscccccsscccscccccccccccscccssccccccccsssssssccccccccccccssssscscssssssscccccsssccssssssssssssssscscccccsssssssssssssscccccccccccscssccccsssccsssscssssssssscssssssssssssssssssssssssssssscssssssssscssssssssssssssscccccccccccccccccccccccccccccccssscsccssscscsssssssssssssssssssssssssssscccccccccccsccccsccccsccsccsccsccccscccccsccsssssssssssssssssssssssssssssssssssscccccccccccccssscsccssscsccccccccccccccccccccccccccccccccccccccccccscsscscccsssscssssssssscssssscccccccssssccssssccsccccccsssscssssssssscsssssssssccscccccccccccccccccccccccccccccccccsssccssssssssssssssssssccssssssssssssssssssssssssssssssssssssssssssssssssssscccccccccccccccccccccccscccsccsccccscccsccsccssscsccssscscccccccccccccccsssssssssssssssssssssssssssssssssccsssccsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssscccccccccccccccccccccccccccccccccccccccccssssscsccssssscsccssscsccssscsccssscsccssscscscscsccsccscsccsccscscsccsccsscccsccccsccsccssssssccssssccsssccscsscccsscccscccsccccsscccsccscccssccssccccsccccsscccsccccsccccsccscccccccsccccscccccccccccccccccccccccccccccccccccccccccccccccccccccsccccccccccccccccccsccccccccccccccccccccccccccscscsscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccssscscccccccccccccccccccccccccccccccccccccccccccccccccccccccccsccscccccscccccccccscccssscsccssscccscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccssssccsscccssscsccsscccccccccccccccccccccccccccccccccccccccccssccssccsssscssccccccccccccccccssssssssssssssssssssssssssscscsssscscsssssssssssssssssssssssssssssssssssssssssssssssccccccccccccccccccssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssccccccccccsscsscssssscsscssscssscsccssscsccsssscssccsssscsscccccccccccsccccscssccssccscscscsccssscsc" /><path
1519 sodipodi:nodetypes="sssss"
1520 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1521 d="m 41,322.20096 c -3.86517,0 -7,3.1502 -7,7.03432 0,3.88412 3.13483,7.03431 7,7.03431 3.86633,0 7,-3.15019 7,-7.03431 0,-3.88412 -3.13367,-7.03432 -7,-7.03432 z"
1522 id="path4290-7"
1523 inkscape:connector-curvature="0" /><path
1524 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1525 d="m 99,2.2352457 0,13.9999983 11,0 0,-8.9999983 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.4999983 -5,0 -3,0 -1,0 z"
1526 id="path4249"
1527 inkscape:connector-curvature="0"
1528 sodipodi:nodetypes="cccccccccccccccc" /><path
1529 sodipodi:nodetypes="cccccccccccccccc"
1530 inkscape:connector-curvature="0"
1531 id="path4303"
1532 d="m 142,2.2352457 0,13.9999983 -11,0 0,-8.9999983 0,-1 4,-4 1,0 z m -1,1 -5.5,0 -3.5,3.5 0,8.4999983 5,0 3,0 1,0 z"
1533 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1534 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1535 d="m 47,2.2352457 0,13.9999983 -11,0 0,-8.9999983 0,-1 4,-4 1,0 z m -1,1 -5.5,0 -3.5,3.5 0,8.4999983 5,0 3,0 1,0 z"
1536 id="path4305"
1537 inkscape:connector-curvature="0"
1538 sodipodi:nodetypes="cccccccccccccccc" /><path
1539 sodipodi:nodetypes="cccccccccccccccc"
1540 inkscape:connector-curvature="0"
1541 id="path4307"
1542 d="m 3,2.2352457 0,13.9999983 11,0 0,-8.9999983 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.4999983 -5,0 -3,0 -1,0 z"
1543 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1544 sodipodi:nodetypes="cccccccccccccccc"
1545 inkscape:connector-curvature="0"
1546 id="path4311"
1547 d="m 259,2.2352457 0,13.9999983 11,0 0,-8.9999983 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.4999983 -5,0 -3,0 -1,0 z"
1548 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1549 inkscape:connector-curvature="0"
1550 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1551 d="m 291,2.2664961 0,4.75 c 0.19146,-0.120143 0.37062,-0.220842 0.5625,-0.3125 l 0.4375,-0.21875 0,-3.21875 5.34375,0 3.65625,3.65625 0,8.3437479 -5,0 0,0.96875 c 0,0.01043 1.6e-4,0.02085 0,0.03125 l 6,0 0,-8.9999979 0,-1 -4,-4 -1,0 -6,0 z m 1,5.34375 c -0.36123,0.1725556 -0.68892,0.3764146 -0.96875,0.6562496 C 290.39787,8.8998727 290,9.7999957 290,10.766494 c 0,1.393522 0.8237,2.564396 2,3.125 l 0,2.34375 c 0,0.554002 0.44599,1.000002 1,1 l 1,0.03125 c 0.554,-2e-6 1,-0.477248 1,-1.03125 l 0,-2.34375 c 1.17629,-0.560603 2,-1.731478 2,-3.125 0,-1.3935203 -0.82119,-2.5931323 -2,-3.1562479 l 0,2.6562479 -1.46875,1 -1.53125,-1 0,-2.6562479 z"
1552 id="path5011-3" /><path
1553 id="path4415"
1554 d="m 334,2.2664961 0,4.75 c -0.19146,-0.120143 -0.37062,-0.220842 -0.5625,-0.3125 L 333,6.4852461 l 0,-3.21875 -5.34375,0 -3.65625,3.65625 0,8.3437479 5,0 0,0.96875 c 0,0.01043 -1.6e-4,0.02085 0,0.03125 l -6,0 0,-8.9999979 0,-1 4,-4 1,0 6,0 z m -1,5.34375 c 0.36123,0.1725556 0.68892,0.3764146 0.96875,0.6562496 0.63338,0.633377 1.03125,1.5335 1.03125,2.4999983 0,1.393522 -0.8237,2.564396 -2,3.125 l 0,2.34375 c 0,0.554002 -0.44599,1.000002 -1,1 l -1,0.03125 c -0.554,-2e-6 -1,-0.477248 -1,-1.03125 l 0,-2.34375 c -1.17629,-0.560603 -2,-1.731478 -2,-3.125 0,-1.3935203 0.82119,-2.5931323 2,-3.1562479 l 0,2.6562479 1.46875,1 1.53125,-1 0,-2.6562479 z"
1555 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1556 inkscape:connector-curvature="0" /><path
1557 inkscape:connector-curvature="0"
1558 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1559 d="m 163,2.2352457 0,13.9999983 8.8125,0 -1,-1 -1.3125,0 -1.5,0 -3,0 -1,0 0,-11.9999983 5.5,0 3.5,3.5 0,1.21875 c 0.61468,0.769889 1,1.728793 1,2.7812483 l 0,-3.4999983 0,-1 -4,-4 -1,0 -6,0 z m 11,8.4999983 c 0,0.483188 -0.20077,0.86276 -0.34375,1.28125 l 0.34375,0.34375 0,-1.625 z m -4.5,-3.4999983 c -1.92115,0 -3.5,1.57884 -3.5,3.4999983 0,1.92115 1.57885,3.5 3.5,3.5 0.49539,0 0.94633,-0.12374 1.375,-0.3125 l 2.34375,2.34375 1.625,-1.625 -2.28125,-2.28125 c 0.2665,-0.49285 0.4375,-1.0296 0.4375,-1.625 0,-1.9211583 -1.57885,-3.4999983 -3.5,-3.4999983 z m -0.0312,1 c 1.38071,0 2.5,1.11929 2.5,2.4999983 0,1.38071 -1.11929,2.5 -2.5,2.5 -1.38071,0 -2.5,-1.11929 -2.5,-2.5 0,-1.3807083 1.11929,-2.4999983 2.5,-2.4999983 z"
1560 id="path4953-8" /><path
1561 id="path4243"
1562 d="m 207,2.2352457 0,13.9999983 -8.8125,0 1,-1 1.3125,0 1.5,0 3,0 1,0 0,-11.9999983 -5.5,0 -3.5,3.5 0,1.21875 c -0.61468,0.769889 -1,1.728793 -1,2.7812483 l 0,-3.4999983 0,-1 4,-4 1,0 6,0 z m -11,8.4999983 c 0,0.483188 0.20077,0.86276 0.34375,1.28125 L 196,12.360244 l 0,-1.625 z m 4.5,-3.4999983 c 1.92115,0 3.5,1.57884 3.5,3.4999983 0,1.92115 -1.57885,3.5 -3.5,3.5 -0.49539,0 -0.94633,-0.12374 -1.375,-0.3125 l -2.34375,2.34375 -1.625,-1.625 2.28125,-2.28125 c -0.2665,-0.49285 -0.4375,-1.0296 -0.4375,-1.625 0,-1.9211583 1.57885,-3.4999983 3.5,-3.4999983 z m 0.0312,1 c -1.38071,0 -2.5,1.11929 -2.5,2.4999983 0,1.38071 1.11929,2.5 2.5,2.5 1.38071,0 2.5,-1.11929 2.5,-2.5 0,-1.3807083 -1.11929,-2.4999983 -2.5,-2.4999983 z"
1563 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1564 inkscape:connector-curvature="0" /><path
1565 inkscape:connector-curvature="0"
1566 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1567 d="m 34,33.235244 0,10 3,0 0,-1 -1,0 -1,0 0,-8 4.5,0 2.5,2.5 0,0.5 1,0 0,-1 -3,-3 -1,0 -5,0 z m 4,5 0,10 9,0 0,-6 0,-1 -3,-3 -1,0 -5,0 z m 1,1 4.5,0 2.5,2.5 0,5.5 -5,0 -1,0 -1,0 0,-8 z"
1568 id="path3594-7" /><path
1569 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1570 d="M 71.53125,33.235244 C 71.236645,33.235244 71,33.471889 71,33.766494 l 0,0.46875 -0.46875,0 C 70.236645,34.235244 70,34.471889 70,34.766494 l 0,0.9375 c 0,0.294605 0.236645,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.294605,0 0.53125,-0.236645 0.53125,-0.53125 l 0,-0.9375 c 0,-0.294605 -0.236645,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.294605 -0.236645,-0.53125 -0.53125,-0.53125 z m -2.53125,1 c -1.090704,0 -2,0.909296 -2,2 l 0,9 c 0,1.090704 0.909296,2 2,2 l 1,0 0,-1 -1,0 c -0.554001,0 -1,-0.445999 -1,-1 l 0,-9 c 0,-0.554001 0.445999,-1 1,-1 l 0,-0.46875 c 0,-0.183581 0.0316,-0.366605 0.09375,-0.53125 z m 7.90625,0 C 76.968395,34.399889 77,34.582913 77,34.766494 l 0,0.46875 c 0.554001,0 1,0.445999 1,1 l 0,2 1,0 0,-2 c 0,-1.090704 -0.909296,-2 -2,-2 z m -4.90625,12 c -0.554,0 -1,1 -1,1 l 0,0 c 0,0 0.446,1 1,1 l 7,0 c 0.554,0 1,-1 1,-1 l 0,0 c 0,0 -0.446,-1 -1,-1 z"
1571 id="rect4963-2"
1572 inkscape:connector-curvature="0"
1573 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccsscsssssssss" /><path
1574 inkscape:connector-curvature="0"
1575 id="path4569"
1576 d="m 103.53125,33.235244 c -0.29461,0 -0.53125,0.236645 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.236645 -0.53125,0.53125 l 0,0.9375 c 0,0.294605 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.236645 0.53125,-0.53125 l 0,-0.9375 c 0,-0.294605 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.294605 -0.23664,-0.53125 -0.53125,-0.53125 z m -2.53125,1 c -1.090704,0 -2,0.909296 -2,2 l 0,9 c 0,1.090704 0.909296,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.445999 -1,-1 l 0,-9 c 0,-0.554001 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.183581 0.0316,-0.366605 0.0937,-0.53125 z m 7.90625,0 c 0.0622,0.164645 0.0937,0.347669 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.445999 1,1 l 0,2 1,0 0,-2 c 0,-1.090704 -0.9093,-2 -2,-2 l -0.0937,0 z m -4.90625,12 c -0.554,0 -1,1 -1,1 l 0,0 c 0,0 0.446,1 1,1 l 7,0 c 0.554,0 1,-1 1,-1 l 0,0 c 0,0 -0.446,-1 -1,-1 z"
1577 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1578 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1579 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1580 d="m 138.46875,33.235244 c 0.29461,0 0.53125,0.236645 0.53125,0.53125 l 0,0.46875 0.46875,0 c 0.29461,0 0.53125,0.236645 0.53125,0.53125 l 0,0.9375 c 0,0.294605 -0.23664,0.53125 -0.53125,0.53125 l -1,0 -2.9375,0 -1,0 c -0.29461,0 -0.53125,-0.236645 -0.53125,-0.53125 l 0,-0.9375 c 0,-0.294605 0.23664,-0.53125 0.53125,-0.53125 l 0.46875,0 0,-0.46875 c 0,-0.294605 0.23664,-0.53125 0.53125,-0.53125 z m 2.53125,1 c 1.0907,0 2,0.909296 2,2 l 0,9 c 0,1.090704 -0.9093,2 -2,2 l -1,0 0,-1 1,0 c 0.554,0 1,-0.445999 1,-1 l 0,-9 c 0,-0.554001 -0.446,-1 -1,-1 l 0,-0.46875 c 0,-0.183581 -0.0316,-0.366605 -0.0937,-0.53125 z m -7.90625,0 C 133.0316,34.399889 133,34.582913 133,34.766494 l 0,0.46875 c -0.554,0 -1,0.445999 -1,1 l 0,2 -1,0 0,-2 c 0,-1.090704 0.9093,-2 2,-2 l 0.0937,0 z m 4.90625,12 c 0.554,0 1,1 1,1 l 0,0 c 0,0 -0.446,1 -1,1 l -7,0 c -0.554,0 -1,-1 -1,-1 l 0,0 c 0,0 0.446,-1 1,-1 z"
1581 id="path4571"
1582 inkscape:connector-curvature="0"
1583 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1584 inkscape:connector-curvature="0"
1585 id="path4573"
1586 d="m 167.53125,33.235244 c -0.29461,0 -0.53125,0.236645 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.236645 -0.53125,0.53125 l 0,0.9375 c 0,0.294605 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.236645 0.53125,-0.53125 l 0,-0.9375 c 0,-0.294605 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.294605 -0.23664,-0.53125 -0.53125,-0.53125 z m -2.53125,1 c -1.0907,0 -2,0.909296 -2,2 l 0,9 c 0,1.090704 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.445999 -1,-1 l 0,-9 c 0,-0.554001 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.183581 0.0316,-0.366605 0.0937,-0.53125 z m 7.90625,0 c 0.0622,0.164645 0.0937,0.347669 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.445999 1,1 l 0,2 1,0 0,-2 c 0,-1.090704 -0.9093,-2 -2,-2 l -0.0937,0 z m -4.90625,12 c -0.554,0 -1,1 -1,1 l 0,0 c 0,0 0.446,1 1,1 l 7,0 c 0.554,0 1,-1 1,-1 l 0,0 c 0,0 -0.446,-1 -1,-1 z"
1587 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1588 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1589 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1590 d="m 202.46875,33.235244 c 0.29461,0 0.53125,0.236645 0.53125,0.53125 l 0,0.46875 0.46875,0 c 0.29461,0 0.53125,0.236645 0.53125,0.53125 l 0,0.9375 c 0,0.294605 -0.23664,0.53125 -0.53125,0.53125 l -1,0 -2.9375,0 -1,0 c -0.29461,0 -0.53125,-0.236645 -0.53125,-0.53125 l 0,-0.9375 c 0,-0.294605 0.23664,-0.53125 0.53125,-0.53125 l 0.46875,0 0,-0.46875 c 0,-0.294605 0.23664,-0.53125 0.53125,-0.53125 z m 2.53125,1 c 1.0907,0 2,0.909296 2,2 l 0,9 c 0,1.090704 -0.9093,2 -2,2 l -1,0 0,-1 1,0 c 0.554,0 1,-0.445999 1,-1 l 0,-9 c 0,-0.554001 -0.446,-1 -1,-1 l 0,-0.46875 c 0,-0.183581 -0.0316,-0.366605 -0.0937,-0.53125 z m -7.90625,0 C 197.0316,34.399889 197,34.582913 197,34.766494 l 0,0.46875 c -0.554,0 -1,0.445999 -1,1 l 0,2 -1,0 0,-2 c 0,-1.090704 0.9093,-2 2,-2 l 0.0937,0 z m 4.90625,12 c 0.554,0 1,1 1,1 l 0,0 c 0,0 -0.446,1 -1,1 l -7,0 c -0.554,0 -1,-1 -1,-1 l 0,0 c 0,0 0.446,-1 1,-1 z"
1591 id="path4575"
1592 inkscape:connector-curvature="0"
1593 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1594 inkscape:connector-curvature="0"
1595 style="opacity:0.98999999;fill:#ffffff;fill-opacity:0.99215686;stroke:none;display:inline"
1596 d="m 65,65.235244 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 10,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z"
1597 id="rect6608-2" /><path
1598 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1599 d="m 137,226.17278 c -3.86517,0 -7,3.14713 -7,7.03125 0,3.88412 3.13483,7.03125 7,7.03125 3.86633,0 7,-3.14713 7,-7.03125 0,-3.88412 -3.13367,-7.03125 -7,-7.03125 z m 0,1.03125 c 3.31371,0 6,2.68629 6,6 0,3.31371 -2.68629,6 -6,6 -3.31371,0 -6,-2.68629 -6,-6 0,-3.31371 2.68629,-6 6,-6 z m -2.34375,3 c -0.78758,0 -1.40625,0.64605 -1.40625,1.4375 0,0.79145 0.61867,1.4375 1.40625,1.4375 0.78761,0 1.4375,-0.64605 1.4375,-1.4375 0,-0.79145 -0.64989,-1.4375 -1.4375,-1.4375 z m 4.6875,0 c -0.7876,0 -1.4375,0.64605 -1.4375,1.4375 0,0.79145 0.6499,1.4375 1.4375,1.4375 0.78759,0 1.40625,-0.64605 1.40625,-1.4375 0,-0.79145 -0.61866,-1.4375 -1.40625,-1.4375 z m -5.23219,4.77513 c -0.0366,0.1544 -0.081,0.31581 -0.081,0.4768 0,1.55998 2.42289,1.8242 2.96945,1.81057 0.54656,-0.0136 2.96945,-0.25059 2.96945,-1.81057 0,-0.16099 -0.0444,-0.3224 -0.081,-0.4768 -1.30709,1.24337 -2.63751,1.02963 -2.88845,1.05774 -0.25094,0.0281 -2.02946,-0.0474 -2.88844,-1.05774 z"
1600 id="path3733"
1601 inkscape:connector-curvature="0"
1602 sodipodi:nodetypes="sssssssssssssssssssscszsczcc" /><path
1603 sodipodi:nodetypes="ssssssssscccccccccccccccccccccccccccccc"
1604 inkscape:connector-curvature="0"
1605 id="path3755"
1606 d="m 67,226.23528 c -1.108,0 -2,0.892 -2,2 l 0,10 c 0,1.108 0.892,2 2,2 l 12,0 c 1.108,0 2,-0.892 2,-2 l 0,-10 c 0,-1.108 -0.892,-2 -2,-2 z m -1,4 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m -10,5 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z"
1607 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline" /><path
1608 style="font-size:15.85716724px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#ffffff;fill-opacity:0.99215686;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
1609 d="m 105.21875,131.23528 c -1.3937,1e-5 -2.47545,0.28684 -3.21875,0.90625 -0.7433,0.61943 -1.09375,1.50517 -1.09375,2.65625 0,0.91881 0.24958,1.67676 0.78125,2.21875 0.0797,0.0804 0.18796,0.14481 0.28125,0.21875 l -2.46875,0 c -0.277,0 -0.5,0.18355 -0.5,0.4375 l 0,0.0937 c 0,0.25396 0.223,0.4688 0.5,0.4688 l 5,0 0.875,0.21875 c 0.70201,0.15486 1.17396,0.30385 1.40625,0.5 0.23744,0.19615 0.37499,0.48242 0.375,0.84375 -1e-5,0.40262 -0.18542,0.7207 -0.53125,0.9375 -0.34585,0.2168 -0.84961,0.3125 -1.5,0.3125 -0.64007,0 -1.30832,-0.0851 -2,-0.28125 -0.68653,-0.20131 -1.38686,-0.51394 -2.125,-0.90625 l 0,2.53125 c 0.73814,0.27358 1.4806,0.48563 2.21875,0.625 0.73814,0.13935 1.45451,0.21875 2.1875,0.21875 1.5537,0 2.71511,-0.31808 3.46875,-0.9375 0.75878,-0.62458 1.15624,-1.56877 1.15625,-2.84375 0,-0.44811 -0.0719,-0.8653 -0.1875,-1.21875 l 1.65625,0 c 0.277,0 0.5,-0.2148 0.5,-0.46875 l 0,-0.0937 c 0,-0.25396 -0.223,-0.43755 -0.5,-0.43755 l -2.25,0 c -0.0105,-0.0105 -0.0206,-0.0209 -0.0312,-0.0312 -0.542,-0.5265 -1.46471,-0.9294 -2.75,-1.1875 l -1.28125,-0.25 c -0.60393,-0.12388 -1.01772,-0.26715 -1.25,-0.4375 -0.22713,-0.17549 -0.34376,-0.44028 -0.34375,-0.75 -1e-5,-0.41294 0.19056,-0.71009 0.53125,-0.90625 0.34068,-0.19613 0.85016,-0.28124 1.5625,-0.28125 0.53683,1e-5 1.11481,0.0742 1.71875,0.21875 0.60393,0.14454 0.99009,0.34111 1.625,0.625 l 0,-2.46875 c -0.7175,-0.19098 -1.17272,-0.31335 -1.84375,-0.40625 -0.67104,-0.0981 -1.33385,-0.12499 -1.96875,-0.125 z"
1610 id="path3568-3"
1611 inkscape:connector-curvature="0" /><path
1612 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1613 d="m 65,322.23528 0,14 3,0 0,-1 -2,0 0,-12 2,0 0,-1 z m 13,0 0,1 2,0 0,12 -2,0 0,1 3,0 0,-14 z"
1614 id="rect3578-3"
1615 inkscape:connector-curvature="0"
1616 sodipodi:nodetypes="cccccccccccccccccc" /><path
1617 inkscape:connector-curvature="0"
1618 style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
1619 d="m 112,322.78127 -6,0.9375 0,1 2,-0.3125 0,2.84375 -3,0 0,1 3,0 0,3 -2,0 -1,0 0,5 1,0 0,-1 5,0 1,0 0,-4 -1,0 -2,0 0,-3 3,0 0,-1 -3,0 0,-3 3,-0.46875 0,-1 z m -13.999999,0.46875 0,1 5.999999,0 0,-1 -5.999999,0 z m -1,2 0,1 7.999999,0 0,-1 -7.999999,0 z m 1,2 0,1 5.999999,0 0,-1 -5.999999,0 z m 0,2 0,1 5.999999,0 0,-1 -5.999999,0 z m 0,2 0,5 1,0 0,-1 3.999999,0 1,0 0,-4 -1,0 -3.999999,0 -1,0 z m 1,1 3.999999,0 0,2 -3.999999,0 0,-2 z m 6.999999,0 5,0 0,2 -5,0 0,-2 z"
1620 id="rect4258-3" /><path
1621 style="fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1622 d="m 129,322.25002 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,5 0,1 0,3 5,0 0,-1 -4,0 0,-1 4,0 1,0 0,-1 -5,0 0,-1 6,0 4,0 0,-1 0,-4 -4,0 -7,0 z m 12,0 0,1 1,0 0,-1 -1,0 z m -11,1 9,0 0,1 -9,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -11,1 8.96875,0 0,1 -8.96875,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -3,1.75 -3.6875,3.375 3.6875,3.28125 0,-1.90625 -1.4375,-1.40625 1.4375,-1.53125 0,-1.8125 z m 1,0 0,1.875 1.375,1.46875 -1.375,1.46875 0,1.90625 3.625,-3.375 -3.625,-3.34375 z m -12,0.25 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z"
1623 id="rect5051-5"
1624 inkscape:connector-curvature="0" /></g><g
1625 inkscape:groupmode="layer"
1626 id="layer3"
1627 inkscape:label="Icons"
1628 style="display:inline"
1629 transform="translate(-1,-0.25001385)"
1630 sodipodi:insensitive="true"><rect
1631 y="321.25006"
1632 x="69"
1633 height="14.00004"
1634 width="8"
1635 id="rect4452"
1636 style="fill:#cccccc;fill-opacity:1;stroke:none" /><rect
1637 style="fill:#cccccc;fill-opacity:1;stroke:none"
1638 id="rect4367"
1639 width="12"
1640 height="10.000055"
1641 x="67"
1642 y="323.25006" /><g
1643 id="g4363"
1644 style="font-size:13.71140385px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#676767;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;font-family:Sans"
1645 transform="translate(2.0000001,0.25006141)"><path
1646 sodipodi:nodetypes="csssccccccsssc"
1647 inkscape:connector-curvature="0"
1648 id="path4365"
1649 style="font-variant:normal;font-weight:bold;font-stretch:normal;fill:#676767;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L Bold"
1650 d="m 70.006423,329.43503 1.991763,0 c 1.837326,0 3.016509,-1.30258 3.016509,-3.33187 0,-2.00186 -1.138049,-3.09877 -3.22218,-3.09877 l -3.790777,0 0,9.99561 2.004685,0 0,-3.56497 m 0,-1.71392 0,-3.0028 1.347327,0 c 1.096911,0 1.604234,0.4799 1.604234,1.50826 0,1.01464 -0.507323,1.49454 -1.604234,1.49454 l -1.347327,0" /></g><path
1651 style="fill:url(#linearGradient4406);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
1652 d="m 7.5,353.8438 c -0.79075,0.009 -1.60031,0.34033 -2.5,1.375 l 0,7 0,0.25 0,0.75 0,0.0312 c 0.22508,-0.25367 0.43768,-0.45147 0.65625,-0.625 0.18735,-0.14874 0.37931,-0.27793 0.5625,-0.375 0.0624,-0.0331 0.12551,-0.0662 0.1875,-0.0937 0.0832,-0.035 0.16738,-0.0679 0.25,-0.0937 0.0314,-0.0105 0.0624,-0.0221 0.0937,-0.0312 0.0824,-0.0228 0.16846,-0.047 0.25,-0.0625 0.009,10e-4 0.0222,-0.001 0.0312,0 0.17684,-0.0316 0.35709,-0.0655 0.53125,-0.0625 1.36919,0.0236 2.67349,0.99995 4.03125,1.375 0.20073,0.0554 0.38983,0.1016 0.59375,0.125 0.0652,0.007 0.12196,0.0277 0.1875,0.0312 0.0591,0.003 0.12808,3.1e-4 0.1875,0 0.028,0.004 0.0652,8.2e-4 0.0937,0 0.0532,-0.002 0.10326,-0.0244 0.15625,-0.0312 0.0415,-0.005 0.0829,0.005 0.125,0 0.0301,-0.004 0.0636,0.005 0.0937,0 0.0961,-0.0161 0.18405,-0.0665 0.28125,-0.0937 0.16842,-0.0473 0.32806,-0.10258 0.5,-0.1875 0.0298,-0.0141 0.0637,-0.0155 0.0937,-0.0312 0.015,-0.008 0.0175,-0.0197 0.0312,-0.0312 0.0138,-0.0116 0.0161,-0.0229 0.0312,-0.0312 0.16236,-0.0914 0.33405,-0.18218 0.5,-0.3125 0.0109,-0.009 0.0203,-0.0225 0.0312,-0.0312 0.16802,-0.13283 0.32813,-0.25969 0.5,-0.4375 l 0,-0.0312 0,-1 0,-6 0,-1 c -0.15402,0.16401 -0.31736,0.31409 -0.46875,0.4375 -0.0109,0.009 -0.0203,0.0224 -0.0312,0.0312 -0.13895,0.11076 -0.26887,0.19638 -0.40625,0.28125 -0.0367,0.0227 -0.0884,0.0417 -0.125,0.0625 -0.33321,0.18959 -0.64527,0.29368 -0.96875,0.34375 -1.94086,0.30044 -3.7208,-1.55267 -5.5,-1.53125 z m -4.5,0.40625 0,13 1,0 0,-13 -1,0 z"
1653 id="path3613"
1654 inkscape:connector-curvature="0"
1655 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
1656 inkscape:export-xdpi="90"
1657 inkscape:export-ydpi="90" /><rect
1658 style="fill:#ffffff;fill-opacity:0;stroke:none"
1659 id="rect4382"
1660 width="16"
1661 height="16"
1662 x="1"
1663 y="352.25006"
1664 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
1665 inkscape:export-xdpi="90"
1666 inkscape:export-ydpi="90" /><path
1667 style="fill:#b8b8b8;fill-opacity:1;stroke:none"
1668 d="m 65,64.250051 0,15 5,0 0,-1.153846 0,-1.153846 0,-1.692308 5,-0.153846 0,1.153846 5,0 0,-12 z"
1669 id="rect6534"
1670 inkscape:connector-curvature="0"
1671 sodipodi:nodetypes="ccccccccccc" /><path
1672 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3726);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1673 d="m 71.53125,32.250051 c -0.294605,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.294605,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.9375 c 0,0.2946 0.236645,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.294605,0 0.53125,-0.23665 0.53125,-0.53125 l 0,-0.9375 c 0,-0.29461 -0.236645,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.29461 -0.236645,-0.53125 -0.53125,-0.53125 l -2.9375,0 z m -2.53125,1 c -1.090704,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.909296,2 2,2 l 1,0 0,-1 -1,0 c -0.554001,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.445999,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0316,-0.36661 0.09375,-0.53125 l -0.09375,0 z m 7.90625,0 C 76.9684,33.414701 77,33.597721 77,33.781301 l 0,0.46875 c 0.554001,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.909296,-2 -2,-2 l -0.09375,0 z m -4.90625,5 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z"
1674 id="path3624"
1675 inkscape:connector-curvature="0" /><path
1676 id="path4583"
1677 d="m 163,1.2500515 0,13.9999995 8.8125,0 -1,-1 -1.3125,0 -1.5,0 -3,0 -1,0 0,-11.9999995 5.5,0 3.5,3.5 0,1.21875 c 0.61468,0.76989 1,1.72879 1,2.78125 l 0,-3.5 0,-1 -4,-4 -1,0 -6,0 z m 11,8.5 c 0,0.4831895 -0.20077,0.8627595 -0.34375,1.2812495 L 174,11.375051 174,9.7500515 z m -4.5,-3.5 c -1.92115,0 -3.5,1.57884 -3.5,3.5 0,1.9211495 1.57885,3.4999995 3.5,3.4999995 0.49539,0 0.94633,-0.12374 1.375,-0.3125 l 2.34375,2.34375 1.625,-1.625 -2.28125,-2.28125 C 172.829,10.882201 173,10.345451 173,9.7500515 c 0,-1.92116 -1.57885,-3.5 -3.5,-3.5 z m -0.0312,1 c 1.38071,0 2.5,1.11929 2.5,2.5 0,1.3807095 -1.11929,2.4999995 -2.5,2.4999995 -1.38071,0 -2.5,-1.11929 -2.5,-2.4999995 0,-1.38071 1.11929,-2.5 2.5,-2.5 z"
1678 style="fill:url(#linearGradient4838);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1679 inkscape:connector-curvature="0" /><path
1680 style="fill:#4c4c4c;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-2)"
1681 d="m 167.53125,32.250051 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.9375 c 0,0.2946 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.23665 0.53125,-0.53125 l 0,-0.9375 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -2.9375,0 z m -2.53125,1 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0317,-0.36661 0.0937,-0.53125 l -0.0937,0 z m 7.90625,0 c 0.0622,0.16465 0.0937,0.34767 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z m -4.90625,5 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 0,4 1,0 1,-1 1,0 1,1 1,0 0,-4 0,-1 -1,0 0,3 -0.25,0 -0.75,0 0,-1 -1,0 0,1 -0.75,0 -0.25,0 0,-3 -1,0 z"
1682 id="path4585"
1683 inkscape:connector-curvature="0" /><path
1684 sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccc"
1685 inkscape:connector-curvature="0"
1686 id="path4589"
1687 d="m 33,64.250051 0,8 2,0 2,0 0,-1 -2,0 0,-3 2,0 0,-1 -2,0 0,-3 z m 4,4 0,3 1,0 0,-3 z m 6,-2 -3,1.9375 3,2 0,-1.3125 c 2.26799,8.8e-4 3.4435,1.45051 4,2.3125 -0.056,-2.03024 -1.74134,-3.6862 -4,-3.6875 z m 0,6 0,1 3,0 0,2 -3,0 0,1 3,0 0,3 -3,0 0,1 3,0 2,0 0,-7 -1,0 0,-1 z m 1,7 0,-3 -2,0 0,3 z m -10,-5 c 0.056,2.03024 1.74134,3.68621 4,3.6875 l 0,1.25 3,-1.9375 -3,-2 0,1.3125 c -2.26799,-8.7e-4 -3.4435,-1.45051 -4,-2.3125 z"
1688 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4840);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1689 id="path4591"
1690 d="m 99,66.250051 0,1 2,0 0,-1 -2,0 z m 2,1 0,3 -2,0 0,-3 -1,0 0,6 1,0 0,-2 2,0 0,2 1,0 0,-6 -1,0 z m 2,-1 0,7 1,0 2,0 0,-1 -2,0 0,-2 2,0 0,-1 -2,0 0,-2 2,0 0,-1 -2,0 -1,0 z m 3,1 0,2 1,0 0,-2 -1,0 z m 0,3 0,2 1,0 0,-2 -1,0 z m 3,-4 0,1 3,0 0,-1 -3,0 z m 0,1 -1,0 0,3 0,1.84375 0,0.15625 1,0 0,-1.15625 0,-0.84375 0,-3 z m 0,5 0,0.25 c -0.42708,0.42709 -0.85415,0.85417 -1.28125,1.28125 l -3.71875,3.75 -2.125,-2.125 -1.40625,1.40625 2.125,2.125 1.40625,1.40625 1.40625,-1.40625 5.21875,-5.25 c -0.13646,-0.14416 -0.26876,-0.29348 -0.40625,-0.4375 l 1.375,0 0.40625,0 0,-1 -1.375,0 -1.375,0 -0.25,0 z"
1691 style="fill:url(#linearGradient4842);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
1692 inkscape:connector-curvature="0" /><path
1693 inkscape:connector-curvature="0"
1694 id="path4593"
1695 d="m 37,99.250061 c -1.0907,0 -2,0.909289 -2,1.999999 l 0,7 c 0,1.0907 0.9093,2 2,2 l 8,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.09071 -0.9093,-1.999999 -2,-1.999999 l -8,0 z m 0,0.999999 8,0 c 0.554,0 1,0.44599 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -8,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.55401 0.446,-1 1,-1 z m 6.59375,1.59375 -3.59375,3.59375 -1.40625,-1.4375 -1.4375,1.40625 1.4375,1.4375 1.40625,1.40625 5,-5 -1.40625,-1.40625 z"
1696 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4844);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1697 sodipodi:nodetypes="ssssssssssssssssssscccssssssccssss"
1698 inkscape:connector-curvature="0"
1699 id="path4595"
1700 d="m 99,99.250061 c -1.0907,0 -2,0.909289 -2,1.999999 l 0,7 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.09071 -0.9093,-1.999999 -2,-1.999999 z m 0,0.999999 12,0 c 0.554,0 1,0.44599 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -12,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.55401 0.446,-1 1,-1 z m 1.5,1 c -0.277,0 -0.5,0.22299 -0.5,0.5 0.0807,0.57703 0.3111,0.49624 1,0.5 l 0,5 -0.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.11921,-0.5 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z"
1701 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4846);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1702 sodipodi:nodetypes="cccccccsssscccsssscccccccccccccccccccccccccccccccccccccccccccccccccc"
1703 inkscape:connector-curvature="0"
1704 id="path4597"
1705 d="m 334,96.250061 -1,2 -2,0 0,1 1.5,0 -4.5,8.999999 -1,0 -4,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.554009 0.446,-0.999999 1,-0.999999 l 4,0 4,0 0,-1 -8,0 c -1.0907,0 -2,0.9093 -2,1.999999 l 0,7 c 0,1.09069 0.9093,2 2,2 l 4.5,0 -1.5,3 2,0 1.5,-3 1.5,0 0,-1 -1,0 4.5,-8.999999 0.5,0 0,-1 1,-2 z m 2,2.28125 0,0.71875 0.71875,0 c -0.17685,-0.30233 -0.41643,-0.5419 -0.71875,-0.71875 z m 0,1.718749 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m -4,2 0,1 1,0 0,-1 z m 2,0 0,1 1,0 0,-1 z m 2,0 0,0.71875 c 0.30232,-0.17686 0.5419,-0.41643 0.71875,-0.71875 z"
1706 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3295);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1707 inkscape:connector-curvature="0"
1708 id="path4600"
1709 d="m 3.0000001,99.250061 c -0.554,0 -1,0.446 -1,0.999999 l 0,9 c 0,0.55399 0.446,1 1,1 l 11.9999999,0 c 0.554,0 1,-0.44601 1,-1 l 0,-9 c 0,-0.553999 -0.446,-0.999999 -1,-0.999999 l -11.9999999,0 z m 0,2.999999 11.9999999,0 0,7 -11.9999999,0 0,-7 z m 1,1 0,1 3,0 0,-1 -3,0 z m 4.9999999,0 0,2 5,0 0,-2 -5,0 z m -4.9999999,3 0,1 3,0 0,-1 -3,0 z m 4.9999999,0 0,2 5,0 0,-2 -5,0 z"
1710 style="fill:url(#linearGradient4848);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1711 id="path4604"
1712 d="m 37,196.25005 c -1.64649,0 -3,1.3535 -3,3 l 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 0.6875,-0.6875 -0.53125,-0.5625 0.65625,-0.71875 1,-1.03125 -4.3125,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 0,-0.27701 0.223,-0.5 0.5,-0.5 l 7,0 c 0.277,0 0.5,0.22299 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -1.1875,0 1,1 0.6875,0 c 0.0353,0 0.0594,-0.0277 0.0937,-0.0312 l 0.875,-0.875 c 0.004,-0.0344 0.0312,-0.0585 0.0312,-0.0938 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 l -3,0 0,-1 3,0 c 1.0907,0 2,0.90929 2,2 l 0,0.4375 0.53125,0.53125 0.4375,0.4375 c 0.019,-0.13548 0.0312,-0.26585 0.0312,-0.40625 l 0,-1 c 0,-1.6465 -1.35351,-3 -3,-3 l -3,0 -1,1 -1,-1 -3,0 z m 0,1 3,0 0,1 -3,0 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,1 -3,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-1 c 0,-1.09071 0.9093,-2 2,-2 z"
1713 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3287);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1714 inkscape:connector-curvature="0" /><path
1715 sodipodi:nodetypes="sssscccsssscccssccssssccsssscssssccssssccsssssss"
1716 inkscape:connector-curvature="0"
1717 id="path4606"
1718 d="m 5.0000001,196.25006 c -1.64649,0 -3,1.3535 -3,3 l 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 0.9999999,-1 1,1 3,0 c 1.64649,0 3,-1.35351 3,-3 l 0,-1 c 0,-1.6465 -1.35351,-3 -3,-3 l -3,0 -1,1 -0.9999999,-1 z m 0,1 3,0 0,1 -3,0 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,1 -3,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-1 c 0,-1.09071 0.9093,-2 2,-2 z m 4.9999999,0 3,0 c 1.0907,0 2,0.90929 2,2 l 0,1 c 0,1.0907 -0.9093,2 -2,2 l -3,0 0,-1 3,0 c 0.554,0 1,-0.446 1,-1 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 l -3,0 z m -4.4999999,2 6.9999999,0 c 0.277,0 0.5,0.22299 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -6.9999999,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 0,-0.27701 0.223,-0.5 0.5,-0.5 z"
1719 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3289);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1720 inkscape:connector-curvature="0"
1721 id="path4608"
1722 d="m 69,130.21881 0,6.5 c 0,0.6818 0.0818,1.2882 0.21875,1.84375 0.13694,0.55554 0.35886,1.04609 0.6875,1.4375 0.32865,0.3914 0.76476,0.6916 1.3125,0.90625 0.56144,0.20201 1.24087,0.28125 2.0625,0.28125 0.8353,0 1.53231,-0.0792 2.09375,-0.28125 0.56143,-0.21465 1.03265,-0.51485 1.375,-0.90625 0.34233,-0.39141 0.5818,-0.88196 0.71875,-1.4375 0.13697,-0.55555 0.18749,-1.16195 0.1875,-1.84375 l 0,-6.5 -2.5,0 0,6.3125 c -1.1e-4,0.49241 -0.039,0.9091 -0.0937,1.25 -0.0548,0.32828 -0.14432,0.59785 -0.28125,0.8125 -0.13695,0.20201 -0.32971,0.34911 -0.5625,0.4375 -0.23279,0.0884 -0.51896,0.15625 -0.875,0.15625 -0.35604,0 -0.67347,-0.0679 -0.90625,-0.15625 -0.2328,-0.0884 -0.39431,-0.23549 -0.53125,-0.4375 -0.12325,-0.20202 -0.22648,-0.45297 -0.28125,-0.78125 -0.0548,-0.3409 -0.0625,-0.75759 -0.0625,-1.25 l 0,-6.34375 -2.5625,0 z m -0.5,12.03125 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 10,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -10,0 z"
1723 style="font-size:15.23443031px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4850);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Sans" /><path
1724 sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
1725 inkscape:connector-curvature="0"
1726 id="path4610"
1727 d="m 292,161.25005 0,7 1,0 2,0 0,-1 -2,0 0,-5 2,0 0,-1 -2,0 z m 3,1 0,3 0,2 1,0 0,-2 0,-3 z m 2,-1 0,7 1,0 0,-7 z m 2,0 0,5 1,0 0,-5 z m 1,5 0,2 2,0 0,-2 z m 2,0 1,0 0,-5 -1,0 z m -8.03585,3.36417 -2.83816,2.83816 2.83816,2.83816 0.95788,-0.9224 -1.88029,-1.91576 1.88029,-1.88028 z m 3.6896,0 -2.41243,5.67632 1.8448,0 2.54323,-5.67222 z m 3.12198,0 -0.95788,0.95788 1.88028,1.88028 -1.88028,1.91576 0.95788,0.9224 2.83816,-2.83816 z"
1728 style="fill:url(#linearGradient4852);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1729 inkscape:connector-curvature="0"
1730 id="path4612"
1731 d="m 73.5,354.25005 c -1.9217,0 -3.5,1.5783 -3.5,3.5 l 0,1.5 -1,0 c -0.554,0 -1,0.44599 -1,1 l 0,6 c 0,0.554 0.446,1 1,1 l 9,0 c 0.554,0 1,-0.446 1,-1 l 0,-6 c 0,-0.55401 -0.446,-1 -1,-1 l -1,0 0,-1.5 c 0,-1.9217 -1.5783,-3.5 -3.5,-3.5 z m 0,1 c 1.385,0 2.5,1.115 2.5,2.5 l 0,1.5 -5,0 0,-1.5 c 0,-1.385 1.115,-2.5 2.5,-2.5 z m 0,7 c 0.82843,0 1.5,0.67157 1.5,1.5 0,0.82842 -0.67157,1.5 -1.5,1.5 -0.82843,0 -1.5,-0.67158 -1.5,-1.5 0,-0.82843 0.67157,-1.5 1.5,-1.5 z"
1732 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3348);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1733 inkscape:connector-curvature="0"
1734 id="path4614"
1735 d="m 34.5,289.25006 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 3.5,0 c -1.0907,0 -2,0.9093 -2,2 l 0,10 c 0,1.0907 0.9093,2 2,2 1.0907,0 2,-0.9093 2,-2 l 0,-10 c 0,-1.0907 -0.9093,-2 -2,-2 z m 0,1 c 0.554,0 1,0.446 1,1 l 0,10 c 0,0.554 -0.446,1 -1,1 -0.554,0 -1,-0.446 -1,-1 l 0,-10 c 0,-0.554 0.446,-1 1,-1 z m -11.5,1 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -8,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -8,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 8,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -8,2 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22386 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27614 -0.22386,-0.5 -0.5,-0.5 z m -6.5,2 c -1.0907,0 -2,0.9093 -2,2 0,1.0907 0.9093,2 2,2 l 5,0 c 1.0907,0 2,-0.9093 2,-2 0,-1.0907 -0.9093,-2 -2,-2 l -5,0 z m 0,1 5,0 c 0.554,0 1,0.446 1,1 0,0.554 -0.446,1 -1,1 l -5,0 c -0.554,0 -1,-0.446 -1,-1 0,-0.554 0.446,-1 1,-1 z"
1736 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4856);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1737 id="path4616"
1738 d="m 290,102.25006 14,0 0,5 -14,0 z"
1739 style="fill:#c4c4c4;fill-opacity:1;stroke:none"
1740 inkscape:connector-curvature="0" /><path
1741 style="fill:url(#linearGradient4858);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1742 d="m 36.3298,257.27124 c -1.28605,0 -2.3298,1.04375 -2.3298,2.3298 l 0,9.31921 c 0,1.28606 1.04375,2.32981 2.3298,2.32981 l 9.31921,0 c 1.28606,0 2.3298,-1.04375 2.3298,-2.32981 l 0,-9.31921 c 0,-1.28605 -1.04374,-2.3298 -2.3298,-2.3298 z m 3.80414,2.33622 1.79284,0 0.11832,0.212 3.64032,9.10079 -2.3298,0 -0.87368,-2.29339 -3.02147,0 -0.87367,2.29339 -2.257,0 3.64032,-8.88237 z"
1743 id="path4618"
1744 inkscape:connector-curvature="0"
1745 sodipodi:nodetypes="sssssssssccccccccccc" /><path
1746 style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1747 d="m 41.57171,265.48627 -1.16491,0 c -0.3215,0 -0.58244,-0.26094 -0.58244,-0.58246 l 1.1381,-2.19467 1.19286,2.19467 c -8.7e-4,0.32152 -0.2621,0.58246 -0.58361,0.58246 z"
1748 id="path4620"
1749 inkscape:connector-curvature="0"
1750 sodipodi:nodetypes="sscccs" /><path
1751 sodipodi:nodetypes="cccccccccccc"
1752 style="fill:url(#linearGradient4860);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1753 d="m 67,193.25006 0,14 1,0 0,-14 z m 4.74999,-0.41664 c -0.86983,0.009 -1.76033,0.34033 -2.74999,1.375 l 0,8.04164 c 3.96132,-4.05865 6.94268,2.81598 11,-1 l 0,-8.04165 c -3.03099,2.934 -5.64051,-0.40352 -8.25001,-0.37496 z"
1754 id="path4622"
1755 inkscape:connector-curvature="0" /><path
1756 sodipodi:nodetypes="cccccccccccccsssssss"
1757 inkscape:connector-curvature="0"
1758 id="path4624"
1759 d="m 202.71875,138.46881 -0.96875,0.90625 1.90625,1.96875 -1.90625,1.96875 0.96875,1 1.90625,-1.96875 1.96875,1.96875 0.96875,-1 -1.9375,-1.96875 1.9375,-1.96875 -0.96875,-0.90625 -1.96875,1.90625 z M 194.5,141.25006 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z"
1760 style="fill:url(#linearGradient4862);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1761 sodipodi:nodetypes="ccccccc"
1762 style="fill:url(#linearGradient4864);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1763 d="m 233,35.250061 -7,5 6.99998,4.99998 2e-5,-3.33332 c 3.41666,0 5.61556,1.22 7,3.33334 0,-4.98333 -3.60112,-6.66667 -7,-6.66667 2e-5,-0.85078 1e-5,-2.61388 0,-3.33333 z"
1764 id="path4626"
1765 inkscape:connector-curvature="0" /><path
1766 style="fill:url(#linearGradient4866);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1767 d="m 418.99999,163.25006 0,2 12.00001,0 0,-2 -12.00001,0 z m 0,3 0,1.99999 12.00001,0 0,-1.99999 -12.00001,0 z m 0,3 0,2 12.00001,0 0,-2 -12.00001,0 z m 0,2.99999 0,2.00001 12.00001,0 0,-2.00001 -12.00001,0 z"
1768 id="path4628"
1769 inkscape:connector-curvature="0" /><path
1770 style="fill:url(#linearGradient4868);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1771 d="m 392,163.25006 0,2 7,0 0,-2 -7,0 z m -4,3 0,1.99999 11,0 0,-1.99999 -11,0 z m 2,3 0,2 9,0 0,-2 -9,0 z m -3,3 0,2 12,0 0,-2 -12,0 z"
1772 id="path4630"
1773 inkscape:connector-curvature="0" /><path
1774 style="fill:url(#linearGradient4870);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1775 d="m 356.8683,163.21055 0,2.02634 8.10536,0 0,-2.02634 -8.10536,0 z m -2.02634,3.03951 0,2.02633 12.15804,0 0,-2.02633 -12.15804,0 z m 2.02634,3.0395 0,2.02634 8.10536,0 0,-2.02634 -8.10536,0 z m -2.02634,3.03951 0,2.02634 12.15804,0 0,-2.02634 -12.15804,0 z"
1776 id="path4632"
1777 inkscape:connector-curvature="0" /><path
1778 style="fill:url(#linearGradient4872);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1779 d="m 323,163.25006 0,2 7,0 0,-2 -7,0 z m 0,3 0,2 11,0 0,-2 -11,0 z m 0,3 0,2 9,0 0,-2 -9,0 z m 0,3 0,2 12,0 0,-2 -12,0 z"
1780 id="path4634"
1781 inkscape:connector-curvature="0" /><path
1782 style="fill:url(#linearGradient4874);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1783 d="m 14.143585,33.304411 -4.126956,5.00918 -4.0880185,-4.93658 c 0,0 -0.8954698,0.0269 -0.8954698,1.05265 0,2.21508 1.5511147,4.31748 3.2704133,5.95293 l -1.7909395,2.17791 0.1167447,0.14519 c -0.089703,-0.009 -0.1790976,-0.0363 -0.2725383,-0.0363 -1.3754463,0 -2.4917443,1.04074 -2.4917443,2.3231 0,1.28234 1.116298,2.3231 2.4917443,2.3231 1.3754463,0 2.4917443,-1.04076 2.4917443,-2.3231 0,-0.69345 -0.3382551,-1.31604 -0.8565423,-1.74234 0.4809109,-0.30316 1.2134861,-0.78955 2.0245501,-1.41563 0.832239,0.64465 1.592846,1.16764 2.102405,1.48823 -0.478416,0.42398 -0.778669,1.00648 -0.778669,1.66974 0,1.28234 1.116298,2.3231 2.491745,2.3231 1.375446,0 2.491744,-1.04076 2.491744,-2.3231 0,-1.28236 -1.115055,-2.32427 -2.491744,-2.3231 -0.06354,0 -0.132378,0.0317 -0.194665,0.0363 l 0.03887,-0.0363 -1.907749,-2.28681 c 1.695639,-1.60874 3.231485,-3.67659 3.231485,-5.84404 0,-1.11857 -0.856533,-1.23414 -0.856533,-1.23414 z m -7.7866987,10.52654 c 0.6877138,0 1.2458722,0.52037 1.2458722,1.16154 0,0.64118 -0.5581584,1.16155 -1.2458722,1.16155 -0.6877231,0 -1.2458721,-0.52037 -1.2458721,-1.16155 0,-0.64117 0.558149,-1.16154 1.2458721,-1.16154 z m 7.4752327,0 c 0.687714,0 1.245872,0.52037 1.245872,1.16154 0,0.64118 -0.558158,1.16155 -1.245872,1.16155 -0.687723,0 -1.245872,-0.52037 -1.245872,-1.16155 0,-0.64117 0.558149,-1.16154 1.245872,-1.16154 z"
1784 id="path4636"
1785 inkscape:connector-curvature="0" /><path
1786 sodipodi:nodetypes="sssssssssssssssssssscszsczcc"
1787 inkscape:connector-curvature="0"
1788 id="path4638"
1789 d="m 137,225.2188 c -3.86517,0 -7,3.14713 -7,7.03125 0,3.88412 3.13483,7.03125 7,7.03125 3.86633,0 7,-3.14713 7,-7.03125 0,-3.88412 -3.13367,-7.03125 -7,-7.03125 z m 0,1.03125 c 3.31371,0 6,2.68629 6,6 0,3.31371 -2.68629,6 -6,6 -3.31371,0 -6,-2.68629 -6,-6 0,-3.31371 2.68629,-6 6,-6 z m -2.34375,3 c -0.78758,0 -1.40625,0.64605 -1.40625,1.4375 0,0.79145 0.61867,1.4375 1.40625,1.4375 0.78761,0 1.4375,-0.64605 1.4375,-1.4375 0,-0.79145 -0.64989,-1.4375 -1.4375,-1.4375 z m 4.6875,0 c -0.7876,0 -1.4375,0.64605 -1.4375,1.4375 0,0.79145 0.6499,1.4375 1.4375,1.4375 0.78759,0 1.40625,-0.64605 1.40625,-1.4375 0,-0.79145 -0.61866,-1.4375 -1.40625,-1.4375 z m -5.23219,4.77513 c -0.0366,0.1544 -0.081,0.31581 -0.081,0.4768 0,1.55998 2.42289,1.8242 2.96945,1.81057 0.54656,-0.0136 2.96945,-0.25059 2.96945,-1.81057 0,-0.16099 -0.0444,-0.3224 -0.081,-0.4768 -1.30709,1.24337 -2.63751,1.02963 -2.88845,1.05774 -0.25094,0.0281 -2.02946,-0.0474 -2.88844,-1.05774 z"
1790 style="fill:url(#linearGradient4876);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1791 transform="matrix(1.0570818,0,0,1.0570818,-13.669289,-9.0845785)"
1792 sodipodi:nodetypes="cssccscccssccscc"
1793 style="fill:url(#linearGradient4878);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1794 d="m 259.65386,163.531 c -1.472,0 -2.66666,1.24939 -2.66666,2.53241 0,1.28301 1.19466,2.3243 2.66666,2.3243 0.0453,0 0.0811,8.7e-4 0.12493,0 -0.196,1.29812 -0.87033,2.97394 -2.79166,4.64861 1.33333,0 5.33332,-2.32431 5.33332,-6.97291 0,-1.28302 -1.19466,-2.53241 -2.66666,-2.53241 z m 7.99998,0.026 c -1.472,0 -2.66666,1.22337 -2.66666,2.50639 0,1.28302 1.19466,2.32431 2.66666,2.32431 0.048,0 0.0784,8.7e-4 0.12493,0 -0.196,1.28069 -0.86633,2.93413 -2.79166,4.61228 1.37466,0 5.33332,-2.28798 5.33332,-6.93659 0,-1.28302 -1.19466,-2.50639 -2.66666,-2.50639 z"
1795 id="path4640"
1796 inkscape:connector-curvature="0" /><path
1797 style="fill:url(#linearGradient4880);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1798 d="m 41,225.25006 c -3.86517,0 -7,3.13483 -7,6.99999 0,3.86518 3.13483,7.00001 7,7.00001 3.86633,0 7,-3.13483 7,-7.00001 0,-3.86516 -3.13367,-6.99999 -7,-6.99999 z m 2.47916,2.29688 c 0.62773,-0.0298 1.3338,0.21291 2.1875,0.80207 -1.27516,0 -2.10904,1.30666 -2.88021,2.91667 l 1.4948,0 c 0.25783,0 0.4375,0.24325 0.4375,0.51041 l -1.16667,1.64063 -1.75,0 c -1.19233,2.56317 -2.57892,4.74454 -5.46875,2.73437 1.33233,-0.003 2.17992,-1.54671 2.98958,-3.31769 l 0.21875,-0.47398 c 1.0115,-2.26011 2.05434,-4.72275 3.9375,-4.81248 z"
1799 id="path4642"
1800 inkscape:connector-curvature="0"
1801 sodipodi:nodetypes="ssssscccsccccccc" /><path
1802 inkscape:connector-curvature="0"
1803 id="path4644"
1804 d="m 8.0000001,6.2500615 0,1.875 -1.375,1.46875 1.375,1.4687495 0,1.90625 -3.625,-3.3749995 z"
1805 style="fill:url(#linearGradient4882);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1806 inkscape:connector-curvature="0"
1807 id="path4646"
1808 d="m 9,6.2500615 3.6875,3.375 L 9,12.906311 9,11.000061 10.4375,9.5938115 9,8.0625615 z"
1809 style="fill:url(#linearGradient4884);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1810 sodipodi:nodetypes="sccsscccssscsssssss"
1811 style="fill:url(#linearGradient4886);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1812 d="m 9.400192,321.25006 c -2.5311594,0 -4.5833578,2.05219 -4.5833578,4.58335 l 2.2916789,0 c 0,-1.26501 1.0266722,-2.29168 2.2916789,-2.29168 1.265007,0 2.29168,1.02667 2.29168,2.29168 0,1.265 -1.026673,2.29168 -2.29168,2.29168 -0.8015237,0.007 -1.2388122,0.57905 -1.1458394,1.14585 l 0,1.0026 0,0.14323 c 0,0.6325 0.5133366,1.14584 1.1458394,1.14584 0.632504,0 1.145839,-0.51334 1.145839,-1.14584 l 0,-0.14323 c 1.976573,-0.5099 3.437519,-2.30544 3.437519,-4.44013 0,-2.53116 -2.052199,-4.58335 -4.583358,-4.58335 z m 0,11.00442 c -0.8830925,0 -1.5998062,0.71671 -1.5998062,1.59981 0,0.88308 0.7167137,1.5998 1.5998062,1.5998 0.883094,0 1.599806,-0.71672 1.599806,-1.5998 0,-0.8831 -0.716712,-1.59981 -1.599806,-1.59981 z"
1813 id="path4648"
1814 inkscape:connector-curvature="0" /><path
1815 style="fill:url(#linearGradient4888);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1816 d="m 36.34264,356.62101 c 0.51469,-0.51344 1.34901,-0.51344 1.86244,0 L 41,359.40963 l 2.79492,-2.78862 c 0.51469,-0.51344 1.34901,-0.51344 1.86244,0 0.51469,0.51344 0.51469,1.34524 0,1.85992 l -2.79492,2.78989 2.79492,2.78864 c 0.51469,0.51341 0.51469,1.34648 0,1.85992 -0.51469,0.51343 -1.34901,0.51343 -1.86244,0 L 41,363.12949 l -2.79492,2.78989 c -0.51469,0.51343 -1.34901,0.51343 -1.86244,0 -0.51469,-0.51344 -0.51469,-1.34651 0,-1.85992 l 2.79492,-2.78864 -2.79492,-2.78989 c -0.51469,-0.51468 -0.51469,-1.34774 0,-1.85992 z"
1817 id="path4651"
1818 inkscape:connector-curvature="0" /><path
1819 style="fill:url(#linearGradient4890);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1820 d="m 137.90909,353.25005 0,7.08065 4.69598,-3.57702 z m -1.17399,2.32963 c -3.2461,0 -5.86997,2.66057 -5.86997,5.90666 0,3.24609 2.62387,5.86997 5.86997,5.86997 3.24609,0 5.86997,-2.62388 5.86997,-5.86997 l 0,-0.0366 -2.34799,0 c 0,1.9453 -1.57667,3.52198 -3.52198,3.52198 -1.94531,0 -3.52198,-1.57668 -3.52198,-3.52198 0,-1.94531 1.57667,-3.52198 3.52198,-3.52198 0.41441,0 0.80535,0.0898 1.17399,0.22013 l 0,-2.42137 c -0.37685,-0.0763 -0.77484,-0.14675 -1.17399,-0.14675 z"
1821 id="path4653"
1822 inkscape:connector-curvature="0"
1823 sodipodi:nodetypes="cccccsssccssscccc" /><path
1824 style="fill:url(#linearGradient4892);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1825 d="m 169.63108,225.85717 c -3.68133,0 -6.66665,2.71633 -6.66665,6.04164 0,2.46666 1.64933,4.56932 3.99999,5.49999 l 0,0.5 -2.66666,0 0,-0.66667 c 0,-0.36933 -0.29733,-0.66666 -0.66667,-0.66666 -0.36933,0 -0.66666,0.29733 -0.66666,0.66666 l 0,1.33333 c 0,0.36933 0.29733,0.66667 0.66666,0.66667 l 3.99999,0 c 0.368,0 0.66667,-0.29867 0.66667,-0.66667 l 0,-0.79166 0,-0.54167 0,-0.83333 c -1.55066,-0.66266 -2.66666,-2.40533 -2.66666,-4.49999 0,-2.65998 1.79066,-4.83331 3.99999,-4.83331 2.20933,0 3.99999,2.17333 3.99999,4.83331 0,2.09466 -1.116,3.83599 -2.66666,4.49999 l 0,0.83333 0,0.54167 0,0.79166 c 0,0.368 0.29866,0.66667 0.66666,0.66667 l 3.99999,0 c 0.0924,0 0.17019,-0.008 0.25,-0.0416 0.23926,-0.1012 0.41667,-0.349 0.41667,-0.625 l 0,-1.33333 c 0,-0.36933 -0.29733,-0.66667 -0.66667,-0.66667 -0.36933,0 -0.66666,0.29734 -0.66666,0.66667 l 0,0.66666 -2.66666,0 0,-0.5 c 2.35066,-0.93066 3.99999,-3.03332 3.99999,-5.49998 0,-3.32531 -2.98399,-6.04164 -6.66665,-6.04164 z"
1826 id="path4655"
1827 inkscape:connector-curvature="0" /><path
1828 id="path4657"
1829 d="m 265,225.25005 c -3.86516,0 -7,3.13484 -7,7 0,3.86516 3.13484,7 7,7 3.86516,0 7,-3.13484 7,-7 0,-3.86516 -3.13484,-7 -7,-7 z m 0,1 c 0.57563,0 1.12928,0.0987 1.65625,0.25 -0.21686,0.024 -0.40509,0.0414 -0.21875,0.0625 0.60892,0.003 -0.1276,0.039 -0.1875,0.125 -0.11394,0.0829 -0.0834,0.026 -0.15625,0.125 -0.11101,0.005 -0.16343,0.0248 -0.1875,0.0312 0.0628,0.0123 0.21665,0.0288 0.3125,0.0312 0.26795,-0.0538 0.54333,-0.1539 0.8125,-0.25 0.0491,0.0177 0.10773,0.0123 0.15625,0.0312 -0.057,0.0184 -0.10829,0.071 -0.15625,0.0625 -0.34875,0.25862 0.70213,-0.0275 0.59375,0.46875 0.0904,0.035 0.0426,-0.16732 0.0312,-0.3125 1.98416,0.97877 3.34375,3.01293 3.34375,5.375 0,2.96499 -2.14232,5.42075 -4.96875,5.90625 0.002,-0.0351 -0.001,-0.0564 0,-0.0937 -0.0607,-0.31041 0.3513,-0.15238 0.375,-0.4375 -0.14618,-0.10055 -0.18095,-0.21709 -0.1875,-0.34375 -0.0227,-0.40268 0.15775,-0.34927 0,0 0.0223,0.0426 0.0716,0.0718 0.125,0.0937 0.0738,0.0209 0.14565,0.10949 0.21875,0.0312 0.41021,-0.33369 0.12457,-1.07604 0.71875,-1.15625 0.47136,-0.164 0.14359,-0.87555 0.4375,-1.1875 0.53462,-0.47621 -0.2551,-0.89849 -0.6875,-0.78125 -0.0559,-0.0857 -0.27353,-0.28009 -0.5,-0.0625 0.15857,-0.1649 -0.008,-0.23324 -0.25,-0.0312 0.24467,-0.17708 0.25848,-0.47377 -0.0625,-0.65625 -0.0508,9.9e-4 -0.10507,-0.004 -0.125,0.0312 -0.0638,-0.0687 -0.22894,-0.0608 -0.28125,0.0312 -0.0101,-0.0804 -0.0318,-0.15944 -0.0625,-0.1875 -0.12961,-0.14754 -0.16689,-0.11264 -0.1875,-0.0312 0.0112,-0.0474 0.002,-0.10756 0,-0.15625 -0.32535,-0.0722 -0.953,-0.49438 -1,0 0.002,-0.20286 -0.0586,-0.23675 -0.0937,-0.1875 0.0276,-0.0332 0.0683,-0.0615 0.125,-0.0937 -0.23557,0.0464 -0.5475,0.32011 -0.5625,0.5625 0.0648,0.41584 -0.42384,0.78976 -0.1875,1.0625 -0.0185,-0.003 -0.0422,0.0103 -0.0625,0 0.20991,0.41324 0.44408,0.73866 0.65625,1.0625 0.23031,0.0604 0.44985,0.14475 0.5625,0.3125 -0.17222,-0.0166 -0.26928,-0.0451 -0.40625,-0.0625 0.17318,0.2949 0.31495,0.60124 0.375,1 0.0695,0.54303 0.19023,1.00029 0.3125,1.375 -0.0919,0.004 -0.18828,0 -0.28125,0 -3.31371,0 -6,-2.6863 -6,-6 0,-1.4656 0.53344,-2.80175 1.40625,-3.84375 0.34206,-0.0211 0.7743,0.12805 0.75,0.4375 0.0307,0.0446 0.0539,0.0428 0.0625,0.0312 -0.0741,0.19641 -0.23979,0.37414 0.0937,0.5625 0.22757,0.0776 -0.005,-0.0939 -0.125,0.1875 -0.18886,-0.0161 -0.54745,0.56888 -0.53125,0.875 -0.006,0.28224 0.15163,0.47561 0.375,0.5625 -0.16645,0.0629 -0.0795,0.49173 0.0937,0.625 0.234,0.59128 0.0786,-0.21992 -0.0625,-0.40625 0.1184,-0.41868 0.28654,0.49131 0.5,0.59375 0.0459,0.40021 0.30654,0.5924 0.6875,0.71875 0.1724,0.007 0.42696,0.0904 0.5625,0 -0.0572,0.0939 -0.0543,0.2011 0.0937,0.21875 0.0497,0.0166 0.18315,0.0719 0.21875,0 0.0368,0.0175 0.10148,0.0198 0.15625,-0.0312 0.0432,-0.0198 0.0361,0.0124 0.0625,0 -0.11865,0.0885 -0.24679,0.23155 0.0312,0.28125 0.18197,0.12198 0.21951,-0.59882 -0.0312,-0.46875 -0.27053,-0.0764 -0.31824,0.10185 -0.25,0.1875 -0.38423,0.10029 0.48507,-0.80377 -0.0312,-0.71875 -0.14636,0.36457 -0.72915,0.44313 -0.71875,-0.0625 0.0733,-0.11228 0.0576,-0.29508 0,-0.4375 0.0762,0.0536 0.14828,-0.0524 0.25,-0.1875 0.0508,-0.20201 0.45865,-0.11762 0.5625,-0.125 -0.007,-0.008 -0.0149,-0.019 -0.0312,-0.0312 0.34794,-0.17518 0.70785,0.0435 0.71875,0.4375 0.0727,0.0592 0.0799,-0.14085 0.0937,-0.15625 -0.34271,-0.59064 0.60005,-0.61065 0.53125,-1.09375 0.086,0.0703 0.16097,-0.25555 0.46875,-0.34375 0.0156,-0.0612 0.5408,-0.25245 0.5625,-0.5625 l 0.0312,-0.0625 c -0.0777,0.58493 0.56903,-0.28504 0.125,-0.125 -0.48342,0.25168 -0.0186,-0.16425 0.21875,-0.15625 0.2339,0.10315 1.13432,-0.3299 0.59375,-0.375 -0.14861,0.004 0.0197,-0.83907 -0.375,-0.375 -0.18201,-0.013 -0.21657,-0.52148 -0.59375,-0.28125 -0.21308,0.35773 -0.42379,0.80911 -0.78125,0.96875 0.10551,-0.34815 -0.17558,-0.37355 -0.4375,-0.46875 -0.50037,-0.22009 0.22843,-0.53767 0.40625,-0.65625 0.42598,0.0488 0.0804,-0.2331 0.40625,-0.1875 0.25965,0.11567 0.79746,-0.45867 0.3125,-0.25 -0.34093,0.38477 -0.21848,-0.29476 -0.5,-0.15625 -0.0588,0.36258 -0.54949,0.31735 -0.9375,0.28125 -0.20901,0.22494 -0.18621,0.0524 -0.40625,0.0312 -0.22948,-0.0557 -0.62539,-0.2074 -1.03125,-0.125 -0.42791,0.0153 -0.77707,0.13054 -1.09375,0.375 0.18446,-0.14534 0.37067,-0.28434 0.3125,-0.34375 -0.13804,-0.0294 -0.26862,-0.0577 -0.40625,-0.0625 1.0158,-0.78806 2.2713,-1.2811 3.6564,-1.2811 z m -0.40625,9.625 c -0.0485,-0.0827 -0.10312,-0.16891 -0.15625,-0.25 -0.72058,-0.18902 -1.52571,0.0359 0.15625,0.25 z m 1.34375,-9.28125 c -0.10926,0.002 -0.25181,0.0495 -0.15625,0.125 l 0.125,0 c 0.22132,-0.0858 0.14056,-0.12682 0.0312,-0.125 z m -0.34375,0.34375 c -0.14885,0.0202 -0.1519,0.1631 0.15625,0.0937 0.007,0.066 0.1702,-0.0245 0.1875,0.0312 0.48589,-0.054 0.0831,-0.1527 -0.15625,-0.0937 -0.0717,-0.0408 -0.13788,-0.038 -0.1875,-0.0312 z m 0.0625,0.15625 c -0.012,-0.0131 -0.0364,0.004 -0.125,0.0625 -0.53787,0.41757 0.48274,0.0767 0.59375,0.34375 0.375,0.26203 -0.0911,0.19656 -0.28125,0.3125 -0.0495,0.0102 -0.0367,0.0257 -0.0625,0.0312 0.11906,0.007 0.28635,0.0602 0.3125,0.1875 l 0.0625,0.0312 c 0.31303,0.0938 -0.14015,-0.27069 0.25,-0.0937 -0.0154,-0.25514 0.0288,-0.26175 0.28125,-0.21875 -0.016,-0.36645 -0.58414,-0.66376 -0.96875,-0.5625 -0.23333,0.21055 -0.0265,-0.0545 -0.0625,-0.0937 z m -0.46875,0.0312 c -0.0468,0.0133 -0.0929,0.0396 -0.125,0.0937 0.0235,10e-4 0.0376,0.0331 0.0625,0 0.33051,-0.0263 0.20282,-0.13358 0.0625,-0.0937 z m -1.5625,0.0312 c -0.17974,0.004 -0.43759,0.0773 -0.4375,0.25 0.11636,0.04 0.22509,-0.1096 0.34375,-0.125 0.35814,-0.0741 0.27354,-0.12883 0.0937,-0.125 z m 1.21875,0 c -0.12212,0.0231 -0.25374,0.0844 -0.125,0.125 l 0.0312,0.0312 0.0937,-0.0312 c 0.22922,-0.13332 0.12212,-0.14807 0,-0.125 z m -0.90625,0.0625 c -0.28655,0.0128 -0.61607,0.21385 -0.1875,0.25 -0.20655,0.0632 -0.46416,0.0131 -0.0625,0.125 0.24304,-0.0302 1.03903,-0.0694 0.625,-0.21875 0.16188,-0.2552 -0.0305,-0.0918 -0.15625,-0.0937 -0.0543,-0.0446 -0.12323,-0.0668 -0.21875,-0.0625 z m 0.71875,0.25 c -0.0294,0.007 -0.0677,0.0411 -0.0937,0.0937 0.23501,0.0305 0.18187,-0.11393 0.0937,-0.0937 z m 2.96875,0 c -0.1229,0.0647 -0.30864,0.56687 0,0.625 0.19641,0.13297 0.0343,-0.35877 0.0625,-0.5 -0.008,-0.10783 -0.0215,-0.14656 -0.0625,-0.125 z m -4.65625,0.3125 c 0.0326,-0.004 0.0441,-0.007 0.0312,0.0312 -0.33578,0.11083 -0.12904,-0.0181 -0.0312,-0.0312 z m 2.3125,0.0625 c -0.1313,-0.0266 -0.39703,0.19962 0,0.125 l 0.0625,0 c 0.0111,-0.0813 -0.0187,-0.11612 -0.0625,-0.125 z m -4.0625,0.78125 c 0.006,0.0143 0.0299,0.014 0.0312,0.0312 0.008,0.0435 -0.0235,0.085 -0.0312,0.125 -0.003,-0.0643 -0.009,-0.12364 0,-0.15625 z M 261,228.81255 c -0.009,0.006 -0.007,0.021 0,0.0625 0.0968,0.0138 0.0264,-0.0815 0,-0.0625 z m 5.5625,0.28125 c -0.0981,0.006 -0.34815,0.29505 -0.21875,0.28125 0.13337,0.0266 0.64304,-0.01 0.25,-0.15625 0.021,-0.0859 9.5e-4,-0.12697 -0.0312,-0.125 z m -5.53125,0.21875 c -0.0218,-10e-4 -0.0245,0.0399 0.0312,0.125 0.30923,0.16511 0.034,-0.12127 -0.0312,-0.125 z m 4.875,0.1875 c -0.0184,-7.1e-4 -0.051,0.0101 -0.0937,0.0312 0.0994,0.0455 0.14896,-0.0291 0.0937,-0.0312 z m 0.125,0.0312 c -0.13693,0.0377 -0.38348,0.14021 -0.4375,0.25 0.10313,-1.8e-4 0.18325,-0.1022 0.28125,-0.125 0.32049,-0.15288 0.29318,-0.16268 0.15625,-0.125 z m -6.375,1 c -0.0116,-0.007 -0.0552,0.0257 -0.0937,0.0937 0.0414,0.1895 0.12849,-0.0728 0.0937,-0.0937 z m 1.5,0.53125 c 0.052,0.004 0.0833,0.0625 0.125,0.0937 -0.0524,-0.0363 -0.0856,-0.0794 -0.125,-0.0937 z m 2.4375,0.8125 c -0.0385,0.01 -0.0523,0.0335 -0.0625,0.0625 0.0946,-0.044 0.49211,0.15054 0.6875,0.21875 0.48854,0.0204 -0.35512,-0.34821 -0.625,-0.28125 z m 0.90625,0.28125 c -0.0182,-0.002 0.003,0.0237 0.0312,0.0937 -0.19576,0.095 -0.24616,0.0339 0.0312,0.0625 0.0616,0.0235 0.0953,0.025 0.0937,0 0.38314,0.0396 0.0666,-0.24469 -0.0312,-0.0625 -0.0308,-0.0484 -0.0997,-0.0915 -0.125,-0.0937 z m 0.53125,0.0938 c -0.0231,2.4e-4 -0.0377,0.0285 -0.0625,0.0625 0.0442,0.0146 0.0742,0.003 0.0937,0 -0.009,-0.0182 -0.005,-0.0628 -0.0312,-0.0625 z m -1.96875,0.0625 c 0.065,-0.0272 0.0304,0.0826 0,0.1875 -0.0131,-0.0878 -0.1107,-0.0462 -0.1875,0.0312 0.0164,-0.0269 0.0254,-0.0519 0.0312,-0.0937 0.0937,-0.0718 0.12538,-0.11212 0.15625,-0.125 z m 0.9375,0 c -0.008,0.003 -0.012,0.0121 0,0.0312 0.23882,0.0542 0.0924,-0.0358 0.0312,-0.0312 -0.0102,5e-4 -0.023,-0.003 -0.0312,0 z m 1.46875,0.75 c -0.0101,0.006 -0.0453,-0.003 -0.0625,0.0312 0.0396,0.0611 0.061,0.007 0.0625,-0.0312 z m -2.1875,0.0312 c -0.0104,0.0169 0.0106,0.052 0.15625,0.15625 0.36178,0.0251 -0.12511,-0.20702 -0.15625,-0.15625 z m 0.34375,0.1563 c -0.0422,0.0167 -0.0392,0.0395 0.0312,0.0937 0.0799,0.0985 0.14452,-0.0616 0.21875,-0.0937 -0.0966,-0.016 -0.19592,-0.0213 -0.25,0 z m 0.28125,0 c 0.0269,0.001 0.0379,0.0223 0.0625,0.0937 0.12084,-0.0286 0.0505,-0.0711 -0.0625,-0.0937 z m 0.59375,0.0625 c 0.0151,0.0164 0.0447,0.016 0.0625,0.0312 -0.0224,-0.004 -0.0368,0.002 -0.0625,0 -0.006,-0.01 0.005,-0.0214 0,-0.0312 z m 0.71875,0.0937 c 0.0918,-0.004 0.19416,0.006 0.3125,0.0312 -0.93272,0.60426 -0.955,-0.004 -0.3125,-0.0312 z m 0.875,0.1875 c 0.0209,0.0339 0.037,0.0652 0,0.125 -0.01,-0.0407 -0.0132,-0.0852 0,-0.125 z m -0.28125,0.0937 c 0.008,0.0407 0.0223,0.0692 0.0625,0.125 0.002,0.0174 0.0188,0.0345 0.0312,0.0312 0.0374,-0.01 0.0901,-0.078 0.0937,-0.0312 0.0326,-0.03 0.0758,-0.0367 0.0937,-0.0625 0.0122,0.0307 0.0395,0.0525 0.0625,0.0625 -0.0786,0.0243 -0.16205,0.0214 -0.25,0.0312 -0.55894,0.20149 0.0265,0.0442 -0.0937,-0.15625 z"
1830 style="fill:url(#linearGradient4894);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1831 inkscape:connector-curvature="0" /><path
1832 inkscape:export-ydpi="90"
1833 inkscape:export-xdpi="90"
1834 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/skins/moono/icons/print.png"
1835 sodipodi:nodetypes="ssccssssssscsssscssssscccccssssssssssssss"
1836 inkscape:connector-curvature="0"
1837 id="path4664"
1838 d="m 229.5,2.2500615 c -0.831,0 -1.5,0.669 -1.5,1.5 l 0,0.49999 10,0 0,-0.49999 c 0,-0.831 -0.669,-1.5 -1.5,-1.5 z m -2.5,3 c -0.554,0 -1,0.44599 -1,1 l 0,5.9999995 c 0,0.554 0.446,1 1,1 l 2,0 0,-4.9999995 c 0,-0.55401 0.446,-1 1,-1 l 6,0 c 0.554,0 1,0.44599 1,1 l 0,4.9999995 2,0 c 0.554,0 1,-0.446 1,-1 l 0,-5.9999995 c 0,-0.55401 -0.446,-1 -1,-1 z m 3,3 0,6.9999995 6,0 0,-6.9999995 z m 1.5,1 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.2769895 -0.223,0.4999995 -0.5,0.4999995 l -3,0 c -0.277,0 -0.5,-0.22301 -0.5,-0.4999995 0,-0.277 0.223,-0.5 0.5,-0.5 z m 0,1.9999995 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.27699 -0.223,0.5 -0.5,0.5 l -3,0 c -0.277,0 -0.5,-0.22301 -0.5,-0.5 0,-0.277 0.223,-0.5 0.5,-0.5 z"
1839 style="fill:url(#linearGradient4898);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1840 inkscape:connector-curvature="0"
1841 id="path4666"
1842 d="m 73,98.250061 c -3.31371,0 -6,2.686289 -6,5.999999 0,3.3137 2.68629,6 6,6 3.31371,0 6,-2.6863 6,-6 0,-3.31371 -2.68629,-5.999999 -6,-5.999999 z m 0,1 c 2.76142,0 5,2.238569 5,4.999999 0,2.76142 -2.23858,5 -5,5 -2.76142,0 -5,-2.23858 -5,-5 0,-2.76143 2.23858,-4.999999 5,-4.999999 z m 0,1.999999 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 1.65685,0 3,-1.34315 3,-3 0,-1.65686 -1.34315,-3 -3,-3 z"
1843 style="fill:url(#linearGradient4900);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1844 sodipodi:nodetypes="ssssssssssssscccccsss"
1845 inkscape:connector-curvature="0"
1846 id="path4670"
1847 d="m 292,100.25006 c -1.662,0 -3,1.33799 -3,3 l 0,2 c 0,1.662 1.338,3 3,3 l 10,0 c 1.662,0 3,-1.338 3,-3 l 0,-2 c 0,-1.66201 -1.338,-3 -3,-3 z m 0,1 10,0 c 1.108,0 2,0.89199 2,2 l 0,2 c 0,1.108 -0.892,2 -2,2 l -2,-3 -3,3 -3,-2 -2,2 c -1.108,0 -2,-0.892 -2,-2 l 0,-2 c 0,-1.10801 0.892,-2 2,-2 z"
1848 style="fill:url(#linearGradient4904);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1849 style="font-size:16.54135895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4906);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Sans"
1850 d="m 140.5,130.25006 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2.5,0 0,1 -2.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 l 0,2 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 0,-1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-2 c 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -3,0 z m -8.375,2.9375 c -0.29577,0 -0.58586,0.11711 -0.8125,0.34375 -0.45327,0.45327 -0.45327,1.20297 0,1.65625 l 2.03125,2.03125 -2.03125,2.03125 c -0.45327,0.45327 -0.45327,1.20297 0,1.65625 0.45327,0.45327 1.17173,0.45327 1.625,0 l 2.0625,-2.03125 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 l -2.03125,-2.03125 2.03125,-2.03125 c 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 -0.45327,-0.45328 -1.17173,-0.45328 -1.625,0 L 135,135.56256 l -2.0625,-2.03125 c -0.22664,-0.22664 -0.51673,-0.34375 -0.8125,-0.34375 z"
1851 id="path4672"
1852 inkscape:connector-curvature="0" /><path
1853 id="path4674"
1854 d="m 172.5,138.25006 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.24281,0.60287 0.5,0.5 l 2.5,0 0,1 -2.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 l 0,2 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 0,-1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-2 c 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m -8.375,-6.0625 c -0.29577,0 -0.58586,0.11711 -0.8125,0.34375 -0.45327,0.45327 -0.45327,1.20297 0,1.65625 l 2.03125,2.03125 -2.03125,2.03125 c -0.45327,0.45327 -0.45327,1.20297 0,1.65625 0.45327,0.45327 1.17173,0.45327 1.625,0 l 2.0625,-2.03125 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 l -2.03125,-2.03125 2.03125,-2.03125 c 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 -0.45327,-0.45328 -1.17173,-0.45328 -1.625,0 L 167,134.56256 l -2.0625,-2.03125 c -0.22664,-0.22664 -0.51673,-0.34375 -0.8125,-0.34375 z"
1855 style="font-size:16.54135895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4908);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Sans"
1856 inkscape:connector-curvature="0"
1857 sodipodi:nodetypes="sssccsssssssccsssssssscssccssscsssccs" /><path
1858 inkscape:connector-curvature="0"
1859 id="path4676"
1860 d="m 7.5000001,65.250051 c -3.03757,0 -5.5,2.46243 -5.5,5.5 0,3.03756 2.46243,5.5 5.5,5.5 0.938705,0 1.7919409,-0.27092 2.5624999,-0.6875 l 3.75,3.75 c 0.587606,0.58761 1.537394,0.58761 2.125,0 0.587606,-0.58761 0.587606,-1.53739 0,-2.125 l -3.71875,-3.71875 C 12.691902,72.662431 13,71.754301 13,70.750051 c 0,-3.03757 -2.46243,-5.5 -5.4999999,-5.5 z m 0,2 c 1.9329999,0 3.4999999,1.567 3.4999999,3.5 0,1.06272 -0.47105,2.01435 -1.21875,2.65625 -0.006,0.005 -0.02525,-0.005 -0.03125,0 -0.60985,0.51643 -1.3882799,0.84375 -2.2499999,0.84375 -1.933,0 -3.5,-1.56701 -3.5,-3.5 0,-1.933 1.567,-3.5 3.5,-3.5 z"
1861 style="fill:url(#linearGradient4910);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1862 inkscape:connector-curvature="0"
1863 id="path4678"
1864 d="m 297.00004,35.250051 7,5 -6.99998,4.99999 -2e-5,-3.33332 c -3.41666,0 -5.61556,1.22 -7,3.33333 0,-4.98332 3.60112,-6.66666 7,-6.66666 -2e-5,-0.85078 -1e-5,-2.61389 0,-3.33334 z"
1865 style="fill:url(#linearGradient4912);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1866 sodipodi:nodetypes="ccccccc" /><path
1867 inkscape:connector-curvature="0"
1868 id="path4680"
1869 d="m 69,163.25006 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m 4.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -6,0 z m -4.5,5 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m 4.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z"
1870 style="fill:url(#linearGradient4914);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1871 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
1872 inkscape:connector-curvature="0"
1873 id="path4682"
1874 d="m 136.53125,162.25006 c -0.25721,0 -0.46875,0.22299 -0.46875,0.5 l 0,12 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 l 0,-12 c 0,-0.27701 -0.21154,-0.5 -0.46875,-0.5 z m -4.03125,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -8.5,2.46875 0,0.0625 2,1.46875 0,-1 2.5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 l -2.5,0 0,-1 z m 8.5,-0.46875 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z"
1875 style="fill:url(#linearGradient4916);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1876 style="fill:url(#linearGradient4918);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
1877 d="m 233.46875,162.25006 c 0.25721,0 0.46875,0.22299 0.46875,0.5 l 0,12 c 0,0.277 -0.21154,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.223 -0.46875,-0.5 l 0,-12 c 0,-0.27701 0.21154,-0.5 0.46875,-0.5 z m 4.03125,2 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 0,2 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 8.49436,2.53125 0,-0.0625 -1.99549,-1.46875 0,1 -2.49436,0 c -0.27637,0 -0.49887,0.18037 -0.49887,0.46875 l 0,0.0625 c 0,0.2631 0.2225,0.46875 0.49887,0.46875 l 2.49436,0 0,1 z M 231.5,168.25006 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 0,2 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z m 6,2 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 0.223,-0.46875 0.5,-0.46875 z"
1878 id="path4684"
1879 inkscape:connector-curvature="0"
1880 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss" /><path
1881 sodipodi:nodetypes="sscccccccccccscccc"
1882 inkscape:connector-curvature="0"
1883 id="path4686"
1884 d="m 459,163.25006 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 l 0,4 1,0 0,-9 1,0 0,1 0,8 1,0 0,-8 1,0 0,-2 z m -8,3 0,6 3,-3 z"
1885 style="fill:url(#linearGradient4920);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1886 sodipodi:nodetypes="sscccccccccccscccc"
1887 inkscape:connector-curvature="0"
1888 id="path4688"
1889 d="m 486,163.25006 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 l 0,4 1,0 0,-9 1,0 0,1 0,8 1,0 0,-8 1,0 0,-2 z m 9.00442,3 0,6 -3.00884,-3 z"
1890 style="fill:url(#linearGradient4922);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
1891 transform="matrix(0.99963181,0,0,1,0.17783468,0)" /><path
1892 sodipodi:nodetypes="ccccccccccccc"
1893 inkscape:connector-curvature="0"
1894 id="path4691"
1895 d="m 42.56445,200.91673 -1.02277,1.06211 2.08489,2.08489 -2.08489,2.12422 1.02277,1.06211 2.12422,-2.12422 2.12423,2.12422 1.02277,-1.06211 -2.08489,-2.12423 2.08489,-2.08488 -1.02277,-1.06211 -2.12423,2.12422 z"
1896 style="fill:url(#linearGradient4924);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
1897 style="fill:url(#linearGradient4926);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
1898 d="m 136.53125,162.25006 c -0.25721,0 -0.46875,0.22299 -0.46875,0.5 l 0,12 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 l 0,-12 c 0,-0.27701 -0.21154,-0.5 -0.46875,-0.5 z m -4.03125,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -8.5,2.46875 0,0.0625 2,1.46875 0,-1 2.5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 l -2.5,0 0,-1 z m 8.5,-0.46875 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z"
1899 id="path4693"
1900 inkscape:connector-curvature="0"
1901 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss" /><path
1902 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
1903 inkscape:connector-curvature="0"
1904 id="path4695"
1905 d="m 168.64267,162.25006 c -0.25721,0 -0.46875,0.223 -0.46875,0.5 l 0,12 c 0,0.27699 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.22301 0.46875,-0.5 l 0,-12 c 0,-0.277 -0.21154,-0.5 -0.46875,-0.5 z m -4.03125,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -3.38858,2.46875 0,0.0625 -2.08914,1.46875 0,-1 -2.61141,0 c -0.28935,0 -0.52229,-0.0347 -0.52229,-0.46875 l 0,-0.0625 c 0,-0.2631 0.23294,-0.46875 0.52229,-0.46875 l 2.61141,0 0,-1 z m 3.38858,-0.46875 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z"
1906 style="fill:url(#linearGradient4928);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1907 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
1908 inkscape:connector-curvature="0"
1909 id="path4698"
1910 d="m 201.46875,162.25006 c 0.25722,0 0.46875,0.223 0.46875,0.5 l 0,12 c 0,0.277 -0.21153,0.5 -0.46875,0.5 -0.25721,0 -0.46875,-0.223 -0.46875,-0.5 l 0,-12 c 0,-0.277 0.21154,-0.5 0.46875,-0.5 z m 4.03125,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 0.223,-0.46875 0.5,-0.46875 z m 0,2 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 0.223,-0.46875 0.5,-0.46875 z m 3.5,2.53125 0,-0.0625 2,-1.46875 0,1 2.5,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.22343,0.48425 -0.5,0.46875 l -2.5,0 0,1 z m -3.5,-0.53125 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 0.223,-0.46875 0.5,-0.46875 z m 0,2 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 0.223,-0.46875 0.5,-0.46875 z m 6,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.223,0.46875 -0.5,0.46875 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 c 0,-0.26309 0.223,-0.46875 0.5,-0.46875 z"
1911 style="fill:url(#linearGradient4930);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1912 inkscape:connector-curvature="0"
1913 id="path4700"
1914 d="m 2.0000001,226.25006 0,12 13.9999999,0 0,-12 -13.9999999,0 z m 1,1 11.9999999,0 0,7.59375 -2.90625,-3.59375 -3.09375,4 -2.9999999,-2 -3,4 0,-10 z m 2.5,1 c -0.82843,0 -1.5,0.67157 -1.5,1.5 0,0.82842 0.67157,1.5 1.5,1.5 0.82842,0 1.5,-0.67158 1.5,-1.5 0,-0.82843 -0.67158,-1.5 -1.5,-1.5 z"
1915 style="fill:url(#linearGradient4932);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1916 sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
1917 inkscape:connector-curvature="0"
1918 id="path4702"
1919 d="m 199,227.25006 0,3 10,0 0,-3 z m -5,2 0,7 4,-3.4375 z m 5,3 0,1 3,0 0,-1 z m 4,0 0,1 3,0 0,-1 z m 4,0 0,1 2,0 0,-1 z m -8,3 0,3 10,0 0,-3 z"
1920 style="fill:url(#linearGradient4934);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1921 sodipodi:nodetypes="sscccssssscccssss"
1922 inkscape:connector-curvature="0"
1923 id="path4704"
1924 d="m 323.5,100.25006 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24236 0.59935,0.45353 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.37612,-0.74776 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
1925 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4936);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1926 sodipodi:nodetypes="ssssssccssssssccsssssscccssssscccssssccccccccccc"
1927 inkscape:connector-curvature="0"
1928 id="path4706"
1929 d="m 131,98.250061 c -1.0907,0 -2,0.9093 -2,1.999999 l 0,9 c 0,1.09069 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.90931 2,-2 l 0,-0.375 c 0.0328,-0.0893 0.0213,-0.17215 0,-0.25 l 0,-8.375 c 0,-1.090699 -0.9093,-1.999999 -2,-1.999999 z m 0,1 12,0 c 0.554,0 1,0.446 1,0.999999 l 0,4.11795 -5.88205,5.88195 -7.11795,1e-4 c -0.554,10e-6 -1,-0.446 -1,-1 l 0,-9 c 0,-0.553999 0.446,-0.999999 1,-0.999999 z m 0.5,0.999999 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.0444,0.53446 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.12178,-0.5281 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 12.5,5.40625 0,0.84375 -3.71875,3.6875 -0.0312,0.0625 -0.84375,0 z m 0,2.21875 0,0.625 -1.71875,1.75 -0.625,0 z"
1930 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4938);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1931 sodipodi:nodetypes="sssssssssssssssssscccc"
1932 inkscape:connector-curvature="0"
1933 id="path4708"
1934 d="m 195,99.250061 c -1.0907,0 -2,0.909299 -2,1.999999 l 0,7 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.0907 -0.9093,-1.999999 -2,-1.999999 z m 0,0.999999 12,0 c 0.554,0 1,0.446 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -12,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.554 0.446,-1 1,-1 z m 6,3 3,4 3,-4 z"
1935 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4940);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1936 inkscape:connector-curvature="0"
1937 id="path4710"
1938 d="m 105.5,354.25005 c -1.37614,0 -2.55454,0.83475 -3.125,2 l 1.125,0 c 0.45491,-0.61149 1.17592,-1 2,-1 1.385,0 2.5,1.115 2.5,2.5 l 0,1.5 -3,0 -2,0 -1,0 -1,0 c -0.554,0 -1,0.44598 -1,1 l 0,6 c 0,0.554 0.446,1 1,1 l 9,0 c 0.554,0 1,-0.446 1,-1 l 0,-6 c 0,-0.55402 -0.446,-1 -1,-1 l -1,0 0,-1.5 c 0,-1.9217 -1.5783,-3.5 -3.5,-3.5 z m 0,8 c 0.82843,0 1.5,0.67157 1.5,1.5 0,0.82841 -0.67157,1.5 -1.5,1.5 -0.82843,0 -1.5,-0.67159 -1.5,-1.5 0,-0.82843 0.67157,-1.5 1.5,-1.5 z"
1939 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3350);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1940 inkscape:connector-curvature="0"
1941 id="path4712"
1942 d="m 4.5000001,163.25006 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 0.5,0 0,3.5 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-4 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1,0 z m 4,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 5.9999999,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -5.9999999,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 5.9999999,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -5.9999999,0 z m -5,5 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,1 -1.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 l 0,2 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1.5,0 0,-1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 0.0252,-0.0599 0.0312,-0.11825 0.0312,-0.1875 l 0,-2 c 0,-0.0693 -0.006,-0.12765 -0.0312,-0.1875 -0.0505,-0.13913 -0.15407,-0.24028 -0.28125,-0.28125 -0.0404,-0.0171 -0.0799,-0.0253 -0.125,-0.0312 l -0.0625,0 -2,0 z m 5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 5.9999999,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -5.9999999,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 5.9999999,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -5.9999999,0 z"
1943 style="fill:url(#linearGradient3293);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1944 sodipodi:nodetypes="cccccccccccccccccccscccscscccscccccccc"
1945 d="m 14.295877,138.53521 c -9e-6,0.70891 -0.137341,1.30388 -0.411995,1.78492 -0.274673,0.46838 -0.650527,0.84815 -1.127571,1.1393 -0.462605,0.2785 -1.019157,0.48105 -1.669674,0.60763 -0.636069,0.11394 -1.322728,0.1709 -2.059977,0.1709 l -3.72966,0.0121 0,-12.04805 3.4694455,-0.003 c 1.0119225,1e-5 1.8359135,0.095 2.4719815,0.28482 0.636059,0.17724 1.134796,0.41776 1.496201,0.72156 0.361395,0.29117 0.607142,0.6203 0.737259,0.9874 0.130097,0.36712 0.195146,0.73423 0.195156,1.10133 -10e-6,0.557 -0.159025,1.0507 -0.477054,1.4811 -0.303581,0.43041 -0.715576,0.7722 -1.235986,1.02538 0.910722,0.29116 1.525098,0.68359 1.843147,1.17728 0.332478,0.49371 0.498718,1.01272 0.498727,1.55705 m -6.3317392,-1.59503 0,3.19006 c 0.1879221,0.0253 0.3903124,0.0443 0.6071515,0.057 0.2312976,0.0127 0.4553617,0.019 0.6722097,0.019 0.303571,1e-5 0.599918,-0.019 0.88904,-0.057 0.289122,-0.0506 0.542103,-0.13292 0.758942,-0.24685 0.231297,-0.12659 0.419219,-0.29748 0.563785,-0.51269 0.144556,-0.22786 0.216839,-0.51268 0.216839,-0.85448 0,-0.56965 -0.209614,-0.97473 -0.628834,-1.21526 -0.404771,-0.25317 -0.954098,-0.37976 -1.647981,-0.37977 l -1.4311522,0 m 1.0408392,-1.93682 c 0.679425,1e-5 1.192611,-0.12658 1.539567,-0.37977 0.346937,-0.26583 0.52041,-0.62661 0.52041,-1.08234 0,-0.27849 -0.05059,-0.50002 -0.15179,-0.66459 -0.101191,-0.17722 -0.238522,-0.31014 -0.411996,-0.39876 -0.173473,-0.10126 -0.375863,-0.16456 -0.607151,-0.18989 -0.231298,-0.038 -0.46982,-0.057 -0.715576,-0.057 -0.2023808,1e-5 -0.4119955,0.006 -0.6288347,0.019 -0.2168391,0.0127 -0.4119953,0.0317 -0.5854685,0.057 l 0,2.69636 1.0408392,0"
1946 style="font-size:22.63113022px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4944);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Ubuntu Mono;-inkscape-font-specification:Ubuntu Mono Bold"
1947 id="path4714"
1948 inkscape:connector-curvature="0"
1949 transform="matrix(1,0,0,0.99576386,0,0.60259052)" /><g
1950 id="g4716"
1951 style="font-size:14.87401295px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4948);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Sans"
1952 transform="matrix(0.90955065,0,-0.23456935,0.90955065,-244.41664,85.857921)"><path
1953 sodipodi:nodetypes="ccccccccccccc"
1954 inkscape:connector-curvature="0"
1955 id="path4718"
1956 style="font-size:21.24859047px;font-variant:normal;font-weight:bold;font-stretch:normal;fill:url(#linearGradient4946);font-family:Ubuntu Mono;-inkscape-font-specification:Ubuntu Mono Bold"
1957 d="m 325.2364,61.999996 0,-2.167356 1.76912,0 -0.1287,-8.818165 -1.76912,0 0,-2.167356 6.15181,0 0,2.167356 -1.74787,0 0.1287,8.818165 1.74787,0 0,2.167356 -6.15181,0" /></g><g
1958 id="g4720"
1959 style="font-size:15.82676315px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4952);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1);font-family:Sans"
1960 transform="matrix(1.0640547,0,0,0.9425284,-84.03155,80.070151)"><path
1961 sodipodi:nodetypes="ccccccccc"
1962 inkscape:connector-curvature="0"
1963 id="path4722"
1964 style="font-size:22.60966301px;font-style:italic;font-variant:normal;font-stretch:normal;fill:url(#linearGradient4950);font-family:'8bitoperator JVE';-inkscape-font-specification:'8bitoperator JVE Italic'"
1965 d="m 263.15116,63.849438 2.25213,-9.18288 -2.8262,0 0.28703,-1.413104 8.47863,0 -0.28704,1.413104 -2.82621,0 -2.25213,9.18288 -2.82621,0" /></g><path
1966 inkscape:connector-curvature="0"
1967 id="path4726"
1968 d="m 265.00004,35.250051 7,5 -6.99998,4.99999 -2e-5,-3.33332 c -3.41666,0 -5.61556,1.22 -7,3.33333 0,-4.98332 3.60112,-6.66666 7,-6.66666 -2e-5,-0.85078 -1e-5,-2.61389 0,-3.33334 z"
1969 style="fill:url(#linearGradient4954);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1970 sodipodi:nodetypes="ccccccc" /><path
1971 sodipodi:nodetypes="ccccccc"
1972 style="fill:url(#linearGradient4956);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1973 d="m 329,35.250061 -7,5 6.99998,4.99998 2e-5,-3.33332 c 3.41666,0 5.61556,1.22 7,3.33334 0,-4.98333 -3.60112,-6.66667 -7,-6.66667 2e-5,-0.85078 10e-6,-2.61388 0,-3.33333 z"
1974 id="path4728"
1975 inkscape:connector-curvature="0" /><path
1976 sodipodi:nodetypes="sssssssssssssssssscccc"
1977 inkscape:connector-curvature="0"
1978 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4958);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1979 d="m 239,99.250061 c 1.0907,0 2,0.909299 2,1.999999 l 0,7 c 0,1.0907 -0.9093,2 -2,2 l -12,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-7 c 0,-1.0907 0.9093,-1.999999 2,-1.999999 z m 0,0.999999 -12,0 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 z m -6,3 -3,4 -3,-4 z"
1980 id="path4730" /><path
1981 inkscape:connector-curvature="0"
1982 id="path4732"
1983 d="m 112,193.25006 0,14 -1,0 0,-14 z m -4.74999,-0.41664 c 0.86983,0.009 1.76033,0.34033 2.74999,1.375 l 0,8.04164 c -3.96132,-4.05865 -6.94268,2.81598 -11,-1 l 0,-8.04165 c 3.03099,2.934 5.64051,-0.40352 8.25001,-0.37496 z"
1984 style="fill:url(#linearGradient4960);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
1985 sodipodi:nodetypes="cccccccccccc" /><path
1986 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4962);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1987 d="m 79.5,289.25006 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -3.5,0 c 1.0907,0 2,0.9093 2,2 l 0,10 c 0,1.0907 -0.9093,2 -2,2 -1.0907,0 -2,-0.9093 -2,-2 l 0,-10 c 0,-1.0907 0.9093,-2 2,-2 z m 0,1 c -0.554,0 -1,0.446 -1,1 l 0,10 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 l 0,-10 c 0,-0.554 -0.446,-1 -1,-1 z m 11.5,1 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 6.5,2 c 1.0907,0 2,0.9093 2,2 0,1.0907 -0.9093,2 -2,2 l -5,0 c -1.0907,0 -2,-0.9093 -2,-2 0,-1.0907 0.9093,-2 2,-2 l 5,0 z m 0,1 -5,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 5,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z"
1988 id="path4734"
1989 inkscape:connector-curvature="0" /><path
1990 sodipodi:nodetypes="ssccsssssccsssscccccccccc"
1991 inkscape:connector-curvature="0"
1992 id="path4736"
1993 d="m 68,1.2500615 c -1.108,0 -2,0.892 -2,2 l 0,8.9374995 3,3.0625 9,0 c 1.108,0 2,-0.892 2,-2 l 0,-9.9999995 c 0,-1.108 -0.892,-2 -2,-2 z m 0,1 10,0 0,4 c 0,1.108 0.108,1 -1,1 l -8,0 c -1.108,0 -1,0.108 -1,-1 z m 1,7.9999995 8,0 0,4 -4,0 0,-3 -2,0 0,3 -2,0 z"
1994 style="fill:url(#linearGradient4964);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
1995 sodipodi:nodetypes="ssscsssssssssssssssssssscssccsssssssccsccssccccccssssssssssssss"
1996 style="fill:url(#linearGradient3291);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
1997 d="m 45.5,163.25006 c 0,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.777,0.5 0.5,0.5 l 0.5,0 0,3.5 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-4 c 0,-0.277 -0.5,-0.5 -0.5,-0.5 z m -10,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 9,5 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,1 -1.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 l 0,2 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1.5,0 0,-1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 0.0252,-0.0599 0.0312,-0.11825 0.0312,-0.1875 l 0,-2 c 0,-0.0693 -0.006,-0.12765 -0.0312,-0.1875 -0.0505,-0.13913 -0.15407,-0.24028 -0.28125,-0.28125 -0.0404,-0.0171 -0.0799,-0.0253 -0.125,-0.0312 l -0.0625,0 -2,0 z m -9,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
1998 id="path4738"
1999 inkscape:connector-curvature="0" /><path
2000 sodipodi:nodetypes="ssssssssssssssssssssssssssssssssssssss"
2001 style="fill:url(#linearGradient4966);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2002 d="m 109,163.25006 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m -10.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 10.5,5 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m -10.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
2003 id="path4740"
2004 inkscape:connector-curvature="0" /><path
2005 style="fill:url(#linearGradient4968);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2006 d="m 235,227.25006 0,3 -10,0 0,-3 z m 5,2 0,7 -4,-3.4375 z m -5,3 0,1 -3,0 0,-1 z m -4,0 0,1 -3,0 0,-1 z m -4,0 0,1 -2,0 0,-1 z m 8,3 0,3 -10,0 0,-3 z"
2007 id="path4742"
2008 inkscape:connector-curvature="0"
2009 sodipodi:nodetypes="ccccccccccccccccccccccccccccc" /><path
2010 inkscape:connector-curvature="0"
2011 id="path4744"
2012 d="m 6.0000001,297.25005 0,1 -1,0 0,1 -1,0 0,0.875 -0.5,-0.5 -1.5,-1.375 0,5 5,0 -1.5,-1.625 -0.375,-0.375 0.875,0 0,-1 1,0 0,-1 1,0 0,-2 -2,0 z"
2013 style="fill:#585858;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)" /><path
2014 inkscape:connector-curvature="0"
2015 id="path4746"
2016 d="m 41,321.21574 c -3.86517,0 -7,3.1502 -7,7.03432 0,3.88412 3.13483,7.03431 7,7.03431 3.86633,0 7,-3.15019 7,-7.03431 0,-3.88412 -3.13367,-7.03432 -7,-7.03432 z"
2017 style="fill:url(#linearGradient4970);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2018 sodipodi:nodetypes="sssss" /><path
2019 inkscape:transform-center-y="2.9999632"
2020 inkscape:transform-center-x="-1.4999864"
2021 sodipodi:end="2.0943951"
2022 sodipodi:start="0"
2023 sodipodi:type="arc"
2024 style="fill:#999999;fill-opacity:1;stroke:none"
2025 id="path4748"
2026 sodipodi:cx="39.5"
2027 sodipodi:cy="327.5"
2028 sodipodi:rx="5.5"
2029 sodipodi:ry="5.5"
2030 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2031 transform="matrix(1.0909017,0,0,1.0909017,-2.0906205,-29.020279)" /><path
2032 transform="matrix(-0.54545087,0.94474863,-0.94474863,-0.54545087,371.95048,469.56763)"
2033 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2034 sodipodi:ry="5.5"
2035 sodipodi:rx="5.5"
2036 sodipodi:cy="327.5"
2037 sodipodi:cx="39.5"
2038 id="path4750"
2039 style="fill:#cccccc;fill-opacity:1;stroke:none"
2040 sodipodi:type="arc"
2041 sodipodi:start="0"
2042 sodipodi:end="2.0943951"
2043 inkscape:transform-center-x="3.0004864" /><path
2044 inkscape:transform-center-y="-3.0004886"
2045 inkscape:transform-center-x="-1.4999969"
2046 sodipodi:end="2.0943951"
2047 sodipodi:start="0"
2048 sodipodi:type="arc"
2049 style="fill:#666666;fill-opacity:1;stroke:none"
2050 id="path4752"
2051 sodipodi:cx="39.5"
2052 sodipodi:cy="327.5"
2053 sodipodi:rx="5.5"
2054 sodipodi:ry="5.5"
2055 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2056 transform="matrix(-0.54545087,-0.94474863,0.94474863,-0.54545087,-246.85986,544.20276)" /><rect
2057 ry="0"
2058 rx="0"
2059 y="231.25003"
2060 x="98"
2061 height="2"
2062 width="14"
2063 id="rect4754"
2064 style="fill:url(#linearGradient4972);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)" /><rect
2065 style="fill:#999999;fill-opacity:1;stroke:none"
2066 id="rect4756"
2067 width="12"
2068 height="0.99999475"
2069 x="99"
2070 y="228.25003"
2071 rx="0"
2072 ry="0" /><rect
2073 ry="0"
2074 rx="0"
2075 y="226.25003"
2076 x="99"
2077 height="0.99999475"
2078 width="12"
2079 id="rect4758"
2080 style="fill:#999999;fill-opacity:1;stroke:none" /><rect
2081 ry="0"
2082 rx="0"
2083 y="237.25003"
2084 x="99"
2085 height="0.99999475"
2086 width="12"
2087 id="rect4760"
2088 style="fill:#999999;fill-opacity:1;stroke:none" /><rect
2089 style="fill:#999999;fill-opacity:1;stroke:none"
2090 id="rect4762"
2091 width="12"
2092 height="0.99999475"
2093 x="99"
2094 y="235.25003"
2095 rx="0"
2096 ry="0" /><rect
2097 style="fill:#999999;fill-opacity:1;stroke:none"
2098 id="rect4764"
2099 width="12"
2100 height="0.99999475"
2101 x="99"
2102 y="224.25003"
2103 rx="0"
2104 ry="0" /><rect
2105 ry="0"
2106 rx="0"
2107 y="239.25003"
2108 x="99"
2109 height="0.99999475"
2110 width="12"
2111 id="rect4766"
2112 style="fill:#999999;fill-opacity:1;stroke:none" /><path
2113 transform="matrix(-1,0,0,1,337.02051,0.25006141)"
2114 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient4974);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2115 d="m 162,98 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.09069 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.90931 2,-2 l 0,-0.375 c 0.0328,-0.0893 0.0213,-0.17215 0,-0.25 L 176,100 c 0,-1.0907 -0.9093,-2 -2,-2 z m 0,1 12,0 c 0.554,0 1,0.446 1,1 l 0,4.11795 -5.88205,5.88195 L 162,110 c -0.554,1e-5 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 z m 0.5,1 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.0444,0.53446 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.12178,-0.5281 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 12.5,5.40625 0,0.84375 -3.71875,3.6875 -0.0312,0.0625 -0.84375,0 z m 0,2.21875 0,0.625 -1.71875,1.75 -0.625,0 z"
2116 id="path4768"
2117 inkscape:connector-curvature="0"
2118 sodipodi:nodetypes="ssssssccssssssccsssssscccssssscccssssccccccccccc" /><path
2119 style="fill:url(#linearGradient6476);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2120 d="m 65,225.25005 0,2 0,10 0,2 16,0 0,-2 0,-10 0,-2 z m 1,4 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m -10,5 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z"
2121 id="path4770"
2122 inkscape:connector-curvature="0"
2123 sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc" /><path
2124 transform="matrix(1,0,0,-1,1.0000001,585.25004)"
2125 inkscape:connector-curvature="0"
2126 style="fill:#585858;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2127 d="m 5,289.99999 0,1 -1,0 0,1 -1,0 0,0.875 -0.5,-0.5 -1.5,-1.375 0,5 5,0 -1.5,-1.625 -0.375,-0.375 0.875,0 0,-1 1,0 0,-1 1,0 0,-2 -2,0 z"
2128 id="path4788" /><path
2129 transform="matrix(-1,0,0,1,25,0.25006141)"
2130 inkscape:connector-curvature="0"
2131 style="fill:#585858;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2132 d="m 13,296.99999 0,1 -1,0 0,1 -1,0 0,0.875 -0.5,-0.5 -1.5,-1.375 0,5 5,0 -1.5,-1.625 -0.375,-0.375 0.875,0 0,-1 1,0 0,-1 1,0 0,-2 -2,0 z"
2133 id="path4790" /><path
2134 id="path4792"
2135 d="m 5,289.99999 0,1 -1,0 0,1 -1,0 0,0.875 -0.5,-0.5 -1.5,-1.375 0,5 5,0 -1.5,-1.625 -0.375,-0.375 0.875,0 0,-1 1,0 0,-1 1,0 0,-2 -2,0 z"
2136 style="fill:#585858;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2137 inkscape:connector-curvature="0"
2138 transform="matrix(-1,0,0,-1,17,585.25004)" /><path
2139 id="path4795"
2140 d="m 259,1.2500515 0,13.9999995 11,0 0,-8.9999995 0,-1 -4,-4 -1,0 -6,0 z m 1,1 5.34375,0 3.65625,3.65625 0,8.3437495 -5,0 -3,0 -1,0 0,-11.9999995 z m 2,5 0,1 5,0 0,-1 -5,0 z m 0,2 0,0.9999995 5,0 0,-0.9999995 -5,0 z m 0,1.9999995 0,1 5,0 0,-1 -5,0 z"
2141 style="fill:url(#linearGradient4980);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2142 inkscape:connector-curvature="0" /><path
2143 style="fill:url(#linearGradient4982);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2144 d="m 3.0000001,1.2500515 0,13.9999995 10.9999999,0 0,-8.9999995 0,-1 -4,-4 -1,0 z m 1,1 5.4999999,0 3.5,3.5 0,8.4999995 -4.9999999,0 -3,0 -1,0 z"
2145 id="path4797"
2146 inkscape:connector-curvature="0"
2147 sodipodi:nodetypes="cccccccccccccccc" /><path
2148 transform="matrix(-1,0,0,1,81,0.25006141)"
2149 style="fill:url(#linearGradient4984);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2150 d="m 39,6 0,1.875 -1.375,1.46875 1.375,1.46875 0,1.90625 -3.625,-3.375 z"
2151 id="path4799"
2152 inkscape:connector-curvature="0" /><path
2153 transform="matrix(-1,0,0,1,81,0.25006141)"
2154 style="fill:url(#linearGradient4986);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2155 d="M 40,6 43.6875,9.375 40,12.65625 40,10.75 41.4375,9.34375 40,7.8125 z"
2156 id="path4801"
2157 inkscape:connector-curvature="0" /><path
2158 transform="matrix(-1,0,0,1,82,0.25006141)"
2159 sodipodi:nodetypes="cccccccccccccccc"
2160 inkscape:connector-curvature="0"
2161 id="path4803"
2162 d="m 35,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2163 style="fill:url(#linearGradient4988);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
2164 style="fill:url(#linearGradient4990);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2165 d="m 99,1.2500515 0,13.9999995 11,0 0,-8.9999995 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.4999995 -5,0 -3,0 -1,0 z"
2166 id="path4805"
2167 inkscape:connector-curvature="0"
2168 sodipodi:nodetypes="cccccccccccccccc" /><path
2169 transform="matrix(-1,0,0,1,273,0.25006141)"
2170 sodipodi:nodetypes="cccccccccccccccc"
2171 inkscape:connector-curvature="0"
2172 id="path4807"
2173 d="m 131,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2174 style="fill:url(#linearGradient4992);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
2175 id="path4809"
2176 d="m 291,1.2500515 0,4.75 c 0.19146,-0.12014 0.37062,-0.22084 0.5625,-0.3125 l 0.4375,-0.21875 0,-3.21875 5.34375,0 3.65625,3.65625 0,8.3437495 -5,0 0,0.96875 c 0,0.0104 1.6e-4,0.0209 0,0.0312 l 6,0 0,-8.9999995 0,-1 -4,-4 -1,0 -6,0 z m 1,5.34375 c -0.36123,0.17256 -0.68892,0.37641 -0.96875,0.65625 -0.63338,0.63338 -1.03125,1.5335 -1.03125,2.5 0,1.3935195 0.8237,2.5643995 2,3.1249995 l 0,2.34375 c 0,0.554 0.44599,1 1,1 l 1,0.0312 c 0.554,0 1,-0.47725 1,-1.03125 l 0,-2.34375 c 1.17629,-0.5606 2,-1.73148 2,-3.1249995 0,-1.39352 -0.82119,-2.59313 -2,-3.15625 l 0,2.65625 -1.46875,0.9999995 L 292,9.2500015 l 0,-2.65625 z"
2177 style="fill:url(#linearGradient4994);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2178 inkscape:connector-curvature="0" /><path
2179 id="path4817"
2180 d="m 34,32.250051 0,10 3,0 0,-1 -1,0 -1,0 0,-8 4.5,0 2.5,2.5 0,0.5 1,0 0,-1 -3,-3 -1,0 -5,0 z m 4,5 0,10 9,0 0,-6 0,-1 -3,-3 -1,0 -5,0 z m 1,1 4.5,0 2.5,2.5 0,5.5 -5,0 -1,0 -1,0 0,-8 z"
2181 style="fill:url(#linearGradient4996);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2182 inkscape:connector-curvature="0" /><path
2183 transform="matrix(-1,0,0,1,389,0.25006141)"
2184 inkscape:connector-curvature="0"
2185 style="fill:url(#linearGradient5002);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2186 d="m 182,0.99999 0,14 8.8125,0 -1,-1 -1.3125,0 -1.5,0 -3,0 -1,0 0,-12 5.5,0 3.5,3.5 0,1.21875 c 0.61468,0.7698887 1,1.7287934 1,2.78125 l 0,-3.5 0,-1 -4,-4 -1,0 -6,0 z m 11,8.5 c 0,0.4831876 -0.20077,0.86276 -0.34375,1.28125 L 193,11.12499 l 0,-1.625 z m -4.5,-3.5 c -1.92115,0 -3.5,1.57884 -3.5,3.5 0,1.92115 1.57885,3.5 3.5,3.5 0.49539,0 0.94633,-0.12374 1.375,-0.3125 l 2.34375,2.34375 1.625,-1.625 -2.28125,-2.28125 C 191.829,10.63214 192,10.09539 192,9.49999 c 0,-1.92116 -1.57885,-3.5 -3.5,-3.5 z m -0.0312,1 c 1.38071,0 2.5,1.11929 2.5,2.5 0,1.38071 -1.11929,2.5 -2.5,2.5 -1.38071,0 -2.5,-1.11929 -2.5,-2.5 0,-1.38071 1.11929,-2.5 2.5,-2.5 z"
2187 id="path4828" /><path
2188 transform="matrix(-1,0,0,1,657,0.25006141)"
2189 inkscape:connector-curvature="0"
2190 style="fill:url(#linearGradient5004);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2191 d="m 323,0.99999 0,4.75 c 0.19146,-0.1201434 0.37062,-0.2208417 0.5625,-0.3125 L 324,5.21874 l 0,-3.21875 5.34375,0 3.65625,3.65625 0,8.34375 -5,0 0,0.96875 c 0,0.01043 1.6e-4,0.02085 0,0.03125 l 6,0 0,-9 0,-1 -4,-4 -1,0 -6,0 z m 1,5.34375 c -0.36123,0.1725562 -0.68892,0.3764154 -0.96875,0.65625 C 322.39787,7.6333667 322,8.5334899 322,9.49999 c 0,1.393522 0.8237,2.564396 2,3.125 l 0,2.34375 c 0,0.554002 0.44599,1.000002 1,1 l 1,0.03125 c 0.554,-2e-6 1,-0.477248 1,-1.03125 l 0,-2.34375 c 1.17629,-0.560603 2,-1.731478 2,-3.125 0,-1.3935222 -0.82119,-2.5931341 -2,-3.15625 l 0,2.65625 -1.46875,1 -1.53125,-1 0,-2.65625 z"
2192 id="path4830" /><rect
2193 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2194 id="rect6517"
2195 width="6.9999981"
2196 height="1"
2197 x="71"
2198 y="68.250053" /><rect
2199 y="70.250053"
2200 x="67"
2201 height="1"
2202 width="11"
2203 id="rect6519"
2204 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2205 y="74.250053"
2206 x="67"
2207 height="1"
2208 width="11"
2209 id="rect6523"
2210 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2211 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2212 id="rect6525"
2213 width="3"
2214 height="1"
2215 x="67"
2216 y="76.250053" /><path
2217 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2218 d="m 71,76.250051 0,1 1,0 0,2 -1,0 0,1 3,0 0,-1 -1,0 0,-2 1,0 0,-1 -1,0 -1,0 -1,0 z"
2219 id="rect6527"
2220 inkscape:connector-curvature="0" /><rect
2221 y="72.250053"
2222 x="67"
2223 height="1"
2224 width="11"
2225 id="rect6539"
2226 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2227 y="66.250053"
2228 x="71"
2229 height="1"
2230 width="7"
2231 id="rect6547"
2232 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2233 style="fill:#2d2d2d;fill-opacity:0.99215686;stroke:none"
2234 id="rect6606"
2235 width="3"
2236 height="3"
2237 x="67"
2238 y="66.250053" /><path
2239 inkscape:connector-curvature="0"
2240 style="fill:url(#linearGradient7390);fill-opacity:1;fill-rule:evenodd;display:inline;filter:url(#filter3224-1-7-1-2)"
2241 d="m 8.4240611,258.26107 c -1.28354,3.14452 -2.79862,6.87174 -4.15625,10.1875 l 2.5,0 0.90625,-2.5 3.3437499,0 0.8125,2.5 2.625,0 c -1.33823,-3.35178 -2.81774,-6.95392 -4.09375,-10.1875 l -1.9374999,0 z m 0.9687499,2.96875 0.90625,2.6875 -1.9062499,0 0.9999999,-2.6875 z"
2242 id="path4763" /><path
2243 style="fill:#999999;fill-opacity:1;fill-rule:evenodd;display:inline"
2244 d="m 2.0000001,270.26107 0,1.98898 14.9999999,0 0,-1.98898 z"
2245 id="path3812"
2246 inkscape:connector-curvature="0" /><path
2247 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3645);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2248 d="m 103.53125,32.250051 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.9375 c 0,0.2946 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.23665 0.53125,-0.53125 l 0,-0.9375 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -2.9375,0 z m -2.53125,1 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0316,-0.36661 0.0937,-0.53125 l -0.0937,0 z m 7.90625,0 c 0.0622,0.16465 0.0937,0.34767 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z m -4.90625,5 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 2,0 0,4 1,0 0,-4 2,0 0,-1 -5,0 z"
2249 id="path3631"
2250 inkscape:connector-curvature="0" /><path
2251 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3667);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2252 d="m 135.53125,32.250051 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.9375 c 0,0.2946 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.23665 0.53125,-0.53125 l 0,-0.9375 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -2.9375,0 z m -2.53125,1 c -1.0907,0 -2,0.9093 -2,2 l 0,2 1,0 0,-2 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0316,-0.3666 0.0937,-0.53125 l -0.0937,0 z m 7.90625,0 c 0.0621,0.16464 0.0937,0.34767 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.446 1,1 l 0,9 c 0,0.554 -0.446,1 -1,1 l -1,0 0,1 1,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-9 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z m -9.90625,5 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 2,0 0,4 1,0 0,-4 2,0 0,-1 -5,0 z"
2253 id="path3655"
2254 inkscape:connector-curvature="0" /><path
2255 style="fill:#4c4c4c;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-2)"
2256 d="m 199.53125,32.250051 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.46875 -0.46875,0 c -0.29461,0 -0.53125,0.23664 -0.53125,0.53125 l 0,0.9375 c 0,0.2946 0.23664,0.53125 0.53125,0.53125 l 1,0 2.9375,0 1,0 c 0.29461,0 0.53125,-0.23665 0.53125,-0.53125 l 0,-0.9375 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -0.46875,0 0,-0.46875 c 0,-0.29461 -0.23664,-0.53125 -0.53125,-0.53125 l -2.9375,0 z m -2.53125,1 c -1.0907,0 -2,0.9093 -2,2 l 0,2 1,0 0,-2 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0316,-0.3666 0.0937,-0.53125 l -0.0937,0 z m 7.90625,0 c 0.0621,0.16464 0.0937,0.34767 0.0937,0.53125 l 0,0.46875 c 0.554,0 1,0.446 1,1 l 0,9 c 0,0.554 -0.446,1 -1,1 l -1,0 0,1 1,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-9 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z m -9.90625,5 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 0,4 1,0 1,-1 1,0 1,1 1,0 0,-4 0,-1 -1,0 0,3 -0.25,0 -0.75,0 0,-1 -1,0 0,1 -0.75,0 -0.25,0 0,-3 -1,0 z"
2257 id="path3708"
2258 inkscape:connector-curvature="0" /><rect
2259 style="fill:url(#linearGradient3809);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-2)"
2260 id="rect3807"
2261 width="16"
2262 height="7.9999976"
2263 x="257"
2264 y="100.25005"
2265 rx="2"
2266 ry="2" /><path
2267 style="fill:#767676;fill-opacity:1;stroke:none"
2268 d="m 259,106.25005 0,-3.375 c 0,-0.35225 0.27275,-0.625 0.625,-0.625 l 12.375,0 0,-0.375 c 0,-0.35225 -0.27275,-0.625 -0.625,-0.625 l -12.75,0 c -0.35225,0 -0.625,0.27275 -0.625,0.625 l 0,3.75 c 0,0.35225 0.27275,0.625 0.625,0.625 l 0.375,0 z"
2269 id="rect3811"
2270 inkscape:connector-curvature="0" /><g
2271 style="font-size:15.85716724px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#585858;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-2);font-family:Sans"
2272 id="text3563"
2273 transform="translate(18,0.25006141)"><path
2274 d="m 91.018035,130.55223 0,2.44671 c -0.634915,-0.28389 -1.011554,-0.48077 -1.615481,-0.62531 -0.603942,-0.14452 -1.174325,-0.21679 -1.71115,-0.2168 -0.712338,10e-6 -1.238845,0.0981 -1.579522,0.29423 -0.340685,0.19616 -0.511026,0.5007 -0.511022,0.91364 -4e-6,0.30972 0.113556,0.55233 0.340681,0.72782 0.232279,0.17035 0.650387,0.31746 1.254327,0.44134 l 1.269812,0.25551 c 1.28529,0.2581 2.198934,0.6504 2.740936,1.1769 0.541983,0.52651 0.81298,1.27498 0.81299,2.2454 -10e-6,1.27498 -0.379405,2.22475 -1.138185,2.84933 -0.753637,0.61942 -1.907307,0.92913 -3.461013,0.92913 -0.732986,0 -1.468547,-0.0697 -2.206686,-0.20905 -0.738146,-0.13937 -1.476288,-0.34584 -2.214429,-0.61942 l 0,-2.5164 c 0.738141,0.39231 1.450474,0.68911 2.137002,0.89042 0.691682,0.19615 1.357558,0.29423 1.997631,0.29423 0.650386,0 1.148502,-0.1084 1.494352,-0.3252 0.345836,-0.2168 0.518757,-0.52651 0.518765,-0.92913 -8e-6,-0.36133 -0.11873,-0.64007 -0.356167,-0.83622 -0.232289,-0.19615 -0.699435,-0.37165 -1.401439,-0.52651 l -1.153671,-0.25551 c -1.156255,-0.24776 -2.002796,-0.64264 -2.539624,-1.18464 -0.531671,-0.54199 -0.797506,-1.27239 -0.797504,-2.1912 -2e-6,-1.15108 0.37165,-2.03634 1.114957,-2.65577 0.743301,-0.61941 1.811801,-0.92912 3.205501,-0.92913 0.6349,1e-5 1.287872,0.049 1.958918,0.14712 0.671031,0.0929 1.122516,0.21753 1.840021,0.40851"
2275 style="font-weight:bold;fill:#585858;-inkscape-font-specification:Sans Bold"
2276 id="path3568"
2277 inkscape:connector-curvature="0"
2278 sodipodi:nodetypes="ccccccccccccsccccsccccccssccc" /></g><path
2279 id="path3593"
2280 d="m 99.5,136.25006 12,0 c 0.277,0 0.5,0.20442 0.5,0.45833 l 0,0.0833 c 0,0.25395 -0.223,0.45837 -0.5,0.45837 l -12,0 c -0.277,0 -0.5,-0.20442 -0.5,-0.45833 l 0,-0.0833 c 0,-0.25395 0.223,-0.45837 0.5,-0.45837 z"
2281 style="fill:#2d2d2d;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1)"
2282 inkscape:connector-curvature="0"
2283 sodipodi:nodetypes="sssssssss" /><path
2284 style="fill:url(#linearGradient3947);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2285 d="m 3,354.25006 0,13 1,0 0,-13 z"
2286 id="path3580"
2287 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2288 inkscape:export-xdpi="90"
2289 inkscape:export-ydpi="90"
2290 inkscape:connector-curvature="0"
2291 sodipodi:nodetypes="ccccc" /><path
2292 style="fill:#b50000;fill-opacity:1;fill-rule:evenodd"
2293 d="m 7.49999,353.83342 c -0.79075,0.009 -1.6003,0.34033 -2.49999,1.375 l 0,8.04164 c 3.6012,-4.05865 6.31153,2.81598 10,-1 l 0,-8.04165 c -2.75545,2.934 -5.12774,-0.40352 -7.50001,-0.37496 z"
2294 id="path3574"
2295 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2296 inkscape:export-xdpi="90"
2297 inkscape:export-ydpi="90"
2298 inkscape:connector-curvature="0" /><path
2299 id="path4350"
2300 d="m 7.49999,354.83342 c -0.79075,0.009 -1.6003,0.34033 -2.49999,1.375 l 0,7.04164 c 3.6012,-4.05865 6.31153,2.81598 10,-1 l 0,-7.04165 c -2.75545,2.934 -5.12774,-0.40352 -7.50001,-0.37496 z"
2301 style="fill:url(#linearGradient3949);fill-opacity:1;fill-rule:evenodd"
2302 inkscape:connector-curvature="0"
2303 sodipodi:nodetypes="ccccccc"
2304 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2305 inkscape:export-xdpi="90"
2306 inkscape:export-ydpi="90" /><path
2307 style="fill:#8e0000;fill-opacity:1;fill-rule:evenodd"
2308 d="m 15,354.2188 c -0.30805,0.32801 -0.61008,0.56529 -0.90909,0.75 l 0,7 c -2.37556,1.46746 -4.48386,-1.15037 -6.59091,-1.125 -0.79075,0.009 -1.60031,0.34033 -2.5,1.375 l 0,0.25 0,0.75 0,0.0312 c 0.17642,-0.19882 0.34007,-0.3831 0.51136,-0.53125 0.17129,-0.14815 0.34405,-0.27195 0.51137,-0.375 0.33463,-0.2061 0.66866,-0.31581 0.99432,-0.375 -0.0646,-0.009 -0.13201,-0.0172 -0.19887,-0.0312 0.22905,-0.0632 0.45744,-0.0912 0.68182,-0.0937 1.52669,-0.0184 3.05867,1.36143 4.6875,1.5625 0.0643,0.008 0.13429,-0.004 0.19886,0 0.086,0.005 0.16893,0.0337 0.25569,0.0312 0.0948,-0.003 0.18827,-0.0188 0.28409,-0.0312 0.13088,-0.017 0.26485,-0.0564 0.39772,-0.0937 0.18899,-0.0529 0.37588,-0.1176 0.56819,-0.21875 0.0301,-0.0155 0.055,-0.0457 0.0852,-0.0625 0.16982,-0.0943 0.33776,-0.20651 0.51137,-0.34375 0.16802,-0.13283 0.33949,-0.25969 0.51136,-0.4375 l 0,-0.0312 0,-1 0,-7 z"
2309 id="path4364"
2310 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2311 inkscape:export-xdpi="90"
2312 inkscape:export-ydpi="90"
2313 inkscape:connector-curvature="0" /><rect
2314 inkscape:export-ydpi="90"
2315 inkscape:export-xdpi="90"
2316 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2317 y="352.25006"
2318 x="1"
2319 height="16"
2320 width="16"
2321 id="rect3598"
2322 style="fill:#ffffff;fill-opacity:0;stroke:none" /><path
2323 sodipodi:nodetypes="ccccc"
2324 inkscape:connector-curvature="0"
2325 inkscape:export-ydpi="90"
2326 inkscape:export-xdpi="90"
2327 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2328 id="path3600"
2329 d="m 3,354.25006 0,13 1,0 0,-13 z"
2330 style="fill:url(#linearGradient3576);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)" /><path
2331 inkscape:connector-curvature="0"
2332 inkscape:export-ydpi="90"
2333 inkscape:export-xdpi="90"
2334 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2335 id="path3602"
2336 d="m 7.49999,353.83342 c -0.79075,0.009 -1.6003,0.34033 -2.49999,1.375 l 0,8.04164 c 3.6012,-4.05865 6.31153,2.81598 10,-1 l 0,-8.04165 c -2.75545,2.934 -5.12774,-0.40352 -7.50001,-0.37496 z"
2337 style="fill:#b50000;fill-opacity:1;fill-rule:evenodd" /><path
2338 inkscape:export-ydpi="90"
2339 inkscape:export-xdpi="90"
2340 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2341 sodipodi:nodetypes="ccccccc"
2342 inkscape:connector-curvature="0"
2343 style="fill:url(#linearGradient4358);fill-opacity:1;fill-rule:evenodd"
2344 d="m 7.49999,354.83342 c -0.79075,0.009 -1.6003,0.34033 -2.49999,1.375 l 0,7.04164 c 3.6012,-4.05865 6.31153,2.81598 10,-1 l 0,-7.04165 c -2.75545,2.934 -5.12774,-0.40352 -7.50001,-0.37496 z"
2345 id="path3604" /><path
2346 inkscape:connector-curvature="0"
2347 inkscape:export-ydpi="90"
2348 inkscape:export-xdpi="90"
2349 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2350 id="path3606"
2351 d="m 15,354.2188 c -0.30805,0.32801 -0.61008,0.56529 -0.90909,0.75 l 0,7 c -2.37556,1.46746 -4.48386,-1.15037 -6.59091,-1.125 -0.79075,0.009 -1.60031,0.34033 -2.5,1.375 l 0,0.25 0,0.75 0,0.0312 c 0.17642,-0.19882 0.34007,-0.3831 0.51136,-0.53125 0.17129,-0.14815 0.34405,-0.27195 0.51137,-0.375 0.33463,-0.2061 0.66866,-0.31581 0.99432,-0.375 -0.0646,-0.009 -0.13201,-0.0172 -0.19887,-0.0312 0.22905,-0.0632 0.45744,-0.0912 0.68182,-0.0937 1.52669,-0.0184 3.05867,1.36143 4.6875,1.5625 0.0643,0.008 0.13429,-0.004 0.19886,0 0.086,0.005 0.16893,0.0337 0.25569,0.0312 0.0948,-0.003 0.18827,-0.0188 0.28409,-0.0312 0.13088,-0.017 0.26485,-0.0564 0.39772,-0.0937 0.18899,-0.0529 0.37588,-0.1176 0.56819,-0.21875 0.0301,-0.0155 0.055,-0.0457 0.0852,-0.0625 0.16982,-0.0943 0.33776,-0.20651 0.51137,-0.34375 0.16802,-0.13283 0.33949,-0.25969 0.51136,-0.4375 l 0,-0.0312 0,-1 0,-7 z"
2352 style="fill:#8e0000;fill-opacity:1;fill-rule:evenodd" /><path
2353 style="fill:url(#linearGradient4386);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-2)"
2354 d="m 65,321.25005 0,14 3,0 0,-1 -2,0 0,-12 2,0 0,-1 z m 13,0 0,1 2,0 0,12 -2,0 0,1 3,0 0,-14 z"
2355 id="rect3578"
2356 inkscape:connector-curvature="0"
2357 sodipodi:nodetypes="cccccccccccccccccc" /><g
2358 style="font-size:13.71140385px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4388);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-2);font-family:Sans"
2359 id="text4354"
2360 transform="translate(2.0000001,0.25006141)"><path
2361 d="m 70.006423,329.43503 1.991763,0 c 1.837326,0 3.016509,-1.30258 3.016509,-3.33187 0,-2.00186 -1.138049,-3.09877 -3.22218,-3.09877 l -3.790777,0 0,9.99561 2.004685,0 0,-3.56497 m 0,-1.71392 0,-3.0028 1.347327,0 c 1.096911,0 1.604234,0.4799 1.604234,1.50826 0,1.01464 -0.507323,1.49454 -1.604234,1.49454 l -1.347327,0"
2362 style="font-variant:normal;font-weight:bold;font-stretch:normal;fill:url(#linearGradient3951);font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L Bold"
2363 id="path4361"
2364 inkscape:connector-curvature="0"
2365 sodipodi:nodetypes="csssccccccsssc" /></g><path
2366 style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3224-1-7-1-5-0-8)"
2367 d="m 111,321.53125 -6,0.9375 0,1 2,-0.3125 0,2.84375 -3,0 0,1 3,0 0,3 -2,0 -1,0 0,5 1,0 0,-1 5,0 1,0 0,-4 -1,0 -2,0 0,-3 3,0 0,-1 -3,0 0,-3 3,-0.46875 0,-1 z M 97,322 l 0,1 6,0 0,-1 -6,0 z m -1,2 0,1 8,0 0,-1 -8,0 z m 1,2 0,1 6,0 0,-1 -6,0 z m 0,2 0,1 6,0 0,-1 -6,0 z m 0,2 0,5 1,0 0,-1 4,0 1,0 0,-4 -1,0 -4,0 -1,0 z m 1,1 4,0 0,2 -4,0 0,-2 z m 7,0 5,0 0,2 -5,0 0,-2 z"
2368 transform="translate(1,0.2500015)"
2369 id="rect4258"
2370 inkscape:connector-curvature="0" /><path
2371 style="fill:#515151;fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-7)"
2372 d="m 129,321.25002 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,5 0,1 0,3 5,0 0,-1 -4,0 0,-1 4,0 1,0 0,-1 -5,0 0,-1 6,0 4,0 0,-1 0,-4 -4,0 -7,0 z m 12,0 0,1 1,0 0,-1 -1,0 z m -11,1 9,0 0,1 -9,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -11,1 8.96875,0 0,1 -8.96875,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -3,1.75 -3.6875,3.375 3.6875,3.28125 0,-1.90625 -1.4375,-1.40625 1.4375,-1.53125 0,-1.8125 z m 1,0 0,1.875 1.375,1.46875 -1.375,1.46875 0,1.90625 3.625,-3.375 -3.625,-3.34375 z m -12,0.25 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z"
2373 id="rect5051"
2374 inkscape:connector-curvature="0" /></g></svg> \ No newline at end of file
diff --git a/sources/skins/moono/dev/icons32.png b/sources/skins/moono/dev/icons32.png
new file mode 100644
index 0000000..a74c093
--- /dev/null
+++ b/sources/skins/moono/dev/icons32.png
Binary files differ
diff --git a/sources/skins/moono/dev/icons32.svg b/sources/skins/moono/dev/icons32.svg
new file mode 100644
index 0000000..12b8908
--- /dev/null
+++ b/sources/skins/moono/dev/icons32.svg
@@ -0,0 +1,2722 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:xlink="http://www.w3.org/1999/xlink"
11 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13 version="1.1"
14 id="Layer_1"
15 x="0px"
16 y="0px"
17 width="992"
18 height="736"
19 viewBox="0 0 992 735.99996"
20 enable-background="new 0 0 612 792"
21 xml:space="preserve"
22 inkscape:version="0.48.3.1 r9886"
23 sodipodi:docname="icons32.svg"
24 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/skins/moono/dev/icons32.png"
25 inkscape:export-xdpi="90"
26 inkscape:export-ydpi="90"><metadata
27 id="metadata9"><rdf:RDF><cc:Work
28 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
29 rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
30 id="defs7"><linearGradient
31 inkscape:collect="always"
32 id="linearGradient4352"><stop
33 style="stop-color:#ff4141;stop-opacity:0"
34 offset="0"
35 id="stop4354" /><stop
36 id="stop4362"
37 offset="0.24227905"
38 style="stop-color:#ff4141;stop-opacity:0.78823529;" /><stop
39 id="stop4360"
40 offset="0.73632693"
41 style="stop-color:#ff4141;stop-opacity:0" /><stop
42 style="stop-color:#ff4141;stop-opacity:1"
43 offset="1"
44 id="stop4356" /></linearGradient><linearGradient
45 id="linearGradient4392"><stop
46 style="stop-color:#666666;stop-opacity:1;"
47 offset="0"
48 id="stop4394" /><stop
49 style="stop-color:#424242;stop-opacity:1;"
50 offset="1"
51 id="stop4396" /></linearGradient><filter
52 id="filter3224-1-7-1-3"
53 inkscape:label="Inner Shadow"
54 inkscape:menu="Shadows and Glows"
55 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
56 color-interpolation-filters="sRGB"
57 width="1"
58 height="1"
59 y="0"
60 x="0"><feOffset
61 id="feOffset3228-5-5-5-70"
62 dx="0"
63 dy="0.69999999999999996"
64 result="result11" /><feComposite
65 id="feComposite3230-2-4-1-9"
66 in2="result11"
67 result="result6"
68 in="SourceGraphic"
69 operator="in" /><feFlood
70 id="feFlood3232-7-3-4-91"
71 result="result10"
72 in="result6"
73 flood-opacity="1"
74 flood-color="rgb(34,34,34)" /><feBlend
75 id="feBlend3234-6-3-5-53"
76 in2="result10"
77 mode="normal"
78 in="result6"
79 result="result12" /><feComposite
80 id="feComposite3236-1-3-5-3"
81 in2="SourceGraphic"
82 result="result2"
83 operator="in" /></filter><linearGradient
84 inkscape:collect="always"
85 xlink:href="#linearGradient4392"
86 id="linearGradient3429"
87 gradientUnits="userSpaceOnUse"
88 x1="72"
89 y1="32"
90 x2="72"
91 y2="47" /><linearGradient
92 inkscape:collect="always"
93 xlink:href="#linearGradient4392"
94 id="linearGradient3431"
95 gradientUnits="userSpaceOnUse"
96 gradientTransform="matrix(1.33333,0,0,1.33333,47.36541,-272.06703)"
97 x1="91"
98 y1="204"
99 x2="91"
100 y2="216" /><linearGradient
101 inkscape:collect="always"
102 xlink:href="#linearGradient4392"
103 id="linearGradient3437"
104 gradientUnits="userSpaceOnUse"
105 gradientTransform="translate(-96,49)"
106 x1="136"
107 y1="50"
108 x2="136"
109 y2="62" /><linearGradient
110 inkscape:collect="always"
111 xlink:href="#linearGradient4392"
112 id="linearGradient3439"
113 gradientUnits="userSpaceOnUse"
114 gradientTransform="translate(-16,49)"
115 x1="120"
116 y1="50"
117 x2="120"
118 y2="62" /><linearGradient
119 inkscape:collect="always"
120 xlink:href="#linearGradient4392"
121 id="linearGradient3441"
122 gradientUnits="userSpaceOnUse"
123 gradientTransform="translate(-80,49)"
124 x1="88"
125 y1="50"
126 x2="88"
127 y2="63" /><linearGradient
128 inkscape:collect="always"
129 xlink:href="#linearGradient4392"
130 id="linearGradient3443"
131 gradientUnits="userSpaceOnUse"
132 gradientTransform="translate(-272,80)"
133 x1="343"
134 y1="50"
135 x2="343"
136 y2="63" /><linearGradient
137 inkscape:collect="always"
138 xlink:href="#linearGradient4392"
139 id="linearGradient3447"
140 gradientUnits="userSpaceOnUse"
141 gradientTransform="translate(-16,192.99999)"
142 x1="88"
143 y1="161"
144 x2="88"
145 y2="174" /><linearGradient
146 inkscape:collect="always"
147 xlink:href="#linearGradient4392"
148 id="linearGradient3451"
149 gradientUnits="userSpaceOnUse"
150 gradientTransform="matrix(1.1649013,0,0,1.1649013,-386.36445,145.11124)"
151 x1="365"
152 y1="96.073685"
153 x2="365"
154 y2="108.07368" /><linearGradient
155 inkscape:collect="always"
156 xlink:href="#linearGradient4392"
157 id="linearGradient3453"
158 gradientUnits="userSpaceOnUse"
159 gradientTransform="matrix(1.33333,0,0,1.33333,-415.467,94.82271)"
160 x1="365"
161 y1="73.073685"
162 x2="365"
163 y2="84.073685" /><linearGradient
164 inkscape:collect="always"
165 xlink:href="#linearGradient4392"
166 id="linearGradient3455"
167 gradientUnits="userSpaceOnUse"
168 gradientTransform="matrix(1.1673123,0,0,1.1673123,-227.67995,73.95948)"
169 x1="366"
170 y1="48.073685"
171 x2="366"
172 y2="60.073685" /><linearGradient
173 inkscape:collect="always"
174 xlink:href="#linearGradient4392"
175 id="linearGradient3457"
176 gradientUnits="userSpaceOnUse"
177 gradientTransform="matrix(1.1111083,0,0,1.1111083,-187.99896,-192.84664)"
178 x1="378"
179 y1="205"
180 x2="378"
181 y2="214" /><linearGradient
182 inkscape:collect="always"
183 xlink:href="#linearGradient4392"
184 id="linearGradient3459"
185 gradientUnits="userSpaceOnUse"
186 gradientTransform="translate(177.99998,89.93748)"
187 x1="246"
188 y1="73.073685"
189 x2="246"
190 y2="84.073685" /><linearGradient
191 inkscape:collect="always"
192 xlink:href="#linearGradient4392"
193 id="linearGradient3461"
194 gradientUnits="userSpaceOnUse"
195 gradientTransform="translate(169.99998,89.93748)"
196 x1="222"
197 y1="73.073685"
198 x2="222"
199 y2="84.073685" /><linearGradient
200 inkscape:collect="always"
201 xlink:href="#linearGradient4392"
202 id="linearGradient3463"
203 gradientUnits="userSpaceOnUse"
204 gradientTransform="matrix(1.0131693,0,0,1.0131693,159.31347,88.9358)"
205 x1="197"
206 y1="73.073685"
207 x2="197"
208 y2="84.073685" /><linearGradient
209 inkscape:collect="always"
210 xlink:href="#linearGradient4392"
211 id="linearGradient3465"
212 gradientUnits="userSpaceOnUse"
213 gradientTransform="translate(153.99998,89.93748)"
214 x1="171"
215 y1="73.073685"
216 x2="171"
217 y2="84.073685" /><linearGradient
218 inkscape:collect="always"
219 xlink:href="#linearGradient4392"
220 id="linearGradient3467"
221 gradientUnits="userSpaceOnUse"
222 gradientTransform="matrix(1.2458722,0,0,1.1615489,-282.43958,-203.90163)"
223 x1="233"
224 y1="204"
225 x2="233"
226 y2="216" /><linearGradient
227 inkscape:collect="always"
228 xlink:href="#linearGradient4392"
229 id="linearGradient3469"
230 gradientUnits="userSpaceOnUse"
231 gradientTransform="matrix(1.1666672,0,0,1.1723864,-11.00007,112.34331)"
232 x1="126"
233 y1="96.073685"
234 x2="126"
235 y2="108.07368" /><linearGradient
236 inkscape:collect="always"
237 xlink:href="#linearGradient4392"
238 id="linearGradient3471"
239 gradientUnits="userSpaceOnUse"
240 gradientTransform="matrix(1.33333,0,0,1.1621519,95.65429,77.66723)"
241 x1="124"
242 y1="74.073685"
243 x2="124"
244 y2="82.073685" /><linearGradient
245 inkscape:collect="always"
246 xlink:href="#linearGradient4392"
247 id="linearGradient3473"
248 gradientUnits="userSpaceOnUse"
249 gradientTransform="matrix(1.1666666,0,0,1.1666669,-23,112.92042)"
250 x1="54"
251 y1="96.073685"
252 x2="54"
253 y2="108.07368" /><linearGradient
254 inkscape:collect="always"
255 xlink:href="#linearGradient4392"
256 id="linearGradient3475"
257 gradientUnits="userSpaceOnUse"
258 gradientTransform="matrix(1.33333,0,0,1.33333,-112.63459,-273.06703)"
259 x1="91"
260 y1="204"
261 x2="91"
262 y2="216" /><linearGradient
263 inkscape:collect="always"
264 xlink:href="#linearGradient4392"
265 id="linearGradient3477"
266 gradientUnits="userSpaceOnUse"
267 gradientTransform="matrix(1.33333,0,0,1.33333,-112.63459,-273.06703)"
268 x1="91"
269 y1="204"
270 x2="91"
271 y2="216" /><linearGradient
272 inkscape:collect="always"
273 xlink:href="#linearGradient4392"
274 id="linearGradient3479"
275 gradientUnits="userSpaceOnUse"
276 gradientTransform="matrix(1.1458395,0,0,1.1458395,-25.974994,183.42764)"
277 x1="30"
278 y1="120.07368"
279 x2="30"
280 y2="132.07368" /><linearGradient
281 inkscape:collect="always"
282 xlink:href="#linearGradient4392"
283 id="linearGradient3481"
284 gradientUnits="userSpaceOnUse"
285 gradientTransform="matrix(1.2584059,0,0,1.2584059,-27.9426,202.38775)"
286 x1="54"
287 y1="122.07368"
288 x2="54"
289 y2="130.07368" /><linearGradient
290 inkscape:collect="always"
291 xlink:href="#linearGradient4392"
292 id="linearGradient3483"
293 gradientUnits="userSpaceOnUse"
294 gradientTransform="matrix(1.1739937,0,0,1.1739937,-40.36396,212.02902)"
295 x1="150"
296 y1="120.07368"
297 x2="150"
298 y2="132.07368" /><linearGradient
299 inkscape:collect="always"
300 xlink:href="#linearGradient4392"
301 id="linearGradient3485"
302 gradientUnits="userSpaceOnUse"
303 gradientTransform="matrix(1.33333,0,0,1.33333,-31.36848,96.23245)"
304 x1="150"
305 y1="97.073685"
306 x2="150"
307 y2="107.07368" /><linearGradient
308 inkscape:collect="always"
309 xlink:href="#linearGradient4392"
310 id="linearGradient3487"
311 gradientUnits="userSpaceOnUse"
312 gradientTransform="matrix(1.1666648,0,0,1.1666669,33.00037,112.92706)"
313 x1="198"
314 y1="96.073685"
315 x2="198"
316 y2="108.07368" /><linearGradient
317 inkscape:collect="always"
318 xlink:href="#linearGradient4392"
319 id="linearGradient3489"
320 gradientUnits="userSpaceOnUse"
321 gradientTransform="translate(96,-204)"
322 x1="136"
323 y1="204"
324 x2="136"
325 y2="220" /><linearGradient
326 inkscape:collect="always"
327 xlink:href="#linearGradient4392"
328 id="linearGradient3491"
329 gradientUnits="userSpaceOnUse"
330 gradientTransform="translate(-112,48)"
331 x1="184"
332 y1="50"
333 x2="184"
334 y2="62" /><linearGradient
335 inkscape:collect="always"
336 xlink:href="#linearGradient4392"
337 id="linearGradient3493"
338 gradientUnits="userSpaceOnUse"
339 gradientTransform="translate(80,48)"
340 x1="216"
341 y1="51.999996"
342 x2="216"
343 y2="59.999996" /><linearGradient
344 inkscape:collect="always"
345 xlink:href="#linearGradient4392"
346 id="linearGradient3495"
347 gradientUnits="userSpaceOnUse"
348 gradientTransform="translate(-272,79)"
349 x1="407"
350 y1="51"
351 x2="407"
352 y2="62" /><linearGradient
353 inkscape:collect="always"
354 xlink:href="#linearGradient4392"
355 id="linearGradient3497"
356 gradientUnits="userSpaceOnUse"
357 gradientTransform="translate(-240,78)"
358 x1="407"
359 y1="51"
360 x2="407"
361 y2="62" /><linearGradient
362 inkscape:collect="always"
363 xlink:href="#linearGradient4392"
364 id="linearGradient3499"
365 gradientUnits="userSpaceOnUse"
366 gradientTransform="translate(-80,48)"
367 x1="87"
368 y1="16.999994"
369 x2="87"
370 y2="30.999994" /><linearGradient
371 inkscape:collect="always"
372 xlink:href="#linearGradient4392"
373 id="linearGradient3501"
374 gradientUnits="userSpaceOnUse"
375 gradientTransform="matrix(-1.1111083,0,0,1.1111083,715.999,-192.84664)"
376 x1="378"
377 y1="205"
378 x2="378"
379 y2="214" /><linearGradient
380 inkscape:collect="always"
381 xlink:href="#linearGradient4392"
382 id="linearGradient3503"
383 gradientUnits="userSpaceOnUse"
384 gradientTransform="translate(16,80)"
385 x1="57"
386 y1="83"
387 x2="57"
388 y2="94" /><linearGradient
389 inkscape:collect="always"
390 xlink:href="#linearGradient4392"
391 id="linearGradient3505"
392 gradientUnits="userSpaceOnUse"
393 gradientTransform="translate(48,80)"
394 x1="87"
395 y1="82"
396 x2="87"
397 y2="95" /><linearGradient
398 inkscape:collect="always"
399 xlink:href="#linearGradient4392"
400 id="linearGradient3507"
401 gradientUnits="userSpaceOnUse"
402 gradientTransform="matrix(-1,0,0,1,320,80)"
403 x1="87"
404 y1="82"
405 x2="87"
406 y2="95" /><linearGradient
407 inkscape:collect="always"
408 xlink:href="#linearGradient4392"
409 id="linearGradient3509"
410 gradientUnits="userSpaceOnUse"
411 gradientTransform="translate(112,81)"
412 x1="344"
413 y1="82"
414 x2="344"
415 y2="93" /><linearGradient
416 inkscape:collect="always"
417 xlink:href="#linearGradient4392"
418 id="linearGradient3511"
419 gradientUnits="userSpaceOnUse"
420 gradientTransform="translate(112,81)"
421 x1="375"
422 y1="82"
423 x2="375"
424 y2="93" /><linearGradient
425 inkscape:collect="always"
426 xlink:href="#linearGradient4392"
427 id="linearGradient3513"
428 gradientUnits="userSpaceOnUse"
429 gradientTransform="matrix(1.2587978,0,0,1.2587978,-391.22595,101.14297)"
430 x1="340"
431 y1="75.073685"
432 x2="340"
433 y2="84.073685" /><linearGradient
434 inkscape:collect="always"
435 xlink:href="#linearGradient4392"
436 id="linearGradient3515"
437 gradientUnits="userSpaceOnUse"
438 gradientTransform="translate(48,80)"
439 x1="87"
440 y1="82"
441 x2="87"
442 y2="95" /><linearGradient
443 inkscape:collect="always"
444 xlink:href="#linearGradient4392"
445 id="linearGradient3517"
446 gradientUnits="userSpaceOnUse"
447 gradientTransform="translate(80.11142,79.99998)"
448 x1="87"
449 y1="82"
450 x2="87"
451 y2="95" /><linearGradient
452 inkscape:collect="always"
453 xlink:href="#linearGradient4392"
454 id="linearGradient3519"
455 gradientUnits="userSpaceOnUse"
456 gradientTransform="matrix(-1,0,0,1,288,79.99999)"
457 x1="87"
458 y1="82"
459 x2="87"
460 y2="95" /><linearGradient
461 inkscape:collect="always"
462 xlink:href="#linearGradient4392"
463 id="linearGradient3521"
464 gradientUnits="userSpaceOnUse"
465 gradientTransform="translate(-16,112)"
466 x1="24"
467 y1="114"
468 x2="24"
469 y2="126" /><linearGradient
470 inkscape:collect="always"
471 xlink:href="#linearGradient4392"
472 id="linearGradient3523"
473 gradientUnits="userSpaceOnUse"
474 gradientTransform="translate(-16,112)"
475 x1="216"
476 y1="115"
477 x2="216"
478 y2="126" /><linearGradient
479 inkscape:collect="always"
480 xlink:href="#linearGradient4392"
481 id="linearGradient3525"
482 gradientUnits="userSpaceOnUse"
483 gradientTransform="translate(206,47.99999)"
484 x1="120"
485 y1="50"
486 x2="120"
487 y2="62" /><linearGradient
488 inkscape:collect="always"
489 xlink:href="#linearGradient4392"
490 id="linearGradient3527"
491 gradientUnits="userSpaceOnUse"
492 gradientTransform="translate(15,47.99999)"
493 x1="120"
494 y1="50"
495 x2="120"
496 y2="62" /><linearGradient
497 inkscape:collect="always"
498 xlink:href="#linearGradient4392"
499 id="linearGradient3529"
500 gradientUnits="userSpaceOnUse"
501 gradientTransform="translate(80.18519,49.11111)"
502 x1="120"
503 y1="50"
504 x2="120"
505 y2="62" /><linearGradient
506 inkscape:collect="always"
507 xlink:href="#linearGradient4392"
508 id="linearGradient3531"
509 gradientUnits="userSpaceOnUse"
510 gradientTransform="matrix(2,0,0,2,32,386.0001)"
511 x1="88"
512 y1="161"
513 x2="88"
514 y2="174" /><linearGradient
515 inkscape:collect="always"
516 xlink:href="#linearGradient4392"
517 id="linearGradient3533"
518 gradientUnits="userSpaceOnUse"
519 gradientTransform="matrix(0.95906074,0,0,0.83983765,-246.54178,86.44281)"
520 x1="263.14438"
521 y1="53.202732"
522 x2="263.14438"
523 y2="65.97139" /><linearGradient
524 inkscape:collect="always"
525 xlink:href="#linearGradient4392"
526 id="linearGradient3535"
527 gradientUnits="userSpaceOnUse"
528 x1="324.89481"
529 y1="49.999996"
530 x2="327.98953"
531 y2="61.999996" /><linearGradient
532 inkscape:collect="always"
533 xlink:href="#linearGradient4392"
534 id="linearGradient3537"
535 gradientUnits="userSpaceOnUse"
536 x1="324.89481"
537 y1="49.999996"
538 x2="327.98953"
539 y2="61.999996" /><linearGradient
540 inkscape:collect="always"
541 xlink:href="#linearGradient4392"
542 id="linearGradient3543"
543 gradientUnits="userSpaceOnUse"
544 gradientTransform="matrix(-1.1111083,0,0,1.1111083,683.999,-192.84664)"
545 x1="378"
546 y1="205"
547 x2="378"
548 y2="214" /><linearGradient
549 inkscape:collect="always"
550 xlink:href="#linearGradient4392"
551 id="linearGradient3545"
552 gradientUnits="userSpaceOnUse"
553 gradientTransform="matrix(1.1111083,0,0,1.1111083,-91.99896,-192.84664)"
554 x1="378"
555 y1="205"
556 x2="378"
557 y2="214" /><linearGradient
558 inkscape:collect="always"
559 xlink:href="#linearGradient4392"
560 id="linearGradient3547"
561 gradientUnits="userSpaceOnUse"
562 gradientTransform="matrix(-1,0,0,1,351.81481,49.11111)"
563 x1="120"
564 y1="50"
565 x2="120"
566 y2="62" /><linearGradient
567 inkscape:collect="always"
568 xlink:href="#linearGradient4392"
569 id="linearGradient3549"
570 gradientUnits="userSpaceOnUse"
571 gradientTransform="matrix(-1.33333,0,0,1.33333,592.467,94.82271)"
572 x1="365"
573 y1="73.073685"
574 x2="365"
575 y2="84.073685" /><linearGradient
576 inkscape:collect="always"
577 xlink:href="#linearGradient4392"
578 id="linearGradient3551"
579 gradientUnits="userSpaceOnUse"
580 gradientTransform="matrix(-1,0,0,1,480,176)"
581 x1="407.125"
582 y1="113.37494"
583 x2="407.125"
584 y2="126.38035" /><linearGradient
585 inkscape:collect="always"
586 xlink:href="#linearGradient4392"
587 id="linearGradient3553"
588 gradientUnits="userSpaceOnUse"
589 gradientTransform="translate(-208,-112.00001)"
590 x1="280"
591 y1="112"
592 x2="280"
593 y2="128" /><linearGradient
594 inkscape:collect="always"
595 xlink:href="#linearGradient4392"
596 id="linearGradient3555"
597 gradientUnits="userSpaceOnUse"
598 gradientTransform="translate(56,80)"
599 x1="57"
600 y1="83"
601 x2="57"
602 y2="94" /><linearGradient
603 inkscape:collect="always"
604 xlink:href="#linearGradient4392"
605 id="linearGradient3557"
606 gradientUnits="userSpaceOnUse"
607 gradientTransform="matrix(-1,0,0,1,448,112)"
608 x1="216"
609 y1="115"
610 x2="216"
611 y2="126" /><linearGradient
612 inkscape:collect="always"
613 xlink:href="#linearGradient4392"
614 id="linearGradient3559"
615 gradientUnits="userSpaceOnUse"
616 gradientTransform="matrix(1.1666672,0,0,1.1723864,-107.00007,208.34331)"
617 x1="126"
618 y1="96.073685"
619 x2="126"
620 y2="108.07368" /><linearGradient
621 inkscape:collect="always"
622 xlink:href="#linearGradient4392"
623 id="linearGradient3561"
624 gradientUnits="userSpaceOnUse"
625 x1="104"
626 y1="230.99998"
627 x2="104"
628 y2="232.99998" /><linearGradient
629 inkscape:collect="always"
630 xlink:href="#linearGradient4392"
631 id="linearGradient3563"
632 gradientUnits="userSpaceOnUse"
633 gradientTransform="translate(47,47.99999)"
634 x1="120"
635 y1="50"
636 x2="120"
637 y2="62" /><linearGradient
638 inkscape:collect="always"
639 xlink:href="#linearGradient4392"
640 id="linearGradient3565"
641 gradientUnits="userSpaceOnUse"
642 gradientTransform="translate(16,-3)"
643 x1="56"
644 y1="228.23837"
645 x2="56"
646 y2="242.00908" /><linearGradient
647 inkscape:collect="always"
648 xlink:href="#linearGradient4392"
649 id="linearGradient3567"
650 gradientUnits="userSpaceOnUse"
651 gradientTransform="matrix(1.33333,0,0,1.33333,143.36541,-272.06703)"
652 x1="91"
653 y1="204"
654 x2="91"
655 y2="216" /><linearGradient
656 inkscape:collect="always"
657 xlink:href="#linearGradient4392"
658 id="linearGradient3569"
659 gradientUnits="userSpaceOnUse"
660 gradientTransform="matrix(1.33333,0,0,1.33333,-112.63459,-272.06703)"
661 x1="91"
662 y1="204"
663 x2="91"
664 y2="216" /><linearGradient
665 inkscape:collect="always"
666 xlink:href="#linearGradient4392"
667 id="linearGradient3571"
668 gradientUnits="userSpaceOnUse"
669 gradientTransform="matrix(1.33333,0,0,1.33333,-80.63459,-273.06703)"
670 x1="91"
671 y1="204"
672 x2="91"
673 y2="216" /><linearGradient
674 inkscape:collect="always"
675 xlink:href="#linearGradient4392"
676 id="linearGradient3573"
677 gradientUnits="userSpaceOnUse"
678 gradientTransform="matrix(1.33333,0,0,1.33333,-80.63459,-273.06703)"
679 x1="91"
680 y1="204"
681 x2="91"
682 y2="216" /><linearGradient
683 inkscape:collect="always"
684 xlink:href="#linearGradient4392"
685 id="linearGradient3575"
686 gradientUnits="userSpaceOnUse"
687 gradientTransform="matrix(1.33333,0,0,1.33333,-79.63459,-272.06703)"
688 x1="91"
689 y1="204"
690 x2="91"
691 y2="216" /><linearGradient
692 inkscape:collect="always"
693 xlink:href="#linearGradient4392"
694 id="linearGradient3577"
695 gradientUnits="userSpaceOnUse"
696 gradientTransform="matrix(1.33333,0,0,1.33333,-16.63459,-272.06703)"
697 x1="91"
698 y1="204"
699 x2="91"
700 y2="216" /><linearGradient
701 inkscape:collect="always"
702 xlink:href="#linearGradient4392"
703 id="linearGradient3579"
704 gradientUnits="userSpaceOnUse"
705 gradientTransform="matrix(1.33333,0,0,1.33333,16.36541,-272.06703)"
706 x1="91"
707 y1="204"
708 x2="91"
709 y2="216" /><linearGradient
710 inkscape:collect="always"
711 xlink:href="#linearGradient4392"
712 id="linearGradient3581"
713 gradientUnits="userSpaceOnUse"
714 gradientTransform="matrix(1.33333,0,0,1.33333,175.36541,-272.06703)"
715 x1="91"
716 y1="204"
717 x2="91"
718 y2="216" /><linearGradient
719 inkscape:collect="always"
720 xlink:href="#linearGradient4392"
721 id="linearGradient3583"
722 gradientUnits="userSpaceOnUse"
723 gradientTransform="matrix(1.33333,0,0,1.33333,-81.63459,-245.06703)"
724 x1="91"
725 y1="208.11006"
726 x2="91"
727 y2="219.18719" /><linearGradient
728 inkscape:collect="always"
729 xlink:href="#linearGradient4392"
730 id="linearGradient3585"
731 gradientUnits="userSpaceOnUse"
732 gradientTransform="matrix(1.33333,0,0,1.33333,67.36541,-272.06703)"
733 x1="91"
734 y1="204"
735 x2="91"
736 y2="216" /><linearGradient
737 inkscape:collect="always"
738 xlink:href="#linearGradient4392"
739 id="linearGradient3587"
740 gradientUnits="userSpaceOnUse"
741 gradientTransform="matrix(1.33333,0,0,1.33333,208.36541,-272.06703)"
742 x1="91"
743 y1="204"
744 x2="91"
745 y2="216" /><linearGradient
746 inkscape:collect="always"
747 xlink:href="#linearGradient4392"
748 id="linearGradient3589"
749 gradientUnits="userSpaceOnUse"
750 gradientTransform="matrix(1.2681238,0,0,1.2681238,-425.35773,134.96337)"
751 x1="342"
752 y1="97.073685"
753 x2="342"
754 y2="108.07368" /><linearGradient
755 inkscape:collect="always"
756 xlink:href="#linearGradient4392"
757 id="linearGradient3591"
758 gradientUnits="userSpaceOnUse"
759 gradientTransform="translate(32,0)"
760 x1="72"
761 y1="32"
762 x2="72"
763 y2="47" /><linearGradient
764 inkscape:collect="always"
765 xlink:href="#linearGradient4392"
766 id="linearGradient3593"
767 gradientUnits="userSpaceOnUse"
768 gradientTransform="matrix(-1,0,0,1,208,0)"
769 x1="72"
770 y1="32"
771 x2="72"
772 y2="47" /><linearGradient
773 inkscape:collect="always"
774 xlink:href="#linearGradient4392"
775 id="linearGradient3595"
776 gradientUnits="userSpaceOnUse"
777 gradientTransform="translate(0,-14.00001)"
778 x1="264"
779 y1="114"
780 x2="264"
781 y2="121" /><linearGradient
782 inkscape:collect="always"
783 xlink:href="#linearGradient4392-45"
784 id="linearGradient3597"
785 gradientUnits="userSpaceOnUse"
786 gradientTransform="matrix(1.33333,0,0,1.33333,-479.467,254.82271)"
787 x1="365"
788 y1="73.073685"
789 x2="365"
790 y2="84.073685" /><linearGradient
791 inkscape:collect="always"
792 xlink:href="#linearGradient4392"
793 id="linearGradient3601"
794 gradientUnits="userSpaceOnUse"
795 gradientTransform="matrix(1.33333,0,0,1.33333,-479.467,254.82271)"
796 x1="365"
797 y1="73.073685"
798 x2="365"
799 y2="84.073685" /><linearGradient
800 inkscape:collect="always"
801 xlink:href="#linearGradient4392"
802 id="linearGradient3605"
803 gradientUnits="userSpaceOnUse"
804 x1="73"
805 y1="321"
806 x2="73"
807 y2="335" /><linearGradient
808 inkscape:collect="always"
809 xlink:href="#linearGradient4392"
810 id="linearGradient3607"
811 gradientUnits="userSpaceOnUse"
812 x1="69"
813 y1="323"
814 x2="69"
815 y2="333" /><linearGradient
816 inkscape:collect="always"
817 xlink:href="#linearGradient4392"
818 id="linearGradient3609"
819 gradientUnits="userSpaceOnUse"
820 x1="69"
821 y1="323"
822 x2="69"
823 y2="333" /><linearGradient
824 inkscape:collect="always"
825 xlink:href="#linearGradient4392"
826 id="linearGradient3667"
827 x1="167.75"
828 y1="32.497749"
829 x2="167.75"
830 y2="46.375"
831 gradientUnits="userSpaceOnUse" /><linearGradient
832 inkscape:collect="always"
833 xlink:href="#linearGradient4392"
834 id="linearGradient3671"
835 x1="40.166676"
836 y1="163.16667"
837 x2="40.166676"
838 y2="174.48146"
839 gradientUnits="userSpaceOnUse" /><linearGradient
840 inkscape:collect="always"
841 xlink:href="#linearGradient4392"
842 id="linearGradient3673"
843 x1="7.7296576"
844 y1="162.72966"
845 x2="7.7296576"
846 y2="174.83665"
847 gradientUnits="userSpaceOnUse" /><linearGradient
848 inkscape:collect="always"
849 xlink:href="#linearGradient4392"
850 id="linearGradient3675"
851 x1="7.7175145"
852 y1="196.31802"
853 x2="7.7175145"
854 y2="202.94867"
855 gradientUnits="userSpaceOnUse" /><linearGradient
856 inkscape:collect="always"
857 xlink:href="#linearGradient4392"
858 id="linearGradient3677"
859 x1="40.159454"
860 y1="195.87607"
861 x2="40.159454"
862 y2="203.08347"
863 gradientUnits="userSpaceOnUse" /><linearGradient
864 inkscape:collect="always"
865 xlink:href="#linearGradient4392"
866 id="linearGradient3679"
867 x1="328.75046"
868 y1="96.928932"
869 x2="328.75046"
870 y2="111.26538"
871 gradientUnits="userSpaceOnUse" /><linearGradient
872 inkscape:collect="always"
873 xlink:href="#linearGradient4392"
874 id="linearGradient3713"
875 x1="86.009781"
876 y1="129.98354"
877 x2="86.009781"
878 y2="142.15057"
879 gradientUnits="userSpaceOnUse" /><linearGradient
880 inkscape:collect="always"
881 xlink:href="#linearGradient4392"
882 id="linearGradient4491"
883 x1="266.98074"
884 y1="53.301754"
885 x2="266.98074"
886 y2="63.243984"
887 gradientUnits="userSpaceOnUse" /><linearGradient
888 inkscape:collect="always"
889 xlink:href="#linearGradient4392"
890 id="linearGradient4534"
891 x1="45"
892 y1="71.999939"
893 x2="45"
894 y2="79.999939"
895 gradientUnits="userSpaceOnUse"
896 gradientTransform="translate(0.21875,0)" /><linearGradient
897 inkscape:collect="always"
898 xlink:href="#linearGradient4392"
899 id="linearGradient4540"
900 gradientUnits="userSpaceOnUse"
901 gradientTransform="translate(10.21875,0)"
902 x1="45"
903 y1="71.999939"
904 x2="45"
905 y2="79.999939" /><linearGradient
906 id="linearGradient4392-7"><stop
907 style="stop-color:#666666;stop-opacity:1;"
908 offset="0"
909 id="stop4394-7" /><stop
910 style="stop-color:#424242;stop-opacity:1;"
911 offset="1"
912 id="stop4396-6" /></linearGradient><linearGradient
913 inkscape:collect="always"
914 xlink:href="#linearGradient4392-7"
915 id="linearGradient4540-8"
916 gradientUnits="userSpaceOnUse"
917 gradientTransform="translate(-4.1709228,8.0000007)"
918 x1="45"
919 y1="71.999939"
920 x2="45"
921 y2="79.999939" /><linearGradient
922 id="linearGradient4392-45"><stop
923 style="stop-color:#666666;stop-opacity:1;"
924 offset="0"
925 id="stop4394-8" /><stop
926 style="stop-color:#424242;stop-opacity:1;"
927 offset="1"
928 id="stop4396-68" /></linearGradient><filter
929 id="filter3224-1-7-1"
930 inkscape:label="Inner Shadow"
931 inkscape:menu="Shadows and Glows"
932 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
933 color-interpolation-filters="sRGB"
934 width="1"
935 height="1"
936 y="0"
937 x="0"><feOffset
938 id="feOffset3228-5-5-5"
939 dx="0"
940 dy="1"
941 result="result11" /><feComposite
942 id="feComposite3230-2-4-1"
943 in2="result11"
944 result="result6"
945 in="SourceGraphic"
946 operator="in" /><feFlood
947 id="feFlood3232-7-3-4"
948 result="result10"
949 in="result6"
950 flood-opacity="1"
951 flood-color="rgb(34,34,34)" /><feBlend
952 id="feBlend3234-6-3-5"
953 in2="result10"
954 mode="normal"
955 in="result6"
956 result="result12" /><feComposite
957 id="feComposite3236-1-3-5"
958 in2="SourceGraphic"
959 result="result2"
960 operator="in" /></filter><linearGradient
961 inkscape:collect="always"
962 xlink:href="#linearGradient4392-9"
963 id="linearGradient3435-5"
964 gradientUnits="userSpaceOnUse"
965 gradientTransform="matrix(2,0,0,2,93.76588,34.31226)"
966 x1="55"
967 y1="49.409008"
968 x2="55"
969 y2="63" /><linearGradient
970 id="linearGradient4392-9"><stop
971 style="stop-color:#666666;stop-opacity:1;"
972 offset="0"
973 id="stop4394-2" /><stop
974 style="stop-color:#424242;stop-opacity:1;"
975 offset="1"
976 id="stop4396-9" /></linearGradient><filter
977 id="filter3224-1-7-1-3-0"
978 inkscape:label="Inner Shadow"
979 inkscape:menu="Shadows and Glows"
980 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
981 color-interpolation-filters="sRGB"
982 width="1"
983 height="1"
984 y="0"
985 x="0"><feOffset
986 id="feOffset3228-5-5-5-70-4"
987 dx="0"
988 dy="0.69999999999999996"
989 result="result11" /><feComposite
990 id="feComposite3230-2-4-1-9-5"
991 in2="result11"
992 result="result6"
993 in="SourceGraphic"
994 operator="in" /><feFlood
995 id="feFlood3232-7-3-4-91-7"
996 result="result10"
997 in="result6"
998 flood-opacity="1"
999 flood-color="rgb(34,34,34)" /><feBlend
1000 id="feBlend3234-6-3-5-53-5"
1001 in2="result10"
1002 mode="normal"
1003 in="result6"
1004 result="result12" /><feComposite
1005 id="feComposite3236-1-3-5-3-2"
1006 in2="SourceGraphic"
1007 result="result2"
1008 operator="in" /></filter><linearGradient
1009 inkscape:collect="always"
1010 xlink:href="#linearGradient4392-0"
1011 id="linearGradient4300-5"
1012 gradientUnits="userSpaceOnUse"
1013 gradientTransform="matrix(2,0,0,2,294,181.85274)"
1014 x1="148"
1015 y1="73.073685"
1016 x2="148"
1017 y2="84.073685" /><linearGradient
1018 id="linearGradient4392-0"><stop
1019 style="stop-color:#666666;stop-opacity:1;"
1020 offset="0"
1021 id="stop4394-6" /><stop
1022 style="stop-color:#424242;stop-opacity:1;"
1023 offset="1"
1024 id="stop4396-2" /></linearGradient><filter
1025 id="filter3224-1-7-1-3-2"
1026 inkscape:label="Inner Shadow"
1027 inkscape:menu="Shadows and Glows"
1028 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1029 color-interpolation-filters="sRGB"
1030 width="1"
1031 height="1"
1032 y="0"
1033 x="0"><feOffset
1034 id="feOffset3228-5-5-5-70-5"
1035 dx="0"
1036 dy="0.69999999999999996"
1037 result="result11" /><feComposite
1038 id="feComposite3230-2-4-1-9-6"
1039 in2="result11"
1040 result="result6"
1041 in="SourceGraphic"
1042 operator="in" /><feFlood
1043 id="feFlood3232-7-3-4-91-0"
1044 result="result10"
1045 in="result6"
1046 flood-opacity="1"
1047 flood-color="rgb(34,34,34)" /><feBlend
1048 id="feBlend3234-6-3-5-53-56"
1049 in2="result10"
1050 mode="normal"
1051 in="result6"
1052 result="result12" /><feComposite
1053 id="feComposite3236-1-3-5-3-24"
1054 in2="SourceGraphic"
1055 result="result2"
1056 operator="in" /></filter><linearGradient
1057 inkscape:collect="always"
1058 xlink:href="#linearGradient4392"
1059 id="linearGradient5619"
1060 gradientUnits="userSpaceOnUse"
1061 x1="266.98074"
1062 y1="53.301754"
1063 x2="266.98074"
1064 y2="63.243984" /><linearGradient
1065 inkscape:collect="always"
1066 xlink:href="#linearGradient4392"
1067 id="linearGradient5621"
1068 gradientUnits="userSpaceOnUse"
1069 x1="86.009781"
1070 y1="129.98354"
1071 x2="86.009781"
1072 y2="142.15057" />
1073<linearGradient
1074 inkscape:collect="always"
1075 xlink:href="#linearGradient4352"
1076 id="linearGradient5632"
1077 gradientUnits="userSpaceOnUse"
1078 gradientTransform="matrix(1.8181818,0,0,2,-638.27272,-321.74989)"
1079 x1="366.95544"
1080 y1="335.06354"
1081 x2="356.00427"
1082 y2="335.08957" /><linearGradient
1083 inkscape:collect="always"
1084 xlink:href="#linearGradient4352"
1085 id="linearGradient5639"
1086 gradientUnits="userSpaceOnUse"
1087 gradientTransform="matrix(1.8181818,0,0,2,-638.27272,-321.74989)"
1088 x1="366.95544"
1089 y1="335.06354"
1090 x2="356.00427"
1091 y2="335.08957" /><linearGradient
1092 inkscape:collect="always"
1093 xlink:href="#linearGradient4392"
1094 id="linearGradient5672"
1095 gradientUnits="userSpaceOnUse"
1096 x1="17.949585"
1097 y1="577.80402"
1098 x2="17.949585"
1099 y2="604.75"
1100 gradientTransform="translate(1,-367.75001)" /><linearGradient
1101 inkscape:collect="always"
1102 xlink:href="#linearGradient4392"
1103 id="linearGradient5746"
1104 gradientUnits="userSpaceOnUse"
1105 gradientTransform="matrix(2,0,0,2,-735,-15.74989)"
1106 x1="408.47479"
1107 y1="113.77696"
1108 x2="408.47479"
1109 y2="126.90414" /><linearGradient
1110 inkscape:collect="always"
1111 xlink:href="#linearGradient4392"
1112 id="linearGradient5750"
1113 gradientUnits="userSpaceOnUse"
1114 gradientTransform="matrix(2,0,0,2,295,-185.89727)"
1115 x1="148"
1116 y1="73.073685"
1117 x2="148"
1118 y2="84.073685" /><linearGradient
1119 inkscape:collect="always"
1120 xlink:href="#linearGradient4392"
1121 id="linearGradient5760"
1122 gradientUnits="userSpaceOnUse"
1123 gradientTransform="matrix(2,0,0,2,94.76588,-333.43775)"
1124 x1="55"
1125 y1="49.409008"
1126 x2="55"
1127 y2="63" /><linearGradient
1128 inkscape:collect="always"
1129 xlink:href="#linearGradient4392-45"
1130 id="linearGradient5768"
1131 gradientUnits="userSpaceOnUse"
1132 gradientTransform="matrix(2.66666,0,0,2.66666,-957.934,141.89553)"
1133 x1="365"
1134 y1="73.073685"
1135 x2="365"
1136 y2="84.073685" /><linearGradient
1137 inkscape:collect="always"
1138 xlink:href="#linearGradient4392-3"
1139 id="linearGradient5624-9"
1140 gradientUnits="userSpaceOnUse"
1141 gradientTransform="matrix(-2,0,0,-2,1022,-175.74999)"
1142 x1="472"
1143 y1="17"
1144 x2="472"
1145 y2="31" /><linearGradient
1146 id="linearGradient4392-3"><stop
1147 style="stop-color:#666666;stop-opacity:1;"
1148 offset="0"
1149 id="stop4394-4" /><stop
1150 style="stop-color:#424242;stop-opacity:1;"
1151 offset="1"
1152 id="stop4396-1" /></linearGradient><filter
1153 id="filter3224-1-7-1-34"
1154 inkscape:label="Inner Shadow"
1155 inkscape:menu="Shadows and Glows"
1156 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1157 color-interpolation-filters="sRGB"
1158 width="1"
1159 height="1"
1160 y="0"
1161 x="0"><feOffset
1162 id="feOffset3228-5-5-5-3"
1163 dx="0"
1164 dy="1"
1165 result="result11" /><feComposite
1166 id="feComposite3230-2-4-1-1"
1167 in2="result11"
1168 result="result6"
1169 in="SourceGraphic"
1170 operator="in" /><feFlood
1171 id="feFlood3232-7-3-4-3"
1172 result="result10"
1173 in="result6"
1174 flood-opacity="1"
1175 flood-color="rgb(34,34,34)" /><feBlend
1176 id="feBlend3234-6-3-5-9"
1177 in2="result10"
1178 mode="normal"
1179 in="result6"
1180 result="result12" /><feComposite
1181 id="feComposite3236-1-3-5-1"
1182 in2="SourceGraphic"
1183 result="result2"
1184 operator="in" /></filter><linearGradient
1185 inkscape:collect="always"
1186 xlink:href="#linearGradient4392"
1187 id="linearGradient5855"
1188 gradientUnits="userSpaceOnUse"
1189 gradientTransform="matrix(-2,0,0,-2,1021,192.00002)"
1190 x1="472"
1191 y1="17"
1192 x2="472"
1193 y2="31" /><linearGradient
1194 inkscape:collect="always"
1195 xlink:href="#linearGradient4392"
1196 id="linearGradient5906"
1197 x1="593.375"
1198 y1="-45.500015"
1199 x2="593.375"
1200 y2="-31.493313"
1201 gradientUnits="userSpaceOnUse" /><linearGradient
1202 inkscape:collect="always"
1203 xlink:href="#linearGradient4392-2"
1204 id="linearGradient5906-9"
1205 x1="593.375"
1206 y1="-45.500015"
1207 x2="593.375"
1208 y2="-31.493313"
1209 gradientUnits="userSpaceOnUse" /><linearGradient
1210 id="linearGradient4392-2"><stop
1211 style="stop-color:#666666;stop-opacity:1;"
1212 offset="0"
1213 id="stop4394-1" /><stop
1214 style="stop-color:#424242;stop-opacity:1;"
1215 offset="1"
1216 id="stop4396-7" /></linearGradient><linearGradient
1217 inkscape:collect="always"
1218 xlink:href="#linearGradient4392-2"
1219 id="linearGradient5922"
1220 x1="593.375"
1221 y1="-45.500015"
1222 x2="593.375"
1223 y2="-31.493313"
1224 gradientUnits="userSpaceOnUse" /><linearGradient
1225 id="linearGradient5924"><stop
1226 style="stop-color:#666666;stop-opacity:1;"
1227 offset="0"
1228 id="stop5926" /><stop
1229 style="stop-color:#424242;stop-opacity:1;"
1230 offset="1"
1231 id="stop5928" /></linearGradient><filter
1232 id="filter3224-1-7-1-3-24"
1233 inkscape:label="Inner Shadow"
1234 inkscape:menu="Shadows and Glows"
1235 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1236 color-interpolation-filters="sRGB"
1237 width="1"
1238 height="1"
1239 y="0"
1240 x="0"><feOffset
1241 id="feOffset3228-5-5-5-70-8"
1242 dx="0"
1243 dy="0.69999999999999996"
1244 result="result11" /><feComposite
1245 id="feComposite3230-2-4-1-9-0"
1246 in2="result11"
1247 result="result6"
1248 in="SourceGraphic"
1249 operator="in" /><feFlood
1250 id="feFlood3232-7-3-4-91-5"
1251 result="result10"
1252 in="result6"
1253 flood-opacity="1"
1254 flood-color="rgb(34,34,34)" /><feBlend
1255 id="feBlend3234-6-3-5-53-2"
1256 in2="result10"
1257 mode="normal"
1258 in="result6"
1259 result="result12" /><feComposite
1260 id="feComposite3236-1-3-5-3-1"
1261 in2="SourceGraphic"
1262 result="result2"
1263 operator="in" /></filter><linearGradient
1264 inkscape:collect="always"
1265 xlink:href="#linearGradient4392-2"
1266 id="linearGradient5936"
1267 x1="593.375"
1268 y1="-45.500015"
1269 x2="593.375"
1270 y2="-31.493313"
1271 gradientUnits="userSpaceOnUse" /><linearGradient
1272 id="linearGradient5938"><stop
1273 style="stop-color:#666666;stop-opacity:1;"
1274 offset="0"
1275 id="stop5940" /><stop
1276 style="stop-color:#424242;stop-opacity:1;"
1277 offset="1"
1278 id="stop5942" /></linearGradient><filter
1279 id="filter5944"
1280 inkscape:label="Inner Shadow"
1281 inkscape:menu="Shadows and Glows"
1282 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1283 color-interpolation-filters="sRGB"
1284 width="1"
1285 height="1"
1286 y="0"
1287 x="0"><feOffset
1288 id="feOffset5946"
1289 dx="0"
1290 dy="0.69999999999999996"
1291 result="result11" /><feComposite
1292 id="feComposite5948"
1293 in2="result11"
1294 result="result6"
1295 in="SourceGraphic"
1296 operator="in" /><feFlood
1297 id="feFlood5950"
1298 result="result10"
1299 in="result6"
1300 flood-opacity="1"
1301 flood-color="rgb(34,34,34)" /><feBlend
1302 id="feBlend5952"
1303 in2="result10"
1304 mode="normal"
1305 in="result6"
1306 result="result12" /><feComposite
1307 id="feComposite5954"
1308 in2="SourceGraphic"
1309 result="result2"
1310 operator="in" /></filter><linearGradient
1311 inkscape:collect="always"
1312 xlink:href="#linearGradient4392-2"
1313 id="linearGradient5956"
1314 x1="593.375"
1315 y1="-45.500015"
1316 x2="593.375"
1317 y2="-31.493313"
1318 gradientUnits="userSpaceOnUse" /><linearGradient
1319 id="linearGradient5958"><stop
1320 style="stop-color:#666666;stop-opacity:1;"
1321 offset="0"
1322 id="stop5960" /><stop
1323 style="stop-color:#424242;stop-opacity:1;"
1324 offset="1"
1325 id="stop5962" /></linearGradient><filter
1326 id="filter5964"
1327 inkscape:label="Inner Shadow"
1328 inkscape:menu="Shadows and Glows"
1329 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1330 color-interpolation-filters="sRGB"
1331 width="1"
1332 height="1"
1333 y="0"
1334 x="0"><feOffset
1335 id="feOffset5966"
1336 dx="0"
1337 dy="0.69999999999999996"
1338 result="result11" /><feComposite
1339 id="feComposite5968"
1340 in2="result11"
1341 result="result6"
1342 in="SourceGraphic"
1343 operator="in" /><feFlood
1344 id="feFlood5970"
1345 result="result10"
1346 in="result6"
1347 flood-opacity="1"
1348 flood-color="rgb(34,34,34)" /><feBlend
1349 id="feBlend5972"
1350 in2="result10"
1351 mode="normal"
1352 in="result6"
1353 result="result12" /><feComposite
1354 id="feComposite5974"
1355 in2="SourceGraphic"
1356 result="result2"
1357 operator="in" /></filter><linearGradient
1358 inkscape:collect="always"
1359 xlink:href="#linearGradient4392-6"
1360 id="linearGradient3667-5"
1361 x1="167.75"
1362 y1="32.497749"
1363 x2="167.75"
1364 y2="46.375"
1365 gradientUnits="userSpaceOnUse" /><linearGradient
1366 id="linearGradient4392-6"><stop
1367 style="stop-color:#666666;stop-opacity:1;"
1368 offset="0"
1369 id="stop4394-64" /><stop
1370 style="stop-color:#424242;stop-opacity:1;"
1371 offset="1"
1372 id="stop4396-14" /></linearGradient><filter
1373 id="filter3224-1-7-1-3-1"
1374 inkscape:label="Inner Shadow"
1375 inkscape:menu="Shadows and Glows"
1376 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1377 color-interpolation-filters="sRGB"
1378 width="1"
1379 height="1"
1380 y="0"
1381 x="0"><feOffset
1382 id="feOffset3228-5-5-5-70-83"
1383 dx="0"
1384 dy="0.69999999999999996"
1385 result="result11" /><feComposite
1386 id="feComposite3230-2-4-1-9-4"
1387 in2="result11"
1388 result="result6"
1389 in="SourceGraphic"
1390 operator="in" /><feFlood
1391 id="feFlood3232-7-3-4-91-3"
1392 result="result10"
1393 in="result6"
1394 flood-opacity="1"
1395 flood-color="rgb(34,34,34)" /><feBlend
1396 id="feBlend3234-6-3-5-53-3"
1397 in2="result10"
1398 mode="normal"
1399 in="result6"
1400 result="result12" /><feComposite
1401 id="feComposite3236-1-3-5-3-7"
1402 in2="SourceGraphic"
1403 result="result2"
1404 operator="in" /></filter><linearGradient
1405 y2="46.375"
1406 x2="167.75"
1407 y1="32.497749"
1408 x1="167.75"
1409 gradientUnits="userSpaceOnUse"
1410 id="linearGradient6101"
1411 xlink:href="#linearGradient4392-6"
1412 inkscape:collect="always" /><linearGradient
1413 inkscape:collect="always"
1414 xlink:href="#linearGradient4392"
1415 id="linearGradient6155"
1416 gradientUnits="userSpaceOnUse"
1417 gradientTransform="matrix(2,0,0,2,93.76588,34.31226)"
1418 x1="55"
1419 y1="49.409008"
1420 x2="55"
1421 y2="63" /><linearGradient
1422 inkscape:collect="always"
1423 xlink:href="#linearGradient4392"
1424 id="linearGradient6173"
1425 gradientUnits="userSpaceOnUse"
1426 gradientTransform="matrix(2,0,0,2,-32,386.0001)"
1427 x1="88"
1428 y1="161"
1429 x2="88"
1430 y2="174" /><filter
1431 id="filter3224-1-7-1-5-0"
1432 inkscape:label="Inner Shadow"
1433 inkscape:menu="Shadows and Glows"
1434 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1435 color-interpolation-filters="sRGB"
1436 width="1"
1437 height="1"
1438 y="0"
1439 x="0"><feOffset
1440 id="feOffset3228-5-5-5-6-7"
1441 dx="0"
1442 dy="1.2"
1443 result="result11" /><feComposite
1444 id="feComposite3230-2-4-1-0-9"
1445 in2="result11"
1446 result="result6"
1447 in="SourceGraphic"
1448 operator="in" /><feFlood
1449 id="feFlood3232-7-3-4-6-7"
1450 result="result10"
1451 in="result6"
1452 flood-opacity="1"
1453 flood-color="rgb(34,34,34)" /><feBlend
1454 id="feBlend3234-6-3-5-6-4"
1455 in2="result10"
1456 mode="normal"
1457 in="result6"
1458 result="result12" /><feComposite
1459 id="feComposite3236-1-3-5-55-7"
1460 in2="SourceGraphic"
1461 result="result2"
1462 operator="in" /></filter><filter
1463 id="filter3224-1-7-1-5-0-2"
1464 inkscape:label="Inner Shadow"
1465 inkscape:menu="Shadows and Glows"
1466 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1467 color-interpolation-filters="sRGB"
1468 width="1"
1469 height="1"
1470 y="0"
1471 x="0"><feOffset
1472 id="feOffset3228-5-5-5-6-7-5"
1473 dx="0"
1474 dy="1.2"
1475 result="result11" /><feComposite
1476 id="feComposite3230-2-4-1-0-9-8"
1477 in2="result11"
1478 result="result6"
1479 in="SourceGraphic"
1480 operator="in" /><feFlood
1481 id="feFlood3232-7-3-4-6-7-0"
1482 result="result10"
1483 in="result6"
1484 flood-opacity="1"
1485 flood-color="rgb(34,34,34)" /><feBlend
1486 id="feBlend3234-6-3-5-6-4-3"
1487 in2="result10"
1488 mode="normal"
1489 in="result6"
1490 result="result12" /><feComposite
1491 id="feComposite3236-1-3-5-55-7-9"
1492 in2="SourceGraphic"
1493 result="result2"
1494 operator="in" /></filter><filter
1495 id="filter3224-1-7-1-5-0-8"
1496 inkscape:label="Inner Shadow"
1497 inkscape:menu="Shadows and Glows"
1498 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1499 color-interpolation-filters="sRGB"
1500 width="1"
1501 height="1"
1502 y="0"
1503 x="0"><feOffset
1504 id="feOffset3228-5-5-5-6-7-6"
1505 dx="0"
1506 dy="1.2"
1507 result="result11" /><feComposite
1508 id="feComposite3230-2-4-1-0-9-3"
1509 in2="result11"
1510 result="result6"
1511 in="SourceGraphic"
1512 operator="in" /><feFlood
1513 id="feFlood3232-7-3-4-6-7-1"
1514 result="result10"
1515 in="result6"
1516 flood-opacity="1"
1517 flood-color="rgb(34,34,34)" /><feBlend
1518 id="feBlend3234-6-3-5-6-4-1"
1519 in2="result10"
1520 mode="normal"
1521 in="result6"
1522 result="result12" /><feComposite
1523 id="feComposite3236-1-3-5-55-7-6"
1524 in2="SourceGraphic"
1525 result="result2"
1526 operator="in" /></filter><filter
1527 id="filter3224-1-7-1-5-0-8-5"
1528 inkscape:label="Inner Shadow"
1529 inkscape:menu="Shadows and Glows"
1530 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1531 color-interpolation-filters="sRGB"
1532 width="1"
1533 height="1"
1534 y="0"
1535 x="0"><feOffset
1536 id="feOffset3228-5-5-5-6-7-6-5"
1537 dx="0"
1538 dy="1.2"
1539 result="result11" /><feComposite
1540 id="feComposite3230-2-4-1-0-9-3-2"
1541 in2="result11"
1542 result="result6"
1543 in="SourceGraphic"
1544 operator="in" /><feFlood
1545 id="feFlood3232-7-3-4-6-7-1-1"
1546 result="result10"
1547 in="result6"
1548 flood-opacity="1"
1549 flood-color="rgb(34,34,34)" /><feBlend
1550 id="feBlend3234-6-3-5-6-4-1-6"
1551 in2="result10"
1552 mode="normal"
1553 in="result6"
1554 result="result12" /><feComposite
1555 id="feComposite3236-1-3-5-55-7-6-3"
1556 in2="SourceGraphic"
1557 result="result2"
1558 operator="in" /></filter><filter
1559 id="filter3224-1-7-1-5-0-8-7"
1560 inkscape:label="Inner Shadow"
1561 inkscape:menu="Shadows and Glows"
1562 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1563 color-interpolation-filters="sRGB"
1564 width="1"
1565 height="1"
1566 y="0"
1567 x="0"><feOffset
1568 id="feOffset3228-5-5-5-6-7-6-9"
1569 dx="0"
1570 dy="1.2"
1571 result="result11" /><feComposite
1572 id="feComposite3230-2-4-1-0-9-3-0"
1573 in2="result11"
1574 result="result6"
1575 in="SourceGraphic"
1576 operator="in" /><feFlood
1577 id="feFlood3232-7-3-4-6-7-1-3"
1578 result="result10"
1579 in="result6"
1580 flood-opacity="1"
1581 flood-color="rgb(34,34,34)" /><feBlend
1582 id="feBlend3234-6-3-5-6-4-1-1"
1583 in2="result10"
1584 mode="normal"
1585 in="result6"
1586 result="result12" /><feComposite
1587 id="feComposite3236-1-3-5-55-7-6-8"
1588 in2="SourceGraphic"
1589 result="result2"
1590 operator="in" /></filter><filter
1591 id="filter3224-1-7-1-5-0-8-7-8"
1592 inkscape:label="Inner Shadow"
1593 inkscape:menu="Shadows and Glows"
1594 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1595 color-interpolation-filters="sRGB"
1596 width="1"
1597 height="1"
1598 y="0"
1599 x="0"><feOffset
1600 id="feOffset3228-5-5-5-6-7-6-9-8"
1601 dx="0"
1602 dy="1.2"
1603 result="result11" /><feComposite
1604 id="feComposite3230-2-4-1-0-9-3-0-9"
1605 in2="result11"
1606 result="result6"
1607 in="SourceGraphic"
1608 operator="in" /><feFlood
1609 id="feFlood3232-7-3-4-6-7-1-3-0"
1610 result="result10"
1611 in="result6"
1612 flood-opacity="1"
1613 flood-color="rgb(34,34,34)" /><feBlend
1614 id="feBlend3234-6-3-5-6-4-1-1-8"
1615 in2="result10"
1616 mode="normal"
1617 in="result6"
1618 result="result12" /><feComposite
1619 id="feComposite3236-1-3-5-55-7-6-8-6"
1620 in2="SourceGraphic"
1621 result="result2"
1622 operator="in" /></filter><filter
1623 id="filter3224-1-7-1-7"
1624 inkscape:label="Inner Shadow"
1625 inkscape:menu="Shadows and Glows"
1626 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1627 color-interpolation-filters="sRGB"
1628 width="1"
1629 height="1"
1630 y="0"
1631 x="0"><feOffset
1632 id="feOffset3228-5-5-5-5"
1633 dx="0"
1634 dy="1.2"
1635 result="result11" /><feComposite
1636 id="feComposite3230-2-4-1-56"
1637 in2="result11"
1638 result="result6"
1639 in="SourceGraphic"
1640 operator="in" /><feFlood
1641 id="feFlood3232-7-3-4-7"
1642 result="result10"
1643 in="result6"
1644 flood-opacity="1"
1645 flood-color="rgb(34,34,34)" /><feBlend
1646 id="feBlend3234-6-3-5-0"
1647 in2="result10"
1648 mode="normal"
1649 in="result6"
1650 result="result12" /><feComposite
1651 id="feComposite3236-1-3-5-9"
1652 in2="SourceGraphic"
1653 result="result2"
1654 operator="in" /></filter><filter
1655 id="filter3224-1-7-1-7-9"
1656 inkscape:label="Inner Shadow"
1657 inkscape:menu="Shadows and Glows"
1658 inkscape:menu-tooltip="Adds a colorizable drop shadow inside"
1659 color-interpolation-filters="sRGB"
1660 width="1"
1661 height="1"
1662 y="0"
1663 x="0"><feOffset
1664 id="feOffset3228-5-5-5-5-8"
1665 dx="0"
1666 dy="1.2"
1667 result="result11" /><feComposite
1668 id="feComposite3230-2-4-1-56-4"
1669 in2="result11"
1670 result="result6"
1671 in="SourceGraphic"
1672 operator="in" /><feFlood
1673 id="feFlood3232-7-3-4-7-8"
1674 result="result10"
1675 in="result6"
1676 flood-opacity="1"
1677 flood-color="rgb(34,34,34)" /><feBlend
1678 id="feBlend3234-6-3-5-0-4"
1679 in2="result10"
1680 mode="normal"
1681 in="result6"
1682 result="result12" /><feComposite
1683 id="feComposite3236-1-3-5-9-9"
1684 in2="SourceGraphic"
1685 result="result2"
1686 operator="in" /></filter></defs><sodipodi:namedview
1687 pagecolor="#d4a8a8"
1688 bordercolor="#666666"
1689 borderopacity="1"
1690 objecttolerance="10"
1691 gridtolerance="10"
1692 guidetolerance="10"
1693 inkscape:pageopacity="0"
1694 inkscape:pageshadow="2"
1695 inkscape:window-width="1466"
1696 inkscape:window-height="925"
1697 id="namedview5"
1698 showgrid="true"
1699 inkscape:showpageshadow="false"
1700 inkscape:zoom="4"
1701 inkscape:cx="212.27233"
1702 inkscape:cy="102.59658"
1703 inkscape:window-x="97"
1704 inkscape:window-y="49"
1705 inkscape:window-maximized="0"
1706 inkscape:current-layer="layer1"
1707 fit-margin-top="0"
1708 fit-margin-left="0"
1709 fit-margin-bottom="32"
1710 fit-margin-right="0"
1711 showguides="true"
1712 inkscape:guide-bbox="true"><inkscape:grid
1713 type="xygrid"
1714 id="grid2986"
1715 units="px"
1716 empspacing="16"
1717 visible="true"
1718 enabled="true"
1719 snapvisiblegridlinesonly="true"
1720 spacingx="1px"
1721 spacingy="1px"
1722 dotted="false"
1723 originx="0px"
1724 originy="0px" /></sodipodi:namedview>
1725
1726
1727<g
1728 inkscape:groupmode="layer"
1729 id="layer2"
1730 inkscape:label="Dark background"
1731 style="display:inline"
1732 transform="translate(-1,367.74999)"
1733 sodipodi:insensitive="true"><rect
1734 style="fill:#e9afaf;fill-opacity:1;stroke:none"
1735 id="rect6406"
1736 width="992"
1737 height="736"
1738 x="1"
1739 y="-367.75" /></g><g
1740 inkscape:groupmode="layer"
1741 id="layer1"
1742 inkscape:label="Shadow"
1743 style="display:inline"
1744 transform="translate(-1,367.74999)"
1745 sodipodi:insensitive="true"><path
1746 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1747 d="m 135,-363.75001 0,2 20,0 0,-2 z m 320.1875,2 c -0.107,0.30896 -0.1874,0.65374 -0.1874,1 0,1.66198 1.338,3 3,3 l 14,0 c 1.662,0 3,-1.33802 3,-3 0,-0.34626 -0.0806,-0.69104 -0.1874,-1 -0.40652,1.17402 -1.49676,2 -2.8125,2 l -14,0 c -1.31574,0 -2.40598,-0.82598 -2.8125,-2 z m 3.8125,8 c -1.108,0 -2,0.89198 -2,2 l 0,2 c 0,-1.10802 0.892,-2 2,-2 l 12,0 c 1.108,0 2,0.89198 2,2 l 0,-2 c 0,-1.10802 -0.892,-2 -2,-2 z m 3,4 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 6,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m -325,2 0,2 4,0 4,0 8,0 0,-2 z m 325,2 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 6,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m -331,1.875 0,2 6,6.125 18,0 c 2.216,0 4,-1.78402 4,-4 l 0,-2 c 0,2.21598 -1.784,4 -4,4 l -2,0 -8,0 -4,0 -4,0 z m 320,0.125 0,2 c 0,1.108 0.892,2 2,2 l 4,0 0,-2 -4,0 c -1.108,0 -2,-0.892 -2,-2 z m 28,0 c 0,1.108 -0.892,2 -2,2 l -4,0 0,2 4,0 c 1.108,0 2,-0.892 2,-2 z m -20,6 0,2 12,0 0,-2 z m -449.8125,39.625 c -0.0642,0.21882 -0.125,0.4551 -0.125,0.75 0,4.04252 2.61966,7.87564 5.6875,11 l 0.875,-1.125 c -3.10738,-2.95582 -5.91722,-6.6716 -6.4375,-10.625 z m 19.75,0.1875 c -0.50602,3.8783 -3.30914,7.52876 -6.375,10.4375 l 0.9375,1.0625 c 2.9932,-3.06606 5.5,-6.8215 5.5,-10.75 0,-0.27964 -0.0162,-0.53042 -0.0625,-0.75 z m 423.4375,11.1875 -1.375,1 14,10 0,-2 z m 89.25,0 -12.625,9 0,2 14,-10 z m 64,0 -12.625,9 0,2 14,-10 z m 38.75,0 -1.375,1 14,10 0,-2 z m -625.3125,2.1875 c -1.62212,1.25216 -3.10068,2.20618 -4.0625,2.8125 0.44064,0.36242 0.78162,0.82428 1.0625,1.3125 0.87208,-0.57004 1.85156,-1.23848 3,-2.125 1.21634,0.9422 2.26918,1.64192 3.1875,2.25 0.26354,-0.49164 0.57806,-0.93856 1,-1.3125 -1.01912,-0.64118 -2.52302,-1.64818 -4.1875,-2.9375 z m 445.9375,0.125 0,2 c 6.83332,0 11.23112,2.46082 14,6.6875 0,-0.74354 -0.048,-1.4538 -0.125,-2.125 -2.77424,-4.13656 -7.1214,-6.5625 -13.875,-6.5625 z m 64,0 c -6.7536,0 -11.10076,2.42596 -13.875,6.5625 -0.077,0.6712 -0.125,1.38146 -0.125,2.125 2.76888,-4.22666 7.16668,-6.6875 14,-6.6875 z m 64,0 c -6.7536,0 -11.10076,2.42596 -13.875,6.5625 -0.077,0.6712 -0.125,1.38146 -0.125,2.125 2.76888,-4.22666 7.16668,-6.6875 14,-6.6875 z m 64,0 0,2 c 6.83332,0 11.23112,2.46082 14,6.6875 0,-0.74354 -0.048,-1.4538 -0.125,-2.125 -2.77424,-4.13656 -7.1214,-6.5625 -13.875,-6.5625 z m -645.3125,3.875 c -1.37544,0 -2.4375,1.03016 -2.4375,2.3125 0,0.36992 0.0912,0.69074 0.25,1 0.39166,-0.76286 1.20882,-1.3125 2.1875,-1.3125 0.96738,0 1.77228,0.56398 2.1875,1.3125 0.1752,-0.31572 0.3125,-0.61956 0.3125,-1 0,-1.28234 -1.12458,-2.3125 -2.5,-2.3125 z m 15,0 c -1.37544,0 -2.5,1.03016 -2.5,2.3125 0,0.38044 0.1374,0.68428 0.3125,1 0.4152,-0.74852 1.2201,-1.3125 2.1875,-1.3125 0.97868,0 1.79584,0.54964 2.1875,1.3125 0.1588,-0.30926 0.25,-0.63008 0.25,-1 0,-1.28234 -1.06208,-2.3125 -2.4375,-2.3125 z m -10.125,3.3125 c -0.49264,2.08248 -2.49068,3.625 -4.875,3.625 -2.36162,0 -4.30912,-1.51004 -4.8125,-3.5625 -0.0652,0.3035 -0.125,0.61692 -0.125,0.9375 0,2.56468 2.1866,4.625 4.9375,4.625 2.7509,0 5,-2.06032 5,-4.625 0,-0.34672 -0.0478,-0.67348 -0.125,-1 z m 5.25,0.0625 c -0.0718,0.31234 -0.125,0.60588 -0.125,0.9375 0,2.56468 2.2491,4.625 5,4.625 2.7509,0 4.9375,-2.06032 4.9375,-4.625 0,-0.32058 -0.06,-0.63394 -0.125,-0.9375 -0.50338,2.05246 -2.45088,3.5625 -4.8125,3.5625 -2.36162,0 -4.35858,-1.51004 -4.875,-3.5625 z M 14,-233.75001 c -3.866,0 -7,3.134 -7,7 0,0.33546 0.0161,0.67712 0.0625,1 0.48018,-3.398 3.40696,-6 6.9375,-6 3.46616,0 6.31682,2.50512 6.875,5.8125 0.0312,-0.26896 0.125,-0.53508 0.125,-0.8125 0,-3.866 -3.134,-7 -7,-7 z m 10.9375,7.875 c -0.1766,2.1855 -0.98174,4.17042 -2.25,5.8125 l 0.75,0.75 c 0.9463,-1.61274 1.5625,-3.429 1.5625,-5.4375 0,-0.3797 -0.0251,-0.75522 -0.0625,-1.125 z m -21.875,0.25 c -0.0228,0.2897 -0.0625,0.57942 -0.0625,0.875 0,6.07512 4.92486,11 11,11 2.0945,0 4.02114,-0.60892 5.6875,-1.625 l 7.0625,7.0625 c 0.78348,0.78346 2.02902,0.78346 2.8125,0 0.6625,-0.6625 0.7079,-1.65918 0.25,-2.4375 -0.0836,0.1422 -0.129,0.31652 -0.25,0.4375 -0.78348,0.78346 -2.02902,0.78346 -2.8125,0 l -7.0625,-7.0625 c -1.66636,1.01608 -3.593,1.625 -5.6875,1.625 -5.69544,0 -10.3742,-4.3282 -10.9375,-9.875 z m 666.9375,51.875 -1,2 0,2 2,-4 z m -1,4 -1,0 -9,18 1,0 8,-16 1,0 z m -596,0 c -1.108,0 -2,0.89198 -2,2 l 0,2 c 0,-1.10802 0.892,-2 2,-2 l 16,0 c 1.108,0 2,0.89198 2,2 l 0,-2 c 0,-1.10802 -0.892,-2 -2,-2 z m 72,0 c -0.41421,0 -0.84659,0.0217 -1.25,0.0625 -0.25156,0.0318 -0.50463,0.0748 -0.75,0.125 -4.55683,0.93246 -8,4.98 -8,9.8125 0,0.34518 0.0284,0.66382 0.0625,1 0.5121,-5.04256 4.75984,-9 9.9375,-9 5.17766,0 9.4254,3.95744 9.9375,9 0.0341,-0.33618 0.0625,-0.65482 0.0625,-1 0,-4.8325 -3.44317,-8.88004 -8,-9.8125 -0.24537,-0.0502 -0.49844,-0.0932 -0.75,-0.125 -0.0805,-0.008 -0.16906,0.006 -0.25,0 -0.33617,-0.0342 -0.65482,-0.0625 -1,-0.0625 z m 116,0 c -1.108,0 -2,0.892 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 l 1,0 4,0 19,0 c 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 64.0625,0 c -1.108,0 -2,0.892 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 l 19,0 4,0 1,0 c 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 63.9375,2 c -1.108,0 -2,2 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 l 24,0 c 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 64,0 c -1.108,0 -2,2 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 l 24,0 c 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 192,-2 c -1.108,0 -2,0.89198 -2,2 l 0,2 c 0,-1.10802 0.892,-2 2,-2 l 1,0 7,0 1,0 7,0 2,0 1,-2 -3,0 -8,0 z m 26,0.5625 0,1.4375 1.4375,0 c -0.3537,-0.60466 -0.83286,-1.0838 -1.4375,-1.4375 z m -474,1.4375 c -1.108,0 -2,0.89198 -2,2 l 0,2 c 0,-1.10802 0.892,-2 2,-2 l 3,0 4,0 17,0 c 1.108,0 2,0.89198 2,2 l 0,-2 c 0,-1.10802 -0.892,-2 -2,-2 z m -192,2 0,2 2,0 6,0 4,0 10,0 2,0 0,-2 z m 257,0 c -0.554,0 -1,0.446 -1,1 0,0.48474 0.0888,1.06892 1.125,1 l 0.875,0 0,-2 -0.875,0 c -0.0514,0.004 -0.0782,-3e-4 -0.125,0 z m 3,0 0,2 1,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 79.0625,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 1,0 0,-2 z m 3,0 0,2 0.875,0 c 1.0362,0.069 1.125,-0.51526 1.125,-1 0,-0.554 -0.446,-1 -1,-1 -0.0468,-3e-4 -0.0736,0.004 -0.125,0 z m 235.9375,0 c -0.37224,0 -0.70936,0.0608 -1.0625,0.125 -1.0136,0.2827 -1.85708,0.97964 -2.375,1.875 l 3.4375,0 20,0 3.4375,0 c -0.51792,-0.89536 -1.3614,-1.5923 -2.375,-1.875 -0.33786,-0.0942 -0.69156,-0.125 -1.0625,-0.125 z m 88,0 0,2 2,0 0,-2 z m -471,2 c -0.554,0 -1,0.44598 -1,1 0.1614,1.15406 0.6222,0.99248 2,1 l 0,-2 -0.875,0 c -0.0526,-8.6e-4 -0.077,0.002 -0.125,0 z m 3,0 0,2 1,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -1.554,-1 -1,-1 z m -115,1 -9,9 -2.8125,-2.8125 -1.875,-1.875 -1,1 2.875,2.875 2.8125,2.8125 10,-10 z m -81,1 0,2 6,0 0,-2 z m 394,2 6,8 6,-8 -1.5,0 -4.5,6 -4.5,-6 z m 52,0 6,8 6,-8 -1.5,0 -4.5,6 -4.5,-6 z m 218,-2 0,2 2,0 0,-2 z m -654,2 0,2 10,0 0,-2 z m 122.125,1 c -0.0574,0.33316 -0.125,0.65048 -0.125,1 0,3.3137 2.6863,6 6,6 3.3137,0 6,-2.6863 6,-6 0,-0.34952 -0.0676,-0.66684 -0.125,-1 -0.48643,2.82528 -2.91083,5 -5.875,5 -2.96417,0 -5.38857,-2.17472 -5.875,-5 z m -6.0625,0.25 c -0.015,0.24518 -0.0625,0.50106 -0.0625,0.75 0,6.6274 5.37258,12 12,12 6.62742,0 12,-5.3726 12,-12 0,-0.24894 -0.0476,-0.50482 -0.0625,-0.75 -0.54764,5.39254 -4.65021,9.68238 -9.9375,10.5625 -0.32549,0.0666 -0.66383,0.0908 -1,0.125 -0.32478,0.0264 -0.66842,0.0624 -1,0.0624 -0.33158,0 -0.67522,-0.0364 -1,-0.0624 -0.0828,-0.008 -0.16786,0.01 -0.25,0 -0.25513,-0.026 -0.49985,-0.0834 -0.75,-0.125 -5.28729,-0.88012 -9.38986,-5.16996 -9.9375,-10.5625 z m 379.9375,0.75 0,2 c 0,3.324 2.676,6 6,6 l 20,0 c 3.324,0 6,-2.676 6,-6 l 0,-2 c 0,3.324 -2.676,6 -6,6 l -20,0 c -3.324,0 -6,-2.676 -6,-6 z m 64,0 0,2 c 0,3.324 2.676,6 6,6 l 20,0 c 3.324,0 6,-2.676 6,-6 l 0,-2 c 0,3.324 -2.676,6 -6,6 l -20,0 c -3.324,0 -6,-2.676 -6,-6 z m 94,0 0,2 2,0 0,-2 z m -384,0.8125 -9.1875,9.1875 1.6875,0 c 0.0268,-0.0356 0.0298,-0.0924 0.0624,-0.125 l 7.4375,-7.375 0,-1.6875 z m 36.0625,0 0,1.6875 7.4375,7.375 c 0.0326,0.0326 0.0358,0.0894 0.0624,0.125 l 1.6875,0 -9.1875,-9.1875 z M 7,-155.75001 l 0,2 6,0 0,-2 z m 643.3125,1.9375 c -0.1034,0.036 -0.1964,0.0624 -0.3125,0.0624 l -1,0 -2,0 -1,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 3,0 1,0 c 0.554,0 1,-0.44602 1,-1 0,-0.3682 -0.32938,-0.8876 -0.625,-1.0625 -0.014,-0.008 -0.0494,0.006 -0.0624,0 z M 17,-153.75001 l 0,2 10,0 0,-2 z m 52,0 0,2 c 0,2.1814 1.8186,4 4,4 l 16,0 c 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 l -16,0 c -2.1814,0 -4,-1.8186 -4,-4 z m 193,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 4,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.24356,-1.0562 -1,-1 l -1,0 -2,0 z m 81.625,0 c -0.38762,0.1434 -0.5625,0.5845 -0.5625,1 0,0.554 0.446,1 1,1 l 4,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 l -1,0 -2,0 -1,0 c -0.189,-0.014 -0.3083,-0.0478 -0.4375,0 z m 41.375,2 0,2 c 0,2.1814 1.8186,4 4,4 l 24,0 c 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 l -24,0 c -2.1814,0 -4,-1.8186 -4,-4 z m 64,0 0,2 c 0,2.1814 1.8186,4 4,4 l 24,0 c 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 l -24,0 c -2.1814,0 -4,-1.8186 -4,-4 z m 192,-2 0,2 c 0,2.18138 1.8186,4 4,4 l 8,0 1,-2 -9,0 c -2.1814,0 -4,-1.81862 -4,-4 z m 30,0 0,2 1.4375,0 0.5625,0 0,-2 z m -384,1.25 -4.6875,4.75 1.25,0 3.4375,-3.5 z m 36.0625,0 0,1.25 3.4375,3.5 1.25,0 z m -320.0625,0.75 0,2 c 0,1.10798 0.892,2 2,2 l 24,0 c 1.108,0 2,-0.89202 2,-2 l 0,-2 c 0,1.10798 -0.892,2 -2,2 l -24,0 c -1.108,0 -2,-0.89202 -2,-2 z m 190,0 0,2 c 0,2.1814 1.8186,4 4,4 l 24,0 c 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 l -24,0 c -2.1814,0 -4,-1.8186 -4,-4 z m 7,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 4,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.23842,-1 -1,-1 l -1,0 -2,0 z m 57,2 0,2 c 0,2.18138 1.8186,4 4,4 l 24,0 c 2.1814,0 4,-1.81862 4,-4 l 0,-0.75 c 0.0656,-0.1786 0.0426,-0.3443 0,-0.5 l 0,-0.75 c 0,2.18138 -1.8186,4 -4,4 l -1.4375,0 -1.25,0 -2.8125,0 -1.6875,0 -6.75,0 -10.0625,0 c -2.1814,0 -4,-1.81862 -4,-4 z m 64.0625,0 0,0.75 c -0.0426,0.1558 -0.0656,0.3214 0,0.5 l 0,0.75 c 0,2.1814 1.8186,4 4,4 l 24,0 c 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 l -14.0625,0 -2.75,0 -1.6875,0 -2.8125,0 -1.25,0 -1.4375,0 c -2.1814,0 -4,-1.8186 -4,-4 z m 336.9375,0 -3,6 -3,0 -1,2 4,0 3,-6 3,0 0,-2 -2,0 z m 5,0 0,2 2,0 0,-2 z m 4,0 0,2 2,0 0,-2 z m 4,0 0,1.4375 c 0.60464,-0.35372 1.0838,-0.83286 1.4375,-1.4375 z m -391,44 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 5,0 0,-2 z m 127.9375,0 -0.1874,0.6875 -6,0 -4.8125,17.3125 -5.4375,0 -0.5625,2 6,0 4.8125,-17.3125 6,0 0.625,-2.6875 -0.4375,0 z m -318.375,0.0624 -0.5,1.9375 -3.1875,0 -4.125,16.0625 0.5,0 3.625,-14.0625 3.1875,0 1,-3.9375 z m 300.625,0.625 -0.4375,2 5.4375,0 0.5625,-2 z m -374.0625,1.3126 c -0.43368,0.0254 -0.84056,0.0744 -1.1875,0.125 l 0,2 c 0.34694,-0.0506 0.75382,-0.0996 1.1875,-0.125 0.43368,-0.0252 0.84524,2e-5 1.25,0 0.49152,2e-5 0.9749,0.049 1.4375,0.125 0.46258,0.0506 0.84056,0.1724 1.1875,0.375 0.34694,0.1772 0.61012,0.39556 0.8125,0.75 0.0506,0.0822 0.0862,0.21168 0.125,0.3125 0.1106,-0.29132 0.1875,-0.58052 0.1875,-0.9375 0,-0.55698 -0.10998,-1.04584 -0.3125,-1.375 -0.20238,-0.35444 -0.46556,-0.5728 -0.8125,-0.75 -0.34694,-0.2026 -0.72492,-0.3244 -1.1875,-0.375 -0.4626,-0.076 -0.94598,-0.125 -1.4375,-0.125 -0.40476,2e-5 -0.81632,-0.0252 -1.25,0 z m 62.25,0 -0.5,2 2.6875,0 0.5,-2 z m 208.625,1 c 0,0.554 -0.446,1 -1,1 l -1,0 -4,0 0,2 5,0 c 0.554,0 1,-0.446 1,-1 z m -260.75,2.0625 c -0.126,0.73254 -0.4229,1.38816 -0.875,2 -0.60716,0.86082 -1.39668,1.55616 -2.4375,2.0625 0.67696,0.21642 1.24742,0.47408 1.75,0.75 0.24546,-0.2493 0.48512,-0.52556 0.6875,-0.8125 0.63606,-0.8608 0.93748,-1.8235 0.9375,-2.9375 0,-0.3671 -0.001,-0.69918 -0.0625,-1.0625 z m 298.9375,0.1874 c -0.38458,0.86222 -0.2642,1.92328 0.4375,2.625 l 3.0625,3.0625 1,-1 -4.0625,-4.0625 c -0.1918,-0.1918 -0.32686,-0.3914 -0.4375,-0.625 z m 15.5625,0 c -0.1106,0.2336 -0.24574,0.43322 -0.4375,0.625 l -4.0625,4.0626 1,1 3.0625,-3.0625 c 0.7017,-0.70172 0.82208,-1.76278 0.4375,-2.625 z m -61.75,1.75 0,2 c 0,0.554 0.446,1 1,1 l 6,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 l -5,0 -1,0 c -0.554,0 -1,-0.446 -1,-1 z m -17.8125,0.25 c -0.38458,0.86222 -0.2642,1.92328 0.4375,2.625 l 3.0625,3.0625 1,-1 -4.0625,-4.0625 c -0.1918,-0.1918 -0.32686,-0.3914 -0.4375,-0.625 z m 15.5625,0 c -0.1106,0.2336 -0.24574,0.43322 -0.4375,0.625 l -4.0625,4.0626 1,1 3.0625,-3.0625 c 0.7017,-0.70172 0.82208,-1.76278 0.4375,-2.625 z m -139.75,3.6876 0,2 c 0,0 0.1636,2.5764 0.4375,3.6875 0.27388,1.11108 0.71772,2.09218 1.375,2.875 0.6573,0.7828 1.52952,1.3832 2.625,1.8125 1.12288,0.40402 2.48174,0.5625 4.125,0.5625 1.6706,0 3.06462,-0.1584 4.1875,-0.5625 1.12286,-0.4293 2.0653,-1.0297 2.75,-1.8125 0.68466,-0.78282 1.1636,-1.76392 1.4375,-2.875 0.27394,-1.1111 0.37498,-2.3239 0.375,-3.6875 l 0,-2 c -2e-5,1.3636 -0.10106,2.5764 -0.375,3.6875 -0.2739,1.11108 -0.75284,2.09218 -1.4375,2.875 -0.6847,0.7828 -1.62714,1.3832 -2.75,1.8125 -1.12288,0.4041 -2.5169,0.5625 -4.1875,0.5625 -1.64326,0 -3.00212,-0.1584 -4.125,-0.5625 -1.09548,-0.4293 -1.9677,-1.0297 -2.625,-1.8125 -0.65728,-0.78282 -1.10112,-1.76392 -1.375,-2.875 -0.2739,-1.1111 -0.4375,-2.3239 -0.4375,-3.6875 z m -122.0625,0.4375 0,2 2.875,0 c 1.38776,2e-5 2.44046,0.30616 3.25,0.8125 0.58546,0.3359 0.9506,0.84108 1.125,1.5 0.0826,-0.31614 0.125,-0.66204 0.125,-1.0625 0,-1.1393 -0.41156,-1.95646 -1.25,-2.4375 -0.80954,-0.50634 -1.86224,-0.81248 -3.25,-0.8125 z m 318.0625,1.875 -4.125,4.0625 c -0.90654,0.90654 -2.34346,0.90654 -3.25,0 -0.20484,-0.20484 -0.32524,-0.4358 -0.4375,-0.6875 -0.41236,0.8707 -0.27728,1.97272 0.4375,2.6875 0.90654,0.90654 2.34346,0.90654 3.25,0 l 4.125,-4.0625 4.0625,4.0625 c 0.90654,0.90654 2.34346,0.90654 3.25,0 0.71478,-0.71478 0.84986,-1.8168 0.4375,-2.6875 -0.1122,0.2517 -0.23266,0.48266 -0.4375,0.6875 -0.90654,0.90654 -2.34346,0.90654 -3.25,0 z m -64,2 -4.125,4.0625 c -0.90654,0.90654 -2.34346,0.90654 -3.25,0 -0.20484,-0.20484 -0.32524,-0.4358 -0.4375,-0.6875 -0.41236,0.8707 -0.27728,1.97272 0.4375,2.6875 0.90654,0.90654 2.34346,0.90654 3.25,0 l 4.125,-4.0625 4.0625,4.0625 c 0.90654,0.90654 2.34346,0.90654 3.25,0 0.71478,-0.71478 0.84986,-1.8168 0.4375,-2.6875 -0.1122,0.2517 -0.23266,0.48266 -0.4375,0.6875 -0.90654,0.90654 -2.34346,0.90654 -3.25,0 z m -241.5,0.5625 c -0.1118,0.896 -0.365,1.7007 -0.75,2.375 -0.54934,0.93676 -1.29592,1.66768 -2.25,2.25 -0.9252,0.557 -2.01146,0.99682 -3.3125,1.25 -1.27214,0.2279 -2.6505,0.3125 -4.125,0.3125 l -7.5,0 0,2 7.5,0 c 1.4745,0 2.85286,-0.0846 4.125,-0.3125 1.30104,-0.25318 2.3873,-0.693 3.3125,-1.25 0.95408,-0.58232 1.70066,-1.31324 2.25,-2.25 0.5493,-0.96208 0.81248,-2.1447 0.8125,-3.5625 0,-0.27216 -0.0207,-0.54564 -0.0625,-0.8125 z m 316.5,0.1874 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.48562,1.20574 1,1 l 5,0 0,-2 z m 59.5,1.3125 -1,0.9375 2.875,2.9375 0.9375,-1 z m 9.625,0 -2.875,2.875 1,1 2.875,-2.9375 z M 351,-86.75001 c 0,0.554 -0.446,1 -1,1 l -1,0 -4,0 0,2 5,0 c 0.554,0 1,-0.446 1,-1 z m -266.5625,1.0625 -0.5,1.9375 -10.6875,0 -0.5625,2 11.25,0 1,-3.9375 z M 388,-83.75001 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m 20.25,0.1874 -3.8125,3.9375 -1,-1 -0.9375,1 1.9375,2 3.8125,-3.9375 3.9375,3.9375 1.9375,-2 -1,-1 -0.9375,1 z m -65.25,0.8125 0,2 c 0,0.554 0.446,1 1,1 l 6,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 l -5,0 -1,0 c -0.554,0 -1,-0.446 -1,-1 z m -207,1 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 20,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m -128,42 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 1,0 0,-2 z m 8,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 54,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 20,0 c 0,0 -1,0.446 -1,1 0,0.48474 1.19869,0.90706 1.125,1 l 0.875,0 0,-2 -0.875,0 z m 56,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m 50,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m 723,0 0,2 2,0 0,-2 z m 54,0 0,2 2,0 0,-2 z m -709,2 c -0.55228,0 -1,0.4477 -1,1 0,0.41422 0.26608,0.7857 0.625,0.9375 0.1196,0.0506 0.23694,0.0624 0.375,0.0624 0.55228,0 1,-0.44772 1,-1 0,-0.5523 -0.44772,-1 -1,-1 z m 4,0 c -0.138,0 -0.25536,0.012 -0.375,0.0624 -0.35892,0.1518 -0.625,0.52328 -0.625,0.9375 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.5523 -0.44772,-1 -1,-1 z m 8,0 c -0.554,0 -1,0.4113 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 4,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.5262 -0.446,-0.9375 -1,-0.9375 z m 74,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -4,0 -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m -18,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -4,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m 82,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -4,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -8,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -1.554,0.9375 -1,0.9375 l -6,0 -4,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 54,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 4,0 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.52618 -0.446,-0.9375 -1,-0.9375 z m 18,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 171,0 0,2 14,0 0,-2 z m 67.75,0 0,2 16.1875,0 0,-2 z m 70.25,0 0,2 14,0 0,-2 z m 54,0 0,2 24,0 0,-2 z m 86,0 0,2 2,0 0,-2 z m 54,0 0,2 2,0 0,-2 z m -843.875,1 c -0.0822,0.31952 -0.125,0.65482 -0.125,1 0,2.20912 1.79086,4 4,4 2.20914,0 4,-1.79088 4,-4 0,-0.34518 -0.0428,-0.68048 -0.125,-1 -0.44393,1.7254 -2.01104,3 -3.875,3 -1.86396,0 -3.43107,-1.2746 -3.875,-3 z m 80,0 c -0.0822,0.31952 -0.125,0.65482 -0.125,1 0,2.20912 1.79086,4 4,4 2.20914,0 4,-1.79088 4,-4 0,-0.34518 -0.0428,-0.68048 -0.125,-1 -0.44392,1.7254 -2.01104,3 -3.875,3 -1.86396,0 -3.43108,-1.2746 -3.875,-3 z m -197.125,1 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 54,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 76,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m 50,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 z m 715.125,1 c -0.0574,0.33316 -0.125,0.65048 -0.125,1 0,3.3137 2.6863,6 6,6 l 0,-2 c -2.96418,0 -5.38856,-2.17472 -5.875,-5 z m 54,0 c -0.0574,0.33316 -0.125,0.65048 -0.125,1 0,3.3137 2.6863,6 6,6 l 0,-2 c -2.96418,0 -5.38856,-2.17472 -5.875,-5 z m -448.25,0.125 c -0.079,0.33192 -0.125,0.66 -0.125,1 0,2.4908 2.23904,4.50914 5.0625,4.625 0.22818,-0.7101 0.4048,-1.36952 0.5,-2 -0.0876,0.002 -0.1594,0 -0.25,0 -2.55268,0 -4.66902,-1.5407 -5.1875,-3.625 z m 16,0 c -0.079,0.33 -0.125,0.66 -0.125,1 0,2.49082 2.23904,4.50914 5.0625,4.625 0.22758,-0.70226 0.4048,-1.37798 0.5,-2 -0.093,0.002 -0.154,0 -0.25,0 -2.55268,0 -4.66902,-1.5407 -5.1875,-3.625 z m -5.5625,0.6875 c -0.65798,6.08074 -4.77536,9.8842 -7.875,11.4375 -0.71906,0.92964 -1.60386,1.86798 -2.6875,2.8125 2.66666,0 10.625,-4.6403 10.625,-13.9375 0,-0.1078 -0.0544,-0.20508 -0.0624,-0.3125 z m 16,0 c -0.65144,6.07564 -4.76304,9.8376 -7.875,11.375 -0.71932,0.92592 -1.60162,1.86602 -2.6875,2.8125 2.74932,0 10.625,-4.57778 10.625,-13.875 0,-0.1078 -0.0544,-0.20528 -0.0624,-0.3125 z M 276,-33.75001 c -0.554,0 -1,0.4113 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.5262 -0.446,-0.9375 -1,-0.9375 z m 70,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 52,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 58,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.52618 -0.446,-0.9375 -1,-0.9375 z m -447,1 0,2 c 0,0.55398 0.446,1 1,1 0.554,0 1,-0.44602 1,-1 l 0,-2 c 0,0.55398 -0.446,1 -1,1 -0.554,0 -1,-0.44602 -1,-1 z m 82,0 0,2 c 0,0.55398 0.446,1 1,1 0.554,0 1,-0.44602 1,-1 l 0,-2 c 0,0.55398 -0.446,1 -1,1 -0.554,0 -1,-0.44602 -1,-1 z m 554,1 0,2 18,0 4,0 0,-2 z m 130,0 0,2 4,0 18,0 0,-2 z m 62,0 0,2 24,0 0,-2 z m -128.3125,0.0624 0,2 4.0625,0 16.1875,0 4.0625,0 0,-2 z m -448.4375,1.9376 -1.25,0.9375 0,0.125 4,2.9375 0,-2 z m 2.75,2 5,0 c 0.1386,0 0.25528,-0.016 0.375,-0.0624 0.35916,-0.1404 0.625,-0.48036 0.625,-0.875 l 0,-0.125 c 0,-0.1316 -0.012,-0.26244 -0.0624,-0.375 -0.1514,-0.33766 -0.522,-0.5625 -0.9375,-0.5625 l -5,0 0,2 z m 13,-2 c -0.554,0 -1,0.4113 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 4,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.5262 -0.446,-0.9375 -1,-0.9375 z m 74,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -4,0 -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m -18.25,0 1.25,0.9375 0,0.125 -4,2.9375 0,-2 z m -2.75,2 -5,0 c -0.55274,0 -1,-0.36074 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.44726,-0.9375 1,-0.9375 l 5,0 z m 85.1875,-2 c 0.5787,0 1.0625,0.4113 1.0625,0.9375 l 0,0.125 c 0,0.8681 -0.4838,0.9375 -1.0625,0.9375 l -5.1875,0 0,-2 z m -5.1875,2 0,2 -4.1875,-2.9375 0,-0.125 1.3125,-0.9375 z m -11,-2 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -1.554,0.9375 -1,0.9375 l -6,0 -4,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 54,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 4,0 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.52618 -0.446,-0.9375 -1,-0.9375 z m 18,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 5,0 0,-2 z m 5,2 0,2 4,-2.9375 0,-0.125 -1.25,-0.9375 z m 431,-1 -5,5 0,2 6,-6 z m 78,0 -1,1 6,6 0,-2 z m -978,3 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 3,0 0,-2 z m 10,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 54,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 18,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 3,0 0,-2 z m 58,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 50,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 80,0 c -0.554,0 -1,0.4113 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.5262 -0.446,-0.9375 -1,-0.9375 z m 70,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 52,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -6,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 58,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 6,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.52618 -0.446,-0.9375 -1,-0.9375 z m 189,0 0,2 18,0 0,-2 z m 134,0 0,2 18,0 0,-2 z m 58,0 0,2 24,0 0,-2 z m -124.25,0.125 0,2 16.1875,0 0,-2 z M 11,-22.75001 c 0,0.1386 -0.0121,0.2551 -0.0625,0.375 -0.101,0.27824 -0.30814,0.4805 -0.5625,0.5625 -0.1198,0.0504 -0.2364,0.0624 -0.375,0.0624 l -1,0 -2,0 0,2 3,0 c 0.1386,0 0.25528,-0.012 0.375,-0.0624 0.25436,-0.082 0.4614,-0.28426 0.5625,-0.5625 0.0504,-0.1198 0.0625,-0.2365 0.0625,-0.375 z m 82,0 c 0,0.1386 -0.0122,0.2551 -0.0625,0.375 -0.1011,0.27824 -0.30814,0.4805 -0.5625,0.5625 -0.11972,0.0504 -0.2364,0.0624 -0.375,0.0624 l -1,0 -2,0 0,2 3,0 c 0.1386,0 0.25528,-0.012 0.375,-0.0624 0.25436,-0.082 0.4614,-0.28426 0.5625,-0.5625 0.0504,-0.1198 0.0625,-0.2365 0.0625,-0.375 z m 40.125,0 c -0.0822,0.31952 -0.125,0.65482 -0.125,1 0,2.20912 1.79086,4 4,4 2.20914,0 4,-1.79088 4,-4 0,-0.34518 -0.0428,-0.68048 -0.125,-1 -0.44393,1.7254 -2.01104,3 -3.875,3 -1.86396,0 -3.43107,-1.2746 -3.875,-3 z m 80,0 c -0.0822,0.31952 -0.125,0.65482 -0.125,1 0,2.20912 1.79086,4 4,4 2.20914,0 4,-1.79088 4,-4 0,-0.34518 -0.0428,-0.68048 -0.125,-1 -0.44392,1.7254 -2.01104,3 -3.875,3 -1.86396,0 -3.43108,-1.2746 -3.875,-3 z m -197.125,1 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 54,0 c -0.554,0 -1,0.446 -1,1 0,0.55398 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 76,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 50,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z m 68,0 c -0.55228,0 -1,0.4477 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.5523 -0.44772,-1 -1,-1 z m 4,0 c -0.138,0 -0.25536,0.012 -0.375,0.0624 -0.35892,0.1518 -0.625,0.52328 -0.625,0.9375 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.5523 -0.44772,-1 -1,-1 z m 8,0 c -0.554,0 -1,0.4113 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 10,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.5262 -0.446,-0.9375 -1,-0.9375 z m 74,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -10,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m -18,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -4,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m 82,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -4,0 c 0.55228,0 1,0.4477 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.5523 0.44772,-1 1,-1 z m -8,0 c 0.554,0 1,0.4113 1,0.9375 l 0,0.125 c 0,0.52618 -0.446,0.9375 -1,0.9375 l -10,0 c -0.554,0 -1,-0.41132 -1,-0.9375 l 0,-0.125 c 0,-0.5262 0.446,-0.9375 1,-0.9375 z m 54,0 c -0.554,0 -1,0.41132 -1,0.9375 l 0,0.125 c 0,0.52618 0.446,0.9375 1,0.9375 l 10,0 c 0.554,0 1,-0.41132 1,-0.9375 l 0,-0.125 c 0,-0.52618 -0.446,-0.9375 -1,-0.9375 z m 18,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 443,0 0,2 2,0 0,-2 z m 4,0 0,2 2,0 0,-2 z m 50,0 0,2 2,0 0,-2 z m 4,0 0,2 2,0 0,-2 z m -330,2 0,2 24,0 0,-2 z m 128,0 0,2 24,0 0,-2 z m 64,0 0,2 24,0 0,-2 z m -128.3125,0.1874 0,2 24.3125,0 0,-2 z M 5,-18.75001 l 0,2 c 0,0.55398 0.446,1 1,1 l 4,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 l -3,0 -1,0 c -0.554,0 -1,-0.44602 -1,-1 z m 82,0 0,2 c 0,0.55398 0.446,1 1,1 l 4,0 c 0.554,0 1,-0.44602 1,-1 0,-0.554 -0.446,-1 -1,-1 l -3,0 -1,0 c -0.554,0 -1,-0.44602 -1,-1 z m 184.125,0 0,2 c 0,0.554 0.42308,1 0.9375,1 0.51442,0 0.9375,-0.446 0.9375,-1 l 0,-2 c 0,0.554 -0.42308,1 -0.9375,1 -0.51442,0 -0.9375,-0.446 -0.9375,-1 z m 65.875,0 0,2 c 0,0.554 -0.42308,1 -0.9375,1 -0.51442,0 -0.9375,-0.446 -0.9375,-1 l 0,-2 c 0,0.554 0.42308,1 0.9375,1 0.51442,0 0.9375,-0.446 0.9375,-1 z m 65.875,0 0,2 c 0,0.55398 -0.42308,1 -0.9375,1 -0.51442,0 -0.9375,-0.44602 -0.9375,-1 l 0,-2 c 0,0.55398 0.42308,1 0.9375,1 0.51442,0 0.9375,-0.44602 0.9375,-1 z m 62.125,0 0,2 c 0,0.554 0.42308,1 0.9375,1 0.51444,0 0.9375,-0.446 0.9375,-1 l 0,-2 c 0,0.554 -0.42306,1 -0.9375,1 -0.51442,0 -0.9375,-0.446 -0.9375,-1 z m -456,45 c -0.3204,0 -0.63738,0.0512 -0.9375,0.125 C 6.3192,26.80395 5,28.38897 5,30.24999 l 0,2 c 0,-2.18142 1.8186,-4 4,-4 l 6,0 0,-2 z m 10,0 0,2 6,0 c 2.1814,0 4,1.81858 4,4 l 0,-2 c 0,-1.86102 -1.3192,-3.44604 -3.0625,-3.875 -0.0432,-0.008 -0.0814,-0.0566 -0.125,-0.0624 -0.2585,-0.054 -0.53982,-0.0624 -0.8125,-0.0624 l -6,0 z m 54,0 c -0.3204,0 -0.63738,0.0512 -0.9375,0.125 C 70.3192,26.80395 69,28.38897 69,30.24999 l 0,2 c 0,-2.18142 1.8186,-4 4,-4 l 6,0 0,-2 z m 10,0 0,2 6,0 c 2.1814,0 4,1.81858 4,4 l 0,0.875 1.0625,1.0625 0.875,0.875 C 94.9756,34.79153 95,34.53079 95,34.24999 l 0,-2 c 0,0.2808 -0.0244,0.54154 -0.0625,0.8125 l -0.875,-0.875 -1.0625,-1.0625 0,-0.875 c 0,-1.86102 -1.31921,-3.44604 -3.0625,-3.875 -0.0432,-0.008 -0.0815,-0.0566 -0.125,-0.0624 -0.25849,-0.054 -0.53983,-0.0624 -0.8125,-0.0624 l -6,0 z m -73,4 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 14,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 l -5,0 -4,0 z m 64,0 c -0.554,0 -1,0.44598 -1,1 0,0.554 0.446,1 1,1 l 8.625,0 3,0 2.375,0 c 0.554,0 1,-0.446 1,-1 0,-0.55402 -0.446,-1 -1,-1 l -5,0 -4,0 z m -71,2 0,2 c 0,3.29298 2.70702,6 6,6 l 6,0 2,-2 2,2 6,0 c 3.29298,0 6,-2.70702 6,-6 l 0,-2 c 0,2.96706 -2.21866,5.41092 -5.0625,5.875 -0.0446,0.01 -0.0798,0.053 -0.125,0.0624 -0.27096,0.038 -0.5317,0.0624 -0.8125,0.0624 l -6,0 -2,-2 -2,2 -6,0 c -0.2808,0 -0.54154,-0.0244 -0.8125,-0.0624 -0.0452,-0.01 -0.0804,-0.0516 -0.125,-0.0624 C 5.21866,37.66091 3,35.21705 3,32.24999 z m 4,0 0,2 c 0,1.108 0.892,2 2,2 l 6,0 0,-2 -5,0 -1,0 c -1.108,0 -2,-0.892 -2,-2 z m 20,0 c 0,1.108 -0.892,2 -2,2 l -1,0 -5,0 0,2 6,0 c 1.108,0 2,-0.892 2,-2 z m 40,0 0,2 c 0,3.29298 2.70702,6 6,6 l 6,0 1.375,-1.375 -1,-1 -0.375,0.375 -6,0 c -0.2808,0 -0.54154,-0.0244 -0.8125,-0.0624 -0.0452,-0.01 -0.0802,-0.0516 -0.125,-0.0624 C 69.21866,37.66071 67,35.21705 67,32.24999 z m 4,0 0,2 c 0,1.108 0.892,2 2,2 l 6,0 0,-2 -5,0 -1,0 c -1.108,0 -2,-0.892 -2,-2 z m 20,0 c 0,0.0706 -0.0554,0.1188 -0.0625,0.1874 l -1.75,1.75 c -0.0687,0.008 -0.1169,0.0624 -0.1875,0.0624 l -1,0 -0.375,0 -2,0 2,2 1.375,0 c 0.0706,0 0.11882,-0.0554 0.1875,-0.0624 l 1.75,-1.75 C 90.9445,34.36889 91,34.32059 91,34.24999 z m 51.625,1.3125 c -1.79992,-0.0282 -3.64434,0.65818 -5.625,2.6875 l 0,2 c 7.92264,-8.1173 13.88536,5.63196 22,-2 l 0,-2 c -6.08598,5.72396 -10.97525,-0.60276 -16.375,-0.6875 z m 70.75,0 c -5.39976,0.0848 -10.28902,6.41148 -16.375,0.6875 l 0,2 c 8.11464,7.63198 14.07736,-6.1173 22,2 l 0,-2 c -1.98066,-2.02932 -3.82508,-2.71576 -5.625,-2.6875 z m -132.6875,0.6875 -0.0625,0.0624 -1.3125,1.4375 0.9375,1 0.375,-0.4375 2,-2.0625 -1.9375,0 z m 2.375,2.4375 -1,1 3.1875,3.1875 1,-1 z m 10.625,0 -3.1875,3.1875 1,1 3.1875,-3.1875 z m -5.3125,5.3125 -4.25,4.25 -1.0625,-1.125 -1,1 2.0625,2.125 4.25,-4.25 4.25,4.25 2.0625,-2.125 -1,-1 -1.0625,1.125 z m 44.625,4.25 0,2 2,0 0,-2 z m 88,0 0,2 2,0 0,-2 z m 308,38 c -0.69256,0 -1.3433,0.0704 -2,0.1874 -1.97012,0.35122 -3.78902,1.19268 -5.3125,2.375 0.27526,0.01 0.53642,0.0662 0.8125,0.125 0.1164,0.1188 -0.25608,0.39682 -0.625,0.6875 0.63336,-0.48892 1.33168,-0.7194 2.1875,-0.75 0.40586,-0.0824 0.83072,-0.0692 1.1875,0 0.3373,-0.1156 0.71222,-0.165 1.0625,-0.25 -0.44024,-0.1258 0.061,-0.4151 0.5625,-0.4375 0.191,-0.008 0.3289,0.0358 0.4375,0.125 0.22006,0.004 0.5148,-0.21686 0.375,0.0624 0.25094,-0.0294 0.49406,-0.0496 0.75,-0.0624 -0.25748,-0.0812 0.006,-0.2038 0.25,-0.25 0.2137,-0.0404 0.32538,0.004 0.0624,0.1874 0.0854,-0.002 0.1642,0 0.25,0 0.27722,0 0.54052,0.041 0.8125,0.0624 0.0466,-0.0624 0.1156,-0.1456 0.25,-0.25 0.1772,-0.117 0.226,-0.1512 0.25,-0.125 0.054,0.0586 -0.1464,0.39984 -0.0624,0.375 0.028,-0.008 0.071,-0.0822 0.1874,-0.1874 0.55138,-0.1452 1.30082,0.1312 1.6875,0.5625 0.018,0.02 0.0462,0.0418 0.0624,0.0624 0.032,0.0406 0.0372,0.082 0.0624,0.125 0.01,0.018 -0.01,0.0442 0,0.0624 0.0448,0.0876 0.1132,0.1556 0.125,0.25 0.22788,-0.076 0.46198,-0.1072 0.6875,-0.1874 0.0982,0.0354 0.21546,0.0246 0.3125,0.0624 -0.114,0.0368 -0.21658,0.142 -0.3125,0.125 -0.4862,0.36054 0.3743,0.23672 0.875,0.4375 -0.0958,-0.34306 0.1384,-0.84584 0.3125,-0.9375 0.082,-0.0432 0.109,0.0344 0.125,0.25 -0.0256,0.1286 0.034,0.38998 0.0624,0.625 3.60122,1.82902 6.13098,5.40748 6.5,9.625 0.024,-0.31088 0.0624,-0.62034 0.0624,-0.9375 0,-4.72414 -2.71918,-8.79246 -6.6875,-10.75 0.0228,0.29036 0.1182,0.695 -0.0624,0.625 0.21676,-0.9925 -1.885,-0.42026 -1.1875,-0.9375 0.096,0.018 0.1984,-0.0882 0.3125,-0.125 -0.097,-0.0378 -0.2143,-0.0274 -0.3125,-0.0624 -0.53834,0.1922 -1.0891,0.3924 -1.625,0.5 -0.1916,-0.004 -0.4994,-0.038 -0.625,-0.0624 0.0482,-0.012 0.153,-0.0528 0.375,-0.0624 0.1458,-0.198 0.0846,-0.0842 0.3125,-0.25 0.1198,-0.172 1.59284,-0.244 0.375,-0.25 -0.0558,-0.006 -0.038,-0.0564 -0.0624,-0.0624 0.1018,-0.02 0.28324,-0.0384 0.5,-0.0624 -0.52698,-0.1512 -1.07252,-0.28782 -1.625,-0.375 -0.55248,-0.0872 -1.11186,-0.125 -1.6875,-0.125 z m 1.875,0.6875 c 0.21882,-0.004 0.38004,0.0784 -0.0624,0.25 l -0.25,0 c -0.1912,-0.151 0.094,-0.246 0.3125,-0.25 z m -0.6875,0.6875 c 0.0992,-0.014 0.2316,-0.02 0.375,0.0624 0.4787,-0.1182 1.28428,0.0798 0.3125,0.1874 -0.0346,-0.1114 -0.361,0.0696 -0.375,-0.0624 -0.6163,0.1388 -0.6102,-0.1472 -0.3125,-0.1874 z m -192.75,0.25 c -4.03432,0.49932 -7.1875,4.70004 -7.1875,9.6875 0,0.3763 0.027,0.7611 0.0624,1.125 0.37244,-4.90892 3.76768,-8.8125 7.9375,-8.8125 4.16982,0 7.56506,3.90358 7.9375,8.8125 0.0348,-0.36386 0.0624,-0.7487 0.0624,-1.125 0,-5.31996 -3.58134,-9.6875 -8,-9.6875 -0.27616,0 -0.54354,-0.0332 -0.8125,0 z m 191.9375,0.125 c 0.28064,-0.0798 0.53602,0.1352 -0.125,0.1874 -0.0498,0.0662 -0.078,0.002 -0.125,0 0.0642,-0.1082 0.1564,-0.161 0.25,-0.1874 z m -3.125,0.0624 c 0.35978,-0.008 0.52868,0.1018 -0.1874,0.25 -0.23732,0.0308 -0.45478,0.33 -0.6875,0.25 -1.8e-4,-0.3454 0.51552,-0.492 0.875,-0.5 z M 5,86.24999 l 0,2 5,0 19,0 0,-2 z m 80.9375,0.625 c -3.76632,0.1794 -5.852,5.04228 -7.875,9.5625 l -0.4375,1 c -1.61934,3.54196 -3.27284,6.619 -5.9375,6.625 0.7764,0.54006 1.51326,0.9325 2.1875,1.1875 1.48694,-1.13738 2.6243,-3.35024 3.75,-5.8125 l 0.4375,-1 c 2.023,-4.52022 4.10868,-9.38304 7.875,-9.5625 0.66332,-0.0314 1.35376,0.0914 2.125,0.375 0.67344,-0.50032 1.41094,-0.8125 2.25,-0.8125 -1.70742,-1.17832 -3.11956,-1.6221 -4.375,-1.5625 z m 444.9375,0.0624 c -0.21852,0.004 -0.50362,0.099 -0.3125,0.25 l 0.25,0 c 0.44264,-0.1716 0.28132,-0.25364 0.0624,-0.25 z m 1,0.3125 c -0.0406,0.0282 -0.0508,0.0534 -0.0624,0.125 0.1448,-0.0388 0.29196,-0.0782 0.4375,-0.125 -0.152,-0.0206 -0.31398,-0.0422 -0.375,0 z m -1.6875,0.375 c -0.24742,0.0336 -0.28268,0.262 0.0624,0.25 0.0702,-0.002 0.1458,-0.0392 0.25,-0.0624 0.014,0.132 0.3404,-0.049 0.375,0.0624 0.175,-0.02 0.24048,-0.0396 0.3125,-0.0624 -0.014,-0.0636 -0.0826,-0.079 -0.125,-0.125 -0.1594,-0.021 -0.32592,-0.043 -0.5,0 -0.1434,-0.0816 -0.27576,-0.076 -0.375,-0.0624 z m 4.0625,0.3125 c 0.008,0.058 0.016,0.113 0,0.1874 0.0768,0.0298 0.1212,-0.0286 0.125,-0.125 -0.0288,0.002 -0.076,-0.0292 -0.125,-0.0624 z m -4.875,0.0624 c -0.0936,0.0266 -0.1858,0.0792 -0.25,0.1874 0.047,0.002 0.0752,0.0662 0.125,0 0.66102,-0.0526 0.40564,-0.26736 0.125,-0.1874 z m -0.6875,0.0624 c -0.24424,0.0462 -0.50748,0.1688 -0.25,0.25 l 0.0624,0.0624 0.1874,-0.0624 c 0.45844,-0.26664 0.24424,-0.29614 0,-0.25 z m 2.125,0.0624 c 0.13,0.1836 0.2144,0.42602 0.375,0.4375 0.1974,-0.23204 0.3534,-0.27744 0.4375,-0.25 -0.2566,-0.1334 -0.53572,-0.1804 -0.8125,-0.1874 z m -3.125,0.0629 c -0.0566,0.012 -0.1614,0.0378 -0.25,0.0624 -0.21282,0.1826 -0.29066,0.38262 -0.125,0.5625 0.46282,-0.0644 0.7947,-0.1386 0.3125,-0.3125 0.1618,-0.2552 0.1498,-0.3299 0.0624,-0.3125 z M 529,88.43739 c -0.0486,-0.01 -0.1174,0.0278 -0.1874,0.0624 -0.0774,0.47708 -0.54184,0.55402 -1.0625,0.5625 0.37506,0.1206 0.69232,0.2438 0.6875,0.625 0.69802,0.0428 0.1254,-0.4624 0.75,-0.375 0.0748,-0.0954 0.119,-0.20842 0.1874,-0.3125 -0.1478,-0.115 -0.1596,-0.52188 -0.375,-0.5625 z m 2.75,0 c 0.0686,0.23898 0.018,0.70016 0.125,0.8125 0.0814,-0.0564 0.24754,-0.043 0.5,0 -0.014,-0.33412 -0.28984,-0.59918 -0.625,-0.8125 z m -11.9375,0.125 c -1.74562,2.084 -2.8125,4.7563 -2.8125,7.6875 0,0.41422 0.0218,0.8466 0.0624,1.25 0.1,-1.55766 0.48326,-3.03742 1.125,-4.375 -0.0268,-0.004 -0.042,-0.0302 -0.0624,-0.125 0.0768,-0.1358 0.1644,-0.2016 0.1874,-0.1874 0.41412,-0.80346 0.9243,-1.5627 1.5,-2.25 0.5131,-0.0316 1.1203,0.157 1.375,0.5 0.0594,-0.0338 0.1376,-0.0668 0.1874,-0.0624 0.084,-0.197 0.16,-0.33974 0.25,-0.375 -0.66688,-0.37672 -0.3358,-0.73218 -0.1874,-1.125 -0.018,0.0232 -0.0636,0.0264 -0.125,-0.0624 0.0486,-0.6189 -0.81588,-0.9172 -1.5,-0.875 z m 8.5,0.125 c -0.0588,0.014 -0.1354,0.0824 -0.1874,0.1874 0.47002,0.061 0.36394,-0.22806 0.1874,-0.1874 z m 5.9375,0 c -0.2458,0.1294 -0.61728,1.13374 0,1.25 0.39282,0.26594 0.0686,-0.71754 0.125,-1 -0.016,-0.21566 -0.043,-0.29312 -0.125,-0.25 z m -12.8125,0.3125 c -0.018,0.0652 -0.006,0.1838 0,0.3125 0.016,-0.08 0.0784,-0.163 0.0624,-0.25 -0.002,-0.0344 -0.0508,-0.0342 -0.0624,-0.0624 z M 521,89.37499 c 0.0528,-0.038 0.1936,0.1526 0,0.125 -0.014,-0.083 -0.018,-0.113 0,-0.125 z m 9.75,0.6875 c -0.4747,-0.016 -1.40434,0.81586 -0.4375,0.3125 0.88806,-0.32008 -0.4054,1.41986 -0.25,0.25 l -0.0624,0.125 c -0.0434,0.6201 -1.0938,1.0026 -1.125,1.125 -0.61556,0.1764 -0.7655,0.8281 -0.9375,0.6875 0.1376,0.9662 -1.74792,1.00622 -1.0625,2.1875 -0.0276,0.0308 -0.0422,0.4309 -0.1874,0.3125 -0.0218,-0.788 -0.74162,-1.22536 -1.4375,-0.875 0.0326,0.0244 0.0484,0.0464 0.0624,0.0624 -0.2077,0.014 -1.0234,-0.154 -1.125,0.25 -0.20344,0.2702 -0.3476,0.4822 -0.5,0.375 0.1152,0.28484 0.1466,0.65044 0,0.875 -0.01,0.47402 0.26298,0.6655 0.5625,0.6875 0.008,-0.014 0.0516,0.012 0.0624,0 0.1232,-0.1296 0.27078,-0.193 0.5,-0.1874 0.1208,-0.0974 0.25052,-0.2206 0.3125,-0.375 0.28392,-0.0468 0.33792,0.0804 0.3125,0.25 0.62754,-0.1842 1.23028,0.22482 1.25,0.9375 0.1454,0.1184 0.1598,-0.2817 0.1874,-0.3125 -0.24332,-0.41936 -0.1364,-0.6508 0.0624,-0.875 -0.008,-0.004 0.008,-0.0594 0,-0.0624 -0.36076,-0.147 -0.75074,-0.2454 -0.875,-0.1874 0.0204,-0.058 0.048,-0.105 0.125,-0.125 0.20426,-0.0506 0.54864,0.0782 0.875,0.1874 0.38522,-0.32534 0.9524,-0.58152 0.875,-1.125 0.172,0.1406 0.32194,-0.5111 0.9375,-0.6875 0.0312,-0.1224 1.0816,-0.5049 1.125,-1.125 l 0.0624,-0.125 c -0.1554,1.16986 1.13806,-0.57008 0.25,-0.25 -0.96684,0.50336 -0.0372,-0.3285 0.4375,-0.3125 0.4678,0.2063 2.26864,-0.6598 1.1875,-0.75 -0.1634,0.004 -0.1146,-0.50876 -0.1874,-0.8125 -0.004,-0.014 -0.0588,0.012 -0.0624,0 -0.0896,0.01 -0.0482,-0.038 0,-0.125 -0.0792,-0.1028 -0.24344,-0.1142 -0.5,0.1874 -0.182,-0.014 -0.28042,-0.30256 -0.4375,-0.5 z m -9.6875,0.3125 c 0.1304,0.008 0.68106,0.58022 0.0624,0.25 -0.1114,-0.1702 -0.106,-0.252 -0.0624,-0.25 z m 9.75,0.375 c 0.1106,0.004 0.012,0.1536 -0.1874,0.0624 0.0854,-0.0422 0.1508,-0.064 0.1874,-0.0624 z m 0.4375,0 c -0.0322,0.0338 -0.1794,0.1596 -0.5,0.3125 -0.196,0.0456 -0.35624,0.24964 -0.5625,0.25 0.108,-0.21958 0.60114,-0.4246 0.875,-0.5 0.137,-0.0376 0.21974,-0.0962 0.1874,-0.0624 z m 0.875,1.1875 c -0.1962,0.012 -0.6963,0.5901 -0.4375,0.5625 0.26674,0.0532 1.28608,-0.02 0.5,-0.3125 0.042,-0.1718 0.002,-0.25394 -0.0624,-0.25 z M 7.1875,92.24999 C 7.0803,92.55863 7,92.90481 7,93.24999 c 0,1.65684 1.34314,3 3,3 1.65686,0 3,-1.34316 3,-3 0,-0.34518 -0.0803,-0.69136 -0.1875,-1 -0.40768,1.17282 -1.50082,2 -2.8125,2 -1.31168,0 -2.40482,-0.82718 -2.8125,-2 z m 187.8125,6 0,2 28,0 0,-2 z m 202,-6 0,2 20,0 0,-2 z m 52,0 0,2 20,0 0,-2 z m 81.8125,0.5 c -0.0368,-10e-4 -0.102,0.0204 -0.1874,0.0624 0.1988,0.091 0.29812,-0.0584 0.1874,-0.0624 z m 0.4375,0 c 0.0322,-0.0338 -0.0506,0.0248 -0.1874,0.0624 -0.27386,0.0754 -0.76696,0.28042 -0.875,0.5 0.20626,-3.6e-4 0.3665,-0.2044 0.5625,-0.25 0.3205,-0.1528 0.46776,-0.2788 0.5,-0.3125 z m -10.5625,0.875 c -0.22246,0.365 -0.3912,0.81888 -0.375,1.125 -0.012,0.56448 0.30326,0.95122 0.75,1.125 -0.3329,0.1258 -0.159,0.98346 0.1874,1.25 0.468,1.18256 0.1572,-0.43984 -0.125,-0.8125 0.2368,-0.83736 0.57308,0.98262 1,1.1875 0.0918,0.80042 0.61308,1.1848 1.375,1.4375 0.3448,0.014 0.85392,0.1808 1.125,0 -0.1144,0.1878 -0.1086,0.4022 0.1874,0.4375 0.0994,0.0332 0.3663,0.1438 0.4375,0 0.0736,0.035 0.20296,0.0394 0.3125,-0.0624 0.0864,-0.0396 0.0722,0.0248 0.125,0 -0.2373,0.177 -0.49338,0.4631 0.0624,0.5625 0.36394,0.24396 0.43882,-1.19764 -0.0624,-0.9375 -0.54106,-0.1528 -0.63648,0.2037 -0.5,0.375 -0.31492,0.0822 -0.22638,-0.24442 -0.0624,-0.5625 -0.0262,-0.1756 -0.2214,-0.0922 -0.375,0.0624 0.0328,-0.0538 0.0508,-0.1042 0.0624,-0.1874 0.1874,-0.1436 0.25076,-0.22424 0.3125,-0.25 0.13,-0.0544 0.0608,0.1652 0,0.375 0.23602,-0.45812 0.60936,-0.97536 0,-0.875 -0.29272,0.72914 -1.4583,0.88626 -1.4375,-0.125 0.137,-0.20974 0.0968,-0.53742 0,-0.8125 -0.0638,-0.008 -0.1308,0.002 -0.1874,0 -0.76192,-0.2527 -1.2832,-0.63708 -1.375,-1.4375 -0.42692,-0.20488 -0.7632,-2.02486 -1,-1.1875 0.2822,0.37266 0.593,1.99506 0.125,0.8125 -0.3464,-0.26654 -0.5205,-1.1242 -0.1874,-1.25 -0.1396,-0.0544 -0.26704,-0.1552 -0.375,-0.25 z M 85.625,94.31249 c -0.3632,0.63758 -0.71926,1.28342 -1.0625,2 l 3,0 c 0.0418,0 0.0854,-0.006 0.125,0 l 0.75,-1 c 0,-0.53432 -0.35934,-1 -0.875,-1 z m 432.6875,0.5 c -0.0232,-0.014 -0.1106,0.0516 -0.1874,0.1874 0.0828,0.379 0.25718,-0.1458 0.1874,-0.1874 z M 325,96.37499 c -0.041,0.38574 -0.0624,0.79256 -0.0624,1.1875 0,4.19556 2.39458,7.85152 6,10 l 2,0 0,-1 c -4.43774,-1.75698 -7.59398,-5.61262 -7.9375,-10.1875 z m 26.5625,0 c -0.34352,4.57488 -3.49976,8.43054 -7.9375,10.1875 l 0,1 2,0 c 3.60542,-2.14846 6,-5.80444 6,-10 0,-0.39494 -0.021,-0.80176 -0.0624,-1.1875 z m -284.5,0.875 c -0.0234,0.33046 -0.0625,0.66362 -0.0625,1 0,7.73036 6.26966,14 14,14 7.73266,0 14,-6.26964 14,-14 0,-0.33638 -0.0392,-0.66954 -0.0625,-1 -0.513,7.26368 -6.54132,13 -13.9375,13 -7.39396,0 -13.42432,-5.73632 -13.9375,-13 z m 448,0 c -0.0234,0.33046 -0.0624,0.66362 -0.0624,1 0,7.73032 6.26968,14 14,14 7.73032,0 14,-6.26968 14,-14 0,-0.33638 -0.0394,-0.66954 -0.0624,-1 -0.46436,6.57258 -5.44906,11.85938 -11.875,12.8125 -0.4944,0.0734 -0.99018,0.1674 -1.5,0.1874 -0.1868,0.008 -0.3738,0 -0.5625,0 -0.47802,0 -0.97408,-0.008 -1.4375,-0.0624 -0.34256,-0.0348 -0.66518,-0.1284 -1,-0.1874 -6.24378,-1.10146 -11.04476,-6.30652 -11.5,-12.75 z m 11.125,0.2498 c -0.077,0.02 -0.1046,0.067 -0.125,0.125 0.1892,-0.088 0.98422,0.30108 1.375,0.4375 0.0502,-0.048 0.1326,-0.083 0.1874,-0.125 -0.2407,-0.1964 -1.0742,-0.52764 -1.4375,-0.4375 z M 397,98.24999 l 0,2 6,0 0,-2 z m 8,0 0,2 6,0 0,-2 z m 8,0 0,2 4,0 0,-2 z m 36,0 0,2 4,0 0,-2 z m 6,0 0,2 6,0 0,-2 z m 8,0 0,2 6,0 0,-2 z m -69.125,0.125 -6.875,5.875 0,2 8,-6.875 z m 78.25,0 -1.125,1 8,6.875 0,-2 z m 54.875,0 c -0.016,0.006 -0.024,0.0244 0,0.0624 0.1792,0.0406 0.1756,0.016 0.1874,0 -0.006,-0.004 0.006,-0.0596 0,-0.0624 -0.042,-0.018 -0.0882,-0.002 -0.125,0 4.2e-4,0.008 -0.0538,-0.008 -0.0624,0 z m -1.4375,1.5625 c -0.0208,0.0338 0.0212,0.104 0.3125,0.3125 0.72356,0.0502 -0.25022,-0.41404 -0.3125,-0.3125 z m 0.6875,0.3125 c -0.0844,0.0334 -0.0784,0.079 0.0624,0.1874 0.0798,0.0986 0.1792,0.0634 0.25,0 0.008,-0.059 0.0422,-0.1256 0.0624,-0.1874 -0.1424,-0.014 -0.29388,-0.032 -0.375,0 z m 0.6875,1.3125 c -0.21608,0.5116 -0.56674,0.94698 -0.25,1.3125 0.32506,-0.014 0.74812,0.01 1.1875,0.125 -0.29524,-0.45062 -0.63082,-0.92572 -0.9375,-1.4375 z m 0.9375,1.4375 c 0.1062,0.1622 0.2155,0.3346 0.3125,0.5 0.27394,0.0348 0.46806,0.0918 0.8125,0.125 -0.2253,-0.3355 -0.66438,-0.5042 -1.125,-0.625 z m 0.3125,0.5 c -0.71494,-0.091 -1.12254,-0.1652 -1.4375,-0.25 0.36268,0.64794 0.76972,1.20772 1.125,1.75 0.42838,0.1124 0.82602,0.27166 1.0625,0.5625 -0.002,-0.0218 0.002,-0.0406 0,-0.0624 -0.12,-0.79752 -0.40364,-1.4102 -0.75,-2 z m -0.3125,1.5 c -1.44116,-0.37804 -3.05142,0.0718 0.3125,0.5 -0.097,-0.1654 -0.20624,-0.33782 -0.3125,-0.5 z m 0.3125,0.5 c 0.34636,0.5898 0.6299,1.20248 0.75,2 0.0348,0.27152 0.079,0.49982 0.125,0.75 0.1664,0.001 0.33662,0.008 0.5,0 -0.23462,-0.71904 -0.48382,-1.5963 -0.625,-2.625 -0.29886,-0.0338 -0.49664,-0.0928 -0.75,-0.125 z m 6,-3 c -0.0896,0.66934 0.0626,1.51078 -0.625,1.75 -1.18836,0.1604 -0.61708,1.64512 -1.4375,2.3125 -0.1462,0.1566 -0.2899,-0.0208 -0.4375,-0.0624 -0.1068,-0.0438 -0.2054,-0.1026 -0.25,-0.1874 0.014,0.25332 0.0826,0.4864 0.375,0.6875 -0.0474,0.57024 -0.8714,0.25418 -0.75,0.875 -0.002,0.0744 0.004,0.1174 0,0.1874 0.1304,-0.0224 0.24604,-0.0984 0.375,-0.125 0.045,-0.24406 0.1664,-0.24266 0.125,0 0.34084,-0.0738 0.67074,-0.21048 1,-0.3125 0.1492,-0.63252 0.23106,-1.2712 1,-1.375 0.94272,-0.328 0.28718,-1.7511 0.875,-2.375 0.65362,-0.58222 0.30764,-1.09524 -0.25,-1.375 z m -2.75,3.8125 c 0.3155,-0.69854 -0.0454,-0.80536 0,0 z M 3,108.24999 l 0,2 28,0 0,-2 -26,0 z m 394,0 0,2 20,0 0,-2 z m 52,0 0,2 20,0 0,-2 z m -124.0625,0.625 0,2 c 0,0.73866 0.57384,1.3125 1.3125,1.3125 l 8,0 c 0.736,0 1.375,-0.5765 1.375,-1.3125 l 0,-1.5625 0,-0.4375 c 0,0.736 -0.639,1.3125 -1.375,1.3125 l -8,0 c -0.73866,0 -1.3125,-0.57384 -1.3125,-1.3125 z m 16,0 0,0.4375 0,1.5625 c 0,0.736 0.5765,1.3125 1.3125,1.3125 l 8,0 c 0.1848,0 0.34038,0.004 0.5,-0.0624 0.47852,-0.2024 0.875,-0.698 0.875,-1.25 l 0,-2 c 0,0.552 -0.39648,1.0476 -0.875,1.25 -0.1596,0.0664 -0.3152,0.0624 -0.5,0.0624 l -8,0 c -0.736,0 -1.3125,-0.5765 -1.3125,-1.3125 z m -143.9375,1.375 0,2 24,0 0,-2 z m -117.75,40.6875 -0.3125,0.875 -7.25,17.75 0.8125,0 6.4375,-15.75 0.3125,-0.875 3.625,0 0.1875,0.4375 6.5,16.1875 0.8125,0 -7.3125,-18.1875 -0.1875,-0.4375 z m -61.66613,2.81074 -2,5.375 0.75,0 1.25,-3.375 1.125,3.375 0.6875,0 z m -3.4375,9.4375 -1.8125,5 -4.1875,0 c -0.2717,0.66452 -0.54614,1.34944 -0.8125,2 l 5,0 1.8125,-5 6.6875,0 1.625,5 5.25,0 c -0.26312,-0.65902 -0.54458,-1.33248 -0.8125,-2 l -4.4375,0 -1.625,-5 z m 65.04113,-0.68574 -0.5625,1.0625 c 0,0.64304 0.5445,1.1875 1.1875,1.1875 l 2.3125,0 c 0.64302,0 1.18576,-0.54446 1.1875,-1.1875 l -0.5625,-1.0625 c -0.1896,0.1296 -0.38386,0.25 -0.625,0.25 l -2.3125,0 c -0.24112,0 -0.4351,-0.1204 -0.625,-0.25 z M 67,169.56249 l 0,2 c 0,2.57212 2.1154,4.6875 4.6875,4.6875 l 18.625,0 c 2.57212,0 4.625,-2.11538 4.625,-4.6875 l 0,-2 c 0,2.57212 -2.05288,4.6875 -4.625,4.6875 l -18.625,0 c -2.5721,0 -4.6875,-2.11538 -4.6875,-4.6875 z m -62.0625,4.6875 0,2 26.0625,0 0,-2 z m 6.1875,38 -1.125,1.25 0.9375,0.9375 2.0625,-2.1875 z m 9.875,0 2.0625,2.1875 0.9375,-0.9375 -1.125,-1.25 z m 47,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 7,0 c -1.108,0 -2,0.892 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 44,0 c -1.108,0 -2,0.892 -2,2 l 0,2 c 0,-1.108 0.892,-2 2,-2 1.108,0 2,0.892 2,2 l 0,-2 c 0,-1.108 -0.892,-2 -2,-2 z m 7,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -90,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 58,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -152,1.25 -3,2.75 0,2 3,-2.75 4,4 4,0 0,-2 -4,0 z m 22,0 -4,4 -4,0 0,2 4,0 4,-4 3,2.75 0,-2 z m 40,2.75 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 58,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -90,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 58,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -90,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 58,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -144,2.75 -4,4 0.9375,1.0625 3.0625,-3.0625 z m 6,0 0,2 3.0625,3.0625 0.9375,-1.0625 z m 51,1.25 c -1.108,0 -2,0.892 -2,2 0,0.3758 0.1336,0.70026 0.3125,1 0.34846,-0.58398 0.9553,-1 1.6875,-1 l 10,0 c 0.7322,0 1.33904,0.41602 1.6875,1 0.1788,-0.29974 0.3125,-0.6242 0.3125,-1 0,-1.108 -0.892,-2 -2,-2 z m 74,0 c -1.108,0 -2,0.892 -2,2 0,0.3758 0.13364,0.70026 0.3125,1 0.34847,-0.58398 0.9553,-1 1.6875,-1 l 10,0 c 0.7322,0 1.33903,0.41602 1.6875,1 0.17886,-0.29974 0.3125,-0.6242 0.3125,-1 0,-1.108 -0.892,-2 -2,-2 z m -58,2 0,2 c 0,2.1814 1.8186,4 4,4 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 -2.1814,0 -4,-1.8186 -4,-4 z m 44,0 0,2 c 0,2.1814 1.8186,4 4,4 2.1814,0 4,-1.8186 4,-4 l 0,-2 c 0,2.1814 -1.8186,4 -4,4 -2.1814,0 -4,-1.8186 -4,-4 z m -63.875,1 c -0.0832,0.31758 -0.125,0.65916 -0.125,1 0,2.1814 1.8186,4 4,4 l 10,0 c 2.1814,0 4,-1.8186 4,-4 0,-0.34084 -0.0418,-0.68242 -0.125,-1 -0.44952,1.7149 -2.03444,3 -3.875,3 l -10,0 c -1.84056,0 -3.42548,-1.2851 -3.875,-3 z m 74,0 c -0.0832,0.31758 -0.125,0.65916 -0.125,1 0,2.1814 1.8186,4 4,4 l 10,0 c 2.1814,0 4,-1.8186 4,-4 0,-0.34084 -0.0418,-0.68242 -0.125,-1 -0.44953,1.7149 -2.03444,3 -3.875,3 l -10,0 c -1.84056,0 -3.42547,-1.2851 -3.875,-3 z m -138.125,3 0,2 10,0 -1.875,-2 z m 19.875,0 -1.875,2 10,0 0,-2 z m -5.0625,40.5625 c -2.53002,0 -4.625,2.09498 -4.625,4.625 l -4.3125,0 c -0.142,0.6402 -0.25,1.318 -0.25,2 l 4.5625,0 c 0,-2.53002 2.09498,-4.625 4.625,-4.625 2.19372,0 4.05502,1.55698 4.5,3.625 0.0686,-0.3161 0.0625,-0.66256 0.0625,-1 0,-2.53002 -2.03248,-4.625 -4.5625,-4.625 z m 9.0625,5.75 c -0.46388,3.76028 -3.21444,6.8218 -6.8125,7.75 l 0,0.25 c 0,1.265 -0.985,2.3125 -2.25,2.3125 -1.265,0 -2.3125,-1.0475 -2.3125,-2.3125 l 0,1.75 0,0.25 c 0,0.82104 0.4694,1.52664 1.125,1.9375 0.36744,-0.1472 0.7662,-0.25 1.1875,-0.25 0.4213,0 0.82006,0.1028 1.1875,0.25 0.63712,-0.41086 1.0625,-1.11646 1.0625,-1.9375 l 0,-0.25 c 3.95314,-1.0198 6.875,-4.60562 6.875,-8.875 0,-0.29446 -0.0357,-0.5875 -0.0625,-0.875 z m -12.0625,15.875 c -0.1058,0.31798 -0.1875,0.64554 -0.1875,1 0,1.76616 1.42132,3.25 3.1875,3.25 1.76618,0 3.1875,-1.48384 3.1875,-3.25 0,-0.35446 -0.0819,-0.68202 -0.1875,-1 -0.42134,1.28246 -1.58826,2.25 -3,2.25 -1.41174,0 -2.57866,-0.96754 -3,-2.25 z"
1748 id="path5248"
1749 inkscape:connector-curvature="0"
1750 sodipodi:nodetypes="ccccccsssscssccsscsscsssssssssscccccccssssssscccsscsccccccssccsccsccsscccccccsccccccsccccccccccccccccccccccccccccccccccccccccccccccccsscscsssscscsscscsssccssscscsscscsscccsccsscssccscscccccccccccccsscsscssssccscscscccssscsccscssssscsccscssssscsscssssscsscssssscsccccccccsccccsscsccscsssccccccccccscccccccssscsssccscccscccsccccccsscccccccccccccsssccccccccccccccccccccccccccccccccccccccccssscsccssscccscccccsssscssccsssscssccccccccccccccccccccccccccsccssscsscccccccccsssscsscssssscccscssssscccccsssscssccsssscssccssccsccccccccccccccccccsssscssccsssscsscssssssccscsssscccscccccsccccsssscscccccscccccccccccccccccccccccccsssccscccccccccccccccccccccccccccccccccccscccccccccccscccssccccccccccccscccccccccssssscscccccscccccccccccccsccccccccscccccccccscccccscsccsscsscccscsccsscsscccccsccscccccsscccscccccccccccscccssccccccccsssssssccccccccccccssssscscssssssssssccssssssssssssssscscccccsssssssssssssscccccccccccscssccccsssccsssscssssssssscssssssssssssssssssssssssssssscssssssssscssssssssssssssscccccccccccccccccccccccccccccccssscsccssscscsssssssssssssssssssssssssssscsccccsccccsccsccsccsccccscccccsccsssssssssssssssssssssssssssssssssssscssscsccssscsccccccccccccccccccccccccccccccccscsscscccsssscssssssssscssssscccccccssssccssssccsccccccsssscssssssssscsssssssssccsccccccccccccccccsssccssssssssssssssssssccssssssssssssssssssssssssssssssssssssssssssssssssssscccccccccccccccccccccccscccsccsccccscccsccsccssscsccssscscsssssssssssssssssssssssssssssssssccsssccsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssscccccccccccccccccccccccccccccccccccccccccssssscsccssssscsccssscsccssscsccssscsccssscscscscsccsccscsccsccscscsccsccsscccsccccsccsccssssssccssssccsssccscsscccsscccscccsccccsscccsccscccssccssccccsccccsscccsccccsccccsccscccccccsccccscccccccccccccccccccccccccccccccccccccccccccccccccccccsccccccccccccccccccsccccccccccccccccccccccccccscscsscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccssscscccccccccccccccccccccccccccccccccccccccccccccccccccccccccsccscccccscccccccccscccssscsccssscccscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccssssccsscccssscsccsscccccccccccccccccccccccccccccccccccccccccssccssccsssscssccccccccccccccccssssssssssssssssssssssssssscscsssscscsssssssssssssssssssssssssssssssssssssssssssssssccccccccccccccccccssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssccccccccccsscsscssssscsscssscssscsccssscsccsssscssccsssscsscccccccccccsccccscssccssccscscscsccssscsc" /><path
1751 sodipodi:nodetypes="sssss"
1752 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1753 d="m 81,276.11885 c -7.73034,0 -14,6.3004 -14,14.06864 0,7.76824 6.26966,14.06862 14,14.06862 7.73266,0 14,-6.30038 14,-14.06862 0,-7.76824 -6.26734,-14.06864 -14,-14.06864 z"
1754 id="path4290-7"
1755 inkscape:connector-curvature="0" /><path
1756 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1757 d="m 197,-363.81251 0,28 22,0 0,-18 0,-2 -8,-8 -2,0 z m 2,2 11,0 7,7 0,17 -10,0 -6,0 -2,0 z"
1758 id="path4249"
1759 inkscape:connector-curvature="0"
1760 sodipodi:nodetypes="cccccccccccccccc" /><path
1761 sodipodi:nodetypes="cccccccccccccccc"
1762 inkscape:connector-curvature="0"
1763 id="path4303"
1764 d="m 283,-363.81251 0,28 -22,0 0,-18 0,-2 8,-8 2,0 z m -2,2 -11,0 -7,7 0,17 10,0 6,0 2,0 z"
1765 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1766 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1767 d="m 93,-363.81251 0,28 -22,0 0,-18 0,-2 8,-8 2,0 z m -2,2 -11,0 -7,7 0,17 10,0 6,0 2,0 z"
1768 id="path4305"
1769 inkscape:connector-curvature="0"
1770 sodipodi:nodetypes="cccccccccccccccc" /><path
1771 sodipodi:nodetypes="cccccccccccccccc"
1772 inkscape:connector-curvature="0"
1773 id="path4307"
1774 d="m 5,-363.81251 0,28 22,0 0,-18 0,-2 -8,-8 -2,0 z m 2,2 11,0 7,7 0,17 -10,0 -6,0 -2,0 z"
1775 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1776 sodipodi:nodetypes="cccccccccccccccc"
1777 inkscape:connector-curvature="0"
1778 id="path4311"
1779 d="m 517,-363.81251 0,28 22,0 0,-18 0,-2 -8,-8 -2,0 z m 2,2 11,0 7,7 0,17 -10,0 -6,0 -2,0 z"
1780 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline" /><path
1781 inkscape:connector-curvature="0"
1782 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1783 d="m 581,-363.75001 0,9.5 c 0.38292,-0.24029 0.74124,-0.44168 1.125,-0.625 l 0.875,-0.4375 0,-6.4375 10.6875,0 7.3125,7.3125 0,16.6875 -10,0 0,1.9375 c 0,0.0209 3.2e-4,0.0417 0,0.0625 l 12,0 0,-18 0,-2 -8,-8 -2,0 -12,0 z m 2,10.6875 c -0.72246,0.34511 -1.37784,0.75283 -1.9375,1.3125 -1.26676,1.26675 -2.0625,3.067 -2.0625,5 0,2.78704 1.6474,5.12879 4,6.25 l 0,4.6875 c 0,1.108 0.89198,2 2,2 l 2,0.0625 c 1.108,0 2,-0.9545 2,-2.0625 l 0,-4.6875 c 2.35258,-1.12121 4,-3.46296 4,-6.25 0,-2.78704 -1.64238,-5.18627 -4,-6.3125 l 0,5.3125 -2.9375,2 -3.0625,-2 0,-5.3125 z"
1784 id="path5011-3" /><path
1785 id="path4415"
1786 d="m 667,-363.75001 0,9.5 c -0.38292,-0.24029 -0.74124,-0.44168 -1.125,-0.625 l -0.875,-0.4375 0,-6.4375 -10.6875,0 -7.3125,7.3125 0,16.6875 10,0 0,1.9375 c 0,0.0209 -3.2e-4,0.0417 0,0.0625 l -12,0 0,-18 0,-2 8,-8 2,0 12,0 z m -2,10.6875 c 0.72246,0.34511 1.37784,0.75283 1.9375,1.3125 1.26676,1.26675 2.0625,3.067 2.0625,5 0,2.78704 -1.6474,5.12879 -4,6.25 l 0,4.6875 c 0,1.108 -0.89198,2 -2,2 l -2,0.0625 c -1.108,0 -2,-0.9545 -2,-2.0625 l 0,-4.6875 c -2.35258,-1.12121 -4,-3.46296 -4,-6.25 0,-2.78704 1.64238,-5.18627 4,-6.3125 l 0,5.3125 2.9375,2 3.0625,-2 0,-5.3125 z"
1787 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1788 inkscape:connector-curvature="0" /><path
1789 inkscape:connector-curvature="0"
1790 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1791 d="m 325,-363.81251 0,28 17.625,0 -2,-2 -2.625,0 -3,0 -6,0 -2,0 0,-24 11,0 7,7 0,2.4375 c 1.22936,1.53978 2,3.45759 2,5.5625 l 0,-7 0,-2 -8,-8 -2,0 -12,0 z m 22,17 c 0,0.96638 -0.40154,1.72552 -0.6875,2.5625 l 0.6875,0.6875 0,-3.25 z m -9,-7 c -3.8423,0 -7,3.15768 -7,7 0,3.8423 3.1577,7 7,7 0.99078,0 1.89266,-0.24748 2.75,-0.625 l 4.6875,4.6875 3.25,-3.25 -4.5625,-4.5625 c 0.533,-0.9857 0.875,-2.0592 0.875,-3.25 0,-3.84232 -3.1577,-7 -7,-7 z m -0.0624,2 c 2.76142,0 5,2.23858 5,5 0,2.76142 -2.23858,5 -5,5 -2.76142,0 -5,-2.23858 -5,-5 0,-2.76142 2.23858,-5 5,-5 z"
1792 id="path4953-8" /><path
1793 id="path4243"
1794 d="m 413,-363.81251 0,28 -17.625,0 2,-2 2.625,0 3,0 6,0 2,0 0,-24 -11,0 -7,7 0,2.4375 c -1.22936,1.53978 -2,3.45759 -2,5.5625 l 0,-7 0,-2 8,-8 2,0 12,0 z m -22,17 c 0,0.96638 0.40154,1.72552 0.6875,2.5625 l -0.6875,0.6875 0,-3.25 z m 9,-7 c 3.8423,0 7,3.15768 7,7 0,3.8423 -3.1577,7 -7,7 -0.99078,0 -1.89266,-0.24748 -2.75,-0.625 l -4.6875,4.6875 -3.25,-3.25 4.5625,-4.5625 c -0.533,-0.9857 -0.875,-2.0592 -0.875,-3.25 0,-3.84232 3.1577,-7 7,-7 z m 0.0624,2 c -2.76142,0 -5,2.23858 -5,5 0,2.76142 2.23858,5 5,5 2.76142,0 5,-2.23858 5,-5 0,-2.76142 -2.23858,-5 -5,-5 z"
1795 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1796 inkscape:connector-curvature="0" /><path
1797 inkscape:connector-curvature="0"
1798 style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1799 d="m 67,-301.81251 0,20 6,0 0,-2 -2,0 -2,0 0,-16 9,0 5,5 0,1 2,0 0,-2 -6,-6 -2,0 -10,0 z m 8,10 0,20 18,0 0,-12 0,-2 -6,-6 -2,0 -10,0 z m 2,2 9,0 5,5 0,11 -10,0 -2,0 -2,0 0,-16 z"
1800 id="path3594-7" /><path
1801 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1802 d="m 142.0625,-301.81251 c -0.58921,0 -1.0625,0.47329 -1.0625,1.0625 l 0,0.9375 -0.9375,0 c -0.58921,0 -1.0625,0.47329 -1.0625,1.0625 l 0,1.875 c 0,0.58921 0.47329,1.0625 1.0625,1.0625 l 2,0 5.875,0 2,0 c 0.58921,0 1.0625,-0.47329 1.0625,-1.0625 l 0,-1.875 c 0,-0.58921 -0.47329,-1.0625 -1.0625,-1.0625 l -0.9375,0 0,-0.9375 c 0,-0.58921 -0.47329,-1.0625 -1.0625,-1.0625 z m -5.0625,2 c -2.18141,0 -4,1.81859 -4,4 l 0,18 c 0,2.18141 1.81859,4 4,4 l 2,0 0,-2 -2,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-18 c 0,-1.108 0.892,-2 2,-2 l 0,-0.9375 c 0,-0.36716 0.0632,-0.73321 0.1875,-1.0625 z m 15.8125,0 c 0.12429,0.32929 0.1875,0.69534 0.1875,1.0625 l 0,0.9375 c 1.108,0 2,0.892 2,2 l 0,4 2,0 0,-4 c 0,-2.18141 -1.81859,-4 -4,-4 z m -9.8125,24 c -1.108,0 -2,2 -2,2 l 0,0 c 0,0 0.892,2 2,2 l 14,0 c 1.108,0 2,-2 2,-2 l 0,0 c 0,0 -0.892,-2 -2,-2 z"
1803 id="rect4963-2"
1804 inkscape:connector-curvature="0"
1805 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccsscsssssssss" /><path
1806 inkscape:connector-curvature="0"
1807 id="path4569"
1808 d="m 206.0625,-301.81251 c -0.58922,0 -1.0625,0.47329 -1.0625,1.0625 l 0,0.9375 -0.9375,0 c -0.58922,0 -1.0625,0.47329 -1.0625,1.0625 l 0,1.875 c 0,0.58921 0.47328,1.0625 1.0625,1.0625 l 2,0 5.875,0 2,0 c 0.58922,0 1.0625,-0.47329 1.0625,-1.0625 l 0,-1.875 c 0,-0.58921 -0.47328,-1.0625 -1.0625,-1.0625 l -0.9375,0 0,-0.9375 c 0,-0.58921 -0.47328,-1.0625 -1.0625,-1.0625 z m -5.0625,2 c -2.18141,0 -4,1.81859 -4,4 l 0,18 c 0,2.18141 1.81859,4 4,4 l 2,0 0,-2 -2,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-18 c 0,-1.108 0.892,-2 2,-2 l 0,-0.9375 c 0,-0.36716 0.0632,-0.73321 0.1874,-1.0625 z m 15.8125,0 c 0.1243,0.32929 0.1875,0.69534 0.1875,1.0625 l 0,0.9375 c 1.108,0 2,0.892 2,2 l 0,4 2,0 0,-4 c 0,-2.18141 -1.8186,-4 -4,-4 l -0.1874,0 z m -9.8125,24 c -1.108,0 -2,2 -2,2 l 0,0 c 0,0 0.892,2 2,2 l 14,0 c 1.108,0 2,-2 2,-2 l 0,0 c 0,0 -0.892,-2 -2,-2 z"
1809 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1810 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1811 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1812 d="m 275.9375,-301.81251 c 0.58922,0 1.0625,0.47329 1.0625,1.0625 l 0,0.9375 0.9375,0 c 0.58922,0 1.0625,0.47329 1.0625,1.0625 l 0,1.875 c 0,0.58921 -0.47328,1.0625 -1.0625,1.0625 l -2,0 -5.875,0 -2,0 c -0.58922,0 -1.0625,-0.47329 -1.0625,-1.0625 l 0,-1.875 c 0,-0.58921 0.47328,-1.0625 1.0625,-1.0625 l 0.9375,0 0,-0.9375 c 0,-0.58921 0.47328,-1.0625 1.0625,-1.0625 z m 5.0625,2 c 2.1814,0 4,1.81859 4,4 l 0,18 c 0,2.18141 -1.8186,4 -4,4 l -2,0 0,-2 2,0 c 1.108,0 2,-0.892 2,-2 l 0,-18 c 0,-1.108 -0.892,-2 -2,-2 l 0,-0.9375 c 0,-0.36716 -0.0632,-0.73321 -0.1874,-1.0625 z m -15.8125,0 c -0.1243,0.32929 -0.1875,0.69534 -0.1875,1.0625 l 0,0.9375 c -1.108,0 -2,0.892 -2,2 l 0,4 -2,0 0,-4 c 0,-2.18141 1.8186,-4 4,-4 l 0.1874,0 z m 9.8125,24 c 1.108,0 2,2 2,2 l 0,0 c 0,0 -0.892,2 -2,2 l -14,0 c -1.108,0 -2,-2 -2,-2 l 0,0 c 0,0 0.892,-2 2,-2 z"
1813 id="path4571"
1814 inkscape:connector-curvature="0"
1815 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1816 inkscape:connector-curvature="0"
1817 id="path4573"
1818 d="m 334.0625,-301.81251 c -0.58922,0 -1.0625,0.47329 -1.0625,1.0625 l 0,0.9375 -0.9375,0 c -0.58922,0 -1.0625,0.47329 -1.0625,1.0625 l 0,1.875 c 0,0.58921 0.47328,1.0625 1.0625,1.0625 l 2,0 5.875,0 2,0 c 0.58922,0 1.0625,-0.47329 1.0625,-1.0625 l 0,-1.875 c 0,-0.58921 -0.47328,-1.0625 -1.0625,-1.0625 l -0.9375,0 0,-0.9375 c 0,-0.58921 -0.47328,-1.0625 -1.0625,-1.0625 z m -5.0625,2 c -2.1814,0 -4,1.81859 -4,4 l 0,18 c 0,2.18141 1.8186,4 4,4 l 2,0 0,-2 -2,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-18 c 0,-1.108 0.892,-2 2,-2 l 0,-0.9375 c 0,-0.36716 0.0632,-0.73321 0.1874,-1.0625 z m 15.8125,0 c 0.1243,0.32929 0.1875,0.69534 0.1875,1.0625 l 0,0.9375 c 1.108,0 2,0.892 2,2 l 0,4 2,0 0,-4 c 0,-2.18141 -1.8186,-4 -4,-4 l -0.1874,0 z m -9.8125,24 c -1.108,0 -2,2 -2,2 l 0,0 c 0,0 0.892,2 2,2 l 14,0 c 1.108,0 2,-2 2,-2 l 0,0 c 0,0 -0.892,-2 -2,-2 z"
1819 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1820 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1821 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1822 d="m 403.9375,-301.81251 c 0.58922,0 1.0625,0.47329 1.0625,1.0625 l 0,0.9375 0.9375,0 c 0.58922,0 1.0625,0.47329 1.0625,1.0625 l 0,1.875 c 0,0.58921 -0.47328,1.0625 -1.0625,1.0625 l -2,0 -5.875,0 -2,0 c -0.58922,0 -1.0625,-0.47329 -1.0625,-1.0625 l 0,-1.875 c 0,-0.58921 0.47328,-1.0625 1.0625,-1.0625 l 0.9375,0 0,-0.9375 c 0,-0.58921 0.47328,-1.0625 1.0625,-1.0625 z m 5.0625,2 c 2.1814,0 4,1.81859 4,4 l 0,18 c 0,2.18141 -1.8186,4 -4,4 l -2,0 0,-2 2,0 c 1.108,0 2,-0.892 2,-2 l 0,-18 c 0,-1.108 -0.892,-2 -2,-2 l 0,-0.9375 c 0,-0.36716 -0.0632,-0.73321 -0.1874,-1.0625 z m -15.8125,0 c -0.1243,0.32929 -0.1875,0.69534 -0.1875,1.0625 l 0,0.9375 c -1.108,0 -2,0.892 -2,2 l 0,4 -2,0 0,-4 c 0,-2.18141 1.8186,-4 4,-4 l 0.1874,0 z m 9.8125,24 c 1.108,0 2,2 2,2 l 0,0 c 0,0 -0.892,2 -2,2 l -14,0 c -1.108,0 -2,-2 -2,-2 l 0,0 c 0,0 0.892,-2 2,-2 z"
1823 id="path4575"
1824 inkscape:connector-curvature="0"
1825 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssss" /><path
1826 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1827 d="m 273,84.06249 c -7.73034,0 -14,6.29426 -14,14.0625 0,7.76824 6.26966,14.0625 14,14.0625 7.73266,0 14,-6.29426 14,-14.0625 0,-7.76824 -6.26734,-14.0625 -14,-14.0625 z m 0,2.0625 c 6.62742,0 12,5.37258 12,12 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62742 5.37258,-12 12,-12 z m -4.6875,6 c -1.57516,0 -2.8125,1.2921 -2.8125,2.875 0,1.5829 1.23734,2.875 2.8125,2.875 1.57522,0 2.875,-1.2921 2.875,-2.875 0,-1.5829 -1.29978,-2.875 -2.875,-2.875 z m 9.375,0 c -1.5752,0 -2.875,1.2921 -2.875,2.875 0,1.5829 1.2998,2.875 2.875,2.875 1.57518,0 2.8125,-1.2921 2.8125,-2.875 0,-1.5829 -1.23732,-2.875 -2.8125,-2.875 z m -10.46438,9.55026 c -0.0732,0.3088 -0.162,0.63162 -0.162,0.9536 0,3.11996 4.84578,3.6484 5.9389,3.62114 1.09312,-0.0272 5.9389,-0.50118 5.9389,-3.62114 0,-0.32198 -0.0888,-0.6448 -0.162,-0.9536 -2.61418,2.48674 -5.27502,2.05926 -5.7769,2.11548 -0.50188,0.0562 -4.05892,-0.0948 -5.77688,-2.11548 z"
1828 id="path3733"
1829 inkscape:connector-curvature="0"
1830 sodipodi:nodetypes="sssssssssssssssssssscszsczcc" /><path
1831 sodipodi:nodetypes="ssssssssscccccccccccccccccccccccccccccc"
1832 inkscape:connector-curvature="0"
1833 id="path3755"
1834 d="m 133,84.18749 c -2.216,0 -4,1.784 -4,4 l 0,20 c 0,2.216 1.784,4 4,4 l 24,0 c 2.216,0 4,-1.784 4,-4 l 0,-20 c 0,-2.216 -1.784,-4 -4,-4 z m -2,8 8,0 0,8 -8,0 z m 10,0 8,0 0,8 -8,0 z m 10,0 8,0 0,8 -8,0 z m -20,10 8,0 0,8 -8,0 z m 10,0 8,0 0,8 -8,0 z m 10,0 8,0 0,8 -8,0 z"
1835 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline" /><path
1836 style="font-size:15.85716724px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#ffffff;fill-opacity:0.99215686;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
1837 d="m 209.4375,-105.81251 c -2.7874,2e-5 -4.9509,0.57368 -6.4375,1.8125 -1.4866,1.23886 -2.1875,3.01034 -2.1875,5.3125 0,1.83762 0.49916,3.35352 1.5625,4.4375 0.1594,0.1608 0.37592,0.28962 0.5625,0.4375 l -4.9375,0 c -0.554,0 -1,0.3671 -1,0.875 l 0,0.1874 c 0,0.50792 0.446,0.9376 1,0.9376 l 10,0 1.75,0.4375 c 1.40402,0.30972 2.34792,0.6077 2.8125,1 0.47488,0.3923 0.74998,0.96484 0.75,1.6875 -2e-5,0.80524 -0.37084,1.4414 -1.0625,1.875 -0.6917,0.4336 -1.69922,0.625 -3,0.625 -1.28014,0 -2.61664,-0.1702 -4,-0.5625 -1.37306,-0.40262 -2.77372,-1.02788 -4.25,-1.8125 l 0,5.0625 c 1.47628,0.54716 2.9612,0.97126 4.4375,1.25 1.47628,0.2787 2.90902,0.4375 4.375,0.4375 3.1074,0 5.43022,-0.63616 6.9375,-1.875 1.51756,-1.24916 2.31248,-3.13754 2.3125,-5.6875 0,-0.89622 -0.1438,-1.7306 -0.375,-2.4375 l 3.3125,0 c 0.554,0 1,-0.4296 1,-0.9375 l 0,-0.1874 c 0,-0.50792 -0.446,-0.8751 -1,-0.8751 l -4.5,0 c -0.021,-0.021 -0.0412,-0.0418 -0.0624,-0.0624 -1.084,-1.053 -2.92942,-1.8588 -5.5,-2.375 l -2.5625,-0.5 c -1.20786,-0.24776 -2.03544,-0.5343 -2.5,-0.875 -0.45426,-0.35098 -0.68752,-0.88056 -0.6875,-1.5 -2e-5,-0.82588 0.38112,-1.42018 1.0625,-1.8125 0.68136,-0.39226 1.70032,-0.56248 3.125,-0.5625 1.07366,2e-5 2.22962,0.1484 3.4375,0.4375 1.20786,0.28908 1.98018,0.68222 3.25,1.25 l 0,-4.9375 c -1.435,-0.38196 -2.34544,-0.6267 -3.6875,-0.8125 -1.34208,-0.1962 -2.6677,-0.24998 -3.9375,-0.25 z"
1838 id="path3568-3"
1839 inkscape:connector-curvature="0" /><path
1840 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1841 d="m 129,276.18749 0,28 6,0 0,-2 -4,0 0,-24 4,0 0,-2 z m 26,0 0,2 4,0 0,24 -4,0 0,2 6,0 0,-28 z"
1842 id="rect3578-3"
1843 inkscape:connector-curvature="0"
1844 sodipodi:nodetypes="cccccccccccccccccc" /><path
1845 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1846 d="m 197.9375,-233.75001 -2.9375,12.25 0,1.75 2.34375,0 0,-1.75 0.5,-2.90625 2.5,0 0.5,2.90625 0,1.75 2.34375,0 0,-1.75 -2.90625,-12.25 -2.34375,0 z m 7.0625,0 0,14 4.6875,0 c 0.68312,-0.0583 1.26208,-0.20417 1.75,-0.4375 1.17106,-0.58333 1.74998,-1.60416 1.75,-3.0625 l 0,-1.15625 c -2e-5,-1.32222 -0.62982,-2.35485 -1.9375,-3.09375 0.91732,-0.42777 1.375,-1.14513 1.375,-2.15625 l 0,-0.59375 c -0.0585,-0.68055 -0.2033,-1.26388 -0.4375,-1.75 -0.58554,-1.16665 -1.62993,-1.74999 -3.09375,-1.75 l -4.09375,0 z m 13.5,0 c -0.68312,0.0583 -1.26206,0.20418 -1.75,0.4375 -1.17106,0.58335 -1.75,1.60418 -1.75,3.0625 l 0,7 c 0.0585,0.68056 0.20328,1.26389 0.4375,1.75 0.20859,0.41563 0.49244,0.73244 0.8125,1 l -1.8125,1.8125 -7.4375,7.5 -4.25,-4.25 -2.8125,2.8125 4.25,4.25 2.8125,2.8125 2.8125,-2.8125 10.4375,-10.5 c -0.10769,-0.11377 -0.62171,-0.47602 -1.1875,-0.875 l 0.625,0 c 0.6831,-0.0389 1.26208,-0.18472 1.75,-0.4375 1.17106,-0.58333 1.74998,-1.60416 1.75,-3.0625 l 0,-0.59375 -2.34375,0 0,1.1875 c -0.0586,0.77778 -0.43413,1.15625 -1.15625,1.15625 l -1.1875,0 c -0.78072,-0.0583 -1.15625,-0.4368 -1.15625,-1.15625 l 0,-8.1875 c 0.0585,-0.77777 0.43409,-1.15624 1.15625,-1.15625 l 1.1875,0 c 0.7807,0.0583 1.15625,0.43682 1.15625,1.15625 l 0,1.1875 2.34375,0 0,-0.59375 c -0.0586,-0.68055 -0.2033,-1.26388 -0.4375,-1.75 -0.58554,-1.16665 -1.5987,-1.74999 -3.0625,-1.75 l -1.1875,0 z m -19.40625,1.75 0.96875,5.84375 -1.9375,0 0.96875,-5.84375 z m 8.25,0 1.75,0 c 0.7807,0.0583 1.1875,0.43682 1.1875,1.15625 l 0,1.75 c -0.0585,0.77779 -0.46536,1.18751 -1.1875,1.1875 l -1.75,0 0,-4.09375 z m 0,5.84375 2.34375,0 c 0.78072,0.0583 1.15625,0.43681 1.15625,1.15625 l 0,2.34375 c -0.0586,0.77778 -0.43411,1.15625 -1.15625,1.15625 l -2.34375,0 0,-4.65625 z"
1847 id="path4591-8"
1848 inkscape:connector-curvature="0" /><path
1849 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1850 d="m 129,-237.75001 0,30 10,0 0,-2.3125 0,-1.6875 0,-0.625 0,-3.375 10,0 0,2 10,0 0,-24 -30,0 z m 12,24 0,2 2,0 0,4 -2,0 0,2 6,0 0,-2 -2,0 0,-4 2,0 0,-2 -2,0 -2,0 -2,0 z"
1851 id="rect6534-3"
1852 inkscape:connector-curvature="0" /><path
1853 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;display:inline"
1854 d="m 586.9375,-27.03126 -5.6875,5.6875 5.6875,5.6875 1.90625,-1.84375 -3.75,-3.84375 3.75,-3.75 z m 7.375,0 -4.84375,11.375 3.71875,0 5.0625,-11.34375 -3.9375,-0.0312 z m 6.25,0 -1.9375,1.9375 3.78125,3.75 -3.78125,3.84375 1.9375,1.84375 5.65625,-5.6875 z"
1855 id="path4610-9"
1856 inkscape:connector-curvature="0"
1857 sodipodi:nodetypes="cccccccccccccccccccc" /><path
1858 sodipodi:nodetypes="sssssssscsscccccccscsssscssssssssssssssscsssscscccccccsssssssss"
1859 inkscape:connector-curvature="0"
1860 id="path4589-5"
1861 d="m 68,-237.75001 c -1.108,0 -2,0.892 -2,2 l 0,12 c 0,1.108 0.892,2 2,2 l 7,0 c 1.108,0 2,-0.892 2,-2 l 0,-6 c 0,-1.108 -0.892,-2 -2,-2 l -5,0 0,-4 c 0,-1.108 -0.892,-2 -2,-2 z m 18,4 -6,3.875 6,4 0,-2.625 c 4.53598,0.002 6.887,2.90102 8,4.625 -0.112,-4.06048 -3.48268,-7.3724 -8,-7.375 z m -15,4 2,0 1,0 c 0,0 1,0.446 1,1 l 0,4 c 0,0.554 -0.446,1 -1,1 l -1,0 -2,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-4 c 0,-0.554 1,-1 1,-1 z m 16,8 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 4,0 c 0.554,0 1,0.446 1,1 l 0,2 c 0,0.554 -0.446,1 -1,1 l -5,0 c -1.108,0 -2,0.892 -2,2 l 0,6 c 0,1.108 0.892,2 2,2 l 6,0 2,0 c 1.108,0 2,-0.892 2,-2 l 0,-12 c 0,-1.108 -0.892,-2 -2,-2 l -1,0 z m -19,4 c 0.112,4.06048 3.48268,7.37242 8,7.375 l 0,2.5 6,-3.875 -6,-4 0,2.625 c -4.53598,-0.002 -6.887,-2.90102 -8,-4.625 z m 20,4 3,0 c 0.554,0 1,0.446 1,1 l 0,4 c 0,0.554 -0.446,1 -1,1 l -3,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-4 c 0,-0.554 0.446,-1 1,-1 z"
1862 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.98999999;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
1863 inkscape:connector-curvature="0"
1864 id="path5866-1"
1865 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98009997;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
1866 d="m 584.66965,-43.747414 c 1.46129,2e-5 2.48419,0.58335 3.06872,1.75001 0.2338,0.48612 0.37993,1.06945 0.43839,1.74999 l 0,7.00001 c -10e-6,1.45834 -0.58452,2.47916 -1.75355,3.0625 -0.48711,0.23333 -1.07162,0.37917 -1.75356,0.4375 l -4.67613,0 0,-14.00001 4.67613,0 m 1.16904,11.08334 0,-8.16667 c -1e-5,-0.71943 -0.38969,-1.10832 -1.16904,-1.16666 l -2.33806,0 0,10.5 2.33806,0 c 0.7209,0 1.11058,-0.38889 1.16904,-1.16667" /><path
1867 inkscape:connector-curvature="0"
1868 id="path5868-6"
1869 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98009997;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
1870 d="m 597.00773,-41.997404 -2.33807,0 0,10.5 2.33807,0 0,1.75 -7.0142,0 0,-1.75 2.33806,0 0,-10.5 -2.33806,0 0,-1.75001 7.0142,0 0,1.75001" /><path
1871 inkscape:connector-curvature="0"
1872 id="path5870-0"
1873 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98009997;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
1874 d="m 607.17677,-41.997404 -2.92259,12.25 -2.33807,0 -2.92258,-12.25 0,-1.75001 2.33807,0 0,1.75001 1.75354,10.5 1.75356,-10.5 0,-1.75001 2.33807,0 0,1.75001" /><path
1875 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
1876 d="m 223.46875,278.31249 c -5.17784,1.61214 -11.48202,1.46403 -12.53125,1.375 l 0.5,1.9375 c 1.53833,0.005 2.5625,0.0382 4.5625,-0.0781 l 0,4.70312 -6,0 0,2 6,0 0,6 -4,0 -2,0 0,10 2,0 0,-2 10,0 0,1 2,0 0,-1 0,-8 -2,0 -4,0 0,-6 6,0 0,-2 -6,0 0,-4.84375 c 2.35241,-0.16735 3.875,-0.53375 5.875,-1.25 z M 196,278.24999 l 0,2 12,0 0,-2 z m -2,4 0,2 16,0 0,-2 z m 2,4 0,2 12,0 0,-2 z m 0,4 0,2 12,0 0,-2 z m 0,4 0,10 2,0 0,-2 8,0 0,1 2,0 0,-1 0,-8 -2,0 -8,0 z m 2,2 8,0 0,4 -8,0 z m 14,0 10,0 0,4 -10,0 z"
1877 id="rect4258-5"
1878 inkscape:connector-curvature="0"
1879 sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" /><path
1880 style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;display:inline"
1881 d="m 257,276.24999 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m -28,4 0,2 2,0 0,-2 -2,0 z m 4,0 0,10 0,2 0,6 10,0 0,-2 -8,0 0,-2 8,0 2,0 0,-2 -10,0 0,-2 12,0 8,0 0,-2 0,-8 -8,0 -14,0 z m 24,0 0,2 2,0 0,-2 -2,0 z m -22,2 18,0 0,2 -18,0 0,-2 z m -6,2 0,2 2,0 0,-2 -2,0 z m 28,0 0,2 2,0 0,-2 -2,0 z m -22,2 17.9374,0 0,2 -17.9374,0 0,-2 z m -6,2 0,2 2,0 0,-2 -2,0 z m 28,0 0,2 2,0 0,-2 -2,0 z m -6,3.5 -7.375,6.75 7.375,6.5625 0,-3.8125 -2.875,-2.8125 2.875,-3.0625 0,-3.625 z m 2,0 0,3.75 2.75,2.9375 -2.75,2.9375 0,3.8125 7.25,-6.75 -7.25,-6.6875 z m -24,0.5 0,2 2,0 0,-2 -2,0 z m 0,4 0,2 2,0 0,-2 -2,0 z m 0,4 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z m 4,0 0,2 2,0 0,-2 -2,0 z"
1882 id="rect5051-9"
1883 inkscape:connector-curvature="0" /></g><g
1884 inkscape:groupmode="layer"
1885 id="layer3"
1886 inkscape:label="Icons"
1887 style="opacity:0.98999999;display:inline"
1888 transform="translate(-1,367.74999)"
1889 sodipodi:insensitive="true"><rect
1890 y="274.25012"
1891 x="137"
1892 height="28.00008"
1893 width="16"
1894 id="rect4452"
1895 style="fill:#cccccc;fill-opacity:1;stroke:none" /><rect
1896 style="fill:#cccccc;fill-opacity:1;stroke:none"
1897 id="rect4367"
1898 width="24"
1899 height="20.000111"
1900 x="133"
1901 y="278.25012" /><g
1902 id="g4363"
1903 style="font-size:13.71140385px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#676767;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;font-family:Sans"
1904 transform="matrix(2,0,0,2,3.0000003,-367.74989)"><path
1905 sodipodi:nodetypes="csssccccccsssc"
1906 inkscape:connector-curvature="0"
1907 id="path4365"
1908 style="font-variant:normal;font-weight:bold;font-stretch:normal;fill:#676767;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L Bold"
1909 d="m 70.006423,329.43503 1.991763,0 c 1.837326,0 3.016509,-1.30258 3.016509,-3.33187 0,-2.00186 -1.138049,-3.09877 -3.22218,-3.09877 l -3.790777,0 0,9.99561 2.004685,0 0,-3.56497 m 0,-1.71392 0,-3.0028 1.347327,0 c 1.096911,0 1.604234,0.4799 1.604234,1.50826 0,1.01464 -0.507323,1.49454 -1.604234,1.49454 l -1.347327,0" /></g><path
1910 style="fill:url(#linearGradient5768);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
1911 d="m 14,339.43759 c -1.5815,0.018 -3.20062,0.68066 -4.9999999,2.75 l 0,14 0,0.5 0,1.5 0,0.0624 c 0.45016,-0.50734 0.87536,-0.90294 1.3124999,-1.25 0.3747,-0.29748 0.75862,-0.55586 1.125,-0.75 0.1248,-0.0662 0.25102,-0.1324 0.375,-0.1874 0.1664,-0.07 0.33476,-0.1358 0.5,-0.1874 0.0628,-0.021 0.1248,-0.0442 0.1874,-0.0624 0.1648,-0.0456 0.33692,-0.094 0.5,-0.125 0.018,0.002 0.0444,-0.002 0.0624,0 0.35368,-0.0632 0.71418,-0.131 1.0625,-0.125 2.73838,0.0472 5.34698,1.9999 8.0625,2.75 0.40146,0.1108 0.77966,0.2032 1.1875,0.25 0.1304,0.014 0.24392,0.0554 0.375,0.0624 0.1182,0.006 0.25616,6.2e-4 0.375,0 0.056,0.008 0.1304,0.002 0.1874,0 0.1064,-0.004 0.20652,-0.0488 0.3125,-0.0624 0.083,-0.01 0.1658,0.01 0.25,0 0.0602,-0.008 0.1272,0.01 0.1874,0 0.1922,-0.0322 0.3681,-0.133 0.5625,-0.1874 0.33684,-0.0946 0.65612,-0.20516 1,-0.375 0.0596,-0.0282 0.1274,-0.031 0.1874,-0.0624 0.03,-0.016 0.035,-0.0394 0.0624,-0.0624 0.0276,-0.0232 0.0322,-0.0458 0.0624,-0.0624 0.32472,-0.1828 0.6681,-0.36436 1,-0.625 0.0218,-0.018 0.0406,-0.045 0.0624,-0.0624 0.33604,-0.26566 0.65626,-0.51938 1,-0.875 l 0,-0.0624 0,-2 0,-12 0,-2 c -0.30804,0.32802 -0.63472,0.62818 -0.9375,0.875 -0.0218,0.018 -0.0406,0.0448 -0.0624,0.0624 -0.2779,0.22152 -0.53774,0.39276 -0.8125,0.5625 -0.0734,0.0454 -0.1768,0.0834 -0.25,0.125 -0.66642,0.37918 -1.29054,0.58736 -1.9375,0.6875 -3.88172,0.60088 -7.4416,-3.10534 -11,-3.0625 z m -8.9999999,0.8125 0,26 2,0 0,-26 -2,0 z"
1912 id="path3613"
1913 inkscape:connector-curvature="0"
1914 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
1915 inkscape:export-xdpi="90"
1916 inkscape:export-ydpi="90" /><rect
1917 style="fill:#ffffff;fill-opacity:0;stroke:none"
1918 id="rect4382"
1919 width="32"
1920 height="32"
1921 x="1"
1922 y="336.25012"
1923 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
1924 inkscape:export-xdpi="90"
1925 inkscape:export-ydpi="90" /><path
1926 style="fill:#b8b8b8;fill-opacity:1;stroke:none"
1927 d="m 129,-239.74991 0,30 10,0 0,-2.30769 0,-2.30769 0,-3.38462 10,-0.30769 0,2.30769 10,0 0,-24 z"
1928 id="rect6534"
1929 inkscape:connector-curvature="0"
1930 sodipodi:nodetypes="ccccccccccc" /><path
1931 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3429);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1932 d="M 70.53125,32 C 70.236645,32 70,32.23664 70,32.53125 L 70,33 69.53125,33 C 69.236645,33 69,33.23664 69,33.53125 l 0,0.9375 C 69,34.76335 69.236645,35 69.53125,35 l 1,0 2.9375,0 1,0 C 74.763355,35 75,34.76335 75,34.46875 l 0,-0.9375 C 75,33.23664 74.763355,33 74.46875,33 L 74,33 74,32.53125 C 74,32.23664 73.763355,32 73.46875,32 l -2.9375,0 z M 68,33 c -1.090704,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.909296,2 2,2 l 1,0 0,-1 -1,0 c -0.554001,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.445999,-1 1,-1 l 0,-0.46875 C 68,33.34767 68.0316,33.16464 68.09375,33 L 68,33 z m 7.90625,0 C 75.9684,33.16465 76,33.34767 76,33.53125 L 76,34 c 0.554001,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.909296,-2 -2,-2 l -0.09375,0 z M 71,38 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z"
1933 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
1934 id="path3624"
1935 inkscape:connector-curvature="0" /><path
1936 id="path4583"
1937 d="m 162,0.99999 0,14 8.8125,0 -1,-1 -1.3125,0 -1.5,0 -3,0 -1,0 0,-12 5.5,0 3.5,3.5 0,1.21875 c 0.61468,0.76989 1,1.72879 1,2.78125 l 0,-3.5 0,-1 -4,-4 -1,0 -6,0 z m 11,8.5 c 0,0.48319 -0.20077,0.86276 -0.34375,1.28125 L 173,11.12499 l 0,-1.625 z m -4.5,-3.5 c -1.92115,0 -3.5,1.57884 -3.5,3.5 0,1.92115 1.57885,3.5 3.5,3.5 0.49539,0 0.94633,-0.12374 1.375,-0.3125 l 2.34375,2.34375 1.625,-1.625 -2.28125,-2.28125 C 171.829,10.63214 172,10.09539 172,9.49999 c 0,-1.92116 -1.57885,-3.5 -3.5,-3.5 z m -0.0312,1 c 1.38071,0 2.5,1.11929 2.5,2.5 0,1.38071 -1.11929,2.5 -2.5,2.5 -1.38071,0 -2.5,-1.11929 -2.5,-2.5 0,-1.38071 1.11929,-2.5 2.5,-2.5 z"
1938 style="fill:url(#linearGradient3431);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
1939 inkscape:connector-curvature="0"
1940 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1941 style="fill:url(#linearGradient3667);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
1942 d="M 166.53125,32 C 166.23664,32 166,32.23664 166,32.53125 L 166,33 165.53125,33 C 165.23664,33 165,33.23664 165,33.53125 l 0,0.9375 C 165,34.76335 165.23664,35 165.53125,35 l 1,0 2.9375,0 1,0 C 170.76336,35 171,34.76335 171,34.46875 l 0,-0.9375 C 171,33.23664 170.76336,33 170.46875,33 L 170,33 170,32.53125 C 170,32.23664 169.76336,32 169.46875,32 z M 164,33 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0317,-0.36661 0.0937,-0.53125 z m 7.90625,0 C 171.9684,33.16465 172,33.34767 172,33.53125 L 172,34 c 0.554,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z M 167,38 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 z m 0,1 7,0 0,7 -7,0 z m 1,1 0,1 0,4 1,0 1,-1 0.5,-0.50005 L 171,44 l 1,1 1,0 0,-4 0,-1 -1,0 0,3 -1,-1 -1,0 -1,1 0,-3 z"
1943 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
1944 id="path4585"
1945 inkscape:connector-curvature="0"
1946 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssssccccccccccccccccccccccc" /><path
1947 style="fill:url(#linearGradient6155);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
1948 d="M 196.9375,132 194,144.25 l 0,1.75 2.34375,0 0,-1.75 0.5,-2.90625 2.5,0 0.5,2.90625 0,1.75 2.34375,0 0,-1.75 -2.90625,-12.25 -2.34375,0 z m 7.0625,0 0,14 4.6875,0 c 0.68312,-0.0583 1.26208,-0.20417 1.75,-0.4375 1.17106,-0.58333 1.74998,-1.60416 1.75,-3.0625 l 0,-1.15625 c -2e-5,-1.32222 -0.62982,-2.35485 -1.9375,-3.09375 0.91732,-0.42777 1.375,-1.14513 1.375,-2.15625 l 0,-0.59375 c -0.0585,-0.68055 -0.2033,-1.26388 -0.4375,-1.75 -0.58554,-1.16665 -1.62993,-1.74999 -3.09375,-1.75 L 204,132 z m 13.5,0 c -0.68312,0.0583 -1.26206,0.20418 -1.75,0.4375 -1.17106,0.58335 -1.75,1.60418 -1.75,3.0625 l 0,7 c 0.0585,0.68056 0.20328,1.26389 0.4375,1.75 l 0.0312,0 c 0.0734,0.14265 0.16363,0.28124 0.25,0.40625 0.0864,0.12501 0.18177,0.23644 0.28125,0.34375 0.0846,0.0856 0.15855,0.17355 0.25,0.25 0.57061,0.47686 1.31935,0.71875 2.25,0.71875 l 1.15625,0 c 0.59333,-0.0339 1.11708,-0.14742 1.5625,-0.34375 l 0.0312,0 c 0.0619,-0.0275 0.12831,-0.0318 0.1875,-0.0625 1.17106,-0.58333 1.74998,-1.60416 1.75,-3.0625 l 0,-0.59375 -2.34375,0 0,1.1875 c -0.0586,0.77778 -0.43413,1.15625 -1.15625,1.15625 l -1.1875,0 c -0.78072,-0.0583 -1.15625,-0.4368 -1.15625,-1.15625 l 0,-8.1875 c 0.0585,-0.77777 0.43409,-1.15624 1.15625,-1.15625 l 1.1875,0 c 0.7807,0.0583 1.15625,0.43682 1.15625,1.15625 l 0,1.1875 2.34375,0 0,-0.59375 c -0.0586,-0.68055 -0.2033,-1.26388 -0.4375,-1.75 -0.58554,-1.16665 -1.5987,-1.74999 -3.0625,-1.75 l -1.1875,0 z m -19.40625,1.75 0.96875,5.84375 -1.9375,0 0.96875,-5.84375 z m 8.25,0 1.75,0 c 0.7807,0.0583 1.1875,0.43682 1.1875,1.15625 l 0,1.75 c -0.0585,0.77779 -0.46536,1.18751 -1.1875,1.1875 l -1.75,0 0,-4.09375 z m 0,5.84375 2.34375,0 c 0.78072,0.0583 1.15625,0.43681 1.15625,1.15625 l 0,2.34375 c -0.0586,0.77778 -0.43411,1.15625 -1.15625,1.15625 l -2.34375,0 0,-4.65625 z m 8.21875,6.34375 -1.125,1.125 -7.4375,7.5 -4.25,-4.25 -2.8125,2.8125 4.25,4.25 2.8125,2.8125 2.8125,-2.8125 10.40625,-10.46875 c -0.16686,0.0246 -0.32642,0.0526 -0.5,0.0625 a 1.0001,1.0001 0 0 1 -0.0625,0 l -1.15625,0 c -1.12657,0 -2.151,-0.37304 -2.9375,-1.03125 z"
1949 transform="translate(1,-367.75001)"
1950 id="path4591"
1951 inkscape:connector-curvature="0" /><path
1952 inkscape:connector-curvature="0"
1953 id="path4593"
1954 d="m 36,99 c -1.0907,0 -2,0.90929 -2,2 l 0,7 c 0,1.0907 0.9093,2 2,2 l 8,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.09071 -0.9093,-2 -2,-2 l -8,0 z m 0,1 8,0 c 0.554,0 1,0.44599 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -8,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.55401 0.446,-1 1,-1 z m 6.59375,1.59375 L 39,105.1875 37.59375,103.75 l -1.4375,1.40625 1.4375,1.4375 L 39,108 l 5,-5 -1.40625,-1.40625 z"
1955 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3437);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1956 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1957 sodipodi:nodetypes="ssssssssssssssssssscccssssssccssss"
1958 inkscape:connector-curvature="0"
1959 id="path4595"
1960 d="m 98,99 c -1.0907,0 -2,0.90929 -2,2 l 0,7 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.09071 -0.9093,-2 -2,-2 z m 0,1 12,0 c 0.554,0 1,0.44599 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -12,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.55401 0.446,-1 1,-1 z m 1.5,1 c -0.277,0 -0.5,0.22299 -0.5,0.5 0.0807,0.57703 0.3111,0.49624 1,0.5 l 0,5 -0.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.11921,-0.5 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z"
1961 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3439);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1962 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1963 sodipodi:nodetypes="cccccccsssscccsssscccccccccccccccccccccccccccccccccccccccccccccccccc"
1964 inkscape:connector-curvature="0"
1965 id="path4597"
1966 d="m 333,96 -1,2 -2,0 0,1 1.5,0 -4.5,9 -1,0 -4,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.55401 0.446,-1 1,-1 l 4,0 4,0 0,-1 -8,0 c -1.0907,0 -2,0.9093 -2,2 l 0,7 c 0,1.09069 0.9093,2 2,2 l 4.5,0 -1.5,3 2,0 1.5,-3 1.5,0 0,-1 -1,0 4.5,-9 0.5,0 0,-1 1,-2 z m 2,2.28125 0,0.71875 0.71875,0 C 335.5419,98.69767 335.30232,98.4581 335,98.28125 z m 0,1.71875 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m 0,2 0,1 1,0 0,-1 z m -4,2 0,1 1,0 0,-1 z m 2,0 0,1 1,0 0,-1 z m 2,0 0,0.71875 c 0.30232,-0.17686 0.5419,-0.41643 0.71875,-0.71875 z"
1967 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3679);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1968 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1969 inkscape:connector-curvature="0"
1970 id="path4600"
1971 d="m 2,99 c -0.554,0 -1,0.446 -1,1 l 0,9 c 0,0.55399 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.44601 1,-1 l 0,-9 c 0,-0.554 -0.446,-1 -1,-1 L 2,99 z m 0,3 12,0 0,7 -12,0 0,-7 z m 1,1 0,1 3,0 0,-1 -3,0 z m 5,0 0,2 5,0 0,-2 -5,0 z m -5,3 0,1 3,0 0,-1 -3,0 z m 5,0 0,2 5,0 0,-2 -5,0 z"
1972 style="fill:url(#linearGradient3441);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
1973 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1974 id="path4604"
1975 d="m 36,195.99999 c -1.64649,0 -3,1.3535 -3,3 l 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 0.6875,-0.6875 -0.53125,-0.5625 0.65625,-0.71875 1,-1.03125 -4.3125,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 0,-0.27701 0.223,-0.5 0.5,-0.5 l 7,0 c 0.277,0 0.5,0.22299 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -1.1875,0 1,1 0.6875,0 c 0.0353,0 0.0594,-0.0277 0.0937,-0.0312 l 0.875,-0.875 c 0.004,-0.0344 0.0312,-0.0585 0.0312,-0.0938 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 l -3,0 0,-1 3,0 c 1.0907,0 2,0.90929 2,2 l 0,0.4375 0.53125,0.53125 0.4375,0.4375 c 0.019,-0.13548 0.0312,-0.26585 0.0312,-0.40625 l 0,-1 c 0,-1.6465 -1.35351,-3 -3,-3 l -3,0 -1,1 -1,-1 -3,0 z m 0,1 3,0 0,1 -3,0 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,1 -3,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-1 c 0,-1.09071 0.9093,-2 2,-2 z"
1976 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3677);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1977 inkscape:connector-curvature="0"
1978 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1979 sodipodi:nodetypes="sssscccsssscccssccssssccsssscssssccssssccsssssss"
1980 inkscape:connector-curvature="0"
1981 id="path4606"
1982 d="m 4,196 c -1.64649,0 -3,1.3535 -3,3 l 0,1 c 0,1.64649 1.35351,3 3,3 l 3,0 1,-1 1,1 3,0 c 1.64649,0 3,-1.35351 3,-3 l 0,-1 c 0,-1.6465 -1.35351,-3 -3,-3 l -3,0 -1,1 -1,-1 z m 0,1 3,0 0,1 -3,0 c -0.554,0 -1,0.44599 -1,1 l 0,1 c 0,0.554 0.446,1 1,1 l 3,0 0,1 -3,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-1 c 0,-1.09071 0.9093,-2 2,-2 z m 5,0 3,0 c 1.0907,0 2,0.90929 2,2 l 0,1 c 0,1.0907 -0.9093,2 -2,2 l -3,0 0,-1 3,0 c 0.554,0 1,-0.446 1,-1 l 0,-1 c 0,-0.55401 -0.446,-1 -1,-1 l -3,0 z m -4.5,2 7,0 c 0.277,0 0.5,0.22299 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -7,0 C 4.223,200 4,199.777 4,199.5 4,199.22299 4.223,199 4.5,199 z"
1983 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3675);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1984 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1985 inkscape:connector-curvature="0"
1986 id="path4608"
1987 d="m 68,129.96875 0,6.5 c 0,0.6818 0.0818,1.2882 0.21875,1.84375 0.13694,0.55554 0.35886,1.04609 0.6875,1.4375 0.32865,0.3914 0.76476,0.6916 1.3125,0.90625 0.56144,0.20201 1.24087,0.28125 2.0625,0.28125 0.8353,0 1.53231,-0.0792 2.09375,-0.28125 0.56143,-0.21465 1.03265,-0.51485 1.375,-0.90625 0.34233,-0.39141 0.5818,-0.88196 0.71875,-1.4375 0.13697,-0.55555 0.18749,-1.16195 0.1875,-1.84375 l 0,-6.5 -2.5,0 0,6.3125 c -1.1e-4,0.49241 -0.039,0.9091 -0.0937,1.25 -0.0548,0.32828 -0.14432,0.59785 -0.28125,0.8125 -0.13695,0.20201 -0.32971,0.34911 -0.5625,0.4375 -0.23279,0.0884 -0.51896,0.15625 -0.875,0.15625 -0.35604,0 -0.67347,-0.0679 -0.90625,-0.15625 -0.2328,-0.0884 -0.39431,-0.23549 -0.53125,-0.4375 -0.12325,-0.20202 -0.22648,-0.45297 -0.28125,-0.78125 -0.0548,-0.3409 -0.0625,-0.75759 -0.0625,-1.25 l 0,-6.34375 -2.5625,0 z M 67.5,142 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 10,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -10,0 z"
1988 style="font-size:15.23443031px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3443);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
1989 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
1990 inkscape:connector-curvature="0"
1991 id="path4610"
1992 d="m 586.9375,-29.03126 -5.6875,5.6875 5.6875,5.6875 1.90625,-1.84375 -3.75,-3.84375 3.75,-3.75 z m 7.375,0 -4.84375,11.375 3.71875,0 5.0625,-11.34375 -3.9375,-0.0312 z m 6.25,0 -1.9375,1.9375 3.78125,3.75 -3.78125,3.84375 1.9375,1.84375 5.65625,-5.6875 z"
1993 style="fill:url(#linearGradient5750);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
1994 sodipodi:nodetypes="cccccccccccccccccccc" /><path
1995 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient6173);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
1996 d="m 145,707 c -4.36281,0 -8,3.63719 -8,8 l 0,3 -1,0 c -1.108,0 -2,0.89198 -2,2 l 0,12 c 0,1.108 0.892,2 2,2 l 18,0 c 1.108,0 2,-0.892 2,-2 l 0,-12 c 0,-1.10802 -0.892,-2 -2,-2 l -1,0 0,-3 c 0,-4.36281 -3.63719,-8 -8,-8 z m 0,4 c 2.216,0 4,1.784 4,4 l 0,3 -8,0 0,-3 c 0,-2.216 1.784,-4 4,-4 z m 0,13 c 1.65686,0 3,1.34314 3,3 0,1.65684 -1.34314,3 -3,3 -1.65686,0 -3,-1.34316 -3,-3 0,-1.65686 1.34314,-3 3,-3 z"
1997 transform="translate(1,-367.75001)"
1998 id="path4612"
1999 inkscape:connector-curvature="0" /><path
2000 inkscape:connector-curvature="0"
2001 id="path4614"
2002 d="m 68,210.24999 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 7,0 c -2.1814,0 -4,1.8186 -4,4 l 0,20 c 0,2.1814 1.8186,4 4,4 2.1814,0 4,-1.8186 4,-4 l 0,-20 c 0,-2.1814 -1.8186,-4 -4,-4 z m 0,2 c 1.108,0 2,0.892 2,2 l 0,20 c 0,1.108 -0.892,2 -2,2 -1.108,0 -2,-0.892 -2,-2 l 0,-20 c 0,-1.108 0.892,-2 2,-2 z m -23,2 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -16,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -16,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 16,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -16,4 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m 4,0 c -0.55228,0 -1,0.44772 -1,1 0,0.55228 0.44772,1 1,1 0.55228,0 1,-0.44772 1,-1 0,-0.55228 -0.44772,-1 -1,-1 z m -13,4 c -2.1814,0 -4,1.8186 -4,4 0,2.1814 1.8186,4 4,4 l 10,0 c 2.1814,0 4,-1.8186 4,-4 0,-2.1814 -1.8186,-4 -4,-4 l -10,0 z m 0,2 10,0 c 1.108,0 2,0.892 2,2 0,1.108 -0.892,2 -2,2 l -10,0 c -1.108,0 -2,-0.892 -2,-2 0,-1.108 0.892,-2 2,-2 z"
2003 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient5746);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path
2004 id="path4616"
2005 d="m 579,-163.74989 28,0 0,10 -28,0 z"
2006 style="fill:#c4c4c4;fill-opacity:1;stroke:none"
2007 inkscape:connector-curvature="0" /><path
2008 style="fill:url(#linearGradient3451);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2009 d="m 35.3298,257.02118 c -1.28605,0 -2.3298,1.04375 -2.3298,2.3298 l 0,9.31921 C 33,269.95625 34.04375,271 35.3298,271 l 9.31921,0 c 1.28606,0 2.3298,-1.04375 2.3298,-2.32981 l 0,-9.31921 c 0,-1.28605 -1.04374,-2.3298 -2.3298,-2.3298 z m 3.80414,2.33622 1.79284,0 0.11832,0.212 3.64032,9.10079 -2.3298,0 -0.87368,-2.29339 -3.02147,0 -0.87367,2.29339 -2.257,0 3.64032,-8.88237 z"
2010 id="path4618"
2011 inkscape:connector-curvature="0"
2012 sodipodi:nodetypes="sssssssssccccccccccc"
2013 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2014 style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2015 d="m 40.57171,265.23621 -1.16491,0 c -0.3215,0 -0.58244,-0.26094 -0.58244,-0.58246 l 1.1381,-2.19467 1.19286,2.19467 c -8.7e-4,0.32152 -0.2621,0.58246 -0.58361,0.58246 z"
2016 id="path4620"
2017 inkscape:connector-curvature="0"
2018 sodipodi:nodetypes="sscccs"
2019 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2020 sodipodi:nodetypes="cccccccccccc"
2021 style="fill:url(#linearGradient3453);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2022 d="m 66,193 0,14 1,0 0,-14 z m 4.74999,-0.41664 c -0.86983,0.009 -1.76033,0.34033 -2.74999,1.375 L 68,202 c 3.96132,-4.05865 6.94268,2.81598 11,-1 l 0,-8.04165 c -3.03099,2.934 -5.64051,-0.40352 -8.25001,-0.37496 z"
2023 id="path4622"
2024 inkscape:connector-curvature="0"
2025 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2026 sodipodi:nodetypes="cccccccccccccsssssss"
2027 inkscape:connector-curvature="0"
2028 id="path4624"
2029 d="m 201.71875,138.21875 -0.96875,0.90625 1.90625,1.96875 -1.90625,1.96875 0.96875,1 1.90625,-1.96875 1.96875,1.96875 0.96875,-1 -1.9375,-1.96875 1.9375,-1.96875 -0.96875,-0.90625 -1.96875,1.90625 z M 193.5,141 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z"
2030 style="fill:url(#linearGradient3455);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2031 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2032 sodipodi:nodetypes="ccccccc"
2033 style="fill:url(#linearGradient3457);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2034 d="m 232,35 -7,5 6.99998,4.99998 2e-5,-3.33332 c 3.41666,0 5.61556,1.22 7,3.33334 0,-4.98333 -3.60112,-6.66667 -7,-6.66667 2e-5,-0.85078 1e-5,-2.61388 0,-3.33333 z"
2035 id="path4626"
2036 inkscape:connector-curvature="0"
2037 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2038 style="fill:url(#linearGradient3459);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2039 d="m 417.99999,163 0,2 12.00001,0 0,-2 -12.00001,0 z m 0,3 0,1.99999 12.00001,0 0,-1.99999 -12.00001,0 z m 0,3 0,2 12.00001,0 0,-2 -12.00001,0 z m 0,2.99999 0,2.00001 12.00001,0 0,-2.00001 -12.00001,0 z"
2040 id="path4628"
2041 inkscape:connector-curvature="0"
2042 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2043 style="fill:url(#linearGradient3461);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2044 d="m 391,163 0,2 7,0 0,-2 -7,0 z m -4,3 0,1.99999 11,0 0,-1.99999 -11,0 z m 2,3 0,2 9,0 0,-2 -9,0 z m -3,3 0,2 12,0 0,-2 -12,0 z"
2045 id="path4630"
2046 inkscape:connector-curvature="0"
2047 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2048 transform="matrix(1.9740024,0,0,1.9740042,10.515129,-363.4347)"
2049 style="fill:url(#linearGradient3463);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2050 d="m 355.8683,162.96049 0,2.02634 8.10536,0 0,-2.02634 -8.10536,0 z M 353.84196,166 l 0,2.02633 12.15804,0 0,-2.02633 -12.15804,0 z m 2.02634,3.0395 0,2.02634 8.10536,0 0,-2.02634 -8.10536,0 z m -2.02634,3.03951 0,2.02634 12.15804,0 0,-2.02634 -12.15804,0 z"
2051 id="path4632"
2052 inkscape:connector-curvature="0" /><path
2053 style="fill:url(#linearGradient3465);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2054 d="m 322,163 0,2 7,0 0,-2 -7,0 z m 0,3 0,2 11,0 0,-2 -11,0 z m 0,3 0,2 9,0 0,-2 -9,0 z m 0,3 0,2 12,0 0,-2 -12,0 z"
2055 id="path4634"
2056 inkscape:connector-curvature="0"
2057 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2058 style="fill:url(#linearGradient3467);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2059 d="M 13.143585,33.05435 9.0166293,38.06353 4.9286104,33.12695 c 0,0 -0.8954698,0.0269 -0.8954698,1.05265 0,2.21508 1.5511147,4.31748 3.2704133,5.95293 l -1.7909395,2.17791 0.1167447,0.14519 c -0.089703,-0.009 -0.1790976,-0.0363 -0.2725383,-0.0363 -1.3754463,0 -2.4917443,1.04074 -2.4917443,2.3231 0,1.28234 1.116298,2.3231 2.4917443,2.3231 1.3754463,0 2.4917443,-1.04076 2.4917443,-2.3231 0,-0.69345 -0.3382551,-1.31604 -0.8565423,-1.74234 0.4809109,-0.30316 1.2134856,-0.78955 2.0245504,-1.41563 0.8322385,0.64465 1.5928458,1.16764 2.1024048,1.48823 -0.478416,0.42398 -0.778669,1.00648 -0.778669,1.66974 0,1.28234 1.116298,2.3231 2.491745,2.3231 1.375446,0 2.491744,-1.04076 2.491744,-2.3231 0,-1.28236 -1.115055,-2.32427 -2.491744,-2.3231 -0.06354,0 -0.132378,0.0317 -0.194665,0.0363 l 0.03887,-0.0363 -1.907749,-2.28681 c 1.695639,-1.60874 3.231485,-3.67659 3.231485,-5.84404 0,-1.11857 -0.856533,-1.23414 -0.856533,-1.23414 z M 5.3568862,43.58089 c 0.6877138,0 1.2458722,0.52037 1.2458722,1.16154 0,0.64118 -0.5581584,1.16155 -1.2458722,1.16155 -0.6877231,0 -1.2458721,-0.52037 -1.2458721,-1.16155 0,-0.64117 0.558149,-1.16154 1.2458721,-1.16154 z m 7.4752328,0 c 0.687714,0 1.245872,0.52037 1.245872,1.16154 0,0.64118 -0.558158,1.16155 -1.245872,1.16155 -0.687723,0 -1.245872,-0.52037 -1.245872,-1.16155 0,-0.64117 0.558149,-1.16154 1.245872,-1.16154 z"
2060 id="path4636"
2061 inkscape:connector-curvature="0"
2062 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2063 sodipodi:nodetypes="sssssssssssssssssssscszsczcc"
2064 inkscape:connector-curvature="0"
2065 id="path4638"
2066 d="m 136,224.96874 c -3.86517,0 -7,3.14713 -7,7.03125 0,3.88412 3.13483,7.03125 7,7.03125 3.86633,0 7,-3.14713 7,-7.03125 0,-3.88412 -3.13367,-7.03125 -7,-7.03125 z m 0,1.03125 c 3.31371,0 6,2.68629 6,6 0,3.31371 -2.68629,6 -6,6 -3.31371,0 -6,-2.68629 -6,-6 0,-3.31371 2.68629,-6 6,-6 z m -2.34375,3 c -0.78758,0 -1.40625,0.64605 -1.40625,1.4375 0,0.79145 0.61867,1.4375 1.40625,1.4375 0.78761,0 1.4375,-0.64605 1.4375,-1.4375 0,-0.79145 -0.64989,-1.4375 -1.4375,-1.4375 z m 4.6875,0 c -0.7876,0 -1.4375,0.64605 -1.4375,1.4375 0,0.79145 0.6499,1.4375 1.4375,1.4375 0.78759,0 1.40625,-0.64605 1.40625,-1.4375 0,-0.79145 -0.61866,-1.4375 -1.40625,-1.4375 z m -5.23219,4.77513 c -0.0366,0.1544 -0.081,0.31581 -0.081,0.4768 0,1.55998 2.42289,1.8242 2.96945,1.81057 0.54656,-0.0136 2.96945,-0.25059 2.96945,-1.81057 0,-0.16099 -0.0444,-0.3224 -0.081,-0.4768 -1.30709,1.24337 -2.63751,1.02963 -2.88845,1.05774 -0.25094,0.0281 -2.02946,-0.0474 -2.88844,-1.05774 z"
2067 style="fill:url(#linearGradient3469);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2068 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2069 transform="matrix(2.1141636,0,0,2.1141636,-28.338578,-386.41917)"
2070 sodipodi:nodetypes="cssccscccssccscc"
2071 style="fill:url(#linearGradient3471);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2072 d="m 259.65386,163.531 c -1.472,0 -2.66666,1.24939 -2.66666,2.53241 0,1.28301 1.19466,2.3243 2.66666,2.3243 0.0453,0 0.0811,8.7e-4 0.12493,0 -0.196,1.29812 -0.87033,2.97394 -2.79166,4.64861 1.33333,0 5.33332,-2.32431 5.33332,-6.97291 0,-1.28302 -1.19466,-2.53241 -2.66666,-2.53241 z m 7.99998,0.026 c -1.472,0 -2.66666,1.22337 -2.66666,2.50639 0,1.28302 1.19466,2.32431 2.66666,2.32431 0.048,0 0.0784,8.7e-4 0.12493,0 -0.196,1.28069 -0.86633,2.93413 -2.79166,4.61228 1.37466,0 5.33332,-2.28798 5.33332,-6.93659 0,-1.28302 -1.19466,-2.50639 -2.66666,-2.50639 z"
2073 id="path4640"
2074 inkscape:connector-curvature="0" /><path
2075 style="fill:url(#linearGradient3473);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2076 d="m 40,225 c -3.86517,0 -7,3.13483 -7,6.99999 0,3.86518 3.13483,7.00001 7,7.00001 3.86633,0 7,-3.13483 7,-7.00001 C 47,228.13483 43.86633,225 40,225 z m 2.47916,2.29688 c 0.62773,-0.0298 1.3338,0.21291 2.1875,0.80207 -1.27516,0 -2.10904,1.30666 -2.88021,2.91667 l 1.4948,0 c 0.25783,0 0.4375,0.24325 0.4375,0.51041 l -1.16667,1.64063 -1.75,0 c -1.19233,2.56317 -2.57892,4.74454 -5.46875,2.73437 1.33233,-0.003 2.17992,-1.54671 2.98958,-3.31769 l 0.21875,-0.47398 c 1.0115,-2.26011 2.05434,-4.72275 3.9375,-4.81248 z"
2077 id="path4642"
2078 inkscape:connector-curvature="0"
2079 sodipodi:nodetypes="ssssscccsccccccc"
2080 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2081 inkscape:connector-curvature="0"
2082 id="path4644"
2083 d="M 7,6 7,7.875 5.625,9.34375 7,10.8125 7,12.71875 3.375,9.34375 z"
2084 style="fill:url(#linearGradient3475);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2085 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2086 inkscape:connector-curvature="0"
2087 id="path4646"
2088 d="M 8,6 11.6875,9.375 8,12.65625 8,10.75 9.4375,9.34375 8,7.8125 z"
2089 style="fill:url(#linearGradient3477);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2090 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2091 sodipodi:nodetypes="sccsscccssscsssssss"
2092 style="fill:url(#linearGradient3479);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2093 d="m 8.4001919,321 c -2.5311594,0 -4.5833578,2.05219 -4.5833578,4.58335 l 2.2916789,0 c 0,-1.26501 1.0266722,-2.29168 2.2916789,-2.29168 1.2650067,0 2.2916801,1.02667 2.2916801,2.29168 0,1.265 -1.0266734,2.29168 -2.2916801,2.29168 -0.8015237,0.007 -1.2388122,0.57905 -1.1458394,1.14585 l 0,1.0026 0,0.14323 c 0,0.6325 0.5133366,1.14584 1.1458394,1.14584 0.6325038,0 1.1458394,-0.51334 1.1458394,-1.14584 l 0,-0.14323 C 11.522604,329.51358 12.98355,327.71804 12.98355,325.58335 12.98355,323.05219 10.931351,321 8.4001919,321 z m 0,11.00442 c -0.8830925,0 -1.5998062,0.71671 -1.5998062,1.59981 0,0.88308 0.7167137,1.5998 1.5998062,1.5998 0.8830935,0 1.5998062,-0.71672 1.5998062,-1.5998 0,-0.8831 -0.7167127,-1.59981 -1.5998062,-1.59981 z"
2094 id="path4648"
2095 inkscape:connector-curvature="0"
2096 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2097 style="fill:url(#linearGradient3481);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2098 d="m 35.34264,356.37095 c 0.51469,-0.51344 1.34901,-0.51344 1.86244,0 L 40,359.15957 l 2.79492,-2.78862 c 0.51469,-0.51344 1.34901,-0.51344 1.86244,0 0.51469,0.51344 0.51469,1.34524 0,1.85992 l -2.79492,2.78989 2.79492,2.78864 c 0.51469,0.51341 0.51469,1.34648 0,1.85992 -0.51469,0.51343 -1.34901,0.51343 -1.86244,0 L 40,362.87943 l -2.79492,2.78989 c -0.51469,0.51343 -1.34901,0.51343 -1.86244,0 -0.51469,-0.51344 -0.51469,-1.34651 0,-1.85992 l 2.79492,-2.78864 -2.79492,-2.78989 c -0.51469,-0.51468 -0.51469,-1.34774 0,-1.85992 z"
2099 id="path4651"
2100 inkscape:connector-curvature="0"
2101 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2102 style="fill:url(#linearGradient3483);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2103 d="m 136.90909,352.99999 0,7.08065 4.69598,-3.57702 z m -1.17399,2.32963 c -3.2461,0 -5.86997,2.66057 -5.86997,5.90666 0,3.24609 2.62387,5.86997 5.86997,5.86997 3.24609,0 5.86997,-2.62388 5.86997,-5.86997 l 0,-0.0366 -2.34799,0 c 0,1.9453 -1.57667,3.52198 -3.52198,3.52198 -1.94531,0 -3.52198,-1.57668 -3.52198,-3.52198 0,-1.94531 1.57667,-3.52198 3.52198,-3.52198 0.41441,0 0.80535,0.0898 1.17399,0.22013 l 0,-2.42137 c -0.37685,-0.0763 -0.77484,-0.14675 -1.17399,-0.14675 z"
2104 id="path4653"
2105 inkscape:connector-curvature="0"
2106 sodipodi:nodetypes="cccccsssccssscccc"
2107 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2108 style="fill:url(#linearGradient3485);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2109 d="m 168.63108,225.60711 c -3.68133,0 -6.66665,2.71633 -6.66665,6.04164 0,2.46666 1.64933,4.56932 3.99999,5.49999 l 0,0.5 -2.66666,0 0,-0.66667 c 0,-0.36933 -0.29733,-0.66666 -0.66667,-0.66666 -0.36933,0 -0.66666,0.29733 -0.66666,0.66666 l 0,1.33333 c 0,0.36933 0.29733,0.66667 0.66666,0.66667 l 3.99999,0 c 0.368,0 0.66667,-0.29867 0.66667,-0.66667 l 0,-0.79166 0,-0.54167 0,-0.83333 c -1.55066,-0.66266 -2.66666,-2.40533 -2.66666,-4.49999 0,-2.65998 1.79066,-4.83331 3.99999,-4.83331 2.20933,0 3.99999,2.17333 3.99999,4.83331 0,2.09466 -1.116,3.83599 -2.66666,4.49999 l 0,0.83333 0,0.54167 0,0.79166 c 0,0.368 0.29866,0.66667 0.66666,0.66667 l 3.99999,0 c 0.0924,0 0.17019,-0.008 0.25,-0.0416 0.23926,-0.1012 0.41667,-0.349 0.41667,-0.625 l 0,-1.33333 c 0,-0.36933 -0.29733,-0.66667 -0.66667,-0.66667 -0.36933,0 -0.66666,0.29734 -0.66666,0.66667 l 0,0.66666 -2.66666,0 0,-0.5 c 2.35066,-0.93066 3.99999,-3.03332 3.99999,-5.49998 0,-3.32531 -2.98399,-6.04164 -6.66665,-6.04164 z"
2110 id="path4655"
2111 inkscape:connector-curvature="0"
2112 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2113 id="path4657"
2114 d="m 264,224.99999 c -3.86516,0 -7,3.13484 -7,7 0,3.86516 3.13484,7 7,7 3.86516,0 7,-3.13484 7,-7 0,-3.86516 -3.13484,-7 -7,-7 z m 0,1 c 0.57563,0 1.12928,0.0987 1.65625,0.25 -0.21686,0.024 -0.40509,0.0414 -0.21875,0.0625 0.60892,0.003 -0.1276,0.039 -0.1875,0.125 -0.11394,0.0829 -0.0834,0.026 -0.15625,0.125 -0.11101,0.005 -0.16343,0.0248 -0.1875,0.0312 0.0628,0.0123 0.21665,0.0288 0.3125,0.0312 0.26795,-0.0538 0.54333,-0.1539 0.8125,-0.25 0.0491,0.0177 0.10773,0.0123 0.15625,0.0312 -0.057,0.0184 -0.10829,0.071 -0.15625,0.0625 -0.34875,0.25862 0.70213,-0.0275 0.59375,0.46875 0.0904,0.035 0.0426,-0.16732 0.0312,-0.3125 1.98416,0.97877 3.34375,3.01293 3.34375,5.375 0,2.96499 -2.14232,5.42075 -4.96875,5.90625 0.002,-0.0351 -0.001,-0.0564 0,-0.0937 -0.0607,-0.31041 0.3513,-0.15238 0.375,-0.4375 -0.14618,-0.10055 -0.18095,-0.21709 -0.1875,-0.34375 -0.0227,-0.40268 0.15775,-0.34927 0,0 0.0223,0.0426 0.0716,0.0718 0.125,0.0937 0.0738,0.0209 0.14565,0.10949 0.21875,0.0312 0.41021,-0.33369 0.12457,-1.07604 0.71875,-1.15625 0.47136,-0.164 0.14359,-0.87555 0.4375,-1.1875 0.53462,-0.47621 -0.2551,-0.89849 -0.6875,-0.78125 -0.0559,-0.0857 -0.27353,-0.28009 -0.5,-0.0625 0.15857,-0.1649 -0.008,-0.23324 -0.25,-0.0312 0.24467,-0.17708 0.25848,-0.47377 -0.0625,-0.65625 -0.0508,9.9e-4 -0.10507,-0.004 -0.125,0.0312 -0.0638,-0.0687 -0.22894,-0.0608 -0.28125,0.0312 -0.0101,-0.0804 -0.0318,-0.15944 -0.0625,-0.1875 -0.12961,-0.14754 -0.16689,-0.11264 -0.1875,-0.0312 0.0112,-0.0474 0.002,-0.10756 0,-0.15625 -0.32535,-0.0722 -0.953,-0.49438 -1,0 0.002,-0.20286 -0.0586,-0.23675 -0.0937,-0.1875 0.0276,-0.0332 0.0683,-0.0615 0.125,-0.0937 -0.23557,0.0464 -0.5475,0.32011 -0.5625,0.5625 0.0648,0.41584 -0.42384,0.78976 -0.1875,1.0625 -0.0185,-0.003 -0.0422,0.0103 -0.0625,0 0.20991,0.41324 0.44408,0.73866 0.65625,1.0625 0.23031,0.0604 0.44985,0.14475 0.5625,0.3125 -0.17222,-0.0166 -0.26928,-0.0451 -0.40625,-0.0625 0.17318,0.2949 0.31495,0.60124 0.375,1 0.0695,0.54303 0.19023,1.00029 0.3125,1.375 -0.0919,0.004 -0.18828,0 -0.28125,0 -3.31371,0 -6,-2.6863 -6,-6 0,-1.4656 0.53344,-2.80175 1.40625,-3.84375 0.34206,-0.0211 0.7743,0.12805 0.75,0.4375 0.0307,0.0446 0.0539,0.0428 0.0625,0.0312 -0.0741,0.19641 -0.23979,0.37414 0.0937,0.5625 0.22757,0.0776 -0.005,-0.0939 -0.125,0.1875 -0.18886,-0.0161 -0.54745,0.56888 -0.53125,0.875 -0.006,0.28224 0.15163,0.47561 0.375,0.5625 -0.16645,0.0629 -0.0795,0.49173 0.0937,0.625 0.234,0.59128 0.0786,-0.21992 -0.0625,-0.40625 0.1184,-0.41868 0.28654,0.49131 0.5,0.59375 0.0459,0.40021 0.30654,0.5924 0.6875,0.71875 0.1724,0.007 0.42696,0.0904 0.5625,0 -0.0572,0.0939 -0.0543,0.2011 0.0937,0.21875 0.0497,0.0166 0.18315,0.0719 0.21875,0 0.0368,0.0175 0.10148,0.0198 0.15625,-0.0312 0.0432,-0.0198 0.0361,0.0124 0.0625,0 -0.11865,0.0885 -0.24679,0.23155 0.0312,0.28125 0.18197,0.12198 0.21951,-0.59882 -0.0312,-0.46875 -0.27053,-0.0764 -0.31824,0.10185 -0.25,0.1875 -0.38423,0.10029 0.48507,-0.80377 -0.0312,-0.71875 -0.14636,0.36457 -0.72915,0.44313 -0.71875,-0.0625 0.0733,-0.11228 0.0576,-0.29508 0,-0.4375 0.0762,0.0536 0.14828,-0.0524 0.25,-0.1875 0.0508,-0.20201 0.45865,-0.11762 0.5625,-0.125 -0.007,-0.008 -0.0149,-0.019 -0.0312,-0.0312 0.34794,-0.17518 0.70785,0.0435 0.71875,0.4375 0.0727,0.0592 0.0799,-0.14085 0.0937,-0.15625 -0.34271,-0.59064 0.60005,-0.61065 0.53125,-1.09375 0.086,0.0703 0.16097,-0.25555 0.46875,-0.34375 0.0156,-0.0612 0.5408,-0.25245 0.5625,-0.5625 l 0.0312,-0.0625 c -0.0777,0.58493 0.56903,-0.28504 0.125,-0.125 -0.48342,0.25168 -0.0186,-0.16425 0.21875,-0.15625 0.2339,0.10315 1.13432,-0.3299 0.59375,-0.375 -0.14861,0.004 0.0197,-0.83907 -0.375,-0.375 -0.18201,-0.013 -0.21657,-0.52148 -0.59375,-0.28125 -0.21308,0.35773 -0.42379,0.80911 -0.78125,0.96875 0.10551,-0.34815 -0.17558,-0.37355 -0.4375,-0.46875 -0.50037,-0.22009 0.22843,-0.53767 0.40625,-0.65625 0.42598,0.0488 0.0804,-0.2331 0.40625,-0.1875 0.25965,0.11567 0.79746,-0.45867 0.3125,-0.25 -0.34093,0.38477 -0.21848,-0.29476 -0.5,-0.15625 -0.0588,0.36258 -0.54949,0.31735 -0.9375,0.28125 -0.20901,0.22494 -0.18621,0.0524 -0.40625,0.0312 -0.22948,-0.0557 -0.62539,-0.2074 -1.03125,-0.125 -0.42791,0.0153 -0.77707,0.13054 -1.09375,0.375 0.18446,-0.14534 0.37067,-0.28434 0.3125,-0.34375 -0.13804,-0.0294 -0.26862,-0.0577 -0.40625,-0.0625 1.0158,-0.78806 2.2713,-1.2811 3.6564,-1.2811 z m -0.40625,9.625 c -0.0485,-0.0827 -0.10312,-0.16891 -0.15625,-0.25 -0.72058,-0.18902 -1.52571,0.0359 0.15625,0.25 z m 1.34375,-9.28125 c -0.10926,0.002 -0.25181,0.0495 -0.15625,0.125 l 0.125,0 c 0.22132,-0.0858 0.14056,-0.12682 0.0312,-0.125 z m -0.34375,0.34375 c -0.14885,0.0202 -0.1519,0.1631 0.15625,0.0937 0.007,0.066 0.1702,-0.0245 0.1875,0.0312 0.48589,-0.054 0.0831,-0.1527 -0.15625,-0.0937 -0.0717,-0.0408 -0.13788,-0.038 -0.1875,-0.0312 z m 0.0625,0.15625 c -0.012,-0.0131 -0.0364,0.004 -0.125,0.0625 -0.53787,0.41757 0.48274,0.0767 0.59375,0.34375 0.375,0.26203 -0.0911,0.19656 -0.28125,0.3125 -0.0495,0.0102 -0.0367,0.0257 -0.0625,0.0312 0.11906,0.007 0.28635,0.0602 0.3125,0.1875 l 0.0625,0.0312 c 0.31303,0.0938 -0.14015,-0.27069 0.25,-0.0937 -0.0154,-0.25514 0.0288,-0.26175 0.28125,-0.21875 -0.016,-0.36645 -0.58414,-0.66376 -0.96875,-0.5625 -0.23333,0.21055 -0.0265,-0.0545 -0.0625,-0.0937 z m -0.46875,0.0312 c -0.0468,0.0133 -0.0929,0.0396 -0.125,0.0937 0.0235,0.001 0.0376,0.0331 0.0625,0 0.33051,-0.0263 0.20282,-0.13358 0.0625,-0.0937 z m -1.5625,0.0312 c -0.17974,0.004 -0.43759,0.0773 -0.4375,0.25 0.11636,0.04 0.22509,-0.1096 0.34375,-0.125 0.35814,-0.0741 0.27354,-0.12883 0.0937,-0.125 z m 1.21875,0 c -0.12212,0.0231 -0.25374,0.0844 -0.125,0.125 l 0.0312,0.0312 0.0937,-0.0312 c 0.22922,-0.13332 0.12212,-0.14807 0,-0.125 z m -0.90625,0.0625 c -0.28655,0.0128 -0.61607,0.21385 -0.1875,0.25 -0.20655,0.0632 -0.46416,0.0131 -0.0625,0.125 0.24304,-0.0302 1.03903,-0.0694 0.625,-0.21875 0.16188,-0.2552 -0.0305,-0.0918 -0.15625,-0.0937 -0.0543,-0.0446 -0.12323,-0.0668 -0.21875,-0.0625 z m 0.71875,0.25 c -0.0294,0.007 -0.0677,0.0411 -0.0937,0.0937 0.23501,0.0305 0.18187,-0.11393 0.0937,-0.0937 z m 2.96875,0 c -0.1229,0.0647 -0.30864,0.56687 0,0.625 0.19641,0.13297 0.0343,-0.35877 0.0625,-0.5 -0.008,-0.10783 -0.0215,-0.14656 -0.0625,-0.125 z m -4.65625,0.3125 c 0.0326,-0.004 0.0441,-0.007 0.0312,0.0312 -0.33578,0.11083 -0.12904,-0.0181 -0.0312,-0.0312 z m 2.3125,0.0625 c -0.1313,-0.0266 -0.39703,0.19962 0,0.125 l 0.0625,0 c 0.0111,-0.0813 -0.0187,-0.11612 -0.0625,-0.125 z m -4.0625,0.78125 c 0.006,0.0143 0.0299,0.014 0.0312,0.0312 0.008,0.0435 -0.0235,0.085 -0.0312,0.125 -0.003,-0.0643 -0.009,-0.12364 0,-0.15625 z M 260,228.56249 c -0.009,0.006 -0.007,0.021 0,0.0625 0.0968,0.0138 0.0264,-0.0815 0,-0.0625 z m 5.5625,0.28125 c -0.0981,0.006 -0.34815,0.29505 -0.21875,0.28125 0.13337,0.0266 0.64304,-0.01 0.25,-0.15625 0.021,-0.0859 9.5e-4,-0.12697 -0.0312,-0.125 z m -5.53125,0.21875 c -0.0218,-0.001 -0.0245,0.0399 0.0312,0.125 0.30923,0.16511 0.034,-0.12127 -0.0312,-0.125 z m 4.875,0.1875 c -0.0184,-7.1e-4 -0.051,0.0101 -0.0937,0.0312 0.0994,0.0455 0.14896,-0.0291 0.0937,-0.0312 z m 0.125,0.0312 c -0.13693,0.0377 -0.38348,0.14021 -0.4375,0.25 0.10313,-1.8e-4 0.18325,-0.1022 0.28125,-0.125 0.32049,-0.15288 0.29318,-0.16268 0.15625,-0.125 z m -6.375,1 c -0.0116,-0.007 -0.0552,0.0257 -0.0937,0.0937 0.0414,0.1895 0.12849,-0.0728 0.0937,-0.0937 z m 1.5,0.53125 c 0.052,0.004 0.0833,0.0625 0.125,0.0937 -0.0524,-0.0363 -0.0856,-0.0794 -0.125,-0.0937 z m 2.4375,0.8125 c -0.0385,0.01 -0.0523,0.0335 -0.0625,0.0625 0.0946,-0.044 0.49211,0.15054 0.6875,0.21875 0.48854,0.0204 -0.35512,-0.34821 -0.625,-0.28125 z m 0.90625,0.28125 c -0.0182,-0.002 0.003,0.0237 0.0312,0.0937 -0.19576,0.095 -0.24616,0.0339 0.0312,0.0625 0.0616,0.0235 0.0953,0.025 0.0937,0 0.38314,0.0396 0.0666,-0.24469 -0.0312,-0.0625 -0.0308,-0.0484 -0.0997,-0.0915 -0.125,-0.0937 z m 0.53125,0.0938 c -0.0231,2.4e-4 -0.0377,0.0285 -0.0625,0.0625 0.0442,0.0146 0.0742,0.003 0.0937,0 -0.009,-0.0182 -0.005,-0.0628 -0.0312,-0.0625 z m -1.96875,0.0625 c 0.065,-0.0272 0.0304,0.0826 0,0.1875 -0.0131,-0.0878 -0.1107,-0.0462 -0.1875,0.0312 0.0164,-0.0269 0.0254,-0.0519 0.0312,-0.0937 0.0937,-0.0718 0.12538,-0.11212 0.15625,-0.125 z m 0.9375,0 c -0.008,0.003 -0.012,0.0121 0,0.0312 0.23882,0.0542 0.0924,-0.0358 0.0312,-0.0312 -0.0102,5e-4 -0.023,-0.003 -0.0312,0 z m 1.46875,0.75 c -0.0101,0.006 -0.0453,-0.003 -0.0625,0.0312 0.0396,0.0611 0.061,0.007 0.0625,-0.0312 z m -2.1875,0.0312 c -0.0104,0.0169 0.0106,0.052 0.15625,0.15625 0.36178,0.0251 -0.12511,-0.20702 -0.15625,-0.15625 z m 0.34375,0.1563 c -0.0422,0.0167 -0.0392,0.0395 0.0312,0.0937 0.0799,0.0985 0.14452,-0.0616 0.21875,-0.0937 -0.0966,-0.016 -0.19592,-0.0213 -0.25,0 z m 0.28125,0 c 0.0269,0.001 0.0379,0.0223 0.0625,0.0937 0.12084,-0.0286 0.0505,-0.0711 -0.0625,-0.0937 z m 0.59375,0.0625 c 0.0151,0.0164 0.0447,0.016 0.0625,0.0312 -0.0224,-0.004 -0.0368,0.002 -0.0625,0 -0.006,-0.01 0.005,-0.0214 0,-0.0312 z m 0.71875,0.0937 c 0.0918,-0.004 0.19416,0.006 0.3125,0.0312 -0.93272,0.60426 -0.955,-0.004 -0.3125,-0.0312 z m 0.875,0.1875 c 0.0209,0.0339 0.037,0.0652 0,0.125 -0.01,-0.0407 -0.0132,-0.0852 0,-0.125 z m -0.28125,0.0937 c 0.008,0.0407 0.0223,0.0692 0.0625,0.125 0.002,0.0174 0.0188,0.0345 0.0312,0.0312 0.0374,-0.01 0.0901,-0.078 0.0937,-0.0312 0.0326,-0.03 0.0758,-0.0367 0.0937,-0.0625 0.0122,0.0307 0.0395,0.0525 0.0625,0.0625 -0.0786,0.0243 -0.16205,0.0214 -0.25,0.0312 -0.55894,0.20149 0.0265,0.0442 -0.0937,-0.15625 z"
2115 style="fill:url(#linearGradient3487);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2116 inkscape:connector-curvature="0"
2117 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2118 inkscape:export-ydpi="90"
2119 inkscape:export-xdpi="90"
2120 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/skins/moono/icons/print.png"
2121 sodipodi:nodetypes="ssccssssssscsssscssssscccccssssssssssssss"
2122 inkscape:connector-curvature="0"
2123 id="path4664"
2124 d="M 228.5,2 C 227.669,2 227,2.669 227,3.5 l 0,0.49999 10,0 L 237,3.5 C 237,2.669 236.331,2 235.5,2 z M 226,5 c -0.554,0 -1,0.44599 -1,1 l 0,6 c 0,0.554 0.446,1 1,1 l 2,0 0,-5 c 0,-0.55401 0.446,-1 1,-1 l 6,0 c 0.554,0 1,0.44599 1,1 l 0,5 2,0 c 0.554,0 1,-0.446 1,-1 l 0,-6 c 0,-0.55401 -0.446,-1 -1,-1 z m 3,3 0,7 6,0 0,-7 z m 1.5,1 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.27699 -0.223,0.5 -0.5,0.5 l -3,0 C 230.223,10 230,9.77699 230,9.5 230,9.223 230.223,9 230.5,9 z m 0,2 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.27699 -0.223,0.5 -0.5,0.5 l -3,0 c -0.277,0 -0.5,-0.22301 -0.5,-0.5 0,-0.277 0.223,-0.5 0.5,-0.5 z"
2125 style="fill:url(#linearGradient3489);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2126 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2127 inkscape:connector-curvature="0"
2128 id="path4666"
2129 d="m 72,98 c -3.31371,0 -6,2.68629 -6,6 0,3.3137 2.68629,6 6,6 3.31371,0 6,-2.6863 6,-6 0,-3.31371 -2.68629,-6 -6,-6 z m 0,1 c 2.76142,0 5,2.23857 5,5 0,2.76142 -2.23858,5 -5,5 -2.76142,0 -5,-2.23858 -5,-5 0,-2.76143 2.23858,-5 5,-5 z m 0,2 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 1.65685,0 3,-1.34315 3,-3 0,-1.65686 -1.34315,-3 -3,-3 z"
2130 style="fill:url(#linearGradient3491);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2131 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2132 sodipodi:nodetypes="ssssssssssssscccccsss"
2133 inkscape:connector-curvature="0"
2134 id="path4670"
2135 d="m 291,100 c -1.662,0 -3,1.33799 -3,3 l 0,2 c 0,1.662 1.338,3 3,3 l 10,0 c 1.662,0 3,-1.338 3,-3 l 0,-2 c 0,-1.66201 -1.338,-3 -3,-3 z m 0,1 10,0 c 1.108,0 2,0.89199 2,2 l 0,2 c 0,1.108 -0.892,2 -2,2 l -2,-3 -3,3 -3,-2 -2,2 c -1.108,0 -2,-0.892 -2,-2 l 0,-2 c 0,-1.10801 0.892,-2 2,-2 z"
2136 style="fill:url(#linearGradient3493);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2137 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2138 style="font-size:16.54135895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3495);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2139 d="m 139.5,130 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 2.5,0 0,1 -2.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 l 0,2 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 0,-1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-2 c 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -3,0 z m -8.375,2.9375 c -0.29577,0 -0.58586,0.11711 -0.8125,0.34375 -0.45327,0.45327 -0.45327,1.20297 0,1.65625 l 2.03125,2.03125 L 130.3125,139 c -0.45327,0.45327 -0.45327,1.20297 0,1.65625 0.45327,0.45327 1.17173,0.45327 1.625,0 L 134,138.625 l 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 l -2.03125,-2.03125 2.03125,-2.03125 c 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 -0.45327,-0.45328 -1.17173,-0.45328 -1.625,0 L 134,135.3125 l -2.0625,-2.03125 c -0.22664,-0.22664 -0.51673,-0.34375 -0.8125,-0.34375 z"
2140 id="path4672"
2141 inkscape:connector-curvature="0"
2142 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2143 id="path4674"
2144 d="m 171.5,138 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.24281,0.60287 0.5,0.5 l 2.5,0 0,1 -2.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 l 0,2 c 0,0.277 0.223,0.5 0.5,0.5 l 3,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -2.5,0 0,-1 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-2 c 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m -8.375,-6.0625 c -0.29577,0 -0.58586,0.11711 -0.8125,0.34375 -0.45327,0.45327 -0.45327,1.20297 0,1.65625 l 2.03125,2.03125 L 162.3125,138 c -0.45327,0.45327 -0.45327,1.20297 0,1.65625 0.45327,0.45327 1.17173,0.45327 1.625,0 L 166,137.625 l 2.03125,2.03125 c 0.45327,0.45327 1.17173,0.45327 1.625,0 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 l -2.03125,-2.03125 2.03125,-2.03125 c 0.45327,-0.45328 0.45327,-1.20298 0,-1.65625 -0.45327,-0.45328 -1.17173,-0.45328 -1.625,0 L 166,134.3125 l -2.0625,-2.03125 c -0.22664,-0.22664 -0.51673,-0.34375 -0.8125,-0.34375 z"
2145 style="font-size:16.54135895px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3497);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2146 inkscape:connector-curvature="0"
2147 sodipodi:nodetypes="sssccsssssssccsssssssscssccssscsssccs"
2148 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2149 inkscape:connector-curvature="0"
2150 id="path4676"
2151 d="m 6.5,64.99999 c -3.03757,0 -5.5,2.46243 -5.5,5.5 0,3.03756 2.46243,5.5 5.5,5.5 0.938705,0 1.7919409,-0.27092 2.5625,-0.6875 l 3.75,3.75 c 0.587606,0.58761 1.537394,0.58761 2.125,0 0.587606,-0.58761 0.587606,-1.53739 0,-2.125 L 11.21875,73.21874 C 11.691902,72.41237 12,71.50424 12,70.49999 c 0,-3.03757 -2.46243,-5.5 -5.5,-5.5 z m 0,2 c 1.933,0 3.5,1.567 3.5,3.5 0,1.06272 -0.47105,2.01435 -1.21875,2.65625 -0.006,0.005 -0.02525,-0.005 -0.03125,0 -0.60985,0.51643 -1.38828,0.84375 -2.25,0.84375 -1.933,0 -3.5,-1.56701 -3.5,-3.5 0,-1.933 1.567,-3.5 3.5,-3.5 z"
2152 style="fill:url(#linearGradient3499);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2153 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2154 inkscape:connector-curvature="0"
2155 id="path4678"
2156 d="m 296.00004,34.99999 7,5 -6.99998,4.99999 -2e-5,-3.33332 c -3.41666,0 -5.61556,1.22 -7,3.33333 0,-4.98332 3.60112,-6.66666 7,-6.66666 -2e-5,-0.85078 -1e-5,-2.61389 0,-3.33334 z"
2157 style="fill:url(#linearGradient3501);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2158 sodipodi:nodetypes="ccccccc"
2159 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2160 inkscape:connector-curvature="0"
2161 id="path4680"
2162 d="m 68,163 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m 4.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 l -6,0 z m -4.5,5 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m 4.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z"
2163 style="fill:url(#linearGradient3503);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2164 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2165 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
2166 inkscape:connector-curvature="0"
2167 id="path4682"
2168 d="m 135.53125,162 c -0.25721,0 -0.46875,0.22299 -0.46875,0.5 l 0,12 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 l 0,-12 c 0,-0.27701 -0.21154,-0.5 -0.46875,-0.5 z M 131.5,164 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,164.20565 142.777,164 142.5,164 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 141,166.20565 140.777,166 140.5,166 z m -8.5,2.46875 0,0.0625 2,1.46875 0,-1 2.5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 134,168.20565 133.777,168 133.5,168 l -2.5,0 0,-1 z M 137.5,168 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,168.20565 142.777,168 142.5,168 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 141,170.20565 140.777,170 140.5,170 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,172.20565 142.777,172 142.5,172 z"
2169 style="fill:url(#linearGradient3505);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2170 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2171 style="fill:url(#linearGradient3507);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2172 d="m 232.46875,162 c 0.25721,0 0.46875,0.22299 0.46875,0.5 l 0,12 c 0,0.277 -0.21154,0.5 -0.46875,0.5 C 232.21154,175 232,174.777 232,174.5 l 0,-12 c 0,-0.27701 0.21154,-0.5 0.46875,-0.5 z m 4.03125,2 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 C 231,164.79434 230.777,165 230.5,165 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 225,164.20565 225.223,164 225.5,164 z m 0,2 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 C 231,166.79434 230.777,167 230.5,167 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 227,166.20565 227.223,166 227.5,166 z m 8.49436,2.53125 0,-0.0625 -1.99549,-1.46875 0,1 -2.49436,0 c -0.27637,0 -0.49887,0.18037 -0.49887,0.46875 l 0,0.0625 c 0,0.2631 0.2225,0.46875 0.49887,0.46875 l 2.49436,0 0,1 z M 230.5,168 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 C 231,168.79434 230.777,169 230.5,169 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 225,168.20565 225.223,168 225.5,168 z m 0,2 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 C 231,170.79434 230.777,171 230.5,171 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 227,170.20565 227.223,170 227.5,170 z m 6,2 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22385 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27615 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20565 0.5,0.46875 l 0,0.0625 C 231,172.79434 230.777,173 230.5,173 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 225,172.20565 225.223,172 225.5,172 z"
2173 id="path4684"
2174 inkscape:connector-curvature="0"
2175 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
2176 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2177 sodipodi:nodetypes="sscccccccccccscccc"
2178 inkscape:connector-curvature="0"
2179 id="path4686"
2180 d="m 458,163 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 l 0,4 1,0 0,-9 1,0 0,1 0,8 1,0 0,-8 1,0 0,-2 z m -8,3 0,6 3,-3 z"
2181 style="fill:url(#linearGradient3509);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2182 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2183 sodipodi:nodetypes="sscccccccccccscccc"
2184 inkscape:connector-curvature="0"
2185 id="path4688"
2186 d="m 485,163 c -1.65685,0 -3,1.34314 -3,3 0,1.65685 1.34315,3 3,3 l 0,4 1,0 0,-9 1,0 0,1 0,8 1,0 0,-8 1,0 0,-2 z m 9.00442,3 0,6 -3.00884,-3 z"
2187 style="fill:url(#linearGradient3511);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2188 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2189 sodipodi:nodetypes="ccccccccccccc"
2190 inkscape:connector-curvature="0"
2191 id="path4691"
2192 d="m 41.56445,200.66667 -1.02277,1.06211 2.08489,2.08489 -2.08489,2.12422 L 41.56445,207 43.68867,204.87578 45.8129,207 l 1.02277,-1.06211 -2.08489,-2.12423 2.08489,-2.08488 -1.02277,-1.06211 -2.12423,2.12422 z"
2193 style="fill:url(#linearGradient3513);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2194 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2195 style="fill:url(#linearGradient3515);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2196 d="m 135.53125,162 c -0.25721,0 -0.46875,0.22299 -0.46875,0.5 l 0,12 c 0,0.277 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.223 0.46875,-0.5 l 0,-12 c 0,-0.27701 -0.21154,-0.5 -0.46875,-0.5 z M 131.5,164 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,164.20565 142.777,164 142.5,164 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 141,166.20565 140.777,166 140.5,166 z m -8.5,2.46875 0,0.0625 2,1.46875 0,-1 2.5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 134,168.20565 133.777,168 133.5,168 l -2.5,0 0,-1 z M 137.5,168 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,168.20565 142.777,168 142.5,168 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 141,170.20565 140.777,170 140.5,170 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 C 143,172.20565 142.777,172 142.5,172 z"
2197 id="path4693"
2198 inkscape:connector-curvature="0"
2199 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
2200 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2201 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
2202 inkscape:connector-curvature="0"
2203 id="path4695"
2204 d="m 167.64267,162 c -0.25721,0 -0.46875,0.223 -0.46875,0.5 l 0,12 c 0,0.27699 0.21154,0.5 0.46875,0.5 0.25721,0 0.46875,-0.22301 0.46875,-0.5 l 0,-12 c 0,-0.277 -0.21154,-0.5 -0.46875,-0.5 z m -4.03125,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -3.38858,2.46875 0,0.0625 -2.08914,1.46875 0,-1 -2.61141,0 C 161.23294,169 161,168.9653 161,168.53125 l 0,-0.0625 C 161,168.20565 161.23294,168 161.52229,168 l 2.61141,0 0,-1 z M 169.61142,168 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m 0,2 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 3,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z m -6,2 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 2,0 c -0.27614,0 -0.5,0.22385 -0.5,0.5 0,0.27614 0.22386,0.5 0.5,0.5 0.27614,0 0.5,-0.22386 0.5,-0.5 0,-0.27615 -0.22386,-0.5 -0.5,-0.5 z m 4,0 c -0.277,0 -0.5,0.20565 -0.5,0.46875 l 0,0.0625 c 0,0.26309 0.223,0.46875 0.5,0.46875 l 5,0 c 0.277,0 0.5,-0.20566 0.5,-0.46875 l 0,-0.0625 c 0,-0.2631 -0.223,-0.46875 -0.5,-0.46875 z"
2205 style="fill:url(#linearGradient3517);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2206 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2207 sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssccccsssscccsssssssssssssssssssssssssssssssssssss"
2208 inkscape:connector-curvature="0"
2209 id="path4698"
2210 d="m 200.46875,162 c 0.25722,0 0.46875,0.223 0.46875,0.5 l 0,12 c 0,0.277 -0.21153,0.5 -0.46875,0.5 C 200.21154,175 200,174.777 200,174.5 l 0,-12 c 0,-0.277 0.21154,-0.5 0.46875,-0.5 z m 4.03125,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 C 199,164.79434 198.777,165 198.5,165 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 193,164.20566 193.223,164 193.5,164 z m 0,2 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 C 199,166.79434 198.777,167 198.5,167 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 195,166.20566 195.223,166 195.5,166 z m 3.5,2.53125 0,-0.0625 2,-1.46875 0,1 2.5,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 c 0,0.26309 -0.22343,0.48425 -0.5,0.46875 l -2.5,0 0,1 z M 198.5,168 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 C 199,168.79434 198.777,169 198.5,169 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 193,168.20566 193.223,168 193.5,168 z m 0,2 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 C 199,170.79434 198.777,171 198.5,171 l -3,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 195,170.20566 195.223,170 195.5,170 z m 6,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -4,0 c 0.277,0 0.5,0.20566 0.5,0.46875 l 0,0.0625 C 199,172.79434 198.777,173 198.5,173 l -5,0 c -0.277,0 -0.5,-0.20566 -0.5,-0.46875 l 0,-0.0625 C 193,172.20566 193.223,172 193.5,172 z"
2211 style="fill:url(#linearGradient3519);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2212 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2213 inkscape:connector-curvature="0"
2214 id="path4700"
2215 d="m 1,226 0,12 14,0 0,-12 -14,0 z m 1,1 12,0 0,7.59375 L 11.09375,231 8,235 5,233 2,237 2,227 z m 2.5,1 C 3.67157,228 3,228.67157 3,229.5 3,230.32842 3.67157,231 4.5,231 5.32842,231 6,230.32842 6,229.5 6,228.67157 5.32842,228 4.5,228 z"
2216 style="fill:url(#linearGradient3521);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2217 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2218 sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
2219 inkscape:connector-curvature="0"
2220 id="path4702"
2221 d="m 198,227 0,3 10,0 0,-3 z m -5,2 0,7 4,-3.4375 z m 5,3 0,1 3,0 0,-1 z m 4,0 0,1 3,0 0,-1 z m 4,0 0,1 2,0 0,-1 z m -8,3 0,3 10,0 0,-3 z"
2222 style="fill:url(#linearGradient3523);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2223 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2224 sodipodi:nodetypes="sscccssssscccssss"
2225 inkscape:connector-curvature="0"
2226 id="path4704"
2227 d="m 322.5,100 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24236 0.59935,0.45353 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.37612,-0.74776 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
2228 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3525);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2229 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2230 sodipodi:nodetypes="ssssssccssssssccsssssscccssssscccssssccccccccccc"
2231 inkscape:connector-curvature="0"
2232 id="path4706"
2233 d="m 130,98 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.09069 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.90931 2,-2 l 0,-0.375 c 0.0328,-0.0893 0.0213,-0.17215 0,-0.25 L 144,100 c 0,-1.0907 -0.9093,-2 -2,-2 z m 0,1 12,0 c 0.554,0 1,0.446 1,1 l 0,4.11795 -5.88205,5.88195 L 130,110 c -0.554,1e-5 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 z m 0.5,1 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.0444,0.53446 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.12178,-0.5281 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 12.5,5.40625 0,0.84375 -3.71875,3.6875 -0.0312,0.0625 -0.84375,0 z m 0,2.21875 0,0.625 -1.71875,1.75 -0.625,0 z"
2234 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3527);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2235 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2236 sodipodi:nodetypes="sssssssssssssssssscccc"
2237 inkscape:connector-curvature="0"
2238 id="path4708"
2239 d="m 194,99 c -1.0907,0 -2,0.9093 -2,2 l 0,7 c 0,1.0907 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-7 c 0,-1.0907 -0.9093,-2 -2,-2 z m 0,1 12,0 c 0.554,0 1,0.446 1,1 l 0,7 c 0,0.554 -0.446,1 -1,1 l -12,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-7 c 0,-0.554 0.446,-1 1,-1 z m 6,3 3,4 3,-4 z"
2240 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3529);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2241 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2242 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3531);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2243 d="m 209,707 c -2.32953,0 -4.43371,1.05678 -5.90625,2.6875 l 3.5625,2.0625 C 207.31214,711.27977 208.12788,711 209,711 c 2.216,0 4,1.784 4,4 l 0,3 -5,0 -4,0 -2,0 -2,0 c -1.108,0 -2,0.89196 -2,2 l 0,12 c 0,1.108 0.892,2 2,2 l 18,0 c 1.108,0 2,-0.892 2,-2 l 0,-12 c 0,-1.10804 -0.892,-2 -2,-2 l -1,0 0,-3 c 0,-4.36281 -3.63719,-8 -8,-8 z m 0,17 c 1.65686,0 3,1.34314 3,3 0,1.65682 -1.34314,3 -3,3 -1.65686,0 -3,-1.34318 -3,-3 0,-1.65686 1.34314,-3 3,-3 z"
2244 transform="translate(1,-367.75001)"
2245 id="path4710"
2246 inkscape:connector-curvature="0" /><path
2247 inkscape:connector-curvature="0"
2248 id="path4712"
2249 d="m 3.5,163 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 0.5,0 0,3.5 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-4 C 5,163.223 4.777,163 4.5,163 l -1,0 z m 4,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z m -5,5 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,1 -1.5,0 C 2.223,172 2,172.223 2,172.5 l 0,2 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 C 4.777,175 5,174.77699 5,174.5 5,174.223 4.777,174 4.5,174 l -1.5,0 0,-1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 0.0252,-0.0599 0.0312,-0.11825 0.0312,-0.1875 l 0,-2 c 0,-0.0693 -0.006,-0.12765 -0.0312,-0.1875 -0.0505,-0.13913 -0.15407,-0.24028 -0.28125,-0.28125 -0.0404,-0.0171 -0.0799,-0.0253 -0.125,-0.0312 l -0.0625,0 -2,0 z m 5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -6,0 z"
2250 style="fill:url(#linearGradient3673);fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2251 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2252 sodipodi:nodetypes="cccccccccccccccccccscccscscccscccccccc"
2253 d="m 13.295487,138.29724 c -9e-6,0.70891 -0.137341,1.30388 -0.411995,1.78492 -0.274673,0.46838 -0.650527,0.84815 -1.127571,1.1393 -0.462605,0.2785 -1.019157,0.48105 -1.669674,0.60763 -0.6360688,0.11394 -1.3227277,0.1709 -2.059977,0.1709 l -3.7296601,0.0121 0,-12.04805 3.4694455,-0.003 c 1.0119224,1e-5 1.8359131,0.095 2.4719816,0.28482 0.636059,0.17724 1.134796,0.41776 1.496201,0.72156 0.361395,0.29117 0.607142,0.6203 0.737259,0.9874 0.130097,0.36712 0.195146,0.73423 0.195156,1.10133 -10e-6,0.557 -0.159025,1.0507 -0.477054,1.4811 -0.303581,0.43041 -0.715576,0.7722 -1.235986,1.02538 0.910722,0.29116 1.525098,0.68359 1.843147,1.17728 0.332478,0.49371 0.498718,1.01272 0.498727,1.55705 m -6.3317393,-1.59503 0,3.19006 c 0.1879221,0.0253 0.3903124,0.0443 0.6071515,0.057 0.2312976,0.0127 0.4553613,0.019 0.67221,0.019 0.303571,1e-5 0.5999175,-0.019 0.8890395,-0.057 0.2891221,-0.0506 0.5421027,-0.13292 0.7589418,-0.24685 0.2312975,-0.12659 0.4192195,-0.29748 0.5637855,-0.51269 0.144556,-0.22786 0.216839,-0.51268 0.216839,-0.85448 0,-0.56965 -0.209614,-0.97473 -0.628834,-1.21526 -0.4047711,-0.25317 -0.9540982,-0.37976 -1.6479815,-0.37977 l -1.4311518,0 m 1.0408394,-1.93682 c 0.6794248,1e-5 1.1926105,-0.12658 1.5395666,-0.37977 0.3469368,-0.26583 0.5204103,-0.62661 0.5204103,-1.08234 0,-0.27849 -0.05059,-0.50002 -0.1517905,-0.66459 -0.1011903,-0.17722 -0.2385221,-0.31014 -0.4119953,-0.39876 -0.1734733,-0.10126 -0.3758635,-0.16456 -0.6071516,-0.18989 -0.2312976,-0.038 -0.4698197,-0.057 -0.7155759,-0.057 -0.2023806,1e-5 -0.4119953,0.006 -0.6288345,0.019 -0.2168391,0.0127 -0.4119953,0.0317 -0.5854685,0.057 l 0,2.69636 1.0408394,0"
2254 style="font-size:22.63113022px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3533);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Ubuntu Mono;-inkscape-font-specification:Ubuntu Mono Bold"
2255 id="path4714"
2256 inkscape:connector-curvature="0"
2257 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><g
2258 id="g4716"
2259 style="font-size:14.87401295px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3537);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2260 transform="matrix(1.8191013,0,-0.4691387,1.8191013,-489.83328,-196.53417)"><path
2261 sodipodi:nodetypes="ccccccccccccc"
2262 inkscape:connector-curvature="0"
2263 id="path4718"
2264 style="font-size:21.24859047px;font-variant:normal;font-weight:bold;font-stretch:normal;fill:url(#linearGradient3535);font-family:Ubuntu Mono;-inkscape-font-specification:Ubuntu Mono Bold"
2265 d="m 325.2364,61.999996 0,-2.167356 1.76912,0 -0.1287,-8.818165 -1.76912,0 0,-2.167356 6.15181,0 0,2.167356 -1.74787,0 0.1287,8.818165 1.74787,0 0,2.167356 -6.15181,0" /></g><g
2266 id="g4720"
2267 style="font-size:15.82676315px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4491);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2268 transform="matrix(2.1281094,0,0,1.8850568,-169.0631,-208.10971)"><path
2269 sodipodi:nodetypes="ccccccccc"
2270 inkscape:connector-curvature="0"
2271 id="path4722"
2272 style="font-size:22.60966301px;font-style:italic;font-variant:normal;font-stretch:normal;fill:url(#linearGradient5619);fill-opacity:1;font-family:'8bitoperator JVE';-inkscape-font-specification:'8bitoperator JVE Italic'"
2273 d="m 263.15116,63.849438 2.25213,-9.18288 -2.8262,0 0.28703,-1.413104 8.47863,0 -0.28704,1.413104 -2.82621,0 -2.25213,9.18288 -2.82621,0" /></g><path
2274 inkscape:connector-curvature="0"
2275 id="path4726"
2276 d="m 264.00004,34.99999 7,5 -6.99998,4.99999 -2e-5,-3.33332 c -3.41666,0 -5.61556,1.22 -7,3.33333 0,-4.98332 3.60112,-6.66666 7,-6.66666 -2e-5,-0.85078 -1e-5,-2.61389 0,-3.33334 z"
2277 style="fill:url(#linearGradient3543);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2278 sodipodi:nodetypes="ccccccc"
2279 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2280 sodipodi:nodetypes="ccccccc"
2281 style="fill:url(#linearGradient3545);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2282 d="m 328,35 -7,5 6.99998,4.99998 2e-5,-3.33332 c 3.41666,0 5.61556,1.22 7,3.33334 0,-4.98333 -3.60112,-6.66667 -7,-6.66667 2e-5,-0.85078 10e-6,-2.61388 0,-3.33333 z"
2283 id="path4728"
2284 inkscape:connector-curvature="0"
2285 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2286 sodipodi:nodetypes="sssssssssssssssssscccc"
2287 inkscape:connector-curvature="0"
2288 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3547);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2289 d="m 238,99 c 1.0907,0 2,0.9093 2,2 l 0,7 c 0,1.0907 -0.9093,2 -2,2 l -12,0 c -1.0907,0 -2,-0.9093 -2,-2 l 0,-7 c 0,-1.0907 0.9093,-2 2,-2 z m 0,1 -12,0 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 z m -6,3 -3,4 -3,-4 z"
2290 id="path4730"
2291 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2292 inkscape:connector-curvature="0"
2293 id="path4732"
2294 d="m 111,193 0,14 -1,0 0,-14 z m -4.74999,-0.41664 c 0.86983,0.009 1.76033,0.34033 2.74999,1.375 L 109,202 c -3.96132,-4.05865 -6.94268,2.81598 -11,-1 l 0,-8.04165 c 3.03099,2.934 5.64051,-0.40352 8.25001,-0.37496 z"
2295 style="fill:url(#linearGradient3549);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2296 sodipodi:nodetypes="cccccccccccc"
2297 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2298 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3551);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2299 d="m 78.5,289 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -3.5,0 c 1.0907,0 2,0.9093 2,2 l 0,10 c 0,1.0907 -0.9093,2 -2,2 -1.0907,0 -2,-0.9093 -2,-2 l 0,-10 c 0,-1.0907 0.9093,-2 2,-2 z m 0,1 c -0.554,0 -1,0.446 -1,1 l 0,10 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 l 0,-10 c 0,-0.554 -0.446,-1 -1,-1 z m 11.5,1 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -8,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 8,2 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m -2,0 c 0.27614,0 0.5,0.22386 0.5,0.5 0,0.27614 -0.22386,0.5 -0.5,0.5 -0.27614,0 -0.5,-0.22386 -0.5,-0.5 0,-0.27614 0.22386,-0.5 0.5,-0.5 z m 6.5,2 c 1.0907,0 2,0.9093 2,2 0,1.0907 -0.9093,2 -2,2 l -5,0 c -1.0907,0 -2,-0.9093 -2,-2 0,-1.0907 0.9093,-2 2,-2 l 5,0 z m 0,1 -5,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 5,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z"
2300 id="path4734"
2301 inkscape:connector-curvature="0"
2302 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2303 sodipodi:nodetypes="ssccsssssccsssscccccccccc"
2304 inkscape:connector-curvature="0"
2305 id="path4736"
2306 d="m 67,1 c -1.108,0 -2,0.892 -2,2 l 0,8.9375 3,3.0625 9,0 c 1.108,0 2,-0.892 2,-2 L 79,3 C 79,1.892 78.108,1 77,1 z m 0,1 10,0 0,4 c 0,1.108 0.108,1 -1,1 L 68,7 C 66.892,7 67,7.108 67,6 z m 1,8 8,0 0,4 -4,0 0,-3 -2,0 0,3 -2,0 z"
2307 style="fill:url(#linearGradient3553);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2308 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2309 sodipodi:nodetypes="ssscsssssssssssssssssssscssccsssssssccsccssccccccssssssssssssss"
2310 style="fill:url(#linearGradient3671);fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2311 d="m 44.5,163 c 0,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.777,0.5 0.5,0.5 l 0.5,0 0,3.5 c 0,0.27699 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.22301 0.5,-0.5 l 0,-4 c 0,-0.277 -0.5,-0.5 -0.5,-0.5 z m -10,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 9,5 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 1.5,0 0,1 -1.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 l 0,2 c 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -1.5,0 0,-1 1.5,0 c 0.0693,0 0.12764,-0.006 0.1875,-0.0312 0.12718,-0.041 0.2307,-0.14213 0.28125,-0.28125 0.0252,-0.0599 0.0312,-0.11825 0.0312,-0.1875 l 0,-2 c 0,-0.0693 -0.006,-0.12765 -0.0312,-0.1875 -0.0505,-0.13913 -0.15407,-0.24028 -0.28125,-0.28125 -0.0404,-0.0171 -0.0799,-0.0253 -0.125,-0.0312 l -0.0625,0 -2,0 z m -9,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
2312 id="path4738"
2313 inkscape:connector-curvature="0"
2314 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2315 sodipodi:nodetypes="ssssssssssssssssssssssssssssssssssssss"
2316 style="fill:url(#linearGradient3555);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2317 d="m 108,163 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m -10.5,0 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.22299 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.27701 -0.223,-0.5 -0.5,-0.5 z m 10.5,5 c -1.10457,0 -2,0.89543 -2,2 0,1.10456 0.89543,2 2,2 1.10457,0 2,-0.89544 2,-2 0,-1.10457 -0.89543,-2 -2,-2 z m -10.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0,2 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.277 0.223,0.5 0.5,0.5 l 6,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z"
2318 id="path4740"
2319 inkscape:connector-curvature="0"
2320 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2321 style="fill:url(#linearGradient3557);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2322 d="m 234,227 0,3 -10,0 0,-3 z m 5,2 0,7 -4,-3.4375 z m -5,3 0,1 -3,0 0,-1 z m -4,0 0,1 -3,0 0,-1 z m -4,0 0,1 -2,0 0,-1 z m 8,3 0,3 -10,0 0,-3 z"
2323 id="path4742"
2324 inkscape:connector-curvature="0"
2325 sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
2326 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2327 inkscape:connector-curvature="0"
2328 id="path4746"
2329 d="m 40,320.96568 c -3.86517,0 -7,3.1502 -7,7.03432 0,3.88412 3.13483,7.03431 7,7.03431 3.86633,0 7,-3.15019 7,-7.03431 0,-3.88412 -3.13367,-7.03432 -7,-7.03432 z"
2330 style="fill:url(#linearGradient3559);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2331 sodipodi:nodetypes="sssss"
2332 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2333 inkscape:transform-center-y="2.9999632"
2334 inkscape:transform-center-x="-1.4999864"
2335 sodipodi:end="2.0943951"
2336 sodipodi:start="0"
2337 sodipodi:type="arc"
2338 style="fill:#999999;fill-opacity:1;stroke:none"
2339 id="path4748"
2340 sodipodi:cx="39.5"
2341 sodipodi:cy="327.5"
2342 sodipodi:rx="5.5"
2343 sodipodi:ry="5.5"
2344 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2345 transform="matrix(2.1818034,0,0,2.1818034,-5.1812409,-426.29057)" /><path
2346 transform="matrix(-1.0909017,1.8894973,-1.8894973,-1.0909017,742.90096,570.88525)"
2347 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2348 sodipodi:ry="5.5"
2349 sodipodi:rx="5.5"
2350 sodipodi:cy="327.5"
2351 sodipodi:cx="39.5"
2352 id="path4750"
2353 style="fill:#cccccc;fill-opacity:1;stroke:none"
2354 sodipodi:type="arc"
2355 sodipodi:start="0"
2356 sodipodi:end="2.0943951"
2357 inkscape:transform-center-x="3.0004864" /><path
2358 inkscape:transform-center-y="-3.0004886"
2359 inkscape:transform-center-x="-1.4999969"
2360 sodipodi:end="2.0943951"
2361 sodipodi:start="0"
2362 sodipodi:type="arc"
2363 style="fill:#666666;fill-opacity:1;stroke:none"
2364 id="path4752"
2365 sodipodi:cx="39.5"
2366 sodipodi:cy="327.5"
2367 sodipodi:rx="5.5"
2368 sodipodi:ry="5.5"
2369 d="m 45,327.5 a 5.5,5.5 0 0 1 -8.25,4.76314 L 39.5,327.5 z"
2370 transform="matrix(-1.0909017,-1.8894973,1.8894973,-1.0909017,-494.71972,720.15551)" /><rect
2371 ry="0"
2372 rx="0"
2373 y="230.99997"
2374 x="97"
2375 height="2"
2376 width="14"
2377 id="rect4754"
2378 style="fill:url(#linearGradient3561);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2379 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2380 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2381 id="rect4756"
2382 width="12"
2383 height="0.99999475"
2384 x="98"
2385 y="227.99997"
2386 rx="0"
2387 ry="0"
2388 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2389 ry="0"
2390 rx="0"
2391 y="225.99997"
2392 x="98"
2393 height="0.99999475"
2394 width="12"
2395 id="rect4758"
2396 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2397 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2398 ry="0"
2399 rx="0"
2400 y="236.99997"
2401 x="98"
2402 height="0.99999475"
2403 width="12"
2404 id="rect4760"
2405 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2406 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2407 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2408 id="rect4762"
2409 width="12"
2410 height="0.99999475"
2411 x="98"
2412 y="234.99997"
2413 rx="0"
2414 ry="0"
2415 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2416 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2417 id="rect4764"
2418 width="12"
2419 height="0.99999475"
2420 x="98"
2421 y="223.99997"
2422 rx="0"
2423 ry="0"
2424 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><rect
2425 ry="0"
2426 rx="0"
2427 y="238.99997"
2428 x="98"
2429 height="0.99999475"
2430 width="12"
2431 id="rect4766"
2432 style="fill:#636363;fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3)"
2433 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2434 transform="matrix(-2,0,0,2,673.04102,-367.74989)"
2435 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3563);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2436 d="m 162,98 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.09069 0.9093,2 2,2 l 12,0 c 1.0907,0 2,-0.90931 2,-2 l 0,-0.375 c 0.0328,-0.0893 0.0213,-0.17215 0,-0.25 L 176,100 c 0,-1.0907 -0.9093,-2 -2,-2 z m 0,1 12,0 c 0.554,0 1,0.446 1,1 l 0,4.11795 -5.88205,5.88195 L 162,110 c -0.554,1e-5 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 z m 0.5,1 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.24237 0.0444,0.53446 0.5625,0.5 l 0.4375,0 0,5 -0.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 0,0.27699 0.223,0.5 0.5,0.5 l 2,0 c 0.277,0 0.5,-0.22301 0.5,-0.5 0,-0.277 -0.12178,-0.5281 -0.5,-0.5 l -0.5,0 0,-5 0.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 12.5,5.40625 0,0.84375 -3.71875,3.6875 -0.0312,0.0625 -0.84375,0 z m 0,2.21875 0,0.625 -1.71875,1.75 -0.625,0 z"
2437 id="path4768"
2438 inkscape:connector-curvature="0"
2439 sodipodi:nodetypes="ssssssccssssssccsssssscccssssscccssssccccccccccc" /><path
2440 style="fill:url(#linearGradient3565);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2441 d="m 64,225 0,2 0,10 0,2 16,0 0,-2 0,-10 0,-2 z m 1,4 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m -10,5 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z m 5,0 4,0 0,4 -4,0 z"
2442 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
2443 id="path4770"
2444 inkscape:connector-curvature="0"
2445 sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc" /><path
2446 inkscape:connector-curvature="0"
2447 id="path4788"
2448 d="m 3,210.24999 0,10 3,-2.75 5,4.75 4,0 0,-4 -5,-4.75 3,-3.25 -10,0 z m 18,0 3,3.25 -5,4.75 0,4 4,0 5,-4.75 3,2.75 0,-10 -10,0 z m -10,16 -5,4.75 -3,-2.75 0,10 10,0 -3,-3.25 5,-4.75 0,-4 -4,0 z m 8,0 0,4 5,4.75 -3,3.25 10,0 0,-10 -3,2.75 -5,-4.75 -4,0 z"
2449 style="fill:url(#linearGradient5672);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)" /><path
2450 id="path4795"
2451 d="m 258,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 -6,0 z m 1,1 5.34375,0 3.65625,3.65625 0,8.34375 -5,0 -3,0 -1,0 0,-12 z m 2,5 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z m 0,2 0,1 5,0 0,-1 -5,0 z"
2452 style="fill:url(#linearGradient3567);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2453 inkscape:connector-curvature="0"
2454 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2455 style="fill:url(#linearGradient3569);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2456 d="m 2,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2457 id="path4797"
2458 inkscape:connector-curvature="0"
2459 sodipodi:nodetypes="cccccccccccccccc"
2460 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2461 transform="matrix(-2,0,0,2,161,-367.74989)"
2462 style="fill:url(#linearGradient3571);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2463 d="m 39,6 0,1.875 -1.375,1.46875 1.375,1.46875 0,1.90625 -3.625,-3.375 z"
2464 id="path4799"
2465 inkscape:connector-curvature="0" /><path
2466 transform="matrix(-2,0,0,2,161,-367.74989)"
2467 style="fill:url(#linearGradient3573);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2468 d="M 40,6 43.6875,9.375 40,12.65625 40,10.75 41.4375,9.34375 40,7.8125 z"
2469 id="path4801"
2470 inkscape:connector-curvature="0" /><path
2471 transform="matrix(-2,0,0,2,163,-367.74989)"
2472 sodipodi:nodetypes="cccccccccccccccc"
2473 inkscape:connector-curvature="0"
2474 id="path4803"
2475 d="m 35,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2476 style="fill:url(#linearGradient3575);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)" /><path
2477 style="fill:url(#linearGradient3577);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2478 d="m 98,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2479 id="path4805"
2480 inkscape:connector-curvature="0"
2481 sodipodi:nodetypes="cccccccccccccccc"
2482 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2483 transform="matrix(-2,0,0,2,545,-367.74989)"
2484 sodipodi:nodetypes="cccccccccccccccc"
2485 inkscape:connector-curvature="0"
2486 id="path4807"
2487 d="m 131,0.99999 0,14 11,0 0,-9 0,-1 -4,-4 -1,0 z m 1,1 5.5,0 3.5,3.5 0,8.5 -5,0 -3,0 -1,0 z"
2488 style="fill:url(#linearGradient3579);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)" /><path
2489 id="path4809"
2490 d="m 290,0.99999 0,4.75 c 0.19146,-0.12014 0.37062,-0.22084 0.5625,-0.3125 L 291,5.21874 l 0,-3.21875 5.34375,0 3.65625,3.65625 0,8.34375 -5,0 0,0.96875 c 0,0.0104 1.6e-4,0.0209 0,0.0312 l 6,0 0,-9 0,-1 -4,-4 -1,0 -6,0 z m 1,5.34375 c -0.36123,0.17256 -0.68892,0.37641 -0.96875,0.65625 -0.63338,0.63338 -1.03125,1.5335 -1.03125,2.5 0,1.39352 0.8237,2.5644 2,3.125 l 0,2.34375 c 0,0.554 0.44599,1 1,1 l 1,0.0312 c 0.554,0 1,-0.47725 1,-1.03125 l 0,-2.34375 c 1.17629,-0.5606 2,-1.73148 2,-3.125 0,-1.39352 -0.82119,-2.59313 -2,-3.15625 l 0,2.65625 -1.46875,1 -1.53125,-1 0,-2.65625 z"
2491 style="fill:url(#linearGradient3581);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2492 inkscape:connector-curvature="0"
2493 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2494 id="path4817"
2495 d="m 33,31.99999 0,10 3,0 0,-1 -1,0 -1,0 0,-8 4.5,0 2.5,2.5 0,0.5 1,0 0,-1 -3,-3 -1,0 -5,0 z m 4,5 0,10 9,0 0,-6 0,-1 -3,-3 -1,0 -5,0 z m 1,1 4.5,0 2.5,2.5 0,5.5 -5,0 -1,0 -1,0 0,-8 z"
2496 style="fill:url(#linearGradient3583);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2497 inkscape:connector-curvature="0"
2498 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2499 transform="matrix(-2,0,0,2,777,-367.74989)"
2500 inkscape:connector-curvature="0"
2501 style="fill:url(#linearGradient3585);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2502 d="m 182,0.99999 0,14 8.8125,0 -1,-1 -1.3125,0 -1.5,0 -3,0 -1,0 0,-12 5.5,0 3.5,3.5 0,1.21875 c 0.61468,0.7698887 1,1.7287934 1,2.78125 l 0,-3.5 0,-1 -4,-4 -1,0 -6,0 z m 11,8.5 c 0,0.4831876 -0.20077,0.86276 -0.34375,1.28125 L 193,11.12499 l 0,-1.625 z m -4.5,-3.5 c -1.92115,0 -3.5,1.57884 -3.5,3.5 0,1.92115 1.57885,3.5 3.5,3.5 0.49539,0 0.94633,-0.12374 1.375,-0.3125 l 2.34375,2.34375 1.625,-1.625 -2.28125,-2.28125 C 191.829,10.63214 192,10.09539 192,9.49999 c 0,-1.92116 -1.57885,-3.5 -3.5,-3.5 z m -0.0312,1 c 1.38071,0 2.5,1.11929 2.5,2.5 0,1.38071 -1.11929,2.5 -2.5,2.5 -1.38071,0 -2.5,-1.11929 -2.5,-2.5 0,-1.38071 1.11929,-2.5 2.5,-2.5 z"
2503 id="path4828" /><path
2504 transform="matrix(-2,0,0,2,1313,-367.74989)"
2505 inkscape:connector-curvature="0"
2506 style="fill:url(#linearGradient3587);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2507 d="m 323,0.99999 0,4.75 c 0.19146,-0.1201434 0.37062,-0.2208417 0.5625,-0.3125 L 324,5.21874 l 0,-3.21875 5.34375,0 3.65625,3.65625 0,8.34375 -5,0 0,0.96875 c 0,0.01043 1.6e-4,0.02085 0,0.03125 l 6,0 0,-9 0,-1 -4,-4 -1,0 -6,0 z m 1,5.34375 c -0.36123,0.1725562 -0.68892,0.3764154 -0.96875,0.65625 C 322.39787,7.6333667 322,8.5334899 322,9.49999 c 0,1.393522 0.8237,2.564396 2,3.125 l 0,2.34375 c 0,0.554002 0.44599,1.000002 1,1 l 1,0.03125 c 0.554,-2e-6 1,-0.477248 1,-1.03125 l 0,-2.34375 c 1.17629,-0.560603 2,-1.731478 2,-3.125 0,-1.3935222 -0.82119,-2.5931341 -2,-3.15625 l 0,2.65625 -1.46875,1 -1.53125,-1 0,-2.65625 z"
2508 id="path4830" /><rect
2509 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2510 id="rect6517"
2511 width="13.999996"
2512 height="2"
2513 x="141"
2514 y="-231.74991" /><rect
2515 y="-227.74991"
2516 x="133"
2517 height="2"
2518 width="22"
2519 id="rect6519"
2520 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2521 y="-219.74991"
2522 x="133"
2523 height="2"
2524 width="22"
2525 id="rect6523"
2526 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2527 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2528 id="rect6525"
2529 width="6"
2530 height="2"
2531 x="133"
2532 y="-215.74991" /><path
2533 style="fill:#2d2d2d;fill-opacity:1;stroke:none"
2534 d="m 141,-215.74991 0,2 2,0 0,4 -2,0 0,2 6,0 0,-2 -2,0 0,-4 2,0 0,-2 -2,0 -2,0 -2,0 z"
2535 id="rect6527"
2536 inkscape:connector-curvature="0" /><rect
2537 y="-223.74991"
2538 x="133"
2539 height="2"
2540 width="22"
2541 id="rect6539"
2542 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2543 y="-235.74991"
2544 x="141"
2545 height="2"
2546 width="14"
2547 id="rect6547"
2548 style="fill:#2d2d2d;fill-opacity:1;stroke:none" /><rect
2549 style="fill:#2d2d2d;fill-opacity:0.99215686;stroke:none"
2550 id="rect6606"
2551 width="6"
2552 height="6"
2553 x="133"
2554 y="-235.74991" /><path
2555 inkscape:connector-curvature="0"
2556 style="fill:url(#linearGradient3589);fill-opacity:1;fill-rule:evenodd;display:inline;filter:url(#filter3224-1-7-1-3)"
2557 d="m 7.424061,258.01101 c -1.28354,3.14452 -2.79862,6.87174 -4.15625,10.1875 l 2.5,0 0.90625,-2.5 3.34375,0 0.8125,2.5 2.625,0 c -1.33823,-3.35178 -2.81774,-6.95392 -4.09375,-10.1875 l -1.9375,0 z m 0.96875,2.96875 0.90625,2.6875 -1.90625,0 1,-2.6875 z"
2558 id="path4763"
2559 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2560 style="fill:#999999;fill-opacity:1;fill-rule:evenodd;display:inline;filter:url(#filter3224-1-7-1-3)"
2561 d="m 1,270.01101 0,1.98898 15,0 0,-1.98898 z"
2562 id="path3812"
2563 inkscape:connector-curvature="0"
2564 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2565 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3591);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2566 d="M 102.53125,32 C 102.23664,32 102,32.23664 102,32.53125 L 102,33 101.53125,33 C 101.23664,33 101,33.23664 101,33.53125 l 0,0.9375 C 101,34.76335 101.23664,35 101.53125,35 l 1,0 2.9375,0 1,0 C 106.76336,35 107,34.76335 107,34.46875 l 0,-0.9375 C 107,33.23664 106.76336,33 106.46875,33 L 106,33 106,32.53125 C 106,32.23664 105.76336,32 105.46875,32 l -2.9375,0 z M 100,33 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 C 100,33.34767 100.0316,33.16464 100.0937,33 L 100,33 z m 7.90625,0 C 107.9684,33.16465 108,33.34767 108,33.53125 L 108,34 c 0.554,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z M 103,38 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 2,0 0,4 1,0 0,-4 2,0 0,-1 -5,0 z"
2567 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
2568 id="path3631"
2569 inkscape:connector-curvature="0" /><path
2570 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient3593);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1-3);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2571 d="M 134.53125,32 C 134.23664,32 134,32.23664 134,32.53125 L 134,33 133.53125,33 C 133.23664,33 133,33.23664 133,33.53125 l 0,0.9375 C 133,34.76335 133.23664,35 133.53125,35 l 1,0 2.9375,0 1,0 C 138.76336,35 139,34.76335 139,34.46875 l 0,-0.9375 C 139,33.23664 138.76336,33 138.46875,33 L 138,33 138,32.53125 C 138,32.23664 137.76336,32 137.46875,32 l -2.9375,0 z M 132,33 c -1.0907,0 -2,0.9093 -2,2 l 0,2 1,0 0,-2 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0316,-0.3666 0.0937,-0.53125 L 132,33 z m 7.90625,0 C 139.96835,33.16464 140,33.34767 140,33.53125 L 140,34 c 0.554,0 1,0.446 1,1 l 0,9 c 0,0.554 -0.446,1 -1,1 l -1,0 0,1 1,0 c 1.0907,0 2,-0.9093 2,-2 l 0,-9 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z M 130,38 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 l -7,0 z m 0,1 7,0 0,7 -7,0 0,-7 z m 1,1 0,1 2,0 0,4 1,0 0,-4 2,0 0,-1 -5,0 z"
2572 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
2573 id="path3655"
2574 inkscape:connector-curvature="0" /><rect
2575 style="fill:url(#linearGradient3595);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2576 id="rect3807"
2577 width="16"
2578 height="7.9999976"
2579 x="256"
2580 y="99.999992"
2581 rx="2"
2582 ry="2"
2583 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><g
2584 style="font-size:15.85716724px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3713);fill-opacity:0.99215686;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2585 id="text3563"
2586 transform="matrix(2,0,0,2,35,-367.74989)"><path
2587 d="m 91.018035,130.55223 0,2.44671 c -0.634915,-0.28389 -1.011554,-0.48077 -1.615481,-0.62531 -0.603942,-0.14452 -1.174325,-0.21679 -1.71115,-0.2168 -0.712338,10e-6 -1.238845,0.0981 -1.579522,0.29423 -0.340685,0.19616 -0.511026,0.5007 -0.511022,0.91364 -4e-6,0.30972 0.113556,0.55233 0.340681,0.72782 0.232279,0.17035 0.650387,0.31746 1.254327,0.44134 l 1.269812,0.25551 c 1.28529,0.2581 2.198934,0.6504 2.740936,1.1769 0.541983,0.52651 0.81298,1.27498 0.81299,2.2454 -10e-6,1.27498 -0.379405,2.22475 -1.138185,2.84933 -0.753637,0.61942 -1.907307,0.92913 -3.461013,0.92913 -0.732986,0 -1.468547,-0.0697 -2.206686,-0.20905 -0.738146,-0.13937 -1.476288,-0.34584 -2.214429,-0.61942 l 0,-2.5164 c 0.738141,0.39231 1.450474,0.68911 2.137002,0.89042 0.691682,0.19615 1.357558,0.29423 1.997631,0.29423 0.650386,0 1.148502,-0.1084 1.494352,-0.3252 0.345836,-0.2168 0.518757,-0.52651 0.518765,-0.92913 -8e-6,-0.36133 -0.11873,-0.64007 -0.356167,-0.83622 -0.232289,-0.19615 -0.699435,-0.37165 -1.401439,-0.52651 l -1.153671,-0.25551 c -1.156255,-0.24776 -2.002796,-0.64264 -2.539624,-1.18464 -0.531671,-0.54199 -0.797506,-1.27239 -0.797504,-2.1912 -2e-6,-1.15108 0.37165,-2.03634 1.114957,-2.65577 0.743301,-0.61941 1.811801,-0.92912 3.205501,-0.92913 0.6349,1e-5 1.287872,0.049 1.958918,0.14712 0.671031,0.0929 1.122516,0.21753 1.840021,0.40851"
2588 style="font-weight:bold;fill:url(#linearGradient5621);-inkscape-font-specification:Sans Bold"
2589 id="path3568"
2590 inkscape:connector-curvature="0"
2591 sodipodi:nodetypes="ccccccccccccsccccsccccccssccc" /></g><path
2592 id="path3593"
2593 d="m 98.5,136 12,0 c 0.277,0 0.5,0.20442 0.5,0.45833 l 0,0.0833 C 111,136.79558 110.777,137 110.5,137 l -12,0 c -0.277,0 -0.5,-0.20442 -0.5,-0.45833 l 0,-0.0833 C 98,136.20442 98.223,136 98.5,136 z"
2594 style="fill:#565656;fill-opacity:0.98431373;stroke:none;filter:url(#filter3224-1-7-1-3)"
2595 inkscape:connector-curvature="0"
2596 sodipodi:nodetypes="sssssssss"
2597 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2598 style="fill:url(#linearGradient3597);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1)"
2599 d="m 1.9999999,354 0,13 1,0 0,-13 z"
2600 id="path3580"
2601 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2602 inkscape:export-xdpi="90"
2603 inkscape:export-ydpi="90"
2604 inkscape:connector-curvature="0"
2605 sodipodi:nodetypes="ccccc"
2606 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2607 style="fill:#b50000;fill-opacity:1;fill-rule:evenodd"
2608 d="m 13.99998,339.41683 c -1.5815,0.018 -3.2006,0.68066 -4.9999799,2.75 l 0,16.08328 C 16.2024,350.13281 21.62306,363.88207 29,356.25011 l 0,-16.0833 c -5.5109,5.868 -10.25548,-0.80704 -15.00002,-0.74992 z"
2609 id="path3574"
2610 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2611 inkscape:export-xdpi="90"
2612 inkscape:export-ydpi="90"
2613 inkscape:connector-curvature="0" /><path
2614 id="path4350"
2615 d="m 13.99998,341.41683 c -1.5815,0.018 -3.2006,0.68066 -4.9999799,2.75 l 0,14.08328 C 16.2024,350.13281 21.62306,363.88207 29,356.25011 l 0,-14.0833 c -5.5109,5.868 -10.25548,-0.80704 -15.00002,-0.74992 z"
2616 style="fill:url(#linearGradient5639);fill-opacity:1;fill-rule:evenodd"
2617 inkscape:connector-curvature="0"
2618 sodipodi:nodetypes="ccccccc"
2619 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2620 inkscape:export-xdpi="90"
2621 inkscape:export-ydpi="90" /><path
2622 style="fill:#8e0000;fill-opacity:1;fill-rule:evenodd"
2623 d="m 29,340.18759 c -0.6161,0.65602 -1.22016,1.13058 -1.81818,1.5 l 0,14 c -4.75112,2.93492 -8.96772,-2.30074 -13.18182,-2.25 -1.5815,0.018 -3.20062,0.68066 -4.9999999,2.75 l 0,0.5 0,1.5 0,0.0624 c 0.35284,-0.39764 0.68014,-0.7662 1.0227199,-1.0625 0.34258,-0.2963 0.6881,-0.5439 1.02274,-0.75 0.66926,-0.4122 1.33732,-0.63162 1.98864,-0.75 -0.1292,-0.018 -0.26402,-0.0344 -0.39774,-0.0624 0.4581,-0.1264 0.91488,-0.1824 1.36364,-0.1874 3.05338,-0.0368 6.11734,2.72286 9.375,3.125 0.1286,0.016 0.26858,-0.008 0.39772,0 0.172,0.01 0.33786,0.0674 0.51138,0.0624 0.1896,-0.006 0.37654,-0.0376 0.56818,-0.0624 0.26176,-0.034 0.5297,-0.1128 0.79544,-0.1874 0.37798,-0.1058 0.75176,-0.2352 1.13638,-0.4375 0.0602,-0.031 0.11,-0.0914 0.1704,-0.125 0.33964,-0.1886 0.67552,-0.41302 1.02274,-0.6875 0.33604,-0.26566 0.67898,-0.51938 1.02272,-0.875 l 0,-0.0624 0,-2 0,-14 z"
2624 id="path4364"
2625 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2626 inkscape:export-xdpi="90"
2627 inkscape:export-ydpi="90"
2628 inkscape:connector-curvature="0" /><rect
2629 inkscape:export-ydpi="90"
2630 inkscape:export-xdpi="90"
2631 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2632 y="336.25012"
2633 x="1"
2634 height="32"
2635 width="32"
2636 id="rect3598"
2637 style="fill:#ffffff;fill-opacity:0;stroke:none" /><path
2638 sodipodi:nodetypes="ccccc"
2639 inkscape:connector-curvature="0"
2640 inkscape:export-ydpi="90"
2641 inkscape:export-xdpi="90"
2642 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2643 id="path3600"
2644 d="m 1.9999999,354 0,13 1,0 0,-13 z"
2645 style="fill:url(#linearGradient3601);fill-opacity:1;fill-rule:evenodd;filter:url(#filter3224-1-7-1-3)"
2646 transform="matrix(2,0,0,2,1.0000003,-367.74989)" /><path
2647 inkscape:connector-curvature="0"
2648 inkscape:export-ydpi="90"
2649 inkscape:export-xdpi="90"
2650 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2651 id="path3602"
2652 d="m 13.99998,339.41683 c -1.5815,0.018 -3.2006,0.68066 -4.9999799,2.75 l 0,16.08328 C 16.2024,350.13281 21.62306,363.88207 29,356.25011 l 0,-16.0833 c -5.5109,5.868 -10.25548,-0.80704 -15.00002,-0.74992 z"
2653 style="fill:#b50000;fill-opacity:1;fill-rule:evenodd" /><path
2654 inkscape:export-ydpi="90"
2655 inkscape:export-xdpi="90"
2656 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2657 sodipodi:nodetypes="ccccccc"
2658 inkscape:connector-curvature="0"
2659 style="fill:url(#linearGradient5632);fill-opacity:1;fill-rule:evenodd"
2660 d="m 13.99998,341.41683 c -1.5815,0.018 -3.2006,0.68066 -4.9999799,2.75 l 0,14.08328 C 16.2024,350.13281 21.62306,363.88207 29,356.25011 l 0,-14.0833 c -5.5109,5.868 -10.25548,-0.80704 -15.00002,-0.74992 z"
2661 id="path3604" /><path
2662 inkscape:connector-curvature="0"
2663 inkscape:export-ydpi="90"
2664 inkscape:export-xdpi="90"
2665 inkscape:export-filename="/home/oleq/ck/ckeditor-dev/plugins/link/images/anchor.png"
2666 id="path3606"
2667 d="m 29,340.18759 c -0.6161,0.65602 -1.22016,1.13058 -1.81818,1.5 l 0,14 c -4.75112,2.93492 -8.96772,-2.30074 -13.18182,-2.25 -1.5815,0.018 -3.20062,0.68066 -4.9999999,2.75 l 0,0.5 0,1.5 0,0.0624 c 0.35284,-0.39764 0.68014,-0.7662 1.0227199,-1.0625 0.34258,-0.2963 0.6881,-0.5439 1.02274,-0.75 0.66926,-0.4122 1.33732,-0.63162 1.98864,-0.75 -0.1292,-0.018 -0.26402,-0.0344 -0.39774,-0.0624 0.4581,-0.1264 0.91488,-0.1824 1.36364,-0.1874 3.05338,-0.0368 6.11734,2.72286 9.375,3.125 0.1286,0.016 0.26858,-0.008 0.39772,0 0.172,0.01 0.33786,0.0674 0.51138,0.0624 0.1896,-0.006 0.37654,-0.0376 0.56818,-0.0624 0.26176,-0.034 0.5297,-0.1128 0.79544,-0.1874 0.37798,-0.1058 0.75176,-0.2352 1.13638,-0.4375 0.0602,-0.031 0.11,-0.0914 0.1704,-0.125 0.33964,-0.1886 0.67552,-0.41302 1.02274,-0.6875 0.33604,-0.26566 0.67898,-0.51938 1.02272,-0.875 l 0,-0.0624 0,-2 0,-14 z"
2668 style="fill:#8e0000;fill-opacity:1;fill-rule:evenodd" /><path
2669 style="fill:url(#linearGradient3605);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3)"
2670 d="m 64,321 0,14 3,0 0,-1 -2,0 0,-12 2,0 0,-1 z m 13,0 0,1 2,0 0,12 -2,0 0,1 3,0 0,-14 z"
2671 transform="matrix(2,0,0,2,1.0000003,-367.74991)"
2672 id="rect3578"
2673 inkscape:connector-curvature="0"
2674 sodipodi:nodetypes="cccccccccccccccccc" /><g
2675 style="font-size:13.71140385px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3609);fill-opacity:1;stroke:none;filter:url(#filter3224-1-7-1-3);font-family:Sans"
2676 id="text4354"
2677 transform="matrix(2,0,0,2,3.0000003,-367.74989)"><path
2678 d="m 70.006423,329.43503 1.991763,0 c 1.837326,0 3.016509,-1.30258 3.016509,-3.33187 0,-2.00186 -1.138049,-3.09877 -3.22218,-3.09877 l -3.790777,0 0,9.99561 2.004685,0 0,-3.56497 m 0,-1.71392 0,-3.0028 1.347327,0 c 1.096911,0 1.604234,0.4799 1.604234,1.50826 0,1.01464 -0.507323,1.49454 -1.604234,1.49454 l -1.347327,0"
2679 style="font-variant:normal;font-weight:bold;font-stretch:normal;fill:url(#linearGradient3607);font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L Bold"
2680 id="path4361"
2681 inkscape:connector-curvature="0"
2682 sodipodi:nodetypes="csssccccccsssc" /></g><path
2683 inkscape:connector-curvature="0"
2684 id="rect4493"
2685 d="m 518,-165.75001 c -1.662,0 -3,1.338 -3,3 l 0,5 c 0,1.36076 0.91892,2.47391 2.15625,2.84375 -0.0819,-0.27391 -0.15625,-0.54251 -0.15625,-0.84375 l 0,-5 c 0,-1.662 1.338,-3 3,-3 l 22,0 c 0.30124,0 0.56984,0.0744 0.84375,0.15625 -0.36984,-1.23733 -1.48299,-2.15625 -2.84375,-2.15625 l -22,0 z"
2686 style="fill:#808080;fill-opacity:0.99215686;fill-rule:nonzero;stroke:none" /><path
2687 style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.98999999;color:#000000;fill:url(#linearGradient5855);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3224-1-7-1);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
2688 d="m 67,128 c -1.108,0 -2,0.892 -2,2 l 0,12 c 0,1.108 0.892,2 2,2 l 1,0 1,0 3,0 c 2.181406,0 4,-1.81859 4,-4 l 0,-2 c 0,-2.18141 -1.818594,-4 -4,-4 l -3,0 0,-4 c 0,-1.108 -0.892,-2 -2,-2 z m 18,4 -6,3.875 6,4 0,-2.625 c 4.53598,0.002 6.887,2.90102 8,4.625 -0.112,-4.06048 -3.48268,-7.3724 -8,-7.375 z m -16,4 3,0 c 1.108,0 2,0.892 2,2 l 0,2 c 0,1.108 -0.892,2 -2,2 l -3,0 z m 17,8 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 2,0 c 3,0 3,2 3,3 l 0,1 -4,0 c -2.181406,0 -4,1.81859 -4,4 l 0,2 c 0,2.18141 1.818594,4 4,4 l 4,0 1,0 1,0 c 1.108,0 2,-0.892 2,-2 l 0,-10 c 0,-4 -5,-4 -5,-4 l -1,0 z m -19,4 c 0.112,4.06048 3.48268,7.37242 8,7.375 l 0,2.5 6,-3.875 -6,-4 0,2.625 C 70.46402,152.623 68.113,149.72398 67,148 z m 20,4 4,0 0,1 0,4 0,1 -4,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-2 c 0,-1.108 0.892,-2 2,-2 z"
2689 transform="translate(1,-367.75001)"
2690 id="path4589"
2691 inkscape:connector-curvature="0"
2692 sodipodi:nodetypes="ssssccsssscssccccccccssssccssssscssssccsssccscccccccsccccssss" /><g
2693 id="g5901"
2694 style="fill:url(#linearGradient5906)"><path
2695 d="m 584.67613,-45.75002 c 1.46129,2e-5 2.48419,0.58335 3.06872,1.75001 0.2338,0.48612 0.37993,1.06945 0.43839,1.74999 l 0,7.00001 c -10e-6,1.45834 -0.58452,2.47916 -1.75355,3.0625 -0.48711,0.23333 -1.07162,0.37917 -1.75356,0.4375 l -4.67613,0 0,-14.00001 4.67613,0 m 1.16904,11.08334 0,-8.16667 c -1e-5,-0.71943 -0.38969,-1.10832 -1.16904,-1.16666 l -2.33806,0 0,10.5 2.33806,0 c 0.7209,0 1.11058,-0.38889 1.16904,-1.16667"
2696 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:url(#linearGradient5906);fill-opacity:1;stroke:none;display:inline;filter:url(#filter3224-1-7-1-3);font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
2697 id="path5866"
2698 inkscape:connector-curvature="0" /><path
2699 d="m 597.01421,-44.00001 -2.33807,0 0,10.5 2.33807,0 0,1.75 -7.0142,0 0,-1.75 2.33806,0 0,-10.5 -2.33806,0 0,-1.75001 7.0142,0 0,1.75001"
2700 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:url(#linearGradient5906);fill-opacity:1;stroke:none;display:inline;filter:url(#filter3224-1-7-1-3);font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
2701 id="path5868"
2702 inkscape:connector-curvature="0" /><path
2703 d="m 607.18325,-44.00001 -2.92259,12.25 -2.33807,0 -2.92258,-12.25 0,-1.75001 2.33807,0 0,1.75001 1.75354,10.5 1.75356,-10.5 0,-1.75001 2.33807,0 0,1.75001"
2704 style="font-size:22.18914413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:url(#linearGradient5906);fill-opacity:1;stroke:none;display:inline;filter:url(#filter3224-1-7-1-3);font-family:Audimat Mono;-inkscape-font-specification:Audimat Mono"
2705 id="path5870"
2706 inkscape:connector-curvature="0" /></g><path
2707 style="opacity:0.98999999;fill:url(#linearGradient6101);fill-opacity:1;stroke:none;display:inline;filter:url(#filter3224-1-7-1-3-1)"
2708 d="M 166.53125,32 C 166.23664,32 166,32.23664 166,32.53125 L 166,33 165.53125,33 C 165.23664,33 165,33.23664 165,33.53125 l 0,0.9375 C 165,34.76335 165.23664,35 165.53125,35 l 1,0 2.9375,0 1,0 C 170.76336,35 171,34.76335 171,34.46875 l 0,-0.9375 C 171,33.23664 170.76336,33 170.46875,33 L 170,33 170,32.53125 C 170,32.23664 169.76336,32 169.46875,32 z M 164,33 c -1.0907,0 -2,0.9093 -2,2 l 0,9 c 0,1.0907 0.9093,2 2,2 l 1,0 0,-1 -1,0 c -0.554,0 -1,-0.446 -1,-1 l 0,-9 c 0,-0.554 0.446,-1 1,-1 l 0,-0.46875 c 0,-0.18358 0.0317,-0.36661 0.0937,-0.53125 z m 7.90625,0 C 171.9684,33.16465 172,33.34767 172,33.53125 L 172,34 c 0.554,0 1,0.446 1,1 l 0,2 1,0 0,-2 c 0,-1.0907 -0.9093,-2 -2,-2 l -0.0937,0 z M 167,38 c -0.554,0 -1,0.446 -1,1 l 0,7 c 0,0.554 0.446,1 1,1 l 7,0 c 0.554,0 1,-0.446 1,-1 l 0,-7 c 0,-0.554 -0.446,-1 -1,-1 z m 0,1 7,0 0,7 -7,0 z m 1,1 0,1 0,4 1,0 1,-1 0.5,-0.50005 L 171,44 l 1,1 1,0 0,-4 0,-1 -1,0 0,3 -1,-1 -1,0 -1,1 0,-3 z"
2709 transform="matrix(-2,0,0,2,737,-367.75001)"
2710 id="path4585-1"
2711 inkscape:connector-curvature="0"
2712 sodipodi:nodetypes="sscssssccsssscsssssssccssscscscscsccssccsssssssssccccccccccccccccccccccc" /><path
2713 style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline;filter:url(#filter3224-1-7-1-5-0-8)"
2714 d="m 223.46875,276.31249 c -5.17784,1.61214 -11.48202,1.46403 -12.53125,1.375 l 0.5,1.9375 c 1.53833,0.005 2.5625,0.0382 4.5625,-0.0781 l 0,4.70312 -6,0 0,2 6,0 0,6 -4,0 -2,0 0,10 2,0 0,-2 10,0 0,1 2,0 0,-1 0,-8 -2,0 -4,0 0,-6 6,0 0,-2 -6,0 0,-4.84375 c 2.35241,-0.16735 3.875,-0.53375 5.875,-1.25 z M 196,276.24999 l 0,2 12,0 0,-2 z m -2,4 0,2 16,0 0,-2 z m 2,4 0,2 12,0 0,-2 z m 0,4 0,2 12,0 0,-2 z m 0,4 0,10 2,0 0,-2 8,0 0,1 2,0 0,-1 0,-8 -2,0 -8,0 z m 2,2 8,0 0,4 -8,0 z m 14,0 10,0 0,4 -10,0 z"
2715 id="rect4258"
2716 inkscape:connector-curvature="0"
2717 sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" /><path
2718 style="fill:#515151;fill-opacity:1;stroke:none;display:inline;filter:url(#filter3224-1-7-1-3-24)"
2719 d="m 170,230.24999 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m -14,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,5 0,1 0,3 5,0 0,-1 -4,0 0,-1 4,0 1,0 0,-1 -5,0 0,-1 6,0 4,0 0,-1 0,-4 -4,0 -7,0 z m 12,0 0,1 1,0 0,-1 -1,0 z m -11,1 9,0 0,1 -9,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -11,1 8.9687,0 0,1 -8.9687,0 0,-1 z m -3,1 0,1 1,0 0,-1 -1,0 z m 14,0 0,1 1,0 0,-1 -1,0 z m -3,1.75 -3.6875,3.375 3.6875,3.28125 0,-1.90625 -1.4375,-1.40625 1.4375,-1.53125 0,-1.8125 z m 1,0 0,1.875 1.375,1.46875 -1.375,1.46875 0,1.90625 3.625,-3.375 -3.625,-3.34375 z m -12,0.25 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 0,2 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z m 2,0 0,1 1,0 0,-1 -1,0 z"
2720 id="rect5051"
2721 inkscape:connector-curvature="0"
2722 transform="matrix(2,0,0,2,-83,-186.24999)" /></g></svg> \ No newline at end of file
diff --git a/sources/skins/moono/dev/locations.json b/sources/skins/moono/dev/locations.json
new file mode 100644
index 0000000..4e09053
--- /dev/null
+++ b/sources/skins/moono/dev/locations.json
@@ -0,0 +1,145 @@
1{
2 "0": [
3 [
4 "plugins/sourcearea/icons/source.png",
5 "plugins/sourcedialog/icons/sourcedialog.png"
6 ],
7 [
8 "plugins/sourcearea/icons/source-rtl.png",
9 "plugins/sourcedialog/icons/sourcedialog-rtl.png"
10 ],
11 "plugins/save/icons/save.png",
12 "plugins/newpage/icons/newpage.png",
13 "plugins/newpage/icons/newpage-rtl.png",
14 "plugins/preview/icons/preview.png",
15 "plugins/preview/icons/preview-rtl.png",
16 "plugins/print/icons/print.png",
17 [
18 "plugins/templates/icons/templates.png",
19 "plugins/templates/icons/templates-rtl.png"
20 ],
21 "plugins/docprops/icons/docprops.png",
22 "plugins/docprops/icons/docprops-rtl.png"
23 ],
24 "1": [
25 [
26 "plugins/clipboard/icons/cut-rtl.png",
27 "plugins/clipboard/icons/cut.png"
28 ],
29 [
30 "plugins/clipboard/icons/copy.png",
31 "plugins/clipboard/icons/copy-rtl.png"
32 ],
33 [
34 "plugins/clipboard/icons/paste.png",
35 "plugins/clipboard/icons/paste-rtl.png"
36 ],
37 "plugins/pastetext/icons/pastetext.png",
38 "plugins/pastetext/icons/pastetext-rtl.png",
39 "plugins/pastefromword/icons/pastefromword.png",
40 "plugins/pastefromword/icons/pastefromword-rtl.png",
41 "plugins/undo/icons/undo.png",
42 "plugins/undo/icons/undo-rtl.png",
43 "plugins/undo/icons/redo.png",
44 "plugins/undo/icons/redo-rtl.png"
45 ],
46 "2": [
47 [
48 "plugins/find/icons/find-rtl.png",
49 "plugins/find/icons/find.png"
50 ],
51 "plugins/find/icons/replace.png",
52 "plugins/selectall/icons/selectall.png",
53 [
54 "plugins/wsc/icons/spellchecker.png",
55 "plugins/scayt/icons/scayt.png"
56 ]
57 ],
58 "3": [
59 "plugins/forms/icons/form.png",
60 "plugins/forms/icons/checkbox.png",
61 "plugins/forms/icons/radio.png",
62 [
63 "plugins/forms/icons/textfield-rtl.png",
64 "plugins/forms/icons/textfield.png"
65 ],
66 "plugins/forms/icons/textarea.png",
67 "plugins/forms/icons/textarea-rtl.png",
68 "plugins/forms/icons/select.png",
69 "plugins/forms/icons/select-rtl.png",
70 "plugins/forms/icons/button.png",
71 "plugins/forms/icons/imagebutton.png",
72 "plugins/forms/icons/hiddenfield.png"
73 ],
74 "4": [
75 "plugins/basicstyles/icons/bold.png",
76 "plugins/basicstyles/icons/italic.png",
77 "plugins/basicstyles/icons/underline.png",
78 "plugins/basicstyles/icons/strike.png",
79 "plugins/basicstyles/icons/superscript.png",
80 "plugins/basicstyles/icons/subscript.png",
81 "plugins/removeformat/icons/removeformat.png"
82 ],
83 "5": [
84 "plugins/list/icons/numberedlist.png",
85 "plugins/list/icons/numberedlist-rtl.png",
86 "plugins/list/icons/bulletedlist.png",
87 "plugins/list/icons/bulletedlist-rtl.png",
88 "plugins/indent/icons/outdent.png",
89 "plugins/indent/icons/indent.png",
90 "plugins/indent/icons/indent-rtl.png",
91 "plugins/indent/icons/outdent-rtl.png",
92 "plugins/blockquote/icons/blockquote.png",
93 "plugins/div/icons/creatediv.png",
94 "plugins/justify/icons/justifyleft.png",
95 "plugins/justify/icons/justifycenter.png",
96 "plugins/justify/icons/justifyright.png",
97 "plugins/justify/icons/justifyblock.png",
98 "plugins/bidi/icons/bidiltr.png",
99 "plugins/bidi/icons/bidirtl.png"
100 ],
101 "6": [
102 "plugins/link/icons/link.png",
103 "plugins/link/icons/unlink.png",
104 "plugins/link/icons/anchor.png",
105 "plugins/link/icons/anchor-rtl.png",
106 "plugins/copyformatting/icons/copyformatting.png"
107 ],
108 "7": [
109 [
110 "plugins/image/icons/image.png",
111 "plugins/image2/icons/image.png"
112 ],
113 "plugins/flash/icons/flash.png",
114 "plugins/table/icons/table.png",
115 "plugins/horizontalrule/icons/horizontalrule.png",
116 "plugins/smiley/icons/smiley.png",
117 "plugins/specialchar/icons/specialchar.png",
118 "plugins/pagebreak/icons/pagebreak.png",
119 "plugins/pagebreak/icons/pagebreak-rtl.png",
120 "plugins/iframe/icons/iframe.png"
121 ],
122 "8": [
123 "plugins/colorbutton/icons/textcolor.png",
124 "plugins/colorbutton/icons/bgcolor.png"
125 ],
126 "9": [
127 "plugins/maximize/icons/maximize.png",
128 "plugins/showblocks/icons/showblocks.png",
129 "plugins/showblocks/icons/showblocks-rtl.png"
130 ],
131 "10": [
132 "plugins/about/icons/about.png",
133 "plugins/uicolor/icons/uicolor.png",
134 "plugins/placeholder/icons/placeholder.png",
135 "plugins/language/icons/language.png",
136 "plugins/codesnippet/icons/codesnippet.png"
137 ],
138 "11": [
139 "plugins/link/images/anchor.png",
140 "skins/moono/images/close.png",
141 "skins/moono/images/lock.png",
142 "skins/moono/images/lock-open.png",
143 "skins/moono/images/refresh.png"
144 ]
145}
diff --git a/sources/skins/moono/dialog.css b/sources/skins/moono/dialog.css
new file mode 100644
index 0000000..93907be
--- /dev/null
+++ b/sources/skins/moono/dialog.css
@@ -0,0 +1,1060 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7dialog.css
8============
9
10This file styles dialogs and all widgets available inside of it (tabs, buttons,
11fields, etc.).
12
13Dialogs are a complex system because they're very flexible. The CKEditor API
14makes it easy to create and customize dialogs by code, by making use of several
15different widgets inside its contents.
16
17All dialogs share a main dialog strucuture, which can be visually represented
18as follows:
19
20+-- .cke_dialog -------------------------------------------------+
21| +-- .cke_dialog_body ----------------------------------------+ |
22| | +-- .cke_dialog_title --+ +-- .cke_dialog_close_button --+ | |
23| | | | | | | |
24| | +-----------------------+ +------------------------------+ | |
25| | +-- .cke_dialog_tabs ------------------------------------+ | |
26| | | | | |
27| | +--------------------------------------------------------+ | |
28| | +-- .cke_dialog_contents --------------------------------+ | |
29| | | +-- .cke_dialog_contents_body -----------------------+ | | |
30| | | | | | | |
31| | | +----------------------------------------------------+ | | |
32| | | +-- .cke_dialog_footer ------------------------------+ | | |
33| | | | | | | |
34| | | +----------------------------------------------------+ | | |
35| | +--------------------------------------------------------+ | |
36| +------------------------------------------------------------+ |
37+----------------------------------------------------------------+
38
39Comments in this file will give more details about each of the above blocks.
40*/
41
42/* The outer container of the dialog. */
43.cke_dialog
44{
45 /* Mandatory: Because the dialog.css file is loaded on demand, we avoid
46 showing an unstyled dialog by hidding it. Here, we restore its visibility. */
47 visibility: visible;
48}
49
50/* The inner boundary container. */
51.cke_dialog_body
52{
53 z-index: 1;
54 background: #eaeaea;
55 border: 1px solid #b2b2b2;
56 border-bottom-color: #999;
57 border-radius: 3px;
58 box-shadow: 0 0 3px rgba(0, 0, 0, .15);
59}
60
61/* Due to our reset we have to recover the styles of some elements. */
62.cke_dialog strong
63{
64 font-weight: bold;
65}
66
67/* The dialog title. */
68.cke_dialog_title
69{
70 font-weight: bold;
71 font-size: 13px;
72 cursor: move;
73 position: relative;
74
75 color: #474747;
76 text-shadow: 0 1px 0 rgba(255,255,255,.75);
77
78 border-bottom: 1px solid #999;
79 padding: 6px 10px;
80
81 border-radius: 2px 2px 0 0;
82 box-shadow: 0 1px 0 #fff inset;
83
84 background: #cfd1cf;
85 background-image: linear-gradient(to bottom, #f5f5f5, #cfd1cf);
86 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f5f5f5', endColorstr='#cfd1cf');
87}
88
89.cke_dialog_spinner
90{
91 border-radius: 50%;
92
93 width: 12px;
94 height: 12px;
95 overflow: hidden;
96
97 text-indent: -9999em;
98
99 border-top: 2px solid rgba(102, 102, 102, 0.2);
100 border-right: 2px solid rgba(102, 102, 102, 0.2);
101 border-bottom: 2px solid rgba(102, 102, 102, 0.2);
102 border-left: 2px solid rgba(102, 102, 102, 1);
103
104 -webkit-animation: dialog_spinner 1s infinite linear;
105 animation: dialog_spinner 1s infinite linear;
106}
107
108/* A GIF fallback for IE8 and IE9 which does not support CSS animations. */
109.cke_browser_ie8 .cke_dialog_spinner,
110.cke_browser_ie9 .cke_dialog_spinner
111{
112 background: url(images/spinner.gif) center top no-repeat;
113 width: 16px;
114 height: 16px;
115 border: 0;
116}
117
118@-webkit-keyframes dialog_spinner
119{
120 0% {
121 -webkit-transform: rotate(0deg);
122 transform: rotate(0deg);
123 }
124 100% {
125 -webkit-transform: rotate(360deg);
126 transform: rotate(360deg);
127 }
128}
129
130@keyframes dialog_spinner
131{
132 0% {
133 -webkit-transform: rotate(0deg);
134 transform: rotate(0deg);
135 }
136 100% {
137 -webkit-transform: rotate(360deg);
138 transform: rotate(360deg);
139 }
140}
141
142/* The outer part of the dialog contants, which contains the contents body
143 and the footer. */
144.cke_dialog_contents
145{
146 background-color: #fff;
147 overflow: auto;
148 padding: 15px 10px 5px 10px;
149 margin-top: 30px;
150 border-top: 1px solid #bfbfbf;
151 border-radius: 0 0 3px 3px;
152}
153
154/* The contents body part, which will hold all elements available in the dialog. */
155.cke_dialog_contents_body
156{
157 overflow: auto;
158 padding: 17px 10px 5px 10px;
159 margin-top: 22px;
160}
161
162/* The dialog footer, which usually contains the "Ok" and "Cancel" buttons as
163 well as a resize handler. */
164.cke_dialog_footer
165{
166 text-align: right;
167 position: relative;
168 border: none;
169 outline: 1px solid #bfbfbf;
170 box-shadow: 0 1px 0 #fff inset;
171 border-radius: 0 0 2px 2px;
172 background: #cfd1cf;
173 background-image: linear-gradient(to bottom, #ebebeb, #cfd1cf);
174 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ebebeb', endColorstr='#cfd1cf');
175}
176
177.cke_rtl .cke_dialog_footer
178{
179 text-align: left;
180}
181
182.cke_hc .cke_dialog_footer
183{
184 outline: none;
185 border-top: 1px solid #fff;
186}
187
188.cke_dialog .cke_resizer
189{
190 margin-top: 22px;
191}
192
193.cke_dialog .cke_resizer_rtl
194{
195 margin-left: 5px;
196}
197
198.cke_dialog .cke_resizer_ltr
199{
200 margin-right: 5px;
201}
202
203/*
204Dialog tabs
205-------------
206
207Tabs are presented on some of the dialogs to make it possible to have its
208contents split on different groups, visible one after the other.
209
210The main element that holds the tabs can be made hidden, in case of no tabs
211available.
212
213The following is the visual representation of the tabs block:
214
215+-- .cke_dialog_tabs ------------------------------------+
216| +-- .cke_dialog_tab --+ +-- .cke_dialog_tab --+ ... |
217| | | | | |
218| +---------------------+ +---------------------+ |
219+--------------------------------------------------------+
220
221The .cke_dialog_tab_selected class is appended to the active tab.
222*/
223
224/* The main tabs container. */
225.cke_dialog_tabs
226{
227 height: 24px;
228 display: inline-block;
229 margin: 5px 0 0;
230 position: absolute;
231 z-index: 2;
232 left: 10px;
233}
234
235.cke_rtl .cke_dialog_tabs
236{
237 right: 10px;
238}
239
240/* A single tab (an <a> element). */
241a.cke_dialog_tab
242{
243
244 height: 16px;
245 padding: 4px 8px;
246 margin-right: 3px;
247 display: inline-block;
248 cursor: pointer;
249 line-height: 16px;
250 outline: none;
251 color: #595959;
252 border: 1px solid #bfbfbf;
253
254 border-radius: 3px 3px 0 0;
255
256 background: #d4d4d4;
257 background-image: linear-gradient(to bottom, #fafafa, #ededed);
258 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#fafafa', endColorstr='#ededed');
259}
260
261.cke_rtl a.cke_dialog_tab
262{
263 margin-right: 0;
264 margin-left: 3px;
265}
266
267/* A hover state of a regular inactive tab. */
268a.cke_dialog_tab:hover,
269a.cke_dialog_tab:focus
270{
271 background: #ebebeb;
272 background: linear-gradient(to bottom, #ebebeb 0%,#dfdfdf 100%);
273 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebebeb', endColorstr='#dfdfdf',GradientType=0 );
274}
275
276a.cke_dialog_tab_selected
277{
278 background: #fff;
279 color: #383838;
280 border-bottom-color: #fff;
281 cursor: default;
282 filter: none;
283}
284
285/* A hover state for selected tab. */
286a.cke_dialog_tab_selected:hover,
287a.cke_dialog_tab_selected:focus
288{
289 background: #ededed;
290 background: linear-gradient(to bottom, #ededed 0%,#ffffff 100%);
291 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 );
292}
293
294.cke_hc a.cke_dialog_tab:hover,
295.cke_hc a.cke_dialog_tab:focus,
296.cke_hc a.cke_dialog_tab_selected
297{
298 border: 3px solid;
299 padding: 2px 6px;
300}
301
302a.cke_dialog_tab_disabled
303{
304 color: #bababa;
305 cursor: default;
306}
307
308/* The .cke_single_page class is appended to the dialog outer element in case
309 of dialogs that has no tabs. */
310.cke_single_page .cke_dialog_tabs
311{
312 display: none;
313}
314
315.cke_single_page .cke_dialog_contents
316{
317 padding-top: 5px;
318 margin-top: 0;
319 border-top: none;
320}
321
322/* The close button at the top of the dialog. */
323
324a.cke_dialog_close_button
325{
326 background-image: url(images/close.png);
327 background-repeat: no-repeat;
328 background-position: 50%;
329 position: absolute;
330 cursor: pointer;
331 text-align: center;
332 height: 20px;
333 width: 20px;
334 top: 4px;
335 z-index: 5;
336 opacity: 0.8;
337 filter: alpha(opacity = 80);
338}
339
340.cke_dialog_close_button:hover
341{
342 opacity: 1;
343 filter: alpha(opacity = 100);
344}
345
346.cke_hidpi .cke_dialog_close_button
347{
348 background-image: url(images/hidpi/close.png);
349 background-size: 16px;
350}
351
352.cke_dialog_close_button span
353{
354 display: none;
355}
356
357.cke_hc .cke_dialog_close_button span
358{
359 display: inline;
360 cursor: pointer;
361 font-weight: bold;
362 position: relative;
363 top: 3px;
364}
365
366.cke_ltr .cke_dialog_close_button
367{
368 right: 5px;
369}
370
371.cke_rtl .cke_dialog_close_button
372{
373 left: 6px;
374}
375
376.cke_dialog_close_button
377{
378 top: 4px;
379}
380
381/*
382Dialog UI Elements
383--------------------
384
385The remaining styles define the UI elements that can be used inside dialog
386contents.
387
388Most of the UI elements on dialogs contain a textual label. All of them share
389the same labelling structure, having the label text inside an element with
390.cke_dialog_ui_labeled_label and the element specific part inside the
391.cke_dialog_ui_labeled_content class.
392*/
393
394/* If an element is supposed to be disabled, the .cke_disabled class is
395 appended to it. */
396div.cke_disabled .cke_dialog_ui_labeled_content div *
397{
398 background-color: #ddd;
399 cursor: default;
400}
401
402/*
403Horizontal-Box and Vertical-Box
404---------------------------------
405
406There are basic layou element used by the editor to properly align elements in
407the dialog. They're basically tables that have each cell filled by UI elements.
408
409The following is the visual representation of a H-Box:
410
411+-- .cke_dialog_ui_hbox --------------------------------------------------------------------------------+
412| +-- .cke_dialog_ui_hbox_first --+ +-- .cke_dialog_ui_hbox_child --+ +-- .cke_dialog_ui_hbox_last --+ |
413| + + + + + + |
414| +-------------------------------+ +-------------------------------+ +------------------------------+ |
415+-------------------------------------------------------------------------------------------------------+
416
417It is possible to have nested V/H-Boxes.
418*/
419
420.cke_dialog_ui_vbox table,
421.cke_dialog_ui_hbox table
422{
423 margin: auto;
424}
425
426.cke_dialog_ui_vbox_child
427{
428 padding: 5px 0px;
429}
430
431.cke_dialog_ui_hbox
432{
433 width: 100%;
434}
435
436.cke_dialog_ui_hbox_first,
437.cke_dialog_ui_hbox_child,
438.cke_dialog_ui_hbox_last
439{
440 vertical-align: top;
441}
442
443.cke_ltr .cke_dialog_ui_hbox_first,
444.cke_ltr .cke_dialog_ui_hbox_child
445{
446 padding-right: 10px;
447}
448
449.cke_rtl .cke_dialog_ui_hbox_first,
450.cke_rtl .cke_dialog_ui_hbox_child
451{
452 padding-left: 10px;
453}
454
455.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,
456.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child
457{
458 padding-right: 5px;
459}
460
461.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,
462.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child
463{
464 padding-left: 5px;
465 padding-right: 0;
466}
467
468/* Applies to all labeled dialog fields */
469.cke_hc div.cke_dialog_ui_input_text,
470.cke_hc div.cke_dialog_ui_input_password,
471.cke_hc div.cke_dialog_ui_input_textarea,
472.cke_hc div.cke_dialog_ui_input_select,
473.cke_hc div.cke_dialog_ui_input_file
474{
475 border: 1px solid;
476}
477
478/*
479Text Input
480------------
481
482The basic text field to input text.
483
484+-- .cke_dialog_ui_text --------------------------+
485| +-- .cke_dialog_ui_labeled_label ------------+ |
486| | | |
487| +--------------------------------------------+ |
488| +-- .cke_dialog_ui_labeled_content ----------+ |
489| | +-- div.cke_dialog_ui_input_text --------+ | |
490| | | +-- input.cke_dialog_ui_input_text --+ | | |
491| | | | | | | |
492| | | +------------------------------------+ | | |
493| | +----------------------------------------+ | |
494| +--------------------------------------------+ |
495+-------------------------------------------------+
496*/
497
498/*
499Textarea
500----------
501
502The textarea field to input larger text.
503
504+-- .cke_dialog_ui_textarea --------------------------+
505| +-- .cke_dialog_ui_labeled_label ----------------+ |
506| | | |
507| +------------------------------------------------+ |
508| +-- .cke_dialog_ui_labeled_content --------------+ |
509| | +-- div.cke_dialog_ui_input_textarea --------+ | |
510| | | +-- input.cke_dialog_ui_input_textarea --+ | | |
511| | | | | | | |
512| | | +----------------------------------------+ | | |
513| | +--------------------------------------------+ | |
514| +------------------------------------------------+ |
515+-----------------------------------------------------+
516*/
517
518textarea.cke_dialog_ui_input_textarea
519{
520 overflow: auto;
521 resize: none;
522}
523
524input.cke_dialog_ui_input_text,
525input.cke_dialog_ui_input_password,
526textarea.cke_dialog_ui_input_textarea
527{
528 background-color: #fff;
529 border: 1px solid #c9cccf;
530 border-top-color: #aeb3b9;
531 padding: 4px 6px;
532 outline: none;
533 width: 100%;
534 *width: 95%;
535
536 box-sizing: border-box;
537
538 border-radius: 3px;
539
540 box-shadow: 0 1px 2px rgba(0,0,0,.15) inset;
541}
542
543input.cke_dialog_ui_input_text:hover,
544input.cke_dialog_ui_input_password:hover,
545textarea.cke_dialog_ui_input_textarea:hover
546{
547 border: 1px solid #aeb3b9;
548 border-top-color: #a0a6ad;
549}
550
551input.cke_dialog_ui_input_text:focus,
552input.cke_dialog_ui_input_password:focus,
553textarea.cke_dialog_ui_input_textarea:focus,
554select.cke_dialog_ui_input_select:focus
555{
556 outline: none;
557 border: 1px solid #139ff7;
558 border-top-color: #1392e9;
559}
560
561/*
562Button
563--------
564
565The buttons used in the dialog footer or inside the contents.
566
567+-- a.cke_dialog_ui_button -----------+
568| +-- span.cke_dialog_ui_button --+ |
569| | | |
570| +-------------------------------+ |
571+-------------------------------------+
572*/
573
574/* The outer part of the button. */
575a.cke_dialog_ui_button
576{
577 display: inline-block;
578 *display: inline;
579 *zoom: 1;
580
581 padding: 4px 0;
582 margin: 0;
583
584 text-align: center;
585 color: #333;
586 vertical-align: middle;
587 cursor: pointer;
588
589 border: 1px solid #b6b6b6;
590 border-bottom-color: #999;
591 border-radius: 3px;
592 box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 0 2px rgba(255,255,255,.15) inset, 0 1px 0 rgba(255,255,255,.15) inset;
593
594 background: #e4e4e4;
595 background-image: linear-gradient(to bottom, #ffffff, #e4e4e4);
596 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ffffff', endColorstr='#e4e4e4');
597
598}
599
600span.cke_dialog_ui_button
601{
602 padding: 0 10px;
603}
604
605a.cke_dialog_ui_button:hover
606{
607 border-color: #9e9e9e;
608
609 background: #ccc;
610 background-image: linear-gradient(to bottom, #f2f2f2, #ccc);
611 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f2f2f2', endColorstr='#cccccc');
612}
613
614/* :focus/:active styles for dialog buttons: regular and footer. */
615a.cke_dialog_ui_button:focus,
616a.cke_dialog_ui_button:active
617{
618 border-color: #969696;
619 outline: none;
620 box-shadow: 0 0 6px rgba(0,0,0,.4) inset;
621}
622
623.cke_hc a.cke_dialog_ui_button:hover,
624.cke_hc a.cke_dialog_ui_button:focus,
625.cke_hc a.cke_dialog_ui_button:active
626{
627 border: 3px solid;
628 padding-top: 1px;
629 padding-bottom: 1px;
630}
631
632.cke_hc a.cke_dialog_ui_button:hover span,
633.cke_hc a.cke_dialog_ui_button:focus span,
634.cke_hc a.cke_dialog_ui_button:active span
635{
636 padding-left: 10px;
637 padding-right: 10px;
638}
639
640/*
641a.cke_dialog_ui_button[style*="width"]
642{
643 display: block !important;
644 width: auto !important;
645}
646*/
647/* The inner part of the button (both in dialog tabs and dialog footer). */
648.cke_dialog_footer_buttons a.cke_dialog_ui_button span
649{
650 color: inherit;
651 font-size: 12px;
652 font-weight: bold;
653 line-height: 18px;
654 padding: 0 12px;
655}
656
657/* Special class appended to the Ok button. */
658a.cke_dialog_ui_button_ok
659{
660 color: #fff;
661 text-shadow: 0 -1px 0 #55830c;
662 border-color: #62a60a #62a60a #4d9200;
663
664 background: #69b10b;
665 background-image: linear-gradient(to bottom, #9ad717, #69b10b);
666 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#9ad717', endColorstr='#69b10b');
667}
668
669a.cke_dialog_ui_button_ok:hover
670{
671 border-color: #5b9909 #5b9909 #478500;
672
673 background: #88be14;
674 background: linear-gradient(to bottom, #88be14 0%,#5d9c0a 100%);
675 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88be14', endColorstr='#5d9c0a',GradientType=0 );
676}
677
678a.cke_dialog_ui_button_ok.cke_disabled {
679 border-color: #7D9F51;
680
681 background: #8DAD62;
682 background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#B3D271), to(#8DAD62));
683 background-image: -webkit-linear-gradient(top, #B3D271, #8DAD62);
684 background-image: -o-linear-gradient(top, #B3D271, #8DAD62);
685 background-image: linear-gradient(to bottom, #B3D271, #8DAD62);
686 background-image: -moz-linear-gradient(top, #B3D271, #8DAD62);
687 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#B3D271', endColorstr='#8DAD62');
688}
689
690a.cke_dialog_ui_button_ok.cke_disabled span {
691 color: #E0E8D1;
692}
693
694/* Default text shadow used for inner parts of all dialog buttons (both in dialog tabs and dialog footer). */
695a.cke_dialog_ui_button span
696{
697 text-shadow: 0 1px 0 #fff;
698}
699
700/* Text shadow used for inner part of OK dialog button in footer. */
701a.cke_dialog_ui_button_ok span
702{
703 text-shadow: 0 -1px 0 #55830c;
704}
705
706span.cke_dialog_ui_button
707{
708 cursor: pointer;
709}
710
711/* :focus/:active styles for dialog footer buttons (ok & cancel) */
712a.cke_dialog_ui_button_ok:focus,
713a.cke_dialog_ui_button_ok:active,
714a.cke_dialog_ui_button_cancel:focus,
715a.cke_dialog_ui_button_cancel:active
716{
717 border-width: 2px;
718 padding: 3px 0;
719}
720
721a.cke_dialog_ui_button_ok:focus,
722a.cke_dialog_ui_button_ok:active
723{
724 border-color: #568C0A;
725}
726
727a.cke_dialog_ui_button_ok.cke_disabled:focus,
728a.cke_dialog_ui_button_ok.cke_disabled:active
729{
730 border-color: #6F8C49;
731}
732
733/* :focus/:active styles for dialog footer buttons (ok & cancel) spans */
734a.cke_dialog_ui_button_ok:focus span,
735a.cke_dialog_ui_button_ok:active span,
736a.cke_dialog_ui_button_cancel:focus span,
737a.cke_dialog_ui_button_cancel:active span
738{
739 padding: 0 11px; /* Thick button border must be compensated. */
740}
741
742/* A special container that holds the footer buttons. */
743.cke_dialog_footer_buttons
744{
745 display: inline-table;
746 margin: 5px;
747 width: auto;
748 position: relative;
749 vertical-align: middle;
750}
751
752/*
753Styles for other dialog element types.
754*/
755
756div.cke_dialog_ui_input_select
757{
758 display: table;
759}
760
761select.cke_dialog_ui_input_select
762{
763 height: 25px;
764 line-height: 25px;
765
766 background-color: #fff;
767 border: 1px solid #c9cccf;
768 border-top-color: #aeb3b9;
769 padding: 3px 3px 3px 6px;
770 outline: none;
771 border-radius: 3px;
772 box-shadow: 0 1px 2px rgba(0,0,0,.15) inset;
773}
774
775.cke_dialog_ui_input_file
776{
777 width: 100%;
778 height: 25px;
779}
780
781.cke_hc .cke_dialog_ui_labeled_content input:focus,
782.cke_hc .cke_dialog_ui_labeled_content select:focus,
783.cke_hc .cke_dialog_ui_labeled_content textarea:focus
784{
785 outline: 1px dotted;
786}
787
788/*
789 * Some utility CSS classes for dialog authors.
790 */
791.cke_dialog .cke_dark_background
792{
793 background-color: #DEDEDE;
794}
795
796.cke_dialog .cke_light_background
797{
798 background-color: #EBEBEB;
799}
800
801.cke_dialog .cke_centered
802{
803 text-align: center;
804}
805
806.cke_dialog a.cke_btn_reset
807{
808 float: right;
809 background: url(images/refresh.png) top left no-repeat;
810 width: 16px;
811 height: 16px;
812 border: 1px none;
813 font-size: 1px;
814}
815
816.cke_hidpi .cke_dialog a.cke_btn_reset {
817 background-size: 16px;
818 background-image: url(images/hidpi/refresh.png);
819}
820
821.cke_rtl .cke_dialog a.cke_btn_reset
822{
823 float: left;
824}
825
826.cke_dialog a.cke_btn_locked,
827.cke_dialog a.cke_btn_unlocked
828{
829 float: left;
830 width: 16px;
831 height: 16px;
832 background-repeat: no-repeat;
833 border: none 1px;
834 font-size: 1px;
835}
836
837.cke_dialog a.cke_btn_locked .cke_icon
838{
839 display: none;
840}
841
842.cke_rtl .cke_dialog a.cke_btn_locked,
843.cke_rtl .cke_dialog a.cke_btn_unlocked
844{
845 float: right;
846}
847
848.cke_dialog a.cke_btn_locked
849{
850 background-image: url(images/lock.png);
851}
852
853.cke_dialog a.cke_btn_unlocked
854{
855 background-image: url(images/lock-open.png);
856}
857
858.cke_hidpi .cke_dialog a.cke_btn_unlocked,
859.cke_hidpi .cke_dialog a.cke_btn_locked {
860 background-size: 16px;
861}
862
863.cke_hidpi .cke_dialog a.cke_btn_locked {
864 background-image: url(images/hidpi/lock.png);
865}
866
867.cke_hidpi .cke_dialog a.cke_btn_unlocked {
868 background-image: url(images/hidpi/lock-open.png);
869}
870
871.cke_dialog .cke_btn_over
872{
873 border: outset 1px;
874 cursor: pointer;
875}
876
877/*
878The rest of the file contains style used on several common plugins. There is a
879tendency that these will be moved to the plugins code in the future.
880*/
881
882.cke_dialog .ImagePreviewBox
883{
884 border: 2px ridge black;
885 overflow: scroll;
886 height: 200px;
887 width: 300px;
888 padding: 2px;
889 background-color: white;
890}
891
892.cke_dialog .ImagePreviewBox table td
893{
894 white-space: normal;
895}
896
897.cke_dialog .ImagePreviewLoader
898{
899 position: absolute;
900 white-space: normal;
901 overflow: hidden;
902 height: 160px;
903 width: 230px;
904 margin: 2px;
905 padding: 2px;
906 opacity: 0.9;
907 filter: alpha(opacity = 90);
908
909 background-color: #e4e4e4;
910}
911
912.cke_dialog .FlashPreviewBox
913{
914 white-space: normal;
915 border: 2px ridge black;
916 overflow: auto;
917 height: 160px;
918 width: 390px;
919 padding: 2px;
920 background-color: white;
921}
922
923.cke_dialog .cke_pastetext
924{
925 width: 346px;
926 height: 170px;
927}
928
929.cke_dialog .cke_pastetext textarea
930{
931 width: 340px;
932 height: 170px;
933 resize: none;
934}
935
936.cke_dialog iframe.cke_pasteframe
937{
938 width: 346px;
939 height: 130px;
940 background-color: white;
941 border: 1px solid #aeb3b9;
942 border-radius: 3px;
943}
944
945.cke_dialog .cke_hand
946{
947 cursor: pointer;
948}
949
950.cke_disabled
951{
952 color: #a0a0a0;
953}
954
955.cke_dialog_body .cke_label
956{
957 display: none;
958}
959
960.cke_dialog_body label
961{
962 display: inline;
963 margin-bottom: auto;
964 cursor: default;
965}
966
967.cke_dialog_body label.cke_required
968{
969 font-weight: bold;
970}
971
972a.cke_smile
973{
974 overflow: hidden;
975 display: block;
976 text-align: center;
977 padding: 0.3em 0;
978}
979
980a.cke_smile img
981{
982 vertical-align: middle;
983}
984
985a.cke_specialchar
986{
987 cursor: inherit;
988 display: block;
989 height: 1.25em;
990 padding: 0.2em 0.3em;
991 text-align: center;
992}
993
994a.cke_smile,
995a.cke_specialchar
996{
997 border: 1px solid transparent;
998}
999
1000a.cke_smile:hover,
1001a.cke_smile:focus,
1002a.cke_smile:active,
1003a.cke_specialchar:hover,
1004a.cke_specialchar:focus,
1005a.cke_specialchar:active
1006{
1007 background: #fff;
1008 outline: 0;
1009}
1010
1011a.cke_smile:hover,
1012a.cke_specialchar:hover
1013{
1014 border-color: #888;
1015}
1016
1017a.cke_smile:focus,
1018a.cke_smile:active,
1019a.cke_specialchar:focus,
1020a.cke_specialchar:active
1021{
1022 border-color: #139FF7;
1023}
1024
1025/**
1026 * Styles specific to "cellProperties" dialog.
1027 */
1028
1029.cke_dialog_contents a.colorChooser
1030{
1031 display: block;
1032 margin-top: 6px;
1033 margin-left: 10px;
1034 width: 80px;
1035}
1036
1037.cke_rtl .cke_dialog_contents a.colorChooser
1038{
1039 margin-right: 10px;
1040}
1041
1042/* Compensate focus outline for some input elements. (#6200) */
1043.cke_dialog_ui_checkbox_input:focus,
1044.cke_dialog_ui_radio_input:focus,
1045.cke_btn_over
1046{
1047 outline: 1px dotted #696969;
1048}
1049
1050.cke_iframe_shim
1051{
1052 display: block;
1053 position: absolute;
1054 top: 0;
1055 left: 0;
1056 z-index: -1;
1057 filter: alpha(opacity = 0);
1058 width: 100%;
1059 height: 100%;
1060}
diff --git a/sources/skins/moono/dialog_ie.css b/sources/skins/moono/dialog_ie.css
new file mode 100644
index 0000000..af86642
--- /dev/null
+++ b/sources/skins/moono/dialog_ie.css
@@ -0,0 +1,62 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7dialog_ie.css
8===============
9
10This file contains styles to used by all versions of Internet Explorer only.
11*/
12
13/* Base it on dialog.css, overriding it with styles defined in this file. */
14@import url("dialog.css");
15
16/* IE doesn't leave enough padding in text input for cursor to blink in RTL. (#6087) */
17.cke_rtl input.cke_dialog_ui_input_text,
18.cke_rtl input.cke_dialog_ui_input_password
19{
20 padding-right: 2px;
21}
22/* Compensate the padding added above on container. */
23.cke_rtl div.cke_dialog_ui_input_text,
24.cke_rtl div.cke_dialog_ui_input_password
25{
26 padding-left: 2px;
27}
28.cke_rtl div.cke_dialog_ui_input_text {
29 padding-right: 1px;
30}
31
32.cke_rtl .cke_dialog_ui_vbox_child,
33.cke_rtl .cke_dialog_ui_hbox_child,
34.cke_rtl .cke_dialog_ui_hbox_first,
35.cke_rtl .cke_dialog_ui_hbox_last
36{
37 padding-right: 2px !important;
38}
39
40
41/* Disable filters for HC mode. */
42.cke_hc .cke_dialog_title,
43.cke_hc .cke_dialog_footer,
44.cke_hc a.cke_dialog_tab,
45.cke_hc a.cke_dialog_ui_button,
46.cke_hc a.cke_dialog_ui_button:hover,
47.cke_hc a.cke_dialog_ui_button_ok,
48.cke_hc a.cke_dialog_ui_button_ok:hover
49{
50 filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
51}
52
53/* Remove border from dialog field wrappers in HC
54 to avoid double borders. */
55.cke_hc div.cke_dialog_ui_input_text,
56.cke_hc div.cke_dialog_ui_input_password,
57.cke_hc div.cke_dialog_ui_input_textarea,
58.cke_hc div.cke_dialog_ui_input_select,
59.cke_hc div.cke_dialog_ui_input_file
60{
61 border: 0;
62}
diff --git a/sources/skins/moono/dialog_ie7.css b/sources/skins/moono/dialog_ie7.css
new file mode 100644
index 0000000..148645d
--- /dev/null
+++ b/sources/skins/moono/dialog_ie7.css
@@ -0,0 +1,68 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7dialog_ie7.css
8===============
9
10This file contains styles to used by Internet Explorer 7 only.
11*/
12
13/* Base it on dialog_ie.css, overriding it with styles defined in this file. */
14@import url("dialog_ie.css");
15
16.cke_dialog_title
17{
18 /* gradient fix */
19 zoom: 1;
20}
21
22.cke_dialog_footer
23{
24 /* IE7 ignores footer's outline. Use border instead. */
25 border-top: 1px solid #bfbfbf;
26}
27
28/* IE7 needs position static #6806 */
29.cke_dialog_footer_buttons
30{
31 position: static;
32}
33
34/* IE7 crops the bottom pixels of footer buttons (#9491) */
35.cke_dialog_footer_buttons a.cke_dialog_ui_button
36{
37 vertical-align: top;
38}
39
40/* IE7 margin loose on float. */
41.cke_dialog .cke_resizer_ltr
42{
43 padding-left: 4px;
44}
45.cke_dialog .cke_resizer_rtl
46{
47 padding-right: 4px;
48}
49
50/* IE7 doesn't support box-sizing and therefore we cannot
51 have sexy inputs which go well with the layout. */
52.cke_dialog_ui_input_text,
53.cke_dialog_ui_input_password,
54.cke_dialog_ui_input_textarea,
55.cke_dialog_ui_input_select
56{
57 padding: 0 !important;
58}
59
60/* Predefined border to avoid visual size change impact. */
61.cke_dialog_ui_checkbox_input,
62.cke_dialog_ui_ratio_input,
63.cke_btn_reset,
64.cke_btn_locked,
65.cke_btn_unlocked
66{
67 border: 1px solid transparent !important;
68}
diff --git a/sources/skins/moono/dialog_ie8.css b/sources/skins/moono/dialog_ie8.css
new file mode 100644
index 0000000..1926e50
--- /dev/null
+++ b/sources/skins/moono/dialog_ie8.css
@@ -0,0 +1,24 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7dialog_ie8.css
8===============
9
10This file contains styles to used by Internet Explorer 8 only.
11*/
12
13/* Base it on dialog_ie.css, overriding it with styles defined in this file. */
14@import url("dialog_ie.css");
15
16/* Without the following, IE8 cannot compensate footer button thick borders
17 on :focus/:active. */
18a.cke_dialog_ui_button_ok:focus span,
19a.cke_dialog_ui_button_ok:active span,
20a.cke_dialog_ui_button_cancel:focus span,
21a.cke_dialog_ui_button_cancel:active span
22{
23 display: block;
24}
diff --git a/sources/skins/moono/dialog_iequirks.css b/sources/skins/moono/dialog_iequirks.css
new file mode 100644
index 0000000..2f89fdf
--- /dev/null
+++ b/sources/skins/moono/dialog_iequirks.css
@@ -0,0 +1,21 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7dialog_ie7.css
8===============
9
10This file contains styles to used by Internet Explorer in
11Quirks mode only.
12*/
13
14/* Base it on dialog_ie.css, overriding it with styles defined in this file. */
15@import url("dialog_ie.css");
16
17/* [IE7-8] Filter on footer causes background artifacts when opening dialog. */
18.cke_dialog_footer
19{
20 filter: "";
21}
diff --git a/sources/skins/moono/editor.css b/sources/skins/moono/editor.css
new file mode 100644
index 0000000..f3f65df
--- /dev/null
+++ b/sources/skins/moono/editor.css
@@ -0,0 +1,69 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor.css
8============
9
10This is he heart of the skin system. This is the file loaded by the editor to
11style all elements inside its main interface.
12
13To make it easier to maintain, instead of including all styles here, we import
14other files.
15*/
16
17/* "Reset" styles, necessary to avoid the editor UI being broken by external CSS. */
18@import url("reset.css");
19
20/* Styles the main interface structure (holding box). */
21@import url("mainui.css");
22
23/* Styles all "panels", which are the floating elements that appear when
24 opening toolbar combos, menu buttons, context menus, etc. */
25@import url("panel.css");
26
27/* Styles the color panel displayed by the color buttons. */
28@import url("colorpanel.css");
29
30/* Styles to toolbar. */
31@import url("toolbar.css");
32
33/* Styles menus, which are lists of selectable items (context menu, menu button). */
34@import url("menu.css");
35
36/* Styles toolbar combos. */
37@import url("richcombo.css");
38
39/* Styles the elements path bar, available at the bottom of the editor UI.*/
40@import url("elementspath.css");
41
42/* Contains hard-coded presets for "configurable-like" options of the UI
43 (e.g. display labels on specific buttons) */
44@import url("presets.css");
45
46/* Styles for notifications. */
47@import url("notification.css");
48
49/* Important!
50 To avoid showing the editor UI while its styles are still not available, the
51 editor creates it with visibility:hidden. Here, we restore the UI visibility. */
52.cke_chrome
53{
54 visibility: inherit;
55}
56
57/* For accessibility purposes, several "voice labels" are present in the UI.
58 These are usually <span> elements that show not be visible, but that are
59 used by screen-readers to announce other elements. Here, we hide these
60 <spans>, in fact. */
61.cke_voice_label
62{
63 display: none;
64}
65
66legend.cke_voice_label
67{
68 display: none;
69}
diff --git a/sources/skins/moono/editor_gecko.css b/sources/skins/moono/editor_gecko.css
new file mode 100644
index 0000000..370ffff
--- /dev/null
+++ b/sources/skins/moono/editor_gecko.css
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor_gecko.css
8==================
9
10This file contains styles to used by all Gecko based browsers (Firefox) only.
11*/
12
13/* Base it on editor.css, overriding it with styles defined in this file. */
14@import url("editor.css");
15
16.cke_bottom
17{
18 padding-bottom: 3px;
19}
20
21.cke_combo_text
22{
23 margin-bottom: -1px;
24 margin-top: 1px;
25}
diff --git a/sources/skins/moono/editor_ie.css b/sources/skins/moono/editor_ie.css
new file mode 100644
index 0000000..504789f
--- /dev/null
+++ b/sources/skins/moono/editor_ie.css
@@ -0,0 +1,71 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor_ie.css
8===============
9
10This file contains styles to used by all versions of Internet Explorer only.
11*/
12
13/* Base it on editor.css, overriding it with styles defined in this file. */
14@import url("editor.css");
15
16a.cke_button_disabled,
17
18/* Those two are to overwrite the gradient filter since we cannot have both of them. */
19a.cke_button_disabled:hover,
20a.cke_button_disabled:focus,
21a.cke_button_disabled:active
22{
23 filter: alpha(opacity = 30);
24}
25
26/* PNG Alpha Transparency Fix For IE<9 */
27.cke_button_disabled .cke_button_icon
28{
29 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff, endColorstr=#00ffffff);
30}
31
32.cke_button_off:hover,
33.cke_button_off:focus,
34.cke_button_off:active
35{
36 filter: alpha(opacity = 100);
37}
38
39.cke_combo_disabled .cke_combo_inlinelabel,
40.cke_combo_disabled .cke_combo_open
41{
42 filter: alpha(opacity = 30);
43}
44
45.cke_toolbox_collapser
46{
47 border: 1px solid #a6a6a6;
48}
49
50.cke_toolbox_collapser .cke_arrow
51{
52 margin-top: 1px;
53}
54
55/* Gradient filters must be removed for HC mode to reveal the background. */
56.cke_hc .cke_top,
57.cke_hc .cke_bottom,
58.cke_hc .cke_combo_button,
59.cke_hc a.cke_combo_button:hover,
60.cke_hc a.cke_combo_button:focus,
61.cke_hc .cke_toolgroup,
62.cke_hc .cke_button_on,
63.cke_hc a.cke_button_off:hover,
64.cke_hc a.cke_button_off:focus,
65.cke_hc a.cke_button_off:active,
66.cke_hc .cke_toolbox_collapser,
67.cke_hc .cke_toolbox_collapser:hover,
68.cke_hc .cke_panel_grouptitle
69{
70 filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
71}
diff --git a/sources/skins/moono/editor_ie7.css b/sources/skins/moono/editor_ie7.css
new file mode 100644
index 0000000..8079504
--- /dev/null
+++ b/sources/skins/moono/editor_ie7.css
@@ -0,0 +1,213 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor_ie7.css
8===============
9
10This file contains styles to used by Internet Explorer 7 only.
11*/
12
13/* Base it on editor_ie.css, overriding it with styles defined in this file. */
14@import url("editor_ie.css");
15
16.cke_rtl .cke_toolgroup,
17.cke_rtl .cke_toolbar_separator,
18.cke_rtl .cke_button,
19.cke_rtl .cke_button *,
20.cke_rtl .cke_combo,
21.cke_rtl .cke_combo *,
22.cke_rtl .cke_path_item,
23.cke_rtl .cke_path_item *,
24.cke_rtl .cke_path_empty
25{
26 float: none;
27}
28
29.cke_rtl .cke_toolgroup,
30.cke_rtl .cke_toolbar_separator,
31.cke_rtl .cke_combo_button,
32.cke_rtl .cke_combo_button *,
33.cke_rtl .cke_button,
34.cke_rtl .cke_button_icon
35{
36 display: inline-block;
37 vertical-align: top;
38}
39
40.cke_toolbox
41{
42 display:inline-block;
43 padding-bottom: 5px;
44 height: 100%;
45}
46.cke_rtl .cke_toolbox
47{
48 padding-bottom: 0;
49}
50
51.cke_toolbar
52{
53 margin-bottom: 5px;
54}
55.cke_rtl .cke_toolbar
56{
57 margin-bottom: 0;
58}
59
60/* IE7: toolgroup must be adapted to toolbar items height. */
61.cke_toolgroup
62{
63 height: 26px;
64}
65
66/* Avoid breaking elements that use background gradient when page zoom > 1 (#9548) */
67.cke_toolgroup,
68.cke_combo
69{
70 position: relative;
71}
72
73a.cke_button
74{
75 /* IE7: buttons must not float to wrap the toolbar in a whole. */
76 float:none;
77
78 /* IE7: buttons have to be aligned to top. Otherwise, some buttons like
79 * source and scayt are displayed a few pixels below the base line.
80 */
81 vertical-align:top;
82}
83
84.cke_toolbar_separator
85{
86 display: inline-block;
87 float: none;
88 vertical-align: top;
89 background-color: #c0c0c0;
90}
91
92.cke_toolbox_collapser .cke_arrow
93{
94 margin-top: 0;
95}
96.cke_toolbox_collapser .cke_arrow
97{
98 border-width:4px;
99}
100.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow
101{
102 border-width:3px;
103}
104
105.cke_rtl .cke_button_arrow
106{
107 padding-top: 8px;
108 margin-right: 2px;
109}
110
111.cke_rtl .cke_combo_inlinelabel
112{
113 display: table-cell;
114 vertical-align: middle;
115}
116
117/*
118 * Editor menus are display:table-driven. IE7 doesn't support this approach,
119 * hence this position&float hybrid fall-back.
120 */
121.cke_menubutton
122{
123 display: block;
124 height: 24px;
125}
126
127.cke_menubutton_inner
128{
129 display: block;
130 position: relative;
131}
132
133.cke_menubutton_icon
134{
135 height: 16px;
136 width: 16px;
137}
138
139.cke_menubutton_icon,
140.cke_menubutton_label,
141.cke_menuarrow
142{
143 display: inline-block;
144}
145
146.cke_menubutton_label
147{
148 width: auto;
149 vertical-align: top;
150 line-height: 24px;
151 height: 24px;
152 margin: 0 10px 0 0;
153}
154
155.cke_menuarrow
156{
157 width: 5px;
158 height: 6px;
159 padding: 0;
160 position: absolute;
161 right: 8px;
162 top: 10px;
163
164 background-position: 0 0;
165}
166
167/* Menus in RTL mode. */
168.cke_rtl .cke_menubutton_icon
169{
170 position: absolute;
171 right: 0px;
172 top: 0px;
173}
174
175.cke_rtl .cke_menubutton_label
176{
177 float: right;
178 clear: both;
179 margin: 0 24px 0 10px;
180}
181
182.cke_hc .cke_rtl .cke_menubutton_label
183{
184 margin-right: 0;
185}
186
187
188.cke_rtl .cke_menuarrow
189{
190 left: 8px;
191 right: auto;
192 background-position: 0 -24px;
193}
194
195.cke_hc .cke_menuarrow
196{
197 top: 5px;
198 padding: 0 5px;
199}
200
201.cke_rtl input.cke_dialog_ui_input_text,
202.cke_rtl input.cke_dialog_ui_input_password
203{
204 /* Positioning is required for IE7 on text inputs not to stretch dialog horizontally. (#8971)*/
205 position: relative;
206}
207
208/* Reset vertical paddings which put editing area under bottom UI space. (#9721) */
209.cke_wysiwyg_div
210{
211 padding-top: 0 !important;
212 padding-bottom: 0 !important;
213}
diff --git a/sources/skins/moono/editor_ie8.css b/sources/skins/moono/editor_ie8.css
new file mode 100644
index 0000000..9862024
--- /dev/null
+++ b/sources/skins/moono/editor_ie8.css
@@ -0,0 +1,27 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor_ie8.css
8===============
9
10This file contains styles to used by Internet Explorer 8 only.
11*/
12
13/* Base it on editor_ie.css, overriding it with styles defined in this file. */
14@import url("editor_ie.css");
15
16.cke_toolbox_collapser .cke_arrow
17{
18 border-width:4px;
19}
20.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow
21{
22 border-width:3px;
23}
24.cke_toolbox_collapser .cke_arrow
25{
26 margin-top: 0;
27}
diff --git a/sources/skins/moono/editor_iequirks.css b/sources/skins/moono/editor_iequirks.css
new file mode 100644
index 0000000..2376992
--- /dev/null
+++ b/sources/skins/moono/editor_iequirks.css
@@ -0,0 +1,79 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7editor_iequirks.css
8===============
9
10This file contains styles to used by all versions of Internet Explorer
11in Quirks mode only.
12*/
13
14/* Base it on editor_ie.css, overriding it with styles defined in this file. */
15@import url("editor_ie.css");
16
17.cke_top,
18.cke_contents,
19.cke_bottom
20{
21 width: 100%; /* hasLayout = true */
22}
23
24.cke_button_arrow
25{
26 font-size: 0; /* Set minimal font size, so arrow won't be streched by the text that doesn't exist. */
27}
28
29/* Bring back toolbar buttons in RTL. */
30
31.cke_rtl .cke_toolgroup,
32.cke_rtl .cke_toolbar_separator,
33.cke_rtl .cke_button,
34.cke_rtl .cke_button *,
35.cke_rtl .cke_combo,
36.cke_rtl .cke_combo *,
37.cke_rtl .cke_path_item,
38.cke_rtl .cke_path_item *,
39.cke_rtl .cke_path_empty
40{
41 float: none;
42}
43
44.cke_rtl .cke_toolgroup,
45.cke_rtl .cke_toolbar_separator,
46.cke_rtl .cke_combo_button,
47.cke_rtl .cke_combo_button *,
48.cke_rtl .cke_button,
49.cke_rtl .cke_button_icon
50{
51 display: inline-block;
52 vertical-align: top;
53}
54
55/* Otherwise formatting toolbar breaks when editing a mixed content (#9893). */
56.cke_rtl .cke_button_icon
57{
58 float: none;
59}
60
61.cke_resizer
62{
63 width: 10px;
64}
65
66.cke_source
67{
68 white-space: normal;
69}
70
71.cke_bottom
72{
73 position: static; /* Without this bottom space doesn't move when resizing editor. */
74}
75
76.cke_colorbox
77{
78 font-size: 0; /* Set minimal font size, so button won't be streched by the text that doesn't exist. */
79}
diff --git a/sources/skins/moono/elementspath.css b/sources/skins/moono/elementspath.css
new file mode 100644
index 0000000..3bf10d6
--- /dev/null
+++ b/sources/skins/moono/elementspath.css
@@ -0,0 +1,76 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7elementspath.css (part of editor.css)
8=======================================
9
10This file styles the "Elements Path", whith is the list of element names
11present at the the bottom bar of the CKEditor interface.
12
13The following is a visual representation of its main elements:
14
15+-- .cke_path ---------------------------------------------------------------+
16| +-- .cke_path_item ----+ +-- .cke_path_item ----+ +-- .cke_path_empty ---+ |
17| | | | | | | |
18| +----------------------+ +----------------------+ +----------------------+ |
19+----------------------------------------------------------------------------+
20*/
21
22/* The box that holds the entire elements path. */
23.cke_path
24{
25 float: left;
26 margin: -2px 0 2px;
27}
28
29/* Each item of the elements path. */
30a.cke_path_item,
31/* Empty element available at the end of the elements path, to help us keeping
32 the proper box size when the elements path is empty. */
33span.cke_path_empty
34{
35 display: inline-block;
36 float: left;
37 padding: 3px 4px;
38 margin-right: 2px;
39 cursor: default;
40 text-decoration: none;
41 outline: 0;
42 border: 0;
43 color: #4c4c4c;
44 text-shadow: 0 1px 0 #fff;
45 font-weight: bold;
46 font-size: 11px;
47}
48
49.cke_rtl .cke_path,
50.cke_rtl .cke_path_item,
51.cke_rtl .cke_path_empty
52{
53 float: right;
54}
55
56/* The items are <a> elements, so we define its hover states here. */
57a.cke_path_item:hover,
58a.cke_path_item:focus,
59a.cke_path_item:active
60{
61 background-color: #bfbfbf;
62 color: #333;
63 text-shadow: 0 1px 0 rgba(255,255,255,.5);
64
65 border-radius: 2px;
66
67 box-shadow: 0 0 4px rgba(0,0,0,.5) inset, 0 1px 0 rgba(255,255,255,.5);
68}
69
70.cke_hc a.cke_path_item:hover,
71.cke_hc a.cke_path_item:focus,
72.cke_hc a.cke_path_item:active
73{
74 border: 2px solid;
75 padding: 1px 2px;
76}
diff --git a/sources/skins/moono/icons/about.png b/sources/skins/moono/icons/about.png
new file mode 100644
index 0000000..d36b8a1
--- /dev/null
+++ b/sources/skins/moono/icons/about.png
Binary files differ
diff --git a/sources/skins/moono/icons/anchor-rtl.png b/sources/skins/moono/icons/anchor-rtl.png
new file mode 100644
index 0000000..a07d34e
--- /dev/null
+++ b/sources/skins/moono/icons/anchor-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/anchor.png b/sources/skins/moono/icons/anchor.png
new file mode 100644
index 0000000..2d2f91d
--- /dev/null
+++ b/sources/skins/moono/icons/anchor.png
Binary files differ
diff --git a/sources/skins/moono/icons/bgcolor.png b/sources/skins/moono/icons/bgcolor.png
new file mode 100644
index 0000000..549f0fa
--- /dev/null
+++ b/sources/skins/moono/icons/bgcolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/bidiltr.png b/sources/skins/moono/icons/bidiltr.png
new file mode 100644
index 0000000..8a11ec5
--- /dev/null
+++ b/sources/skins/moono/icons/bidiltr.png
Binary files differ
diff --git a/sources/skins/moono/icons/bidirtl.png b/sources/skins/moono/icons/bidirtl.png
new file mode 100644
index 0000000..318e245
--- /dev/null
+++ b/sources/skins/moono/icons/bidirtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/blockquote.png b/sources/skins/moono/icons/blockquote.png
new file mode 100644
index 0000000..61d8fd3
--- /dev/null
+++ b/sources/skins/moono/icons/blockquote.png
Binary files differ
diff --git a/sources/skins/moono/icons/bold.png b/sources/skins/moono/icons/bold.png
new file mode 100644
index 0000000..885e916
--- /dev/null
+++ b/sources/skins/moono/icons/bold.png
Binary files differ
diff --git a/sources/skins/moono/icons/bulletedlist-rtl.png b/sources/skins/moono/icons/bulletedlist-rtl.png
new file mode 100644
index 0000000..617096f
--- /dev/null
+++ b/sources/skins/moono/icons/bulletedlist-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/bulletedlist.png b/sources/skins/moono/icons/bulletedlist.png
new file mode 100644
index 0000000..6bef9a5
--- /dev/null
+++ b/sources/skins/moono/icons/bulletedlist.png
Binary files differ
diff --git a/sources/skins/moono/icons/button.png b/sources/skins/moono/icons/button.png
new file mode 100644
index 0000000..c0f2fcc
--- /dev/null
+++ b/sources/skins/moono/icons/button.png
Binary files differ
diff --git a/sources/skins/moono/icons/checkbox.png b/sources/skins/moono/icons/checkbox.png
new file mode 100644
index 0000000..45397d4
--- /dev/null
+++ b/sources/skins/moono/icons/checkbox.png
Binary files differ
diff --git a/sources/skins/moono/icons/codesnippet.png b/sources/skins/moono/icons/codesnippet.png
new file mode 100644
index 0000000..6493f6f
--- /dev/null
+++ b/sources/skins/moono/icons/codesnippet.png
Binary files differ
diff --git a/sources/skins/moono/icons/copy-rtl.png b/sources/skins/moono/icons/copy-rtl.png
new file mode 100644
index 0000000..1d65071
--- /dev/null
+++ b/sources/skins/moono/icons/copy-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/copy.png b/sources/skins/moono/icons/copy.png
new file mode 100644
index 0000000..1d65071
--- /dev/null
+++ b/sources/skins/moono/icons/copy.png
Binary files differ
diff --git a/sources/skins/moono/icons/copyformatting.png b/sources/skins/moono/icons/copyformatting.png
new file mode 100644
index 0000000..0eb02ee
--- /dev/null
+++ b/sources/skins/moono/icons/copyformatting.png
Binary files differ
diff --git a/sources/skins/moono/icons/creatediv.png b/sources/skins/moono/icons/creatediv.png
new file mode 100644
index 0000000..79d5bb5
--- /dev/null
+++ b/sources/skins/moono/icons/creatediv.png
Binary files differ
diff --git a/sources/skins/moono/icons/cut-rtl.png b/sources/skins/moono/icons/cut-rtl.png
new file mode 100644
index 0000000..97f826e
--- /dev/null
+++ b/sources/skins/moono/icons/cut-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/cut.png b/sources/skins/moono/icons/cut.png
new file mode 100644
index 0000000..97f826e
--- /dev/null
+++ b/sources/skins/moono/icons/cut.png
Binary files differ
diff --git a/sources/skins/moono/icons/docprops-rtl.png b/sources/skins/moono/icons/docprops-rtl.png
new file mode 100644
index 0000000..1e6d212
--- /dev/null
+++ b/sources/skins/moono/icons/docprops-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/docprops.png b/sources/skins/moono/icons/docprops.png
new file mode 100644
index 0000000..dd7e1e8
--- /dev/null
+++ b/sources/skins/moono/icons/docprops.png
Binary files differ
diff --git a/sources/skins/moono/icons/find-rtl.png b/sources/skins/moono/icons/find-rtl.png
new file mode 100644
index 0000000..8d94455
--- /dev/null
+++ b/sources/skins/moono/icons/find-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/find.png b/sources/skins/moono/icons/find.png
new file mode 100644
index 0000000..8d94455
--- /dev/null
+++ b/sources/skins/moono/icons/find.png
Binary files differ
diff --git a/sources/skins/moono/icons/flash.png b/sources/skins/moono/icons/flash.png
new file mode 100644
index 0000000..6b7c843
--- /dev/null
+++ b/sources/skins/moono/icons/flash.png
Binary files differ
diff --git a/sources/skins/moono/icons/form.png b/sources/skins/moono/icons/form.png
new file mode 100644
index 0000000..68c5b6b
--- /dev/null
+++ b/sources/skins/moono/icons/form.png
Binary files differ
diff --git a/sources/skins/moono/icons/hiddenfield.png b/sources/skins/moono/icons/hiddenfield.png
new file mode 100644
index 0000000..ddc547f
--- /dev/null
+++ b/sources/skins/moono/icons/hiddenfield.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/.DS_Store b/sources/skins/moono/icons/hidpi/.DS_Store
new file mode 100644
index 0000000..9d2abe5
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/.DS_Store
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/about.png b/sources/skins/moono/icons/hidpi/about.png
new file mode 100644
index 0000000..8ecc4a6
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/about.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/anchor-rtl.png b/sources/skins/moono/icons/hidpi/anchor-rtl.png
new file mode 100644
index 0000000..318a138
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/anchor-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/anchor.png b/sources/skins/moono/icons/hidpi/anchor.png
new file mode 100644
index 0000000..53486a8
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/anchor.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bgcolor.png b/sources/skins/moono/icons/hidpi/bgcolor.png
new file mode 100644
index 0000000..20fcf37
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bgcolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bidiltr.png b/sources/skins/moono/icons/hidpi/bidiltr.png
new file mode 100644
index 0000000..6fb7456
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bidiltr.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bidirtl.png b/sources/skins/moono/icons/hidpi/bidirtl.png
new file mode 100644
index 0000000..80f063d
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bidirtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/blockquote.png b/sources/skins/moono/icons/hidpi/blockquote.png
new file mode 100644
index 0000000..965f910
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/blockquote.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bold.png b/sources/skins/moono/icons/hidpi/bold.png
new file mode 100644
index 0000000..613319b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bold.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bulletedlist-rtl.png b/sources/skins/moono/icons/hidpi/bulletedlist-rtl.png
new file mode 100644
index 0000000..34da46b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bulletedlist-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/bulletedlist.png b/sources/skins/moono/icons/hidpi/bulletedlist.png
new file mode 100644
index 0000000..f322ed9
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/bulletedlist.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/button.png b/sources/skins/moono/icons/hidpi/button.png
new file mode 100644
index 0000000..a7b2b42
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/button.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/checkbox.png b/sources/skins/moono/icons/hidpi/checkbox.png
new file mode 100644
index 0000000..53ac357
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/checkbox.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/codesnippet.png b/sources/skins/moono/icons/hidpi/codesnippet.png
new file mode 100644
index 0000000..a9b3a98
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/codesnippet.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/copy-rtl.png b/sources/skins/moono/icons/hidpi/copy-rtl.png
new file mode 100644
index 0000000..6c9a0fe
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/copy-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/copy.png b/sources/skins/moono/icons/hidpi/copy.png
new file mode 100644
index 0000000..6c9a0fe
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/copy.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/copyformatting.png b/sources/skins/moono/icons/hidpi/copyformatting.png
new file mode 100644
index 0000000..4f95e7a
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/copyformatting.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/creatediv.png b/sources/skins/moono/icons/hidpi/creatediv.png
new file mode 100644
index 0000000..808e466
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/creatediv.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/cut-rtl.png b/sources/skins/moono/icons/hidpi/cut-rtl.png
new file mode 100644
index 0000000..39c4af0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/cut-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/cut.png b/sources/skins/moono/icons/hidpi/cut.png
new file mode 100644
index 0000000..39c4af0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/cut.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/docprops-rtl.png b/sources/skins/moono/icons/hidpi/docprops-rtl.png
new file mode 100644
index 0000000..de8722f
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/docprops-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/docprops.png b/sources/skins/moono/icons/hidpi/docprops.png
new file mode 100644
index 0000000..74af812
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/docprops.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/find-rtl.png b/sources/skins/moono/icons/hidpi/find-rtl.png
new file mode 100644
index 0000000..ff0e0c6
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/find-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/find.png b/sources/skins/moono/icons/hidpi/find.png
new file mode 100644
index 0000000..ff0e0c6
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/find.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/flash.png b/sources/skins/moono/icons/hidpi/flash.png
new file mode 100644
index 0000000..7323b19
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/flash.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/form.png b/sources/skins/moono/icons/hidpi/form.png
new file mode 100644
index 0000000..90f4813
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/form.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/hiddenfield.png b/sources/skins/moono/icons/hidpi/hiddenfield.png
new file mode 100644
index 0000000..fd10781
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/hiddenfield.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/horizontalrule.png b/sources/skins/moono/icons/hidpi/horizontalrule.png
new file mode 100644
index 0000000..0ae87fb
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/horizontalrule.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/iframe.png b/sources/skins/moono/icons/hidpi/iframe.png
new file mode 100644
index 0000000..a56ecb0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/iframe.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/image.png b/sources/skins/moono/icons/hidpi/image.png
new file mode 100644
index 0000000..e9579fb
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/image.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/imagebutton.png b/sources/skins/moono/icons/hidpi/imagebutton.png
new file mode 100644
index 0000000..f38b758
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/imagebutton.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/indent-rtl.png b/sources/skins/moono/icons/hidpi/indent-rtl.png
new file mode 100644
index 0000000..44eea22
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/indent-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/indent.png b/sources/skins/moono/icons/hidpi/indent.png
new file mode 100644
index 0000000..417f092
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/indent.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/italic.png b/sources/skins/moono/icons/hidpi/italic.png
new file mode 100644
index 0000000..07b1d1d
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/italic.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/justifyblock.png b/sources/skins/moono/icons/hidpi/justifyblock.png
new file mode 100644
index 0000000..4535a39
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/justifyblock.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/justifycenter.png b/sources/skins/moono/icons/hidpi/justifycenter.png
new file mode 100644
index 0000000..8749f69
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/justifycenter.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/justifyleft.png b/sources/skins/moono/icons/hidpi/justifyleft.png
new file mode 100644
index 0000000..50a4307
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/justifyleft.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/justifyright.png b/sources/skins/moono/icons/hidpi/justifyright.png
new file mode 100644
index 0000000..6d127e7
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/justifyright.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/language.png b/sources/skins/moono/icons/hidpi/language.png
new file mode 100644
index 0000000..d778031
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/language.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/link.png b/sources/skins/moono/icons/hidpi/link.png
new file mode 100644
index 0000000..fed6b91
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/link.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/maximize.png b/sources/skins/moono/icons/hidpi/maximize.png
new file mode 100644
index 0000000..eeaa700
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/maximize.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/newpage-rtl.png b/sources/skins/moono/icons/hidpi/newpage-rtl.png
new file mode 100644
index 0000000..c5e1d3b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/newpage-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/newpage.png b/sources/skins/moono/icons/hidpi/newpage.png
new file mode 100644
index 0000000..139279b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/newpage.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/numberedlist-rtl.png b/sources/skins/moono/icons/hidpi/numberedlist-rtl.png
new file mode 100644
index 0000000..b449c2b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/numberedlist-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/numberedlist.png b/sources/skins/moono/icons/hidpi/numberedlist.png
new file mode 100644
index 0000000..b7442ef
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/numberedlist.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/outdent-rtl.png b/sources/skins/moono/icons/hidpi/outdent-rtl.png
new file mode 100644
index 0000000..a642bca
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/outdent-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/outdent.png b/sources/skins/moono/icons/hidpi/outdent.png
new file mode 100644
index 0000000..6d715a5
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/outdent.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pagebreak-rtl.png b/sources/skins/moono/icons/hidpi/pagebreak-rtl.png
new file mode 100644
index 0000000..6fc486b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pagebreak-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pagebreak.png b/sources/skins/moono/icons/hidpi/pagebreak.png
new file mode 100644
index 0000000..a19ecc0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pagebreak.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/paste-rtl.png b/sources/skins/moono/icons/hidpi/paste-rtl.png
new file mode 100644
index 0000000..14f9eff
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/paste-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/paste.png b/sources/skins/moono/icons/hidpi/paste.png
new file mode 100644
index 0000000..14f9eff
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/paste.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pastefromword-rtl.png b/sources/skins/moono/icons/hidpi/pastefromword-rtl.png
new file mode 100644
index 0000000..fb9ef9e
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pastefromword-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pastefromword.png b/sources/skins/moono/icons/hidpi/pastefromword.png
new file mode 100644
index 0000000..7666b0f
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pastefromword.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pastetext-rtl.png b/sources/skins/moono/icons/hidpi/pastetext-rtl.png
new file mode 100644
index 0000000..b30fc9b
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pastetext-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/pastetext.png b/sources/skins/moono/icons/hidpi/pastetext.png
new file mode 100644
index 0000000..e811afc
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/pastetext.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/placeholder.png b/sources/skins/moono/icons/hidpi/placeholder.png
new file mode 100644
index 0000000..0874f14
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/placeholder.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/preview-rtl.png b/sources/skins/moono/icons/hidpi/preview-rtl.png
new file mode 100644
index 0000000..06d06c0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/preview-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/preview.png b/sources/skins/moono/icons/hidpi/preview.png
new file mode 100644
index 0000000..993e79e
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/preview.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/print.png b/sources/skins/moono/icons/hidpi/print.png
new file mode 100644
index 0000000..42064c2
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/print.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/radio.png b/sources/skins/moono/icons/hidpi/radio.png
new file mode 100644
index 0000000..c84bc00
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/radio.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/redo-rtl.png b/sources/skins/moono/icons/hidpi/redo-rtl.png
new file mode 100644
index 0000000..c8583ea
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/redo-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/redo.png b/sources/skins/moono/icons/hidpi/redo.png
new file mode 100644
index 0000000..fb25750
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/redo.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/removeformat.png b/sources/skins/moono/icons/hidpi/removeformat.png
new file mode 100644
index 0000000..738ebcd
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/removeformat.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/replace.png b/sources/skins/moono/icons/hidpi/replace.png
new file mode 100644
index 0000000..3944ec3
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/replace.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/save.png b/sources/skins/moono/icons/hidpi/save.png
new file mode 100644
index 0000000..21f92bf
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/save.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/scayt.png b/sources/skins/moono/icons/hidpi/scayt.png
new file mode 100644
index 0000000..5f0b6d9
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/scayt.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/select-rtl.png b/sources/skins/moono/icons/hidpi/select-rtl.png
new file mode 100644
index 0000000..925c06d
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/select-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/select.png b/sources/skins/moono/icons/hidpi/select.png
new file mode 100644
index 0000000..0e995f9
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/select.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/selectall.png b/sources/skins/moono/icons/hidpi/selectall.png
new file mode 100644
index 0000000..68f3239
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/selectall.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/showblocks-rtl.png b/sources/skins/moono/icons/hidpi/showblocks-rtl.png
new file mode 100644
index 0000000..d210fad
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/showblocks-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/showblocks.png b/sources/skins/moono/icons/hidpi/showblocks.png
new file mode 100644
index 0000000..d6d51d1
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/showblocks.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/smiley.png b/sources/skins/moono/icons/hidpi/smiley.png
new file mode 100644
index 0000000..5a70b89
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/smiley.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/source-rtl.png b/sources/skins/moono/icons/hidpi/source-rtl.png
new file mode 100644
index 0000000..64b2266
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/source-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/source.png b/sources/skins/moono/icons/hidpi/source.png
new file mode 100644
index 0000000..4e732c0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/source.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/sourcedialog-rtl.png b/sources/skins/moono/icons/hidpi/sourcedialog-rtl.png
new file mode 100644
index 0000000..64b2266
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/sourcedialog-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/sourcedialog.png b/sources/skins/moono/icons/hidpi/sourcedialog.png
new file mode 100644
index 0000000..4e732c0
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/sourcedialog.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/specialchar.png b/sources/skins/moono/icons/hidpi/specialchar.png
new file mode 100644
index 0000000..5874ea3
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/specialchar.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/spellchecker.png b/sources/skins/moono/icons/hidpi/spellchecker.png
new file mode 100644
index 0000000..5f0b6d9
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/spellchecker.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/strike.png b/sources/skins/moono/icons/hidpi/strike.png
new file mode 100644
index 0000000..45c3269
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/strike.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/subscript.png b/sources/skins/moono/icons/hidpi/subscript.png
new file mode 100644
index 0000000..d59e216
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/subscript.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/superscript.png b/sources/skins/moono/icons/hidpi/superscript.png
new file mode 100644
index 0000000..2951416
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/superscript.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/table.png b/sources/skins/moono/icons/hidpi/table.png
new file mode 100644
index 0000000..795e8c8
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/table.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/templates-rtl.png b/sources/skins/moono/icons/hidpi/templates-rtl.png
new file mode 100644
index 0000000..0784b00
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/templates-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/templates.png b/sources/skins/moono/icons/hidpi/templates.png
new file mode 100644
index 0000000..0784b00
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/templates.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/textarea-rtl.png b/sources/skins/moono/icons/hidpi/textarea-rtl.png
new file mode 100644
index 0000000..4bc1c06
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/textarea-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/textarea.png b/sources/skins/moono/icons/hidpi/textarea.png
new file mode 100644
index 0000000..8156e51
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/textarea.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/textcolor.png b/sources/skins/moono/icons/hidpi/textcolor.png
new file mode 100644
index 0000000..42c5e4f
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/textcolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/textfield-rtl.png b/sources/skins/moono/icons/hidpi/textfield-rtl.png
new file mode 100644
index 0000000..1d5970a
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/textfield-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/textfield.png b/sources/skins/moono/icons/hidpi/textfield.png
new file mode 100644
index 0000000..1d5970a
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/textfield.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/uicolor.png b/sources/skins/moono/icons/hidpi/uicolor.png
new file mode 100644
index 0000000..dbd21ff
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/uicolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/underline.png b/sources/skins/moono/icons/hidpi/underline.png
new file mode 100644
index 0000000..53302c6
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/underline.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/undo-rtl.png b/sources/skins/moono/icons/hidpi/undo-rtl.png
new file mode 100644
index 0000000..fb25750
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/undo-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/undo.png b/sources/skins/moono/icons/hidpi/undo.png
new file mode 100644
index 0000000..c8583ea
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/undo.png
Binary files differ
diff --git a/sources/skins/moono/icons/hidpi/unlink.png b/sources/skins/moono/icons/hidpi/unlink.png
new file mode 100644
index 0000000..dc7fc78
--- /dev/null
+++ b/sources/skins/moono/icons/hidpi/unlink.png
Binary files differ
diff --git a/sources/skins/moono/icons/horizontalrule.png b/sources/skins/moono/icons/horizontalrule.png
new file mode 100644
index 0000000..513d193
--- /dev/null
+++ b/sources/skins/moono/icons/horizontalrule.png
Binary files differ
diff --git a/sources/skins/moono/icons/iframe.png b/sources/skins/moono/icons/iframe.png
new file mode 100644
index 0000000..2393ca5
--- /dev/null
+++ b/sources/skins/moono/icons/iframe.png
Binary files differ
diff --git a/sources/skins/moono/icons/image.png b/sources/skins/moono/icons/image.png
new file mode 100644
index 0000000..281dbc7
--- /dev/null
+++ b/sources/skins/moono/icons/image.png
Binary files differ
diff --git a/sources/skins/moono/icons/imagebutton.png b/sources/skins/moono/icons/imagebutton.png
new file mode 100644
index 0000000..e26854b
--- /dev/null
+++ b/sources/skins/moono/icons/imagebutton.png
Binary files differ
diff --git a/sources/skins/moono/icons/indent-rtl.png b/sources/skins/moono/icons/indent-rtl.png
new file mode 100644
index 0000000..23ab113
--- /dev/null
+++ b/sources/skins/moono/icons/indent-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/indent.png b/sources/skins/moono/icons/indent.png
new file mode 100644
index 0000000..8c2ee08
--- /dev/null
+++ b/sources/skins/moono/icons/indent.png
Binary files differ
diff --git a/sources/skins/moono/icons/italic.png b/sources/skins/moono/icons/italic.png
new file mode 100644
index 0000000..0983afe
--- /dev/null
+++ b/sources/skins/moono/icons/italic.png
Binary files differ
diff --git a/sources/skins/moono/icons/justifyblock.png b/sources/skins/moono/icons/justifyblock.png
new file mode 100644
index 0000000..72164e7
--- /dev/null
+++ b/sources/skins/moono/icons/justifyblock.png
Binary files differ
diff --git a/sources/skins/moono/icons/justifycenter.png b/sources/skins/moono/icons/justifycenter.png
new file mode 100644
index 0000000..5721c9e
--- /dev/null
+++ b/sources/skins/moono/icons/justifycenter.png
Binary files differ
diff --git a/sources/skins/moono/icons/justifyleft.png b/sources/skins/moono/icons/justifyleft.png
new file mode 100644
index 0000000..0b1fa97
--- /dev/null
+++ b/sources/skins/moono/icons/justifyleft.png
Binary files differ
diff --git a/sources/skins/moono/icons/justifyright.png b/sources/skins/moono/icons/justifyright.png
new file mode 100644
index 0000000..f039348
--- /dev/null
+++ b/sources/skins/moono/icons/justifyright.png
Binary files differ
diff --git a/sources/skins/moono/icons/language.png b/sources/skins/moono/icons/language.png
new file mode 100644
index 0000000..dfa11fa
--- /dev/null
+++ b/sources/skins/moono/icons/language.png
Binary files differ
diff --git a/sources/skins/moono/icons/link.png b/sources/skins/moono/icons/link.png
new file mode 100644
index 0000000..2bf8900
--- /dev/null
+++ b/sources/skins/moono/icons/link.png
Binary files differ
diff --git a/sources/skins/moono/icons/maximize.png b/sources/skins/moono/icons/maximize.png
new file mode 100644
index 0000000..95427dc
--- /dev/null
+++ b/sources/skins/moono/icons/maximize.png
Binary files differ
diff --git a/sources/skins/moono/icons/newpage-rtl.png b/sources/skins/moono/icons/newpage-rtl.png
new file mode 100644
index 0000000..e88f7f4
--- /dev/null
+++ b/sources/skins/moono/icons/newpage-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/newpage.png b/sources/skins/moono/icons/newpage.png
new file mode 100644
index 0000000..410eb50
--- /dev/null
+++ b/sources/skins/moono/icons/newpage.png
Binary files differ
diff --git a/sources/skins/moono/icons/numberedlist-rtl.png b/sources/skins/moono/icons/numberedlist-rtl.png
new file mode 100644
index 0000000..d40582d
--- /dev/null
+++ b/sources/skins/moono/icons/numberedlist-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/numberedlist.png b/sources/skins/moono/icons/numberedlist.png
new file mode 100644
index 0000000..beaa1b2
--- /dev/null
+++ b/sources/skins/moono/icons/numberedlist.png
Binary files differ
diff --git a/sources/skins/moono/icons/outdent-rtl.png b/sources/skins/moono/icons/outdent-rtl.png
new file mode 100644
index 0000000..bd7bb34
--- /dev/null
+++ b/sources/skins/moono/icons/outdent-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/outdent.png b/sources/skins/moono/icons/outdent.png
new file mode 100644
index 0000000..b48e099
--- /dev/null
+++ b/sources/skins/moono/icons/outdent.png
Binary files differ
diff --git a/sources/skins/moono/icons/pagebreak-rtl.png b/sources/skins/moono/icons/pagebreak-rtl.png
new file mode 100644
index 0000000..c8b22cc
--- /dev/null
+++ b/sources/skins/moono/icons/pagebreak-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/pagebreak.png b/sources/skins/moono/icons/pagebreak.png
new file mode 100644
index 0000000..616dfcd
--- /dev/null
+++ b/sources/skins/moono/icons/pagebreak.png
Binary files differ
diff --git a/sources/skins/moono/icons/paste-rtl.png b/sources/skins/moono/icons/paste-rtl.png
new file mode 100644
index 0000000..beb842b
--- /dev/null
+++ b/sources/skins/moono/icons/paste-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/paste.png b/sources/skins/moono/icons/paste.png
new file mode 100644
index 0000000..beb842b
--- /dev/null
+++ b/sources/skins/moono/icons/paste.png
Binary files differ
diff --git a/sources/skins/moono/icons/pastefromword-rtl.png b/sources/skins/moono/icons/pastefromword-rtl.png
new file mode 100644
index 0000000..234e660
--- /dev/null
+++ b/sources/skins/moono/icons/pastefromword-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/pastefromword.png b/sources/skins/moono/icons/pastefromword.png
new file mode 100644
index 0000000..39afbe3
--- /dev/null
+++ b/sources/skins/moono/icons/pastefromword.png
Binary files differ
diff --git a/sources/skins/moono/icons/pastetext-rtl.png b/sources/skins/moono/icons/pastetext-rtl.png
new file mode 100644
index 0000000..7dffd18
--- /dev/null
+++ b/sources/skins/moono/icons/pastetext-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/pastetext.png b/sources/skins/moono/icons/pastetext.png
new file mode 100644
index 0000000..f5aba32
--- /dev/null
+++ b/sources/skins/moono/icons/pastetext.png
Binary files differ
diff --git a/sources/skins/moono/icons/placeholder.png b/sources/skins/moono/icons/placeholder.png
new file mode 100644
index 0000000..8bd808a
--- /dev/null
+++ b/sources/skins/moono/icons/placeholder.png
Binary files differ
diff --git a/sources/skins/moono/icons/preview-rtl.png b/sources/skins/moono/icons/preview-rtl.png
new file mode 100644
index 0000000..a1402fb
--- /dev/null
+++ b/sources/skins/moono/icons/preview-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/preview.png b/sources/skins/moono/icons/preview.png
new file mode 100644
index 0000000..256fa5a
--- /dev/null
+++ b/sources/skins/moono/icons/preview.png
Binary files differ
diff --git a/sources/skins/moono/icons/print.png b/sources/skins/moono/icons/print.png
new file mode 100644
index 0000000..e2fd5c3
--- /dev/null
+++ b/sources/skins/moono/icons/print.png
Binary files differ
diff --git a/sources/skins/moono/icons/radio.png b/sources/skins/moono/icons/radio.png
new file mode 100644
index 0000000..136e433
--- /dev/null
+++ b/sources/skins/moono/icons/radio.png
Binary files differ
diff --git a/sources/skins/moono/icons/redo-rtl.png b/sources/skins/moono/icons/redo-rtl.png
new file mode 100644
index 0000000..9e03f4a
--- /dev/null
+++ b/sources/skins/moono/icons/redo-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/redo.png b/sources/skins/moono/icons/redo.png
new file mode 100644
index 0000000..f7119cb
--- /dev/null
+++ b/sources/skins/moono/icons/redo.png
Binary files differ
diff --git a/sources/skins/moono/icons/removeformat.png b/sources/skins/moono/icons/removeformat.png
new file mode 100644
index 0000000..4e74dfc
--- /dev/null
+++ b/sources/skins/moono/icons/removeformat.png
Binary files differ
diff --git a/sources/skins/moono/icons/replace.png b/sources/skins/moono/icons/replace.png
new file mode 100644
index 0000000..9597eb1
--- /dev/null
+++ b/sources/skins/moono/icons/replace.png
Binary files differ
diff --git a/sources/skins/moono/icons/save.png b/sources/skins/moono/icons/save.png
new file mode 100644
index 0000000..97635c8
--- /dev/null
+++ b/sources/skins/moono/icons/save.png
Binary files differ
diff --git a/sources/skins/moono/icons/scayt.png b/sources/skins/moono/icons/scayt.png
new file mode 100644
index 0000000..46d7570
--- /dev/null
+++ b/sources/skins/moono/icons/scayt.png
Binary files differ
diff --git a/sources/skins/moono/icons/select-rtl.png b/sources/skins/moono/icons/select-rtl.png
new file mode 100644
index 0000000..33dd89d
--- /dev/null
+++ b/sources/skins/moono/icons/select-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/select.png b/sources/skins/moono/icons/select.png
new file mode 100644
index 0000000..c3d89cc
--- /dev/null
+++ b/sources/skins/moono/icons/select.png
Binary files differ
diff --git a/sources/skins/moono/icons/selectall.png b/sources/skins/moono/icons/selectall.png
new file mode 100644
index 0000000..a4cff3d
--- /dev/null
+++ b/sources/skins/moono/icons/selectall.png
Binary files differ
diff --git a/sources/skins/moono/icons/showblocks-rtl.png b/sources/skins/moono/icons/showblocks-rtl.png
new file mode 100644
index 0000000..6f391b1
--- /dev/null
+++ b/sources/skins/moono/icons/showblocks-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/showblocks.png b/sources/skins/moono/icons/showblocks.png
new file mode 100644
index 0000000..0b240e8
--- /dev/null
+++ b/sources/skins/moono/icons/showblocks.png
Binary files differ
diff --git a/sources/skins/moono/icons/smiley.png b/sources/skins/moono/icons/smiley.png
new file mode 100644
index 0000000..e7607ca
--- /dev/null
+++ b/sources/skins/moono/icons/smiley.png
Binary files differ
diff --git a/sources/skins/moono/icons/source-rtl.png b/sources/skins/moono/icons/source-rtl.png
new file mode 100644
index 0000000..c734db6
--- /dev/null
+++ b/sources/skins/moono/icons/source-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/source.png b/sources/skins/moono/icons/source.png
new file mode 100644
index 0000000..004e73b
--- /dev/null
+++ b/sources/skins/moono/icons/source.png
Binary files differ
diff --git a/sources/skins/moono/icons/sourcedialog-rtl.png b/sources/skins/moono/icons/sourcedialog-rtl.png
new file mode 100644
index 0000000..c734db6
--- /dev/null
+++ b/sources/skins/moono/icons/sourcedialog-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/sourcedialog.png b/sources/skins/moono/icons/sourcedialog.png
new file mode 100644
index 0000000..004e73b
--- /dev/null
+++ b/sources/skins/moono/icons/sourcedialog.png
Binary files differ
diff --git a/sources/skins/moono/icons/specialchar.png b/sources/skins/moono/icons/specialchar.png
new file mode 100644
index 0000000..4dafefd
--- /dev/null
+++ b/sources/skins/moono/icons/specialchar.png
Binary files differ
diff --git a/sources/skins/moono/icons/spellchecker.png b/sources/skins/moono/icons/spellchecker.png
new file mode 100644
index 0000000..46d7570
--- /dev/null
+++ b/sources/skins/moono/icons/spellchecker.png
Binary files differ
diff --git a/sources/skins/moono/icons/strike.png b/sources/skins/moono/icons/strike.png
new file mode 100644
index 0000000..8007832
--- /dev/null
+++ b/sources/skins/moono/icons/strike.png
Binary files differ
diff --git a/sources/skins/moono/icons/subscript.png b/sources/skins/moono/icons/subscript.png
new file mode 100644
index 0000000..89e8bf4
--- /dev/null
+++ b/sources/skins/moono/icons/subscript.png
Binary files differ
diff --git a/sources/skins/moono/icons/superscript.png b/sources/skins/moono/icons/superscript.png
new file mode 100644
index 0000000..1a269c6
--- /dev/null
+++ b/sources/skins/moono/icons/superscript.png
Binary files differ
diff --git a/sources/skins/moono/icons/table.png b/sources/skins/moono/icons/table.png
new file mode 100644
index 0000000..f29d051
--- /dev/null
+++ b/sources/skins/moono/icons/table.png
Binary files differ
diff --git a/sources/skins/moono/icons/templates-rtl.png b/sources/skins/moono/icons/templates-rtl.png
new file mode 100644
index 0000000..0ebeb55
--- /dev/null
+++ b/sources/skins/moono/icons/templates-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/templates.png b/sources/skins/moono/icons/templates.png
new file mode 100644
index 0000000..0ebeb55
--- /dev/null
+++ b/sources/skins/moono/icons/templates.png
Binary files differ
diff --git a/sources/skins/moono/icons/textarea-rtl.png b/sources/skins/moono/icons/textarea-rtl.png
new file mode 100644
index 0000000..6ae1560
--- /dev/null
+++ b/sources/skins/moono/icons/textarea-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/textarea.png b/sources/skins/moono/icons/textarea.png
new file mode 100644
index 0000000..4edac92
--- /dev/null
+++ b/sources/skins/moono/icons/textarea.png
Binary files differ
diff --git a/sources/skins/moono/icons/textcolor.png b/sources/skins/moono/icons/textcolor.png
new file mode 100644
index 0000000..48ed589
--- /dev/null
+++ b/sources/skins/moono/icons/textcolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/textfield-rtl.png b/sources/skins/moono/icons/textfield-rtl.png
new file mode 100644
index 0000000..a0564ea
--- /dev/null
+++ b/sources/skins/moono/icons/textfield-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/textfield.png b/sources/skins/moono/icons/textfield.png
new file mode 100644
index 0000000..a0564ea
--- /dev/null
+++ b/sources/skins/moono/icons/textfield.png
Binary files differ
diff --git a/sources/skins/moono/icons/uicolor.png b/sources/skins/moono/icons/uicolor.png
new file mode 100644
index 0000000..b633a3c
--- /dev/null
+++ b/sources/skins/moono/icons/uicolor.png
Binary files differ
diff --git a/sources/skins/moono/icons/underline.png b/sources/skins/moono/icons/underline.png
new file mode 100644
index 0000000..2ac6fb7
--- /dev/null
+++ b/sources/skins/moono/icons/underline.png
Binary files differ
diff --git a/sources/skins/moono/icons/undo-rtl.png b/sources/skins/moono/icons/undo-rtl.png
new file mode 100644
index 0000000..f7119cb
--- /dev/null
+++ b/sources/skins/moono/icons/undo-rtl.png
Binary files differ
diff --git a/sources/skins/moono/icons/undo.png b/sources/skins/moono/icons/undo.png
new file mode 100644
index 0000000..4c80228
--- /dev/null
+++ b/sources/skins/moono/icons/undo.png
Binary files differ
diff --git a/sources/skins/moono/icons/unlink.png b/sources/skins/moono/icons/unlink.png
new file mode 100644
index 0000000..8a4c84d
--- /dev/null
+++ b/sources/skins/moono/icons/unlink.png
Binary files differ
diff --git a/sources/skins/moono/images/anchor.png b/sources/skins/moono/images/anchor.png
new file mode 100644
index 0000000..1c802f5
--- /dev/null
+++ b/sources/skins/moono/images/anchor.png
Binary files differ
diff --git a/sources/skins/moono/images/arrow.png b/sources/skins/moono/images/arrow.png
new file mode 100644
index 0000000..d72b5f3
--- /dev/null
+++ b/sources/skins/moono/images/arrow.png
Binary files differ
diff --git a/sources/skins/moono/images/close.png b/sources/skins/moono/images/close.png
new file mode 100644
index 0000000..2d02977
--- /dev/null
+++ b/sources/skins/moono/images/close.png
Binary files differ
diff --git a/sources/skins/moono/images/hidpi/anchor.png b/sources/skins/moono/images/hidpi/anchor.png
new file mode 100644
index 0000000..17cca97
--- /dev/null
+++ b/sources/skins/moono/images/hidpi/anchor.png
Binary files differ
diff --git a/sources/skins/moono/images/hidpi/close.png b/sources/skins/moono/images/hidpi/close.png
new file mode 100644
index 0000000..de4eedf
--- /dev/null
+++ b/sources/skins/moono/images/hidpi/close.png
Binary files differ
diff --git a/sources/skins/moono/images/hidpi/lock-open.png b/sources/skins/moono/images/hidpi/lock-open.png
new file mode 100644
index 0000000..594f0d3
--- /dev/null
+++ b/sources/skins/moono/images/hidpi/lock-open.png
Binary files differ
diff --git a/sources/skins/moono/images/hidpi/lock.png b/sources/skins/moono/images/hidpi/lock.png
new file mode 100644
index 0000000..1e23a0b
--- /dev/null
+++ b/sources/skins/moono/images/hidpi/lock.png
Binary files differ
diff --git a/sources/skins/moono/images/hidpi/refresh.png b/sources/skins/moono/images/hidpi/refresh.png
new file mode 100644
index 0000000..42d94a9
--- /dev/null
+++ b/sources/skins/moono/images/hidpi/refresh.png
Binary files differ
diff --git a/sources/skins/moono/images/lock-open.png b/sources/skins/moono/images/lock-open.png
new file mode 100644
index 0000000..7d24c5f
--- /dev/null
+++ b/sources/skins/moono/images/lock-open.png
Binary files differ
diff --git a/sources/skins/moono/images/lock.png b/sources/skins/moono/images/lock.png
new file mode 100644
index 0000000..8baeaa4
--- /dev/null
+++ b/sources/skins/moono/images/lock.png
Binary files differ
diff --git a/sources/skins/moono/images/refresh.png b/sources/skins/moono/images/refresh.png
new file mode 100644
index 0000000..d8106b0
--- /dev/null
+++ b/sources/skins/moono/images/refresh.png
Binary files differ
diff --git a/sources/skins/moono/images/spinner.gif b/sources/skins/moono/images/spinner.gif
new file mode 100644
index 0000000..d898d41
--- /dev/null
+++ b/sources/skins/moono/images/spinner.gif
Binary files differ
diff --git a/sources/skins/moono/mainui.css b/sources/skins/moono/mainui.css
new file mode 100644
index 0000000..6ad85ef
--- /dev/null
+++ b/sources/skins/moono/mainui.css
@@ -0,0 +1,214 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7mainui.css (part of editor.css)
8=================================
9
10This file styles the basic structure of the CKEditor user interface - the box
11that holds everything.
12
13CKEditor offers two main editing modes. The main UI blocks that compose these
14modes are:
15
16 For "Theme UI" mode, the one most generally used:
17
18 +-- .cke_chrome ----------------------+
19 |+-- .cke_inner ---------------------+|
20 || +-- .cke_top -------------------+ ||
21 || | | ||
22 || +-------------------------------+ ||
23 || +-- .cke_contents --------------+ ||
24 || | | ||
25 || +-------------------------------+ ||
26 || +-- .cke_bottom ----------------+ ||
27 || | | ||
28 || +-------------------------------+ ||
29 |+-----------------------------------+|
30 +-------------------------------------+
31
32 For "Inline Editing" mode:
33
34 +-- .cke_chrome .cke_float------------+
35 |+-- .cke_inner ---------------------+|
36 || +-- .cke_top -------------------+ ||
37 || | | ||
38 || +-------------------------------+ ||
39 |+-----------------------------------+|
40 +-------------------------------------+
41
42Special outer level classes used in this file:
43
44 .cke_hc: Available when the editor is rendered on "High Contrast".
45
46*/
47
48/* The outer boundary of the interface. */
49.cke_chrome
50{
51 /* This is <span>, so transform it into a block.*/
52 display: block;
53 border: 1px solid #b6b6b6;
54 padding: 0;
55
56 box-shadow: 0 0 3px rgba(0,0,0,.15);
57}
58
59/* The inner boundary of the interface. */
60.cke_inner
61{
62 /* This is <span>, so transform it into a block.*/
63 display: block;
64
65 -webkit-touch-callout: none;
66
67 background: #fff;
68 padding: 0;
69}
70
71/* Added to the outer boundary of the UI when in inline editing,
72 when the UI is floating. */
73.cke_float
74{
75 /* Make white the space between the outer and the inner borders. */
76 border: none;
77}
78
79.cke_float .cke_inner
80{
81 /* As we don't have blocks following top (toolbar) we suppress the padding
82 as the toolbar defines its own margin. */
83 padding-bottom: 0;
84}
85
86/* Make the main spaces enlarge to hold potentially floated content. */
87.cke_top,
88.cke_contents,
89.cke_bottom
90{
91 /* These are <span>s, so transform them into blocks.*/
92 display: block;
93
94 /* Ideally this should be "auto", but it shows scrollbars in IE7. */
95 overflow: hidden;
96}
97
98.cke_top
99{
100 /*border: 1px solid #b2b2b2;*/
101 border-bottom: 1px solid #b6b6b6;
102 padding: 6px 8px 2px;
103
104 /* Allow breaking toolbars when in a narrow editor. (#9947) */
105 white-space: normal;
106
107 box-shadow: 0 1px 0 #fff inset;
108
109 background: #cfd1cf;
110 background-image: linear-gradient(to bottom, #f5f5f5, #cfd1cf);
111 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f5f5f5', endColorstr='#cfd1cf');
112}
113
114.cke_float .cke_top
115{
116 border: 1px solid #b6b6b6;
117 border-bottom-color: #999;
118}
119
120.cke_bottom
121{
122 padding: 6px 8px 2px;
123 position: relative;
124
125 border-top: 1px solid #bfbfbf;
126
127 box-shadow: 0 1px 0 #fff inset;
128
129 background: #cfd1cf;
130 background-image: linear-gradient(to bottom, #ebebeb, #cfd1cf);
131 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ebebeb', endColorstr='#cfd1cf');
132}
133
134/* On iOS we need to manually enable scrolling in the contents block. (#9945) */
135.cke_browser_ios .cke_contents
136{
137 overflow-y: auto;
138 -webkit-overflow-scrolling: touch;
139}
140
141/* The resizer is the small UI element that is rendered at the bottom right
142 part of the editor. It makes is possible to resize the editor UI. */
143.cke_resizer
144{
145 /* To avoid using images for the resizer, we create a small triangle,
146 using some CSS magic. */
147 width: 0;
148 height: 0;
149 overflow: hidden;
150 width: 0;
151 height: 0;
152 overflow: hidden;
153 border-width: 10px 10px 0 0;
154 border-color: transparent #666 transparent transparent;
155 border-style: dashed solid dashed dashed;
156
157 font-size: 0;
158 vertical-align: bottom;
159
160 margin-top: 6px;
161
162 /* A margin in case of no other element in the same container
163 to keep a distance to the bottom edge. */
164 margin-bottom: 2px;
165
166 box-shadow: 0 1px 0 rgba(255,255,255,.3);
167}
168
169.cke_hc .cke_resizer
170{
171 font-size: 15px;
172 width: auto;
173 height: auto;
174 border-width: 0;
175}
176
177.cke_resizer_ltr
178{
179 cursor: se-resize;
180
181 float: right;
182 margin-right: -4px;
183}
184
185/* This class is added in RTL mode. This is a special case for the resizer
186 (usually the .cke_rtl class is used), because it may not necessarily be in
187 RTL mode if the main UI is RTL. It depends instead on the context where the
188 editor is inserted on. */
189.cke_resizer_rtl
190{
191 border-width: 10px 0 0 10px;
192 border-color: transparent transparent transparent #A5A5A5;
193 border-style: dashed dashed dashed solid;
194
195 cursor: sw-resize;
196
197 float: left;
198 margin-left: -4px;
199 right: auto;
200}
201
202/* The editing area (where users type) can be rendered as an editable <div>
203 element (e.g. divarea plugin). In that case, this is the class applied to
204 that element. */
205.cke_wysiwyg_div
206{
207 display: block;
208 height: 100%;
209 overflow: auto;
210 padding: 0 8px;
211 outline-style: none;
212
213 box-sizing: border-box;
214}
diff --git a/sources/skins/moono/menu.css b/sources/skins/moono/menu.css
new file mode 100644
index 0000000..0c1ab59
--- /dev/null
+++ b/sources/skins/moono/menu.css
@@ -0,0 +1,207 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7menu.css (part of editor.css)
8===============================
9
10This file styles menus used in the editor UI. These menus are the list of
11options available inside some "floating panels", like menu buttons of the
12toolbar or the context menu.
13
14Note that the menu itself doesn't include the floating element that holds it.
15That element is styles in the panel.css file.
16
17The following is a visual representation of the main elements of a menu:
18
19+-- .cke_menu -----------------+
20| +-- .cke_menuitem --------+ |
21| | +-- .cke_menubutton ---+ | |
22| | | | | |
23| | +----------------------+ | |
24| +--------------------------+ |
25| +-- .cke_menuseparator ----+ |
26| ... |
27+------------------------------+
28
29This is the .cke_menubutton structure:
30(Note that the menu button icon shares with toolbar button the common class .cke_button_icon to achieve the same outlook.)
31
32+-- .cke_menubutton -------------------------------------------------------------------------+
33| +-- .cke_menubutton_inner ---------------------------------------------------------------+ |
34| | +-- .cke_menubutton_icon ---+ +-- .cke_menubutton_label --+ +-- .cke_cke_menuarrow --+ | |
35| | | +-- .cke_button_icon ---+ | | | | | | |
36| | | | | | | | | | | |
37| | | +-----------------------+ | | | | | | |
38| | +---------------------------+ +---------------------------+ +------------------------+ | |
39| +----------------------------------------------------------------------------------------+ |
40+--------------------------------------------------------------------------------------------+
41
42Special outer level classes used in this file:
43
44 .cke_hc: Available when the editor is rendered on "High Contrast".
45 .cke_rtl: Available when the editor UI is on RTL.
46*/
47
48/* .cke_menuitem is the element that holds the entire structure of each of the
49 menu items. */
50
51.cke_menubutton
52{
53 /* The "button" inside a menu item is a <a> element.
54 Transforms it into a block. */
55 display: block;
56}
57
58.cke_menuitem span
59{
60 /* Avoid the text selection cursor inside menu items. */
61 cursor: default;
62}
63
64.cke_menubutton:hover,
65.cke_menubutton:focus,
66.cke_menubutton:active
67{
68 background-color: #D3D3D3;
69 display: block;
70}
71
72.cke_hc .cke_menubutton
73{
74 padding: 2px;
75}
76
77.cke_hc .cke_menubutton:hover,
78.cke_hc .cke_menubutton:focus,
79.cke_hc .cke_menubutton:active
80{
81 border: 2px solid;
82 padding: 0;
83}
84
85.cke_menubutton_inner {
86 display: table-row;
87}
88
89.cke_menubutton_icon,
90.cke_menubutton_label,
91.cke_menuarrow {
92 display: table-cell;
93}
94
95/* The menu item icon. */
96.cke_menubutton_icon
97{
98 background-color: #D7D8D7;
99 opacity: 0.70; /* Safari, Opera and Mozilla */
100 filter: alpha(opacity=70); /* IE */
101 padding: 4px;
102}
103
104.cke_hc .cke_menubutton_icon
105{
106 height: 16px;
107 width: 0;
108 padding: 4px 0;
109}
110
111.cke_menubutton:hover .cke_menubutton_icon,
112.cke_menubutton:focus .cke_menubutton_icon,
113.cke_menubutton:active .cke_menubutton_icon
114{
115 background-color: #D0D2D0;
116}
117
118.cke_menubutton_disabled:hover .cke_menubutton_icon,
119.cke_menubutton_disabled:focus .cke_menubutton_icon,
120.cke_menubutton_disabled:active .cke_menubutton_icon
121{
122 /* The icon will get opacity as well when hovered. */
123 opacity: 0.3;
124 filter: alpha(opacity=30);
125}
126
127/* The textual part of each menu item. */
128.cke_menubutton_label
129{
130 padding: 0 5px;
131 background-color: transparent;
132 width: 100%;
133 vertical-align: middle;
134}
135
136/* Keyboard shortcut placed next to the label. */
137.cke_menubutton_shortcut
138{
139 color: #979797;
140}
141
142.cke_menubutton_disabled .cke_menubutton_label
143{
144 /* Greyed label text indicates a disabled menu item. */
145 opacity: 0.3;
146 filter: alpha(opacity=30);
147}
148
149.cke_menubutton_on
150{
151 border: 1px solid #dedede;
152 background-color: #f2f2f2;
153
154 box-shadow: 0 0 2px rgba(0,0,0,.1) inset;
155}
156
157.cke_menubutton_on .cke_menubutton_icon
158{
159 padding-right: 3px;
160}
161
162.cke_menubutton:hover,
163.cke_menubutton:focus,
164.cke_menubutton:active
165{
166 background-color: #EFF0EF;
167}
168
169.cke_panel_frame .cke_menubutton_label
170{
171 display: none;
172}
173
174/* The separator used to separate menu item groups. */
175.cke_menuseparator
176{
177 background-color: #D3D3D3;
178 height: 1px;
179 filter: alpha(opacity=70); /* IE */
180 opacity: 0.70; /* Safari, Opera and Mozilla */
181}
182
183/* The small arrow shown for item with sub-menus. */
184.cke_menuarrow
185{
186 background-image: url(images/arrow.png);
187 background-position: 0 10px;
188 background-repeat: no-repeat;
189 padding: 0 5px;
190}
191
192.cke_rtl .cke_menuarrow
193{
194 background-position: 5px -13px;
195 background-repeat: no-repeat;
196}
197
198.cke_menuarrow span
199{
200 display: none;
201}
202
203.cke_hc .cke_menuarrow span
204{
205 vertical-align: middle;
206 display: inline;
207}
diff --git a/sources/skins/moono/notification.css b/sources/skins/moono/notification.css
new file mode 100644
index 0000000..659fef7
--- /dev/null
+++ b/sources/skins/moono/notification.css
@@ -0,0 +1,168 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/**
7 * Progress notification structure:
8 *
9 * +---div.cke_notification cke_notification_info--------------------------+
10 * | |
11 * | +---div.cke_notification_progress-----------------------------------+ |
12 * | | | |
13 * | +-------------------------------------------------------------------+ |
14 * | |
15 * | +---p.cke_notification_message--------------------------------------+ |
16 * | | Foo | |
17 * | +-------------------------------------------------------------------+ |
18 * | |
19 * | +---a.cke_notification_close----------------------------------------+ |
20 * | | +---span.cke_label----------------------------------------------+ | |
21 * | | | X | | |
22 * | | +---------------------------------------------------------------+ | |
23 * | +-------------------------------------------------------------------+ |
24 * | |
25 * +-----------------------------------------------------------------------+
26 *
27 *
28 * Warning notification structure:
29 *
30 * +---div.cke_notification cke_notification_warning-----------------------+
31 * | |
32 * | +---p.cke_notification_message--------------------------------------+ |
33 * | | Foo | |
34 * | +-------------------------------------------------------------------+ |
35 * | |
36 * | +---a.cke_notification_close----------------------------------------+ |
37 * | | +---span.cke_label----------------------------------------------+ | |
38 * | | | X | | |
39 * | | +---------------------------------------------------------------+ | |
40 * | +-------------------------------------------------------------------+ |
41 * | |
42 * +-----------------------------------------------------------------------+
43 *
44 * Success and info notifications have the same structure as warning, but use
45 * `cke_notification_success` and `cke_notification_info` instead of `cke_notification_warning`.
46 */
47.cke_notifications_area
48{
49 /* Prevent notification margin capture clicking. */
50 pointer-events: none;
51}
52.cke_notification
53{
54 pointer-events: auto;
55 position: relative;
56 margin: 10px;
57 width: 300px;
58 color: white;
59 border-radius: 3px;
60 text-align: center;
61 opacity: 0.95;
62 filter: alpha(opacity = 95);
63 box-shadow: 2px 2px 3px 0px rgba(50, 50, 50, 0.3);
64
65 -webkit-animation: fadeIn 0.7s;
66 animation: fadeIn 0.7s;
67}
68
69.cke_notification_message a
70{
71 color: #12306F;
72}
73
74@-webkit-keyframes fadeIn
75{
76 from { opacity: 0.4; }
77 to { opacity: 0.95; }
78}
79
80@keyframes fadeIn
81{
82 from { opacity: 0.4; }
83 to { opacity: 0.95; }
84}
85
86.cke_notification_success
87{
88 background: #72B572;
89 border: 1px solid #63A563;
90}
91
92.cke_notification_warning
93{
94 background: #C83939;
95 border: 1px solid #902B2B;
96}
97
98.cke_notification_info
99{
100 background: #2E9AD0;
101 border: 1px solid #0F74A8;
102}
103
104.cke_notification_info span.cke_notification_progress
105{
106 background-color: #0F74A8;
107 display: block;
108 padding: 0;
109 margin: 0;
110 height: 100%;
111 overflow: hidden;
112 position: absolute;
113 z-index: 1;
114}
115
116.cke_notification_message
117{
118 position: relative;
119 margin: 4px 23px 3px;
120 font-family: Arial, Helvetica, sans-serif;
121 font-size: 12px;
122 line-height: 18px;
123 z-index: 4;
124 text-overflow: ellipsis;
125 overflow: hidden;
126}
127
128.cke_notification_close
129{
130 background-image: url(images/close.png);
131 background-repeat: no-repeat;
132 background-position: 50%;
133 position: absolute;
134 cursor: pointer;
135 text-align: center;
136 height: 20px;
137 width: 20px;
138 top: 1px;
139 right: 1px;
140 padding: 0;
141 margin: 0;
142 z-index: 5;
143 opacity: 0.6;
144 filter: alpha(opacity = 60);
145}
146
147.cke_notification_close:hover
148{
149 opacity: 1;
150 filter: alpha(opacity = 100);
151}
152
153.cke_notification_close span
154{
155 display: none;
156}
157
158.cke_notification_warning a.cke_notification_close
159{
160 opacity: 0.8;
161 filter: alpha(opacity = 80);
162}
163
164.cke_notification_warning a.cke_notification_close:hover
165{
166 opacity: 1;
167 filter: alpha(opacity = 100);
168}
diff --git a/sources/skins/moono/panel.css b/sources/skins/moono/panel.css
new file mode 100644
index 0000000..b1f457f
--- /dev/null
+++ b/sources/skins/moono/panel.css
@@ -0,0 +1,237 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7panel.css (part of editor.css)
8================================
9
10Panels are floating elements that can hold different types of contents.
11The following are common uses of it:
12
13 - The element that toolbar combos display when opening them.
14 - The context menu.
15 - The list of items displayed by "menu buttons" (e.g. scayt).
16 - The panel shown when opening "panel buttons" (e.g. color buttons).
17
18Panel contents are wrapped into an iframe, so it is possible to have additional
19CSS loaded inside them (e.g. to have more accurate preview on the styles combo).
20
21The following is a visual representation of the outer elements of a panel:
22
23+-- .cke_panel(*) ---------------------+
24| +-- IFRAME.cke_panel_frame --------+ |
25| | +-- HTML.cke_panel_container --+ | |
26| | | +-- .cke_panel_block ------+ | | |
27| | | | | | | |
28| | | | (contents here) | | | |
29| | | | | | | |
30| | | +--------------------------+ | | |
31| | +------------------------------+ | |
32| +----------------------------------+ |
33+--------------------------------------+
34
35(*) All kinds of panel share the above structure. Menu panels adds the
36 .cke_menu_panel class to the outer element, while toolbar combos add the
37 .cke_combopanel class.
38
39This file also defines styles for panel lists (used by combos). For menu-like
40panel contents and color panels check menu.css and colorpanel.css.
41*/
42
43/* The box that holds an IFRAME. It's inserted into a host document and positioned
44 absolutely by the application. It floats above the host document/editor. */
45.cke_panel
46{
47 /* Restore the loading hide */
48 visibility: visible;
49 width: 120px;
50 height: 100px;
51 overflow: hidden;
52
53 background-color: #fff;
54 border: 1px solid #b6b6b6;
55 border-bottom-color: #999;
56
57 border-radius: 3px;
58
59 box-shadow: 0 0 3px rgba(0,0,0,.15);
60}
61
62/* This class represents panels which are used as context menus. */
63.cke_menu_panel
64{
65 padding: 0;
66 margin: 0;
67}
68
69/* This class represents panels which are used by rich combos. */
70.cke_combopanel
71{
72 width: 150px;
73 height: 170px;
74}
75
76/* The IFRAME the panel is wrapped into. */
77.cke_panel_frame
78{
79 width: 100%;
80 height: 100%;
81 font-size: 12px;
82
83 overflow: auto;
84 overflow-x: hidden;
85}
86
87/* The HTML document which is a direct descendant of the IFRAME */
88.cke_panel_container
89{
90 overflow-y: auto;
91 overflow-x: hidden;
92}
93
94/*
95Here we start the definition of panel lists (e.g. combo panels). The following
96is its visual representation:
97
98+-- .cke_panel_block -----------------+
99| +-- .cke_panel_grouptitle --------+ |
100| | | |
101| +---------------------------------+ |
102| +-- .cke_panel_list --------------+ |
103| | +-- .cke_panel_listItem ------+ | |
104| | | +-- a --------------------+ | | |
105| | | | +-- span -------------+ | | | |
106| | | | | | | | | |
107| | | | +---------------------+ | | | |
108| | | +-------------------------+ | | |
109| | +-----------------------------+ | |
110| | +-- .cke_panel_listItem ------+ | |
111| | | +-- a --------------------+ | | |
112| | | | +-- span -------------+ | | | |
113| | | | | | | | | |
114| | | | +---------------------+ | | | |
115| | | +-------------------------+ | | |
116| | +-----------------------------+ | |
117| | ... | |
118| +---------------------------------+ |
119+-------------------------------------+
120*/
121
122
123/* The list of panel items. */
124.cke_panel_list
125{
126 list-style-type: none;
127 margin: 3px;
128 padding: 0;
129 white-space: nowrap;
130}
131
132/* The item of .cke_panel_list */
133.cke_panel_listItem
134{
135 margin: 0;
136 padding-bottom: 1px;
137}
138
139/* The child of .cke_panel_listItem. These elements contain spans which are
140 to display a real name of the property which is visible for an end-user. */
141.cke_panel_listItem a
142{
143 padding: 3px 4px;
144 display: block;
145 border: 1px solid #fff;
146 color: inherit !important;
147 text-decoration: none;
148 overflow: hidden;
149 text-overflow: ellipsis;
150
151 border-radius: 2px;
152}
153
154/* IE6 */
155* html .cke_panel_listItem a
156{
157 width : 100%;
158
159 /* IE is not able to inherit the color, so we must force it to black */
160 color: #000;
161}
162
163/* IE7 */
164*:first-child+html .cke_panel_listItem a
165{
166 /* IE is not able to inherit the color, so we must force it to black */
167 color: #000;
168}
169
170.cke_panel_listItem.cke_selected a
171{
172 border: 1px solid #dedede;
173 background-color: #f2f2f2;
174
175 box-shadow: 0 0 2px rgba(0,0,0,.1) inset;
176}
177
178.cke_panel_listItem a:hover,
179.cke_panel_listItem a:focus,
180.cke_panel_listItem a:active
181{
182 border-color: #dedede;
183 background-color: #f2f2f2;
184
185 box-shadow: 0 0 2px rgba(0,0,0,.1) inset;
186}
187
188.cke_hc .cke_panel_listItem a
189{
190 border-style: none;
191}
192
193.cke_hc .cke_panel_listItem a:hover,
194.cke_hc .cke_panel_listItem a:focus,
195.cke_hc .cke_panel_listItem a:active
196{
197 border: 2px solid;
198 padding: 1px 2px;
199}
200
201/* The title of the entire panel which is visible on top of the list. */
202.cke_panel_grouptitle
203{
204 cursor: default;
205 font-size: 11px;
206 font-weight: bold;
207 white-space: nowrap;
208 margin: 0;
209 padding: 4px 6px;
210
211 color: #474747;
212 text-shadow: 0 1px 0 rgba(255,255,255,.75);
213 border-bottom: 1px solid #b6b6b6;
214
215 border-radius: 2px 2px 0 0;
216
217 box-shadow: 0 1px 0 #fff inset;
218
219 background: #cfd1cf;
220 background-image: linear-gradient(to bottom, #f5f5f5, #cfd1cf);
221 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f5f5f5', endColorstr='#cfd1cf');
222}
223
224/* The following styles set defaults of the elements used by the Paragraph
225 Format panel. */
226.cke_panel_listItem p,
227.cke_panel_listItem h1,
228.cke_panel_listItem h2,
229.cke_panel_listItem h3,
230.cke_panel_listItem h4,
231.cke_panel_listItem h5,
232.cke_panel_listItem h6,
233.cke_panel_listItem pre
234{
235 margin-top: 0px;
236 margin-bottom: 0px;
237}
diff --git a/sources/skins/moono/presets.css b/sources/skins/moono/presets.css
new file mode 100644
index 0000000..2d06deb
--- /dev/null
+++ b/sources/skins/moono/presets.css
@@ -0,0 +1,41 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/* "Source" button label */
7.cke_button__source_label,
8.cke_button__sourcedialog_label
9{
10 display: inline;
11}
12
13/* "Font Size" combo width */
14.cke_combo__fontsize .cke_combo_text
15{
16 width: 30px;
17}
18
19/* "Font Size" panel size */
20.cke_combopanel__fontsize
21{
22 width: 120px;
23}
24
25/* Editable regions */
26textarea.cke_source
27{
28 font-family: 'Courier New', Monospace;
29 font-size: small;
30 background-color: #fff;
31 white-space: pre-wrap;
32 border: none;
33 padding: 0;
34 margin: 0;
35 display: block;
36}
37
38.cke_wysiwyg_frame, .cke_wysiwyg_div
39{
40 background-color: #fff;
41}
diff --git a/sources/skins/moono/readme.md b/sources/skins/moono/readme.md
new file mode 100644
index 0000000..4a4ed6b
--- /dev/null
+++ b/sources/skins/moono/readme.md
@@ -0,0 +1,49 @@
1"Moono" Skin
2====================
3
4This skin has been chosen for the **default skin** of CKEditor 4.x (replaced by "Moono-lisa" skin since CKEditor 4.6.0),
5elected from the CKEditor [skin contest](http://ckeditor.com/blog/new_ckeditor_4_skin) and further shaped by
6the CKEditor team. "Moono" is maintained by the core developers.
7
8For more information about skins, please check the [CKEditor Skin SDK](http://docs.cksource.com/CKEditor_4.x/Skin_SDK)
9documentation.
10
11Features
12-------------------
13"Moono" is a monochromatic skin, which offers a modern look coupled with gradients and transparency.
14It comes with the following features:
15
16- Chameleon feature with brightness,
17- high-contrast compatibility,
18- graphics source provided in SVG.
19
20Directory Structure
21-------------------
22
23CSS parts:
24- **editor.css**: the main CSS file. It's simply loading several other files, for easier maintenance,
25- **mainui.css**: the file contains styles of entire editor outline structures,
26- **toolbar.css**: the file contains styles of the editor toolbar space (top),
27- **richcombo.css**: the file contains styles of the rich combo ui elements on toolbar,
28- **panel.css**: the file contains styles of the rich combo drop-down, it's not loaded
29until the first panel open up,
30- **elementspath.css**: the file contains styles of the editor elements path bar (bottom),
31- **menu.css**: the file contains styles of all editor menus including context menu and button drop-down,
32it's not loaded until the first menu open up,
33- **dialog.css**: the CSS files for the dialog UI, it's not loaded until the first dialog open,
34- **reset.css**: the file defines the basis of style resets among all editor UI spaces,
35- **preset.css**: the file defines the default styles of some UI elements reflecting the skin preference,
36- **editor_XYZ.css** and **dialog_XYZ.css**: browser specific CSS hacks.
37
38Other parts:
39- **skin.js**: the only JavaScript part of the skin that registers the skin, its browser specific files and its icons and defines the Chameleon feature,
40- **icons/**: contains all skin defined icons,
41- **images/**: contains a fill general used images,
42- **dev/**: contains SVG source of the skin icons.
43
44License
45-------
46
47Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
48
49For licensing, see LICENSE.md or [http://ckeditor.com/license](http://ckeditor.com/license)
diff --git a/sources/skins/moono/reset.css b/sources/skins/moono/reset.css
new file mode 100644
index 0000000..d64bf82
--- /dev/null
+++ b/sources/skins/moono/reset.css
@@ -0,0 +1,115 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7reset.css (part of editor.css)
8================================
9
10This file holds the "reset" requirements of CKEditor, as well as define the
11default interface styles.
12
13CKEditor includes two main "reset" class names in the DOM structure created for
14editors:
15
16 * .cke_reset: Intended to reset a specific element, but not its children.
17 Because of this, only styles that will not be inherited can be defined.
18
19 * .cke_reset_all: Intended to reset not only the element holding it, but
20 also its child elements.
21
22To understand why "reset" is needed, check the CKEditor Skin SDK:
23http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Reset
24*/
25
26/* Reset for single elements, not their children. */
27.cke_reset
28{
29 /* Do not include inheritable rules here. */
30 margin: 0;
31 padding: 0;
32 border: 0;
33 background: transparent;
34 text-decoration: none;
35 width: auto;
36 height: auto;
37 vertical-align: baseline;
38 box-sizing: content-box;
39 position: static;
40 transition: none;
41}
42
43/* Reset for elements and their children. */
44.cke_reset_all, .cke_reset_all *,
45.cke_reset_all a, .cke_reset_all textarea
46{
47 /* The following must be identical to .cke_reset. */
48 margin: 0;
49 padding: 0;
50 border: 0;
51 background: transparent;
52 text-decoration: none;
53 width: auto;
54 height: auto;
55 vertical-align: baseline;
56 box-sizing: content-box;
57 position: static;
58 transition: none;
59
60 /* These are rule inherited by all children elements. */
61 border-collapse: collapse;
62 font: normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;
63 color: #000;
64 text-align: left;
65 white-space: nowrap;
66 cursor: auto;
67 float: none;
68}
69
70.cke_reset_all .cke_rtl *
71{
72 text-align: right;
73}
74
75/* Defaults for some elements. */
76
77.cke_reset_all iframe
78{
79 vertical-align: inherit; /** For IE */
80}
81
82.cke_reset_all textarea
83{
84 white-space: pre-wrap;
85}
86
87.cke_reset_all textarea,
88.cke_reset_all input[type="text"],
89.cke_reset_all input[type="password"]
90{
91 cursor: text;
92}
93
94.cke_reset_all textarea[disabled],
95.cke_reset_all input[type="text"][disabled],
96.cke_reset_all input[type="password"][disabled]
97{
98 cursor: default;
99}
100
101.cke_reset_all fieldset
102{
103 padding: 10px;
104 border: 2px groove #E0DFE3;
105}
106
107.cke_reset_all select
108{
109 box-sizing: border-box;
110}
111
112.cke_reset_all table
113{
114 table-layout: auto;
115}
diff --git a/sources/skins/moono/richcombo.css b/sources/skins/moono/richcombo.css
new file mode 100644
index 0000000..7897a66
--- /dev/null
+++ b/sources/skins/moono/richcombo.css
@@ -0,0 +1,210 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7richcombo.css (part of editor.css)
8=================================
9
10This file holds the style set of the "Rich Combo" widget which is commonly used
11in the toolbar. It doesn't, however, styles the panel that is displayed when
12clicking on the combo, which is instead styled by panel.css.
13
14The visual representation of a rich combo widget looks as follows:
15
16+-- .cke_combo----------------------------------------------------------------------+
17| +-- .cke_combo_label --+ +-- .cke_combo_button ---------------------------------+ |
18| | | | +-- .cke_combo_text --+ +-- .cke_combo_open -------+ | |
19| | | | | | | +-- .cke_combo_arrow --+ | | |
20| | | | | | | | | | | |
21| | | | | | | +----------------------+ | | |
22| | | | +---------------------+ +--------------------------+ | |
23| +----------------------+ +------------------------------------------------------+ |
24+-----------------------------------------------------------------------------------+
25*/
26
27/* The box that hold the entire combo widget */
28.cke_combo
29{
30 display: inline-block;
31 float: left;
32}
33
34.cke_rtl .cke_combo
35{
36 float: right;
37}
38
39.cke_hc .cke_combo
40{
41 margin-top: -2px;
42}
43
44/* The label of the combo widget. It is invisible by default, yet
45 it's important for semantics and accessibility. */
46.cke_combo_label
47{
48 display: none;
49 float: left;
50 line-height: 26px;
51 vertical-align: top;
52 margin-right: 5px;
53}
54
55.cke_rtl .cke_combo_label
56{
57 float: right;
58 margin-left: 5px;
59 margin-right: 0;
60}
61
62/* The container for combo text and arrow. */
63a.cke_combo_button
64{
65 cursor: default;
66 display: inline-block;
67 float: left;
68 margin: 0 6px 5px 0;
69
70 border: 1px solid #a6a6a6;
71 border-bottom-color: #979797;
72
73 border-radius: 3px;
74
75 box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 0 2px rgba(255,255,255,.15) inset, 0 1px 0 rgba(255,255,255,.15) inset;
76
77 background: #e4e4e4;
78 background-image: linear-gradient(to bottom, #ffffff, #e4e4e4);
79 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ffffff', endColorstr='#e4e4e4');
80}
81
82/* Different states of the container. */
83.cke_combo_off a.cke_combo_button:hover,
84.cke_combo_off a.cke_combo_button:focus
85{
86 background: #ccc;
87 background-image: linear-gradient(to bottom, #f2f2f2, #ccc);
88 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f2f2f2', endColorstr='#cccccc');
89
90 outline: none;
91}
92
93.cke_combo_off a.cke_combo_button:active,
94.cke_combo_on a.cke_combo_button
95{
96 border: 1px solid #777;
97
98 box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 1px 5px rgba(0,0,0,.6) inset;
99
100 background: #b5b5b5;
101 background-image: linear-gradient(to bottom, #aaa, #cacaca);
102 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#aaaaaa', endColorstr='#cacaca');
103}
104
105.cke_combo_on a.cke_combo_button:hover,
106.cke_combo_on a.cke_combo_button:focus,
107.cke_combo_on a.cke_combo_button:active
108{
109 box-shadow: 0 1px 6px rgba(0,0,0,.7) inset, 0 1px 0 rgba(0,0,0,.2);
110}
111
112.cke_rtl .cke_combo_button
113{
114 float: right;
115 margin-left: 5px;
116 margin-right: 0;
117}
118
119.cke_hc a.cke_combo_button
120{
121 padding: 3px;
122}
123
124.cke_hc .cke_combo_on a.cke_combo_button,
125.cke_hc .cke_combo_off a.cke_combo_button:hover,
126.cke_hc .cke_combo_off a.cke_combo_button:focus,
127.cke_hc .cke_combo_off a.cke_combo_button:active
128{
129 border-width: 3px;
130 padding: 1px;
131}
132
133/* The label that shows the current value of the rich combo.
134 By default, it holds the name of the property.
135 See: .cke_combo_inlinelabel */
136.cke_combo_text
137{
138 line-height: 26px;
139 padding-left: 10px;
140 text-overflow: ellipsis;
141 overflow: hidden;
142 float: left;
143 cursor: default;
144 color: #474747;
145 text-shadow: 0 1px 0 rgba(255,255,255,.5);
146 width: 60px;
147}
148
149.cke_rtl .cke_combo_text
150{
151 float: right;
152 text-align: right;
153 padding-left: 0;
154 padding-right: 10px;
155}
156
157.cke_hc .cke_combo_text
158{
159 line-height: 18px;
160 font-size: 12px;
161}
162
163/* The handler which opens the panel of rich combo properties.
164 It holds an arrow as a visual indicator. */
165.cke_combo_open
166{
167 cursor: default;
168 display: inline-block;
169 font-size: 0;
170 height: 19px;
171 line-height: 17px;
172 margin: 1px 7px 1px;
173 width: 5px;
174}
175
176.cke_hc .cke_combo_open
177{
178 height: 12px;
179}
180
181/* The arrow which is displayed inside of the .cke_combo_open handler. */
182.cke_combo_arrow
183{
184 cursor: default;
185 margin: 11px 0 0;
186 float: left;
187
188 /* Pure CSS Arrow */
189 height: 0;
190 width: 0;
191 font-size: 0;
192 border-left: 3px solid transparent;
193 border-right: 3px solid transparent;
194 border-top: 3px solid #474747;
195}
196
197.cke_hc .cke_combo_arrow
198{
199 font-size: 10px;
200 width: auto;
201 border: 0;
202 margin-top: 3px;
203}
204
205/* Disabled combo button styles. */
206.cke_combo_disabled .cke_combo_inlinelabel,
207.cke_combo_disabled .cke_combo_open
208{
209 opacity: 0.3;
210}
diff --git a/sources/skins/moono/skin.js b/sources/skins/moono/skin.js
new file mode 100644
index 0000000..420b22e
--- /dev/null
+++ b/sources/skins/moono/skin.js
@@ -0,0 +1,316 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/*
7skin.js
8=========
9
10In this file we interact with the CKEditor JavaScript API to register the skin
11and enable additional skin related features.
12
13The level of complexity of this file depends on the features available in the
14skin. There is only one mandatory line of code to be included here, which is
15setting CKEDITOR.skin.name. All the rest is optional, but recommended to be
16implemented as they make higher quality skins.
17
18For this skin, the following tasks are achieved in this file:
19
20 1. Register the skin.
21 2. Register browser specific skin files.
22 3. Define the "Chameleon" feature.
23 4. Register the skin icons, to have them used on the development version of
24 the skin.
25*/
26
27// 1. Register the skin
28// ----------------------
29// The CKEDITOR.skin.name property must be set to the skin name. This is a
30// lower-cased name, which must match the skin folder name as well as the value
31// used on config.skin to tell the editor to use the skin.
32//
33// This is the only mandatory property to be defined in this file.
34CKEDITOR.skin.name = 'moono';
35
36// 2. Register browser specific skin files
37// -----------------------------------------
38// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Browser_Hacks)
39//
40// To help implementing browser specific "hacks" to the skin files and have it
41// easy to maintain, it is possible to have dedicated files for such browsers,
42// for both the main skin CSS files: editor.css and dialog.css.
43//
44// The browser files must be named after the main file names, appended by an
45// underscore and the browser name (e.g. editor_ie.css, dialog_ie8.css).
46//
47// The accepted browser names must match the CKEDITOR.env properties. The most
48// common names are: ie, webkit and gecko. Check the documentation for the complete
49// list:
50// http://docs.ckeditor.com/#!/api/CKEDITOR.env
51//
52// Internet explorer is an expection and the browser version is also accepted
53// (ie7, ie8, ie9, ie10), as well as a special name for IE in Quirks mode (iequirks).
54//
55// The available browser specific files must be set separately for editor.css
56// and dialog.css.
57CKEDITOR.skin.ua_editor = 'ie,iequirks,ie7,ie8,gecko';
58CKEDITOR.skin.ua_dialog = 'ie,iequirks,ie7,ie8';
59
60// 3. Define the "Chameleon" feature
61// -----------------------------------
62// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Chameleon)
63//
64// "Chameleon" is a unique feature available in CKEditor. It makes it possible
65// to end users to specify which color to use as the basis for the editor UI.
66// It is enough to set config.uiColor to any color value and voila, the UI is
67// colored.
68//
69// The only detail here is that the skin itself must be compatible with the
70// Chameleon feature. That's because the skin CSS files are the responsible to
71// apply colors in the UI and each skin do that in different way and on
72// different places.
73//
74// Implementing the Chameleon feature requires a bit of JavaScript programming.
75// The CKEDITOR.skin.chameleon function must be defined. It must return the CSS
76// "template" to be used to change the color of a specific CKEditor instance
77// available in the page. When a color change is required, this template is
78// appended to the page holding the editor, overriding styles defined in the
79// skin files.
80//
81// The "$color" placeholder can be used in the returned string. It'll be
82// replaced with the desired color.
83CKEDITOR.skin.chameleon = ( function() {
84 // This method can be used to adjust colour brightness of various element.
85 // Colours are accepted in 7-byte hex format, for example: #00ff00.
86 // Brightness ratio must be a float number within [-1, 1],
87 // where -1 is black, 1 is white and 0 is the original colour.
88 var colorBrightness = ( function() {
89 function channelBrightness( channel, ratio ) {
90 var brighten = ratio < 0 ? (
91 0 | channel * ( 1 + ratio )
92 ) : (
93 0 | channel + ( 255 - channel ) * ratio
94 );
95
96 return ( '0' + brighten.toString( 16 ) ).slice( -2 );
97 }
98
99 return function( hexColor, ratio ) {
100 var channels = hexColor.match( /[^#]./g );
101
102 for ( var i = 0 ; i < 3 ; i++ )
103 channels[ i ] = channelBrightness( parseInt( channels[ i ], 16 ), ratio );
104
105 return '#' + channels.join( '' );
106 };
107 } )(),
108
109 // Use this function just to avoid having to repeat all these rules on
110 // several places of our template.
111 verticalGradient = ( function() {
112 var template = new CKEDITOR.template( 'background:#{to};' +
113 'background-image:linear-gradient(to bottom,{from},{to});' +
114 'filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr=\'{from}\',endColorstr=\'{to}\');' );
115
116 return function( from, to ) {
117 return template.output( { from: from, to: to } );
118 };
119 } )(),
120
121 // Style templates for various user interface parts:
122 // * Default editor template.
123 // * Default panel template.
124 templates = {
125 editor: new CKEDITOR.template(
126 '{id}.cke_chrome [border-color:{defaultBorder};] ' +
127 '{id} .cke_top [ ' +
128 '{defaultGradient}' +
129 'border-bottom-color:{defaultBorder};' +
130 '] ' +
131 '{id} .cke_bottom [' +
132 '{defaultGradient}' +
133 'border-top-color:{defaultBorder};' +
134 '] ' +
135 '{id} .cke_resizer [border-right-color:{ckeResizer}] ' +
136
137 // Dialogs.
138 '{id} .cke_dialog_title [' +
139 '{defaultGradient}' +
140 'border-bottom-color:{defaultBorder};' +
141 '] ' +
142 '{id} .cke_dialog_footer [' +
143 '{defaultGradient}' +
144 'outline-color:{defaultBorder};' +
145 'border-top-color:{defaultBorder};' + // IE7 doesn't use outline.
146 '] ' +
147 '{id} .cke_dialog_tab [' +
148 '{lightGradient}' +
149 'border-color:{defaultBorder};' +
150 '] ' +
151 '{id} .cke_dialog_tab:hover [' +
152 '{mediumGradient}' +
153 '] ' +
154 '{id} .cke_dialog_contents [' +
155 'border-top-color:{defaultBorder};' +
156 '] ' +
157 '{id} .cke_dialog_tab_selected, {id} .cke_dialog_tab_selected:hover [' +
158 'background:{dialogTabSelected};' +
159 'border-bottom-color:{dialogTabSelectedBorder};' +
160 '] ' +
161 '{id} .cke_dialog_body [' +
162 'background:{dialogBody};' +
163 'border-color:{defaultBorder};' +
164 '] ' +
165
166 // Toolbars, buttons.
167 '{id} .cke_toolgroup [' +
168 '{lightGradient}' +
169 'border-color:{defaultBorder};' +
170 '] ' +
171 '{id} a.cke_button_off:hover, {id} a.cke_button_off:focus, {id} a.cke_button_off:active [' +
172 '{mediumGradient}' +
173 '] ' +
174 '{id} .cke_button_on [' +
175 '{ckeButtonOn}' +
176 '] ' +
177 '{id} .cke_toolbar_separator [' +
178 'background-color: {ckeToolbarSeparator};' +
179 '] ' +
180
181 // Combo buttons.
182 '{id} .cke_combo_button [' +
183 'border-color:{defaultBorder};' +
184 '{lightGradient}' +
185 '] ' +
186 '{id} a.cke_combo_button:hover, {id} a.cke_combo_button:focus, {id} .cke_combo_on a.cke_combo_button [' +
187 'border-color:{defaultBorder};' +
188 '{mediumGradient}' +
189 '] ' +
190
191 // Elementspath.
192 '{id} .cke_path_item [' +
193 'color:{elementsPathColor};' +
194 '] ' +
195 '{id} a.cke_path_item:hover, {id} a.cke_path_item:focus, {id} a.cke_path_item:active [' +
196 'background-color:{elementsPathBg};' +
197 '] ' +
198
199 '{id}.cke_panel [' +
200 'border-color:{defaultBorder};' +
201 '] '
202 ),
203 panel: new CKEDITOR.template(
204 // Panel drop-downs.
205 '.cke_panel_grouptitle [' +
206 '{lightGradient}' +
207 'border-color:{defaultBorder};' +
208 '] ' +
209
210 // Context menus.
211 '.cke_menubutton_icon [' +
212 'background-color:{menubuttonIcon};' +
213 '] ' +
214 '.cke_menubutton:hover .cke_menubutton_icon, .cke_menubutton:focus .cke_menubutton_icon, .cke_menubutton:active .cke_menubutton_icon [' +
215 'background-color:{menubuttonIconHover};' +
216 '] ' +
217 '.cke_menuseparator [' +
218 'background-color:{menubuttonIcon};' +
219 '] ' +
220
221 // Color boxes.
222 'a:hover.cke_colorbox, a:focus.cke_colorbox, a:active.cke_colorbox [' +
223 'border-color:{defaultBorder};' +
224 '] ' +
225 'a:hover.cke_colorauto, a:hover.cke_colormore, a:focus.cke_colorauto, a:focus.cke_colormore, a:active.cke_colorauto, a:active.cke_colormore [' +
226 'background-color:{ckeColorauto};' +
227 'border-color:{defaultBorder};' +
228 '] '
229 )
230 };
231
232 return function( editor, part ) {
233 var uiColor = editor.uiColor,
234 // The following are CSS styles used in templates.
235 // Styles are generated according to current editor.uiColor.
236 templateStyles = {
237 // CKEditor instances have a unique ID, which is used as class name into
238 // the outer container of the editor UI (e.g. ".cke_1").
239 //
240 // The Chameleon feature is available for each CKEditor instance,
241 // independently. Because of this, we need to prefix all CSS selectors with
242 // the unique class name of the instance.
243 id: '.' + editor.id,
244
245 // These styles are used by various UI elements.
246 defaultBorder: colorBrightness( uiColor, -0.1 ),
247 defaultGradient: verticalGradient( colorBrightness( uiColor, 0.9 ), uiColor ),
248 lightGradient: verticalGradient( colorBrightness( uiColor, 1 ), colorBrightness( uiColor, 0.7 ) ),
249 mediumGradient: verticalGradient( colorBrightness( uiColor, 0.8 ), colorBrightness( uiColor, 0.5 ) ),
250
251 // These are for specific UI elements.
252 ckeButtonOn: verticalGradient( colorBrightness( uiColor, 0.6 ), colorBrightness( uiColor, 0.7 ) ),
253 ckeResizer: colorBrightness( uiColor, -0.4 ),
254 ckeToolbarSeparator: colorBrightness( uiColor, 0.5 ),
255 ckeColorauto: colorBrightness( uiColor, 0.8 ),
256 dialogBody: colorBrightness( uiColor, 0.7 ),
257 // Use gradient instead of simple hex to avoid further filter resetting in IE.
258 dialogTabSelected: verticalGradient( '#FFFFFF', '#FFFFFF' ),
259 dialogTabSelectedBorder: '#FFF',
260 elementsPathColor: colorBrightness( uiColor, -0.6 ),
261 elementsPathBg: uiColor,
262 menubuttonIcon: colorBrightness( uiColor, 0.5 ),
263 menubuttonIconHover: colorBrightness( uiColor, 0.3 )
264 };
265
266 return templates[ part ]
267 .output( templateStyles )
268 .replace( /\[/g, '{' ) // Replace brackets with braces.
269 .replace( /\]/g, '}' );
270 };
271} )();
272
273// %REMOVE_START%
274
275// 4. Register the skin icons for development purposes only
276// ----------------------------------------------------------
277// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Icons)
278//
279// This code is here just to make the skin work fully when using its "source"
280// version. Without this, the skin will still work, but its icons will not be
281// used (again, on source version only).
282//
283// This block of code is not necessary on the release version of the skin.
284// Because of this it is very important to include it inside the REMOVE_START
285// and REMOVE_END comment markers, so the skin builder will properly clean
286// things up.
287//
288// If a required icon is not available here, the plugin defined icon will be
289// used instead. This means that a skin is not required to provide all icons.
290// Actually, it is not required to provide icons at all.
291
292( function() {
293 // The available icons. This list must match the file names (without
294 // extension) available inside the "icons" folder.
295 var icons = ( 'about,anchor-rtl,anchor,bgcolor,bidiltr,bidirtl,blockquote,' +
296 'bold,bulletedlist-rtl,bulletedlist,button,checkbox,copy-rtl,copy,copyformatting,' +
297 'creatediv,cut-rtl,cut,docprops-rtl,docprops,find-rtl,find,flash,form,' +
298 'hiddenfield,horizontalrule,icons,iframe,image,imagebutton,indent-rtl,' +
299 'indent,italic,justifyblock,justifycenter,justifyleft,justifyright,' +
300 'link,maximize,newpage-rtl,newpage,numberedlist-rtl,numberedlist,' +
301 'outdent-rtl,outdent,pagebreak-rtl,pagebreak,paste-rtl,paste,' +
302 'pastefromword-rtl,pastefromword,pastetext-rtl,pastetext,preview-rtl,' +
303 'preview,print,radio,redo-rtl,redo,removeformat,replace,save,scayt,' +
304 'select-rtl,select,selectall,showblocks-rtl,showblocks,smiley,' +
305 'source-rtl,source,specialchar,spellchecker,strike,subscript,' +
306 'superscript,table,templates-rtl,templates,textarea-rtl,textarea,' +
307 'textcolor,textfield-rtl,textfield,uicolor,underline,undo-rtl,undo,unlink' ).split( ',' );
308
309 var iconsFolder = CKEDITOR.getUrl( CKEDITOR.skin.path() + 'icons/' + ( CKEDITOR.env.hidpi ? 'hidpi/' : '' ) );
310
311 for ( var i = 0; i < icons.length; i++ ) {
312 CKEDITOR.skin.addIcon( icons[ i ], iconsFolder + icons[ i ] + '.png' );
313 }
314} )();
315
316// %REMOVE_END%
diff --git a/sources/skins/moono/toolbar.css b/sources/skins/moono/toolbar.css
new file mode 100644
index 0000000..a5d32d4
--- /dev/null
+++ b/sources/skins/moono/toolbar.css
@@ -0,0 +1,387 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5
6/*
7toolbar.css (part of editor.css)
8==================================
9
10This files styles the CKEditor toolbar and its buttons. For toolbar combo
11styles, check richcombo.css.
12
13The toolbar is rendered as a big container (called toolbox), which contains
14smaller "toolbars". Each toolbar represents a group of items that cannot be
15separated. The following is the visual representation of the toolbox.
16
17+-- .cke_toolbox ----------------------------------------------------------+
18| +-- .cke_toolbar --+ +-- .cke_toolbar --+ ... +-- .cke_toolbar_break --+ |
19| | | | | | | |
20| +------------------+ +------------------+ +------------------------+ |
21| +-- .cke_toolbar --+ +-- .cke_toolbar --+ ... |
22| | | | | |
23| +------------------+ +------------------+ |
24+--------------------------------------------------------------------------+
25
26The following instead is the visual representation of a single toolbar:
27
28+-- .cke_toolbar ----------------------------------------------------------------+
29| +-- .cke_toolbar_start --+ +-- .cke_toolgroup (*) --+ +-- .cke_toolbar_end --+ |
30| | | | | | | |
31| +------------------------+ +------------------------+ +----------------------+ |
32+--------------------------------------------------------------------------------+
33(*) .cke_toolgroup is available only when the toolbar items can be grouped
34 (buttons). If the items can't be group (combos), this box is not available
35 and the items are rendered straight in that place.
36
37This file also styles toolbar buttons, which are rendered inside the above
38.cke_toolgroup containers. This is the visual representation of a button:
39
40+-- .cke_button -------------------------------------+
41| +-- .cke_button_icon --+ +-- .cke_button_label --+ |
42| | | | | |
43| +----------------------+ +-----------------------+ |
44+----------------------------------------------------+
45
46Special outer level classes used in this file:
47
48 .cke_hc: Available when the editor is rendered on "High Contrast".
49 .cke_rtl: Available when the editor UI is on RTL.
50*/
51
52/* The box that holds each toolbar. */
53.cke_toolbar
54{
55 float: left;
56}
57
58.cke_rtl .cke_toolbar
59{
60 float: right;
61}
62
63/* The box that holds buttons. */
64.cke_toolgroup
65{
66 float: left;
67 margin: 0 6px 5px 0;
68 border: 1px solid #a6a6a6;
69 border-bottom-color: #979797;
70
71 border-radius: 3px;
72
73 box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 0 2px rgba(255,255,255,.15) inset, 0 1px 0 rgba(255,255,255,.15) inset;
74
75 background: #e4e4e4;
76 background-image: linear-gradient(to bottom, #ffffff, #e4e4e4);
77 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ffffff', endColorstr='#e4e4e4');
78}
79
80.cke_hc .cke_toolgroup
81{
82 border: 0;
83 margin-right: 10px;
84 margin-bottom: 10px;
85}
86
87.cke_rtl .cke_toolgroup
88{
89 float: right;
90 margin-left: 6px;
91 margin-right: 0;
92}
93
94/* A toolbar button . */
95a.cke_button
96{
97 display: inline-block;
98 height: 18px;
99 padding: 4px 6px;
100 outline: none;
101 cursor: default;
102 float: left;
103 border: 0;
104}
105
106.cke_ltr .cke_button:last-child,
107.cke_rtl .cke_button:first-child
108{
109 /* Don't distort parent's rounded border. */
110 border-radius: 0 2px 2px 0;
111}
112
113.cke_ltr .cke_button:first-child,
114.cke_rtl .cke_button:last-child
115{
116 /* Don't distort parent's rounded border. */
117 border-radius: 2px 0 0 2px;
118}
119
120.cke_rtl .cke_button
121{
122 float: right;
123}
124
125.cke_hc .cke_button
126{
127 border: 1px solid black;
128
129 /* Compensate the added border */
130 padding: 3px 5px;
131 margin: -2px 4px 0 -2px;
132}
133
134/* This class is applied to the button when it is "active" (pushed).
135 This style indicates that the feature associated with the button is active
136 i.e. currently writing in bold or when spell checking is enabled. */
137a.cke_button_on
138{
139 box-shadow: 0 1px 5px rgba(0,0,0,.6) inset, 0 1px 0 rgba(0,0,0,.2);
140
141 background: #b5b5b5;
142 background-image: linear-gradient(to bottom, #aaa, #cacaca);
143 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#aaaaaa', endColorstr='#cacaca');
144}
145
146.cke_hc .cke_button_on,
147.cke_hc a.cke_button_off:hover,
148.cke_hc a.cke_button_off:focus,
149.cke_hc a.cke_button_off:active,
150.cke_hc a.cke_button_disabled:hover,
151.cke_hc a.cke_button_disabled:focus,
152.cke_hc a.cke_button_disabled:active
153{
154 border-width: 3px;
155
156 /* Compensate the border change */
157 padding: 1px 3px;
158}
159
160/* This class is applied to the button when the feature associated with the
161 button cannot be used (grayed-out).
162 i.e. paste button remains disabled when there is nothing in the clipboard to
163 be pasted. */
164.cke_button_disabled .cke_button_icon
165{
166 opacity: 0.3;
167}
168
169.cke_hc .cke_button_disabled
170{
171 opacity: 0.5;
172}
173
174a.cke_button_on:hover,
175a.cke_button_on:focus,
176a.cke_button_on:active
177{
178 box-shadow: 0 1px 6px rgba(0,0,0,.7) inset, 0 1px 0 rgba(0,0,0,.2);
179}
180
181a.cke_button_off:hover,
182a.cke_button_off:focus,
183a.cke_button_off:active,
184a.cke_button_disabled:hover,
185a.cke_button_disabled:focus,
186a.cke_button_disabled:active
187{
188 box-shadow: 0 0 1px rgba(0,0,0,.3) inset;
189
190 background: #ccc;
191 background-image: linear-gradient(to bottom, #f2f2f2, #ccc);
192 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f2f2f2', endColorstr='#cccccc');
193}
194
195/* The icon which is a visual representation of the button. */
196.cke_button_icon
197{
198 cursor: inherit;
199 background-repeat: no-repeat;
200 margin-top: 1px;
201 width: 16px;
202 height: 16px;
203 float: left;
204 display: inline-block;
205}
206
207.cke_rtl .cke_button_icon
208{
209 float: right;
210}
211
212.cke_hc .cke_button_icon
213{
214 display: none;
215}
216
217/* The label of the button that stores the name of the feature. By default,
218 labels are invisible. They can be revealed on demand though. */
219.cke_button_label
220{
221 display: none;
222 padding-left: 3px;
223 margin-top: 1px;
224 line-height: 17px;
225 vertical-align: middle;
226 float: left;
227 cursor: default;
228 color: #474747;
229 text-shadow: 0 1px 0 rgba(255,255,255,.5);
230}
231
232.cke_rtl .cke_button_label
233{
234 padding-right: 3px;
235 padding-left: 0;
236 float: right;
237}
238
239.cke_hc .cke_button_label
240{
241 padding: 0;
242 display: inline-block;
243 font-size: 12px;
244}
245
246/* The small arrow available on buttons that can be expanded
247 (e.g. the color buttons). */
248.cke_button_arrow
249{
250 /* Arrow in CSS */
251 display: inline-block;
252 margin: 8px 0 0 1px;
253 width: 0;
254 height: 0;
255 cursor: default;
256 vertical-align: top;
257 border-left: 3px solid transparent;
258 border-right: 3px solid transparent;
259 border-top: 3px solid #474747;
260}
261
262.cke_rtl .cke_button_arrow
263{
264 margin-right: 5px;
265 margin-left: 0;
266}
267
268.cke_hc .cke_button_arrow
269{
270 font-size: 10px;
271 margin: 3px -2px 0 3px;
272 width: auto;
273 border: 0;
274}
275
276/* The vertical separator which is used within a single toolbar to split
277 buttons into sub-groups. */
278.cke_toolbar_separator
279{
280 float: left;
281 background-color: #c0c0c0;
282 background-color: rgba(0,0,0,.2);
283 margin: 5px 2px 0;
284 height: 18px;
285 width: 1px;
286
287 box-shadow: 1px 0 1px rgba(255,255,255,.5);
288}
289
290.cke_rtl .cke_toolbar_separator
291{
292 float: right;
293
294 box-shadow: -1px 0 1px rgba(255,255,255,.1);
295}
296
297.cke_hc .cke_toolbar_separator
298{
299 width: 0;
300 border-left: 1px solid;
301 margin: 1px 5px 0 0px;
302}
303
304/* The dummy element that breaks toolbars.
305 Once it is placed, the very next toolbar is moved to the new row. */
306.cke_toolbar_break
307{
308 display: block;
309 clear: left;
310}
311
312.cke_rtl .cke_toolbar_break
313{
314 clear: right;
315}
316
317/* The button, which when clicked hides (collapses) all the toolbars. */
318a.cke_toolbox_collapser
319{
320 width: 12px;
321 height: 11px;
322 float: right;
323 margin: 11px 0 0;
324 font-size: 0;
325 cursor: default;
326 text-align: center;
327
328 border: 1px solid #a6a6a6;
329 border-bottom-color: #979797;
330
331 border-radius: 3px;
332
333 box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 0 2px rgba(255,255,255,.15) inset, 0 1px 0 rgba(255,255,255,.15) inset;
334
335 background: #e4e4e4;
336 background-image: linear-gradient(to bottom, #ffffff, #e4e4e4);
337 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ffffff', endColorstr='#e4e4e4');
338}
339
340.cke_toolbox_collapser:hover
341{
342 background: #ccc;
343 background-image: linear-gradient(to bottom, #f2f2f2, #ccc);
344 filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f2f2f2', endColorstr='#cccccc');
345}
346
347.cke_toolbox_collapser.cke_toolbox_collapser_min
348{
349 margin: 0 2px 4px;
350}
351
352.cke_rtl .cke_toolbox_collapser
353{
354 float: left;
355}
356
357/* The CSS arrow, which belongs to the toolbar collapser. */
358.cke_toolbox_collapser .cke_arrow
359{
360 display: inline-block;
361
362 /* Pure CSS Arrow */
363 height: 0;
364 width: 0;
365 font-size: 0;
366 margin-top: 1px;
367 border-left: 3px solid transparent;
368 border-right: 3px solid transparent;
369 border-bottom: 3px solid #474747;
370 border-top: 3px solid transparent;
371}
372
373.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow
374{
375 margin-top: 4px;
376 border-bottom-color: transparent;
377 border-top-color: #474747;
378}
379
380.cke_hc .cke_toolbox_collapser .cke_arrow
381{
382 font-size: 8px;
383 width: auto;
384 border: 0;
385 margin-top: 0;
386 margin-right: 2px;
387}
diff --git a/sources/styles.js b/sources/styles.js
new file mode 100644
index 0000000..733bb4b
--- /dev/null
+++ b/sources/styles.js
@@ -0,0 +1,138 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6// This file contains style definitions that can be used by CKEditor plugins.
7//
8// The most common use for it is the "stylescombo" plugin which shows the Styles drop-down
9// list containing all styles in the editor toolbar. Other plugins, like
10// the "div" plugin, use a subset of the styles for their features.
11//
12// If you do not have plugins that depend on this file in your editor build, you can simply
13// ignore it. Otherwise it is strongly recommended to customize this file to match your
14// website requirements and design properly.
15//
16// For more information refer to: http://docs.ckeditor.com/#!/guide/dev_styles-section-style-rules
17
18CKEDITOR.stylesSet.add( 'default', [
19 /* Block styles */
20
21 // These styles are already available in the "Format" drop-down list ("format" plugin),
22 // so they are not needed here by default. You may enable them to avoid
23 // placing the "Format" combo in the toolbar, maintaining the same features.
24 /*
25 { name: 'Paragraph', element: 'p' },
26 { name: 'Heading 1', element: 'h1' },
27 { name: 'Heading 2', element: 'h2' },
28 { name: 'Heading 3', element: 'h3' },
29 { name: 'Heading 4', element: 'h4' },
30 { name: 'Heading 5', element: 'h5' },
31 { name: 'Heading 6', element: 'h6' },
32 { name: 'Preformatted Text',element: 'pre' },
33 { name: 'Address', element: 'address' },
34 */
35
36 { name: 'Italic Title', element: 'h2', styles: { 'font-style': 'italic' } },
37 { name: 'Subtitle', element: 'h3', styles: { 'color': '#aaa', 'font-style': 'italic' } },
38 {
39 name: 'Special Container',
40 element: 'div',
41 styles: {
42 padding: '5px 10px',
43 background: '#eee',
44 border: '1px solid #ccc'
45 }
46 },
47
48 /* Inline styles */
49
50 // These are core styles available as toolbar buttons. You may opt enabling
51 // some of them in the Styles drop-down list, removing them from the toolbar.
52 // (This requires the "stylescombo" plugin.)
53 /*
54 { name: 'Strong', element: 'strong', overrides: 'b' },
55 { name: 'Emphasis', element: 'em' , overrides: 'i' },
56 { name: 'Underline', element: 'u' },
57 { name: 'Strikethrough', element: 'strike' },
58 { name: 'Subscript', element: 'sub' },
59 { name: 'Superscript', element: 'sup' },
60 */
61
62 { name: 'Marker', element: 'span', attributes: { 'class': 'marker' } },
63
64 { name: 'Big', element: 'big' },
65 { name: 'Small', element: 'small' },
66 { name: 'Typewriter', element: 'tt' },
67
68 { name: 'Computer Code', element: 'code' },
69 { name: 'Keyboard Phrase', element: 'kbd' },
70 { name: 'Sample Text', element: 'samp' },
71 { name: 'Variable', element: 'var' },
72
73 { name: 'Deleted Text', element: 'del' },
74 { name: 'Inserted Text', element: 'ins' },
75
76 { name: 'Cited Work', element: 'cite' },
77 { name: 'Inline Quotation', element: 'q' },
78
79 { name: 'Language: RTL', element: 'span', attributes: { 'dir': 'rtl' } },
80 { name: 'Language: LTR', element: 'span', attributes: { 'dir': 'ltr' } },
81
82 /* Object styles */
83
84 {
85 name: 'Styled Image (left)',
86 element: 'img',
87 attributes: { 'class': 'left' }
88 },
89
90 {
91 name: 'Styled Image (right)',
92 element: 'img',
93 attributes: { 'class': 'right' }
94 },
95
96 {
97 name: 'Compact Table',
98 element: 'table',
99 attributes: {
100 cellpadding: '5',
101 cellspacing: '0',
102 border: '1',
103 bordercolor: '#ccc'
104 },
105 styles: {
106 'border-collapse': 'collapse'
107 }
108 },
109
110 { name: 'Borderless Table', element: 'table', styles: { 'border-style': 'hidden', 'background-color': '#E6E6FA' } },
111 { name: 'Square Bulleted List', element: 'ul', styles: { 'list-style-type': 'square' } },
112
113 /* Widget styles */
114
115 { name: 'Clean Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-clean' } },
116 { name: 'Grayscale Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-grayscale' } },
117
118 { name: 'Featured Snippet', type: 'widget', widget: 'codeSnippet', attributes: { 'class': 'code-featured' } },
119
120 { name: 'Featured Formula', type: 'widget', widget: 'mathjax', attributes: { 'class': 'math-featured' } },
121
122 { name: '240p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-240p' }, group: 'size' },
123 { name: '360p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-360p' }, group: 'size' },
124 { name: '480p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-480p' }, group: 'size' },
125 { name: '720p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-720p' }, group: 'size' },
126 { name: '1080p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-1080p' }, group: 'size' },
127
128 // Adding space after the style name is an intended workaround. For now, there
129 // is no option to create two styles with the same name for different widget types. See #16664.
130 { name: '240p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-240p' }, group: 'size' },
131 { name: '360p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-360p' }, group: 'size' },
132 { name: '480p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-480p' }, group: 'size' },
133 { name: '720p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-720p' }, group: 'size' },
134 { name: '1080p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-1080p' }, group: 'size' }
135
136] );
137
138// %LEAVE_UNMINIFIED% %REMOVE_LINE%