type_station 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/type_station/editables/admin_bar.js.coffee +19 -48
- data/app/assets/javascripts/type_station/editables/entity_editor.js.coffee +152 -0
- data/app/assets/javascripts/type_station/editables/file_editor.js.coffee +46 -0
- data/app/assets/javascripts/type_station/editables/link_finder.js.coffee +26 -26
- data/app/assets/javascripts/type_station/editables/text_html_editor.js.coffee +63 -0
- data/app/assets/javascripts/type_station/init.js.coffee +8 -50
- data/app/assets/javascripts/type_station/lib/models.js.coffee +5 -5
- data/app/assets/javascripts/type_station/lib/ts.js.coffee +84 -1
- data/app/assets/stylesheets/type_station/admin_bar.css.scss +10 -16
- data/app/assets/stylesheets/type_station/base.css.scss +26 -51
- data/app/controllers/type_station/admin/entities_controller.rb +53 -0
- data/app/controllers/type_station/admin/pages_controller.rb +4 -50
- data/app/controllers/type_station/application_controller.rb +1 -11
- data/app/controllers/type_station/pages_controller.rb +5 -5
- data/app/models/type_station/content.rb +14 -1
- data/app/models/type_station/entity.rb +80 -0
- data/app/models/type_station/page.rb +8 -120
- data/app/presenters/type_station/admin_bar_presenter.rb +9 -0
- data/app/presenters/type_station/content_presenter.rb +12 -2
- data/app/presenters/type_station/page_presenter.rb +6 -39
- data/app/presenters/type_station/presenter.rb +71 -0
- data/app/views/type_station/toolbars/_admin_bar.html.haml +18 -123
- data/config/routes.rb +3 -1
- data/lib/type_station/blocks/base.rb +32 -20
- data/lib/type_station/blocks/entity.rb +56 -0
- data/lib/type_station/blocks/field.rb +34 -0
- data/lib/type_station/concerns/path_generator.rb +69 -0
- data/lib/type_station/concerns/templatable.rb +16 -0
- data/lib/type_station/concerns.rb +2 -0
- data/lib/type_station/configuration.rb +8 -4
- data/lib/type_station/dsl.rb +6 -7
- data/lib/type_station/engine.rb +6 -0
- data/lib/type_station/railtie.rb +3 -5
- data/lib/type_station/version.rb +2 -2
- data/lib/type_station/view_helpers.rb +23 -86
- data/spec/dummy/app/helpers/another_name_helper.rb +1 -1
- data/spec/dummy/app/models/team.rb +3 -0
- data/spec/dummy/app/presenters/index_presenter.rb +18 -0
- data/spec/dummy/app/presenters/team_presenter.rb +7 -0
- data/spec/dummy/app/views/pages/index_other.html.erb +79 -78
- data/spec/dummy/config/initializers/config.rb +3 -3
- data/spec/dummy/config/mongoid.yml +2 -2
- data/spec/dummy/log/development.log +3229 -63846
- data/spec/dummy/tmp/cache/assets/development/sass/{d54c17bdece82ab7e34807e87c417af01a5b0646 → 5195863f2e60bebe518d97f94bb3d4b177b0b425}/chosen.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/631a1227c978d11ae414a23c82459b12296c5574/admin_bar.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/631a1227c978d11ae414a23c82459b12296c5574/base.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/{6fe6492bf5ccb83234e7598f9cf2dee000d6fd1d → d9d756bcf855b539202ff507923feaef562a86d9}/_ionicons-font.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/{6fe6492bf5ccb83234e7598f9cf2dee000d6fd1d → d9d756bcf855b539202ff507923feaef562a86d9}/_ionicons-icons.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/{6fe6492bf5ccb83234e7598f9cf2dee000d6fd1d → d9d756bcf855b539202ff507923feaef562a86d9}/_ionicons-variables.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/{6fe6492bf5ccb83234e7598f9cf2dee000d6fd1d → d9d756bcf855b539202ff507923feaef562a86d9}/ionicons.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/03faf403247b5c2b01bfc3b194c9a108 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{42a12b3c21e3f05a34cb05b0c63c690c → 04ce8830b8d9eb9869b4e717c72e4c77} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{ffa56cf66ebfb8bbe51b752fa5e854b7 → 05111c950181c5c7db004ab0537ad63a} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{12f3bf6fe9d52ff385ee5f0e1a94e256 → 06f720204faca086942ed12e58cc7e99} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{d11321573db03471f91362fca3d3c5c5 → 06fe7bcbc391b00c5a196a93f90ecabb} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/07a3408841510f4fb1eb0ede33cdb028 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/1057bd97781bd01e53c6be1c18815331 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{311ffc36d5a7e1d3216e672b3e57e7ed → 11a2e83f32c39554a1d8d1812fcfefa8} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/1e7d8fa3d4680fd1b85b0881f495525f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/21bece9bdb4b2b78355dfc15633484fb +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{a37ae28c4ac4e0bc0e2cb4423c40b24c → 268002ee16dde5d8865159003c5b9f56} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{8bec81b5959299e431f5adfc6c410719 → 2b6923a6b24ec5ce8800fedede741151} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2bf3770399e96a6b30d1d1078739c1f0 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2e14a727c7ff43dcd32c2d15c7d4e49c +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{3030c5140945ca6d88763e4f9136b93d → 2ed9e055cb4bc9748131e083298e90f3} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{5c2d0bbd303da757c44328df9bccedf7 → 2f14bda8290314a0fd6c175fcad55e69} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{985af24e0c117b294f64311bf0187513 → 2fbff71a6bc8ae2a4172de51e568ea3b} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{f566af7037e0e3042b19bd5ee11b21c4 → 305b28bd53201553c837a27834d3fee9} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{c0c85148a1307bb6d6a87139811da3ad → 318672b968af34804563871c8b1e1d23} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{0b495c71c71a2d087e00d9f77c89b537 → 3203d681677ab8bf95858a71dca72ad1} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{4d6d33dd083743a6d1e0d708c4e4e7aa → 333827a9cf72b750448f816161e1ecda} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{0d8f54d1682f575aec8f27993d3af45e → 34c2fc984403383284ed5696d70c010e} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{0c7b9a1778b05de10a66fde42c60b47c → 35191399e8ceb198f89ffa9a8e5e6d18} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{90c324b461b60cdeb6b549dbf932f162 → 3af1f1791459e78c28c4e7e55115168b} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/412cf59ab3b41a364279e5d53ad68152 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{f7345825a6e023e880e9a0744a4896bd → 4440e4eecd7f5abe3a350795b7c562a3} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/48d06b052d87bd96e9e9b8a50a69b18a +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/4c48023968030daffd8c05e4e1ea78bf +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{7ef9b3c736e553151f79c509136b1c44 → 4d43e505f0233833295b19c57e3f51bb} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{b6cef25e5142cb56f70ca0a8d31f312e → 5374e389194ac8d6d65ecfcfb0659919} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{cf5014041f97c55eee7c67feddf11b81 → 5403ae64c2a793b44bcc6728afa05e81} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/55e73132107a6039a07892904fb85b3f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/57096386bc19c2ad35327c072821d712 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/57a2ad49228767f4bdd4a7d12ab9fdeb +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{db1a08b3c680b077476f767a8addb44b → 58db8276645522fa111c4a297a6b3252} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/5963d34af3b79a722db1c029191b2127 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{da50fa3c24d736a5eb19bc107acd4ae7 → 5fd77f69e8769780727bcddc3bbef6da} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6527d2ff5eb008ef2a32f7796a6490d6 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{8438f80ca5340a65edcf7a37bde5d43d → 6694f57666543a152f6f95b772233bd3} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/685c03a878584655eb4475b4cdacdd75 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6aad7e14a81065dffac7093aacf234f2 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6c54d2efe05a3f58e5194a546a67d7b3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6e3a8b3faf7a8b9b6491dc8a5c1e8d23 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{f1567fa9088d43b2fb0f9a0caa1ed107 → 6eea7ea5e4bfeeb41ccc235189ffd18b} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{d4248f8b11c6b21abffed4a5e718722d → 722eee3ce416c20905dda68eab3d517e} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{56afaea2e164564be4d5f5bbc7f81050 → 7960910c69f2bcf82925d090b4745c83} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{740af710fe4125080680a8561398cd43 → 7f512b27e66494dd23baf2e5fb34b96a} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{e842f1fb8542889be369b76982f3157c → 80dca6b775b0c8c933ba3bd53864a11f} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/82cfb0f0bcd16b930ec1befc0d5cd8b8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/83c193129690d0c85c5370d822c4da82 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/83d012091edd332e8b52f58cf1a8aba5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/848f8022bef8c0160c31cfa94841c896 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{0d5a85a524a12561b8cfff4e8d06b332 → 85944b215ca6c0d1a1d7806605dfd545} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{570677a99f6abc19d74f793d5cb24f5f → 88c61205fb088e828eaf562152fb80e1} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{849593e0c4cb1f2e2b3f7941be4bfb17 → 895bfeb62235ec6bfdc13f057e975c50} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8a5150409eaf099549443d23d5d53c88 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8db596b50a3235e0956dfbc06ac6c990 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8f4346bc63f61c8274390947394eeeb7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{79b7c5b4127ac19346c56dd224bf8b19 → 8feb7e7adc10eec24e0ab54bef0c0857} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{a87019c62b5fb3b3dc75db921d98ad59 → 95130b18f8c813f4fa587e14f232c241} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{98bae9585542e37b839b68b25937fdf6 → 963c4df95ae6a8d8e54c7fe89d702fff} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/973acef0f44b868ef5c17c4d65d80ab0 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{ce5a41536c75e4bc37a5b0be19e9f786 → 98a60691ad77eb6c878a60773f6ca69a} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9a5b201b4dddc98127641bcf852a4ea8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9eafacb2fca5506e20523d97e92f5251 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a0c3540cd0a5390bd8985db285d1574f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a17ca57bada5cb7cb8c1d0b10fbd9904 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{ff96189f6d2677d5fa7c400167c74874 → a1b319a55f70f85dbee50bcb28aa81d4} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{99fd048521a12239746f91aa138613bf → a51f09cb29d7bd6071434928f56887af} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{f084a3a159f23d2f0f9943c4a2e5f8e9 → a6195a184397922f6afd2e7bf3d4a7e7} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a8ecf10c3e4c97b944e10c2cb0931fd5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{0b230f1bf23bd7b1392e34cacde00da0 → aa5deb52794e98d34cc0b868202211ee} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/aa9f5420651d522078eadd9de8350d35 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{99a40b6133b9eaa016bd6cf01fff987a → aab1005ca95fedeee05cb5f8d06eaa6c} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{21f725a9b3479e57849414f8272a905b → ab1e4897ca815d147fb473e23bf35bd7} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{a87cf4d10d892fb23f2fc818d7ca7207 → afa9de4377b9615980b737000fc68a2a} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b1fc0c5413b58bf1bf40a04dcd687d18 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b3383c0b0b1d8449e7a9c742a544edb7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b3b877cfd5c63c892cfe8c6248e3d003 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{cad829df95038ddc2958dab7e1b591ad → b401f905161e2ce92571718065d5e35c} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b62bf39167cc044d19958ff731ef6578 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bb1b5b9fd84c67b2b994666f8162e79b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bc7d25832d4cd5332bdf3ec19783ae76 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bcdec54b8cd89a231c20c7c45d8eca71 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{492de35b811aed43fc60de0227a5d0ab → bf1e850366946d51a864f66042acb16d} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c06990d2e8f15c9de915a7b33d17dac5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c136f3c36aea515920f7a51809e79094 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{c0600b832214f9e16294a1c37c0c3f6e → c39ca879cd6484827df2dd7605577066} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c4b181c541556124b2275b0ae4a94461 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c7699aedd27ae409c1ccf0c02a7782fc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{ef7d0257e22920401b54d6662e627252 → c85e062576453cbe6504556843184e48} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/ccc931022e80caf6ac008099f2589e7d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{a8e9ef7143431aa34568a350dad82af2 → cf5e51adf346ca56aee15b72f394fce9} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{b6f21db694cacb7f5bcbb93cf45f65ed → cf6bd170bc3f231ca9da6434bd53359b} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cfcaaf334e027f46a4eddee54f3e3b27 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d54b81fedb82c1d520b92cfd20e18ef5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d5de77884a5b0a88b13f76a0d8d2075e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d63daaafe9be33950037e285fb142eb5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/ddf237d5e172776d2061090bbf8fc6a5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{e736f7cd2394078039a3b11e6ee42802 → deb9cd21864c66e80861376afc6e17cd} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{d02809f043bce2445374a43a8f64b4b8 → e03864d9763609a4fa6412863f2c9a8c} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e080ee3bf59ec12040e4cabaa97dc241 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e1bc9024b810c879e24aa1de0f013358 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{147a08ea451b98ff5a28a0088b7d5c89 → e348418df158e4447a3120415eaeb3c5} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e39cb3a82453b50e888022543695b4e2 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e77bfcad61fabf7ed2d4dd21e881b8c8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{a855b42a37290315d53e93434721869d → ea306a2a3565b22cd16bf45555e751b5} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/eb1b637b8414e22b792fe2f3549283e3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{e8d6c5a2e13578e611f85cd7acd0088f → ebfd318084bf0cbcc2ab7ee6bf5c306c} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{42a7cd7e7e7d73b1882a085a3ed212b5 → ef58d6e4cfadfdd86e4f38c165c82e0a} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f4205d4b499b80a483c15c2408be1874 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{7316e0f7a256fd92f78a590981226fbe → f4a54e3803a4dbd2339782565404ffc1} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{d1e5823c113c9ee03e6c6d7773eb6fac → f7fe63074e55b9b04eef14bac17d6344} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f8a56681cc92b0dba2c2fdb753933a8b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{f14e64162f52a8d2d22ff9e1c1cc4fac → f9c9583263fc196b23e3630ecaca20ef} +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fba3208cb66e48884d72c7875e5ff4ca +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/{6f7174fb7f1fbb8e01d382a128a979e8 → fee315e7956140b77895e8a26e569ca5} +0 -0
- data/spec/dummy/tmp/pids/server.pid +1 -0
- data/vendor/assets/javascripts/medium-editor.js +1919 -1125
- data/vendor/assets/stylesheets/medium-editor/medium-editor.css +39 -9
- data/vendor/assets/stylesheets/medium-editor/themes/bootstrap.css +3 -5
- data/vendor/assets/stylesheets/medium-editor/themes/bootstrap.min.css +1 -1
- data/vendor/assets/stylesheets/medium-editor/themes/default.css +6 -8
- data/vendor/assets/stylesheets/medium-editor/themes/default.min.css +1 -1
- data/vendor/assets/stylesheets/medium-editor/themes/flat.css +2 -2
- data/vendor/assets/stylesheets/medium-editor/themes/mani.css +4 -4
- data/vendor/assets/stylesheets/medium-editor/themes/mani.min.css +1 -1
- data/vendor/assets/stylesheets/medium-editor/themes/roman.css +4 -4
- data/vendor/assets/stylesheets/medium-editor/themes/roman.min.css +1 -1
- metadata +337 -669
- data/app/assets/javascripts/type_station/editables/edit_link.js.coffee +0 -90
- data/app/assets/javascripts/type_station/editables/edit_page.js.coffee +0 -116
- data/app/assets/javascripts/type_station/editables/file.js.coffee +0 -66
- data/app/assets/javascripts/type_station/editables/image.js.coffee +0 -68
- data/app/assets/javascripts/type_station/editables/new_page.js.coffee +0 -79
- data/app/assets/javascripts/type_station/editables/text_html.js.coffee +0 -66
- data/app/views/layouts/type_station/application.html.erb +0 -14
- data/lib/type_station/blocks/edit_link.rb +0 -27
- data/lib/type_station/blocks/edit_page.rb +0 -28
- data/lib/type_station/blocks/editable_file.rb +0 -19
- data/lib/type_station/blocks/editable_html.rb +0 -15
- data/lib/type_station/blocks/editable_image.rb +0 -19
- data/lib/type_station/blocks/editable_text.rb +0 -19
- data/lib/type_station/blocks/new_collection.rb +0 -15
- data/lib/type_station/blocks/new_page.rb +0 -19
- data/lib/type_station/blocks/static_link.rb +0 -31
- data/lib/type_station/blocks/stickable.rb +0 -23
- data/lib/type_station/helpers/edit.rb +0 -36
- data/lib/type_station/helpers/editable.rb +0 -37
- data/lib/type_station/helpers/new.rb +0 -25
- data/lib/type_station/helpers/utilities.rb +0 -40
- data/lib/type_station/helpers.rb +0 -2
- data/spec/dummy/log/test.log +0 -1380
- data/spec/dummy/tmp/cache/assets/development/sass/d51071614a47c21d9e7a31bac67dfe51fed9abe3/_buttons.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/d51071614a47c21d9e7a31bac67dfe51fed9abe3/_mixins.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/d51071614a47c21d9e7a31bac67dfe51fed9abe3/_variables.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_alerts.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_background-variant.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_border-radius.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_buttons.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_center-block.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_clearfix.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_forms.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_gradients.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_grid-framework.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_grid.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_hide-text.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_image.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_labels.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_list-group.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_nav-divider.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_nav-vertical-align.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_opacity.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_pagination.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_panels.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_progress-bar.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_reset-filter.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_resize.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_responsive-visibility.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_size.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_tab-focus.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_table-row.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_text-emphasis.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_text-overflow.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/e63a0fef5d60e74f917815e496f07ccb348b5adc/_vendor-prefixes.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/fde2fd9fd4415e2893f7c202128d5909c847645f/admin_bar.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sass/fde2fd9fd4415e2893f7c202128d5909c847645f/base.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/07d82d3c1e3632b7f4bf807c2965e13b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0825425ebf24766be13ebf4e696dc267 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0aa47ff15e22d0e74389460968c32717 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0b163fa81b2ba6f9e0a9d3e6164af7cd +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0cbda04368ddbf6d761e788334075e7c +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0dd8d5d73e593c919592d3d02deb62e8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/0e846d0579634bd3924d701ebcd09040 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/127cceefef1ada19384ec7fec980c5ee +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/182d8b06dcdb4f799088741f553903d3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/1b64a5fd92110dbd078f4ea964e2d0ad +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/1d67ea254300e2a208df8f296477fca2 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/1ff95c0ddc6f6687c044d2a11b8323eb +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2155dbeb10a65c2519b49179b3bc6f3a +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2535956b4e5e79e8fbd3d30f68de7024 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/28ad54c6e5882957dd269b1b2a3c3c75 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/29a7d8d0307a932153f20c48b57ecda1 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2d0ee72828e0dcbaf2390d3d67595461 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/2d13dd9465026b66cce912e30e142020 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/300f6f1e08668cacf691691df4d13889 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/30e3d4f790a4234a26c7f74efba15a2e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/33ba18d4294cbb074bd3afee4728e2b9 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/3571d341c3629bb4c9034d2f924f34ac +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/3a3d03c0a92f21419e1e85991774a28b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/3dea6de9e06b1e372ebf4790f5eecc48 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/3e7667a45f81a73030337cb8afe0acc3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/4144b15d96ec80b5c7fb367b57aaeef3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/43c1381ebee89f30d22f80f305f78ee6 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/450d192e072fd68fb5c20711bdd21c9e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/4729c7f6ab6a91a079ab04a8f04e932b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/48f052ab53e11ca42b15cc7f40fe2d4c +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/4c324a18fe6bf7dbf7a04cccbfdb366e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/4fc791a177c880f50bf425e8d2862c20 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/51c578f550b2fd1ff7a873dbcf75b75b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/535f36c50d5b36ff83bc03bc6a19b8fc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/539ac885f1ce2ff4f1d693223a77b74d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/53ef9dcaf6b6ddcefceec48187797dc5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/55c2f55c27a62b998b8d33555158da53 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/575f0b5d245887cf587b0169d6993308 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/579b1a727fe5b55dfe450b0835c56a65 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/5a806147b739da644a296d2def76c243 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/5d79ea654842f86bec8702b02616c633 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/60b14e8e4c0d91f7af9d162cf4c67a9c +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/61d7a0e99e49f7a9917d385223a97015 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/623a22125c47f6f4391fd1a56e40b8a0 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/65cf3864264ab5fd70d6e74a934adf8d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6b734dd1ce043b913eb812a20ea2d42f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/6e0fcc860289a427d98aa4ee86bd12b7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/709e51f7191f25018b0012df4ff6389f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/70dfe9a7b27467587b0d4d00a7e0f6fb +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/71e10ee69b177ab54cb6033385a77ef9 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/735d50df5dc976a13b56aa81f5970298 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/73939a29e193b5a1fad031fa75f94119 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/73cc8ce397fbfe4408bcac87302a6952 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/7cfbbb15a3f9dcb4a5ee988ea309504d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/7efe4acab136927c0b1df06d7c1212cd +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/7f14b0b39c11df4f58e03d390b589547 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/7fc9c7161658070c78790a28b4ff590f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/825bd4dba50f1ea2c0ae5e8a3708119e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/84822f25094f67b515ad5f452381dcb0 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/85c54085eea77d703dd054b1adcf309d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/85d858ed64f06543161931735cb77748 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/85fe1c52386ac4419fdf124a22228a98 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8803d0a63bbf3fce683c968d4a900480 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/887e2151ef4cd6e915fd9bfc27c41d7d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8b33a159429f95c8fbb14e5d45b01967 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8caeabedf4518243187dbf20bf76a0d8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/8e60a95e73cedfb4b58fbf6fc32564b3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/92c1d07e65b1251e6a9f62064f749658 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/92d59399e3f951cc11721f03a2b328fd +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/966db607ae0e7aad72cf171b8fec537a +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9a9290586c54792a989ea679f38ebc98 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9c6580777be29320c993da37d292fcae +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9c8cd77db76e28f0a074573a72509ce9 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9d5a258ab9e431a1a7eaf931ed4c3fb3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/9d961151482903524be9a51e312c8d49 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a165e7cd7871ea0af12d29ef10193272 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a2b3a282d5d8a5c20444d1a27f70a61e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/a539d3e91d5fb8eeb973ac8706bbf5c9 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/ab4192212bd78e95967e5a716548236f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/acbb40a3fca4d574f84a89894274b5ab +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/af97ed366de5933460d41b9198ddc99e +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/afad1821c4be2be037ae8672c21db00a +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b0acb9e437685aa3f0c0a2ca751a04ce +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b0b0cf6bca2dad4b85f30801d615eac4 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b1a982f644c0350cb843b63d69a9506f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b772142455a4c78005e67264e239e867 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b85e6623f6fed5c83a7a375ff15bdd79 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/b89a0282f37737eb86781a8ddbdf14a3 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bc2f1083a88e2e7c4e88f13f025824ed +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bcf0359847dcb2f9179c6a46248bcea5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/bd3113e1418cbc640eb6e1b06d486163 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c4e5a8fece2f70f43c6e7cc4a790def7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c4ec64020d1ff391bab8c2f0bbc7cd02 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c501910d385d42ea0cf75ae3c4f220e6 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/c7628a8a59ea560abb9213543333222c +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cb80f61fc678a70e99e16156ae6e07d1 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cc9a378dda4e65e86b1f3fd522d019a1 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cdaf4cc6f0288db4f6fa5b8073ac6272 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/cdedc95319572f0c3e36a3a5a044572d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d05d272f053261f2d5e3dcca85f19172 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d05d2c6ed489a61e2a9756430af9f48f +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d07ab5a5474c0fb71b3bd351947707e5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d1f0a2d6fd58a203f3ca66950c822c33 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d3a2586089547d98e033029b94eb86a5 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/d9924e9691068558c4ce3a20bec7fea1 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/da9349ff5720f218552184c8fef40d7a +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/dd9f84cc20227ad66bbd1f26bbc11ccc +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/de9d72cab443cce32e1d45e62d2b4c04 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e03c578b73cf9936edc84ff2b48c07da +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e04691fd3eaee6408ac1d1b7fade69e6 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e40f49d676971d013ad991bdf2dc344b +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e72700144fea9ebdc4813bc00f023fc7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/e9b5bc7c65d160f7e31993bbe7a05d63 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/ebdd71d1c3cf34d7d174e5c1abb123b7 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/ec22367449630f093cf0449cea0abdfd +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f479b0a1614f114b61a63664e172dec1 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f6eeeb889d424f50b0f725d4656e0721 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/f7c0e18cf77ef251a27e9ff91578fb47 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fa8cab89937bf25aa48b23445f1b4f64 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fc5de94b46d8aff03ec5355f912a9a81 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fd1cae0417fea68172ab7b747a1d6fd8 +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fd2dacd118d6197c3a9325e2103abe7d +0 -0
- data/spec/dummy/tmp/cache/assets/development/sprockets/fe43b3c0b7d3233a250ce9c46342919c +0 -0
- data/spec/dummy/tmp/cache/assets/test/sass/fde2fd9fd4415e2893f7c202128d5909c847645f/admin_bar.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/test/sass/fde2fd9fd4415e2893f7c202128d5909c847645f/base.css.scssc +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/0825425ebf24766be13ebf4e696dc267 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/0b495c71c71a2d087e00d9f77c89b537 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/0cbda04368ddbf6d761e788334075e7c +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/0d8f54d1682f575aec8f27993d3af45e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/12f3bf6fe9d52ff385ee5f0e1a94e256 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/182d8b06dcdb4f799088741f553903d3 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/1b64a5fd92110dbd078f4ea964e2d0ad +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/2155dbeb10a65c2519b49179b3bc6f3a +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/21f725a9b3479e57849414f8272a905b +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/2535956b4e5e79e8fbd3d30f68de7024 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/28ad54c6e5882957dd269b1b2a3c3c75 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/29a7d8d0307a932153f20c48b57ecda1 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/2d13dd9465026b66cce912e30e142020 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/300f6f1e08668cacf691691df4d13889 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/311ffc36d5a7e1d3216e672b3e57e7ed +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/3a3d03c0a92f21419e1e85991774a28b +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/3dea6de9e06b1e372ebf4790f5eecc48 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/4144b15d96ec80b5c7fb367b57aaeef3 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/4729c7f6ab6a91a079ab04a8f04e932b +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/4c324a18fe6bf7dbf7a04cccbfdb366e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/535f36c50d5b36ff83bc03bc6a19b8fc +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/55c2f55c27a62b998b8d33555158da53 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/56afaea2e164564be4d5f5bbc7f81050 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/570677a99f6abc19d74f793d5cb24f5f +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/579b1a727fe5b55dfe450b0835c56a65 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/6f7174fb7f1fbb8e01d382a128a979e8 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/735d50df5dc976a13b56aa81f5970298 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/7746e5b6582f701e40ad5ae69e7a6d25 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/7f14b0b39c11df4f58e03d390b589547 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/8091ad5bff4f0d3d70f874750430241b +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/825bd4dba50f1ea2c0ae5e8a3708119e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/849593e0c4cb1f2e2b3f7941be4bfb17 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/85d858ed64f06543161931735cb77748 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/8803d0a63bbf3fce683c968d4a900480 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/887e2151ef4cd6e915fd9bfc27c41d7d +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/8bec81b5959299e431f5adfc6c410719 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/90c324b461b60cdeb6b549dbf932f162 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/92d59399e3f951cc11721f03a2b328fd +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/966db607ae0e7aad72cf171b8fec537a +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/98bae9585542e37b839b68b25937fdf6 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/99fd048521a12239746f91aa138613bf +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/a539d3e91d5fb8eeb973ac8706bbf5c9 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/a87019c62b5fb3b3dc75db921d98ad59 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/a87cf4d10d892fb23f2fc818d7ca7207 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/ab4192212bd78e95967e5a716548236f +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/af97ed366de5933460d41b9198ddc99e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/b6cef25e5142cb56f70ca0a8d31f312e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/b6f21db694cacb7f5bcbb93cf45f65ed +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/bd3113e1418cbc640eb6e1b06d486163 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/c0600b832214f9e16294a1c37c0c3f6e +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/cad829df95038ddc2958dab7e1b591ad +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d05d272f053261f2d5e3dcca85f19172 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d1e5823c113c9ee03e6c6d7773eb6fac +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d1f0a2d6fd58a203f3ca66950c822c33 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d3a2586089547d98e033029b94eb86a5 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d4248f8b11c6b21abffed4a5e718722d +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/da50fa3c24d736a5eb19bc107acd4ae7 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/db1a08b3c680b077476f767a8addb44b +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/dd9f84cc20227ad66bbd1f26bbc11ccc +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/de9d72cab443cce32e1d45e62d2b4c04 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/e03c578b73cf9936edc84ff2b48c07da +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/e842f1fb8542889be369b76982f3157c +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/ebdd71d1c3cf34d7d174e5c1abb123b7 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/f14e64162f52a8d2d22ff9e1c1cc4fac +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/f566af7037e0e3042b19bd5ee11b21c4 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/fd1cae0417fea68172ab7b747a1d6fd8 +0 -0
@@ -1,253 +1,1399 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/*global self, document, DOMException */
|
2
|
+
|
3
|
+
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
|
4
|
+
|
5
|
+
// Full polyfill for browsers with no classList support
|
6
|
+
if (!("classList" in document.createElement("_"))) {
|
7
|
+
(function (view) {
|
8
|
+
|
9
|
+
"use strict";
|
10
|
+
|
11
|
+
if (!('Element' in view)) return;
|
12
|
+
|
13
|
+
var
|
14
|
+
classListProp = "classList"
|
15
|
+
, protoProp = "prototype"
|
16
|
+
, elemCtrProto = view.Element[protoProp]
|
17
|
+
, objCtr = Object
|
18
|
+
, strTrim = String[protoProp].trim || function () {
|
19
|
+
return this.replace(/^\s+|\s+$/g, "");
|
20
|
+
}
|
21
|
+
, arrIndexOf = Array[protoProp].indexOf || function (item) {
|
22
|
+
var
|
23
|
+
i = 0
|
24
|
+
, len = this.length
|
25
|
+
;
|
26
|
+
for (; i < len; i++) {
|
27
|
+
if (i in this && this[i] === item) {
|
28
|
+
return i;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
return -1;
|
32
|
+
}
|
33
|
+
// Vendors: please allow content code to instantiate DOMExceptions
|
34
|
+
, DOMEx = function (type, message) {
|
35
|
+
this.name = type;
|
36
|
+
this.code = DOMException[type];
|
37
|
+
this.message = message;
|
38
|
+
}
|
39
|
+
, checkTokenAndGetIndex = function (classList, token) {
|
40
|
+
if (token === "") {
|
41
|
+
throw new DOMEx(
|
42
|
+
"SYNTAX_ERR"
|
43
|
+
, "An invalid or illegal string was specified"
|
44
|
+
);
|
45
|
+
}
|
46
|
+
if (/\s/.test(token)) {
|
47
|
+
throw new DOMEx(
|
48
|
+
"INVALID_CHARACTER_ERR"
|
49
|
+
, "String contains an invalid character"
|
50
|
+
);
|
51
|
+
}
|
52
|
+
return arrIndexOf.call(classList, token);
|
53
|
+
}
|
54
|
+
, ClassList = function (elem) {
|
55
|
+
var
|
56
|
+
trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
|
57
|
+
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
|
58
|
+
, i = 0
|
59
|
+
, len = classes.length
|
60
|
+
;
|
61
|
+
for (; i < len; i++) {
|
62
|
+
this.push(classes[i]);
|
63
|
+
}
|
64
|
+
this._updateClassName = function () {
|
65
|
+
elem.setAttribute("class", this.toString());
|
66
|
+
};
|
67
|
+
}
|
68
|
+
, classListProto = ClassList[protoProp] = []
|
69
|
+
, classListGetter = function () {
|
70
|
+
return new ClassList(this);
|
71
|
+
}
|
72
|
+
;
|
73
|
+
// Most DOMException implementations don't allow calling DOMException's toString()
|
74
|
+
// on non-DOMExceptions. Error's toString() is sufficient here.
|
75
|
+
DOMEx[protoProp] = Error[protoProp];
|
76
|
+
classListProto.item = function (i) {
|
77
|
+
return this[i] || null;
|
78
|
+
};
|
79
|
+
classListProto.contains = function (token) {
|
80
|
+
token += "";
|
81
|
+
return checkTokenAndGetIndex(this, token) !== -1;
|
82
|
+
};
|
83
|
+
classListProto.add = function () {
|
84
|
+
var
|
85
|
+
tokens = arguments
|
86
|
+
, i = 0
|
87
|
+
, l = tokens.length
|
88
|
+
, token
|
89
|
+
, updated = false
|
90
|
+
;
|
91
|
+
do {
|
92
|
+
token = tokens[i] + "";
|
93
|
+
if (checkTokenAndGetIndex(this, token) === -1) {
|
94
|
+
this.push(token);
|
95
|
+
updated = true;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
while (++i < l);
|
99
|
+
|
100
|
+
if (updated) {
|
101
|
+
this._updateClassName();
|
102
|
+
}
|
103
|
+
};
|
104
|
+
classListProto.remove = function () {
|
105
|
+
var
|
106
|
+
tokens = arguments
|
107
|
+
, i = 0
|
108
|
+
, l = tokens.length
|
109
|
+
, token
|
110
|
+
, updated = false
|
111
|
+
, index
|
112
|
+
;
|
113
|
+
do {
|
114
|
+
token = tokens[i] + "";
|
115
|
+
index = checkTokenAndGetIndex(this, token);
|
116
|
+
while (index !== -1) {
|
117
|
+
this.splice(index, 1);
|
118
|
+
updated = true;
|
119
|
+
index = checkTokenAndGetIndex(this, token);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
while (++i < l);
|
123
|
+
|
124
|
+
if (updated) {
|
125
|
+
this._updateClassName();
|
126
|
+
}
|
127
|
+
};
|
128
|
+
classListProto.toggle = function (token, force) {
|
129
|
+
token += "";
|
130
|
+
|
131
|
+
var
|
132
|
+
result = this.contains(token)
|
133
|
+
, method = result ?
|
134
|
+
force !== true && "remove"
|
135
|
+
:
|
136
|
+
force !== false && "add"
|
137
|
+
;
|
138
|
+
|
139
|
+
if (method) {
|
140
|
+
this[method](token);
|
141
|
+
}
|
142
|
+
|
143
|
+
if (force === true || force === false) {
|
144
|
+
return force;
|
145
|
+
} else {
|
146
|
+
return !result;
|
147
|
+
}
|
148
|
+
};
|
149
|
+
classListProto.toString = function () {
|
150
|
+
return this.join(" ");
|
151
|
+
};
|
152
|
+
|
153
|
+
if (objCtr.defineProperty) {
|
154
|
+
var classListPropDesc = {
|
155
|
+
get: classListGetter
|
156
|
+
, enumerable: true
|
157
|
+
, configurable: true
|
158
|
+
};
|
159
|
+
try {
|
160
|
+
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
|
161
|
+
} catch (ex) { // IE 8 doesn't support enumerable:true
|
162
|
+
if (ex.number === -0x7FF5EC54) {
|
163
|
+
classListPropDesc.enumerable = false;
|
164
|
+
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
} else if (objCtr[protoProp].__defineGetter__) {
|
168
|
+
elemCtrProto.__defineGetter__(classListProp, classListGetter);
|
169
|
+
}
|
170
|
+
|
171
|
+
}(self));
|
4
172
|
}
|
5
173
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
define
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
}
|
174
|
+
(function (root, factory) {
|
175
|
+
'use strict';
|
176
|
+
if (typeof module === 'object') {
|
177
|
+
module.exports = factory;
|
178
|
+
} else if (typeof define === 'function' && define.amd) {
|
179
|
+
define(function () {
|
180
|
+
return factory;
|
181
|
+
});
|
182
|
+
} else {
|
183
|
+
root.MediumEditor = factory;
|
184
|
+
}
|
185
|
+
}(this, function () {
|
186
|
+
|
187
|
+
'use strict';
|
188
|
+
|
189
|
+
var Util;
|
190
|
+
|
191
|
+
(function (window, document) {
|
192
|
+
'use strict';
|
193
|
+
|
194
|
+
function copyInto(dest, source, overwrite) {
|
195
|
+
var prop;
|
196
|
+
dest = dest || {};
|
197
|
+
for (prop in source) {
|
198
|
+
if (source.hasOwnProperty(prop) && (overwrite || dest.hasOwnProperty(prop) === false)) {
|
199
|
+
dest[prop] = source[prop];
|
200
|
+
}
|
201
|
+
}
|
202
|
+
return dest;
|
203
|
+
}
|
204
|
+
|
205
|
+
Util = {
|
206
|
+
|
207
|
+
// http://stackoverflow.com/questions/17907445/how-to-detect-ie11#comment30165888_17907562
|
208
|
+
// by rg89
|
209
|
+
isIE: ((navigator.appName === 'Microsoft Internet Explorer') || ((navigator.appName === 'Netscape') && (new RegExp('Trident/.*rv:([0-9]{1,}[.0-9]{0,})').exec(navigator.userAgent) !== null))),
|
210
|
+
|
211
|
+
// https://github.com/jashkenas/underscore
|
212
|
+
keyCode: {
|
213
|
+
BACKSPACE: 8,
|
214
|
+
TAB: 9,
|
215
|
+
ENTER: 13,
|
216
|
+
ESCAPE: 27,
|
217
|
+
SPACE: 32,
|
218
|
+
DELETE: 46
|
219
|
+
},
|
220
|
+
|
221
|
+
parentElements: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre'],
|
222
|
+
|
223
|
+
defaults: function defaults(dest, source) {
|
224
|
+
return copyInto(dest, source);
|
225
|
+
},
|
226
|
+
|
227
|
+
extend: function extend(dest, source) {
|
228
|
+
return copyInto(dest, source, true);
|
229
|
+
},
|
230
|
+
|
231
|
+
derives: function derives(base, derived) {
|
232
|
+
var origPrototype = derived.prototype;
|
233
|
+
function Proto() { }
|
234
|
+
Proto.prototype = base.prototype;
|
235
|
+
derived.prototype = new Proto();
|
236
|
+
derived.prototype.constructor = base;
|
237
|
+
derived.prototype = copyInto(derived.prototype, origPrototype);
|
238
|
+
return derived;
|
239
|
+
},
|
240
|
+
|
241
|
+
// Find the next node in the DOM tree that represents any text that is being
|
242
|
+
// displayed directly next to the targetNode (passed as an argument)
|
243
|
+
// Text that appears directly next to the current node can be:
|
244
|
+
// - A sibling text node
|
245
|
+
// - A descendant of a sibling element
|
246
|
+
// - A sibling text node of an ancestor
|
247
|
+
// - A descendant of a sibling element of an ancestor
|
248
|
+
findAdjacentTextNodeWithContent: function findAdjacentTextNodeWithContent(rootNode, targetNode, ownerDocument) {
|
249
|
+
var pastTarget = false,
|
250
|
+
nextNode,
|
251
|
+
nodeIterator = ownerDocument.createNodeIterator(rootNode, NodeFilter.SHOW_TEXT, null, false);
|
252
|
+
|
253
|
+
// Use a native NodeIterator to iterate over all the text nodes that are descendants
|
254
|
+
// of the rootNode. Once past the targetNode, choose the first non-empty text node
|
255
|
+
nextNode = nodeIterator.nextNode();
|
256
|
+
while (nextNode) {
|
257
|
+
if (nextNode === targetNode) {
|
258
|
+
pastTarget = true;
|
259
|
+
} else if (pastTarget) {
|
260
|
+
if (nextNode.nodeType === 3 && nextNode.nodeValue && nextNode.nodeValue.trim().length > 0) {
|
261
|
+
break;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
nextNode = nodeIterator.nextNode();
|
265
|
+
}
|
266
|
+
|
267
|
+
return nextNode;
|
268
|
+
},
|
269
|
+
|
270
|
+
isDescendant: function isDescendant(parent, child) {
|
271
|
+
if (!parent || !child) {
|
272
|
+
return false;
|
273
|
+
}
|
274
|
+
var node = child.parentNode;
|
275
|
+
while (node !== null) {
|
276
|
+
if (node === parent) {
|
277
|
+
return true;
|
278
|
+
}
|
279
|
+
node = node.parentNode;
|
280
|
+
}
|
281
|
+
return false;
|
282
|
+
},
|
283
|
+
|
284
|
+
// https://github.com/jashkenas/underscore
|
285
|
+
isElement: function isElement(obj) {
|
286
|
+
return !!(obj && obj.nodeType === 1);
|
287
|
+
},
|
288
|
+
|
289
|
+
now: function now() {
|
290
|
+
return Date.now || new Date().getTime();
|
291
|
+
},
|
292
|
+
|
293
|
+
// https://github.com/jashkenas/underscore
|
294
|
+
throttle: function throttle(func, wait) {
|
295
|
+
var THROTTLE_INTERVAL = 50,
|
296
|
+
context,
|
297
|
+
args,
|
298
|
+
result,
|
299
|
+
timeout = null,
|
300
|
+
previous = 0,
|
301
|
+
later;
|
302
|
+
|
303
|
+
if (!wait && wait !== 0) {
|
304
|
+
wait = THROTTLE_INTERVAL;
|
305
|
+
}
|
306
|
+
|
307
|
+
later = function () {
|
308
|
+
previous = Util.now();
|
309
|
+
timeout = null;
|
310
|
+
result = func.apply(context, args);
|
311
|
+
if (!timeout) {
|
312
|
+
context = args = null;
|
313
|
+
}
|
314
|
+
};
|
315
|
+
|
316
|
+
return function () {
|
317
|
+
var currNow = Util.now(),
|
318
|
+
remaining = wait - (currNow - previous);
|
319
|
+
context = this;
|
320
|
+
args = arguments;
|
321
|
+
if (remaining <= 0 || remaining > wait) {
|
322
|
+
clearTimeout(timeout);
|
323
|
+
timeout = null;
|
324
|
+
previous = currNow;
|
325
|
+
result = func.apply(context, args);
|
326
|
+
if (!timeout) {
|
327
|
+
context = args = null;
|
328
|
+
}
|
329
|
+
} else if (!timeout) {
|
330
|
+
timeout = setTimeout(later, remaining);
|
331
|
+
}
|
332
|
+
return result;
|
333
|
+
};
|
334
|
+
},
|
335
|
+
|
336
|
+
traverseUp: function (current, testElementFunction) {
|
337
|
+
|
338
|
+
do {
|
339
|
+
if (current.nodeType === 1) {
|
340
|
+
if (testElementFunction(current)) {
|
341
|
+
return current;
|
342
|
+
}
|
343
|
+
// do not traverse upwards past the nearest containing editor
|
344
|
+
if (current.getAttribute('data-medium-element')) {
|
345
|
+
return false;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
349
|
+
current = current.parentNode;
|
350
|
+
} while (current);
|
351
|
+
|
352
|
+
return false;
|
353
|
+
|
354
|
+
},
|
355
|
+
|
356
|
+
htmlEntities: function (str) {
|
357
|
+
// converts special characters (like <) into their escaped/encoded values (like <).
|
358
|
+
// This allows you to show to display the string without the browser reading it as HTML.
|
359
|
+
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
360
|
+
},
|
361
|
+
|
362
|
+
// http://stackoverflow.com/questions/6690752/insert-html-at-caret-in-a-contenteditable-div
|
363
|
+
insertHTMLCommand: function (doc, html) {
|
364
|
+
var selection, range, el, fragment, node, lastNode;
|
365
|
+
|
366
|
+
if (doc.queryCommandSupported('insertHTML')) {
|
367
|
+
try {
|
368
|
+
return doc.execCommand('insertHTML', false, html);
|
369
|
+
} catch (ignore) {}
|
370
|
+
}
|
371
|
+
|
372
|
+
selection = window.getSelection();
|
373
|
+
if (selection.getRangeAt && selection.rangeCount) {
|
374
|
+
range = selection.getRangeAt(0);
|
375
|
+
range.deleteContents();
|
376
|
+
|
377
|
+
el = doc.createElement("div");
|
378
|
+
el.innerHTML = html;
|
379
|
+
fragment = doc.createDocumentFragment();
|
380
|
+
while (el.firstChild) {
|
381
|
+
node = el.firstChild;
|
382
|
+
lastNode = fragment.appendChild(node);
|
383
|
+
}
|
384
|
+
range.insertNode(fragment);
|
385
|
+
|
386
|
+
// Preserve the selection:
|
387
|
+
if (lastNode) {
|
388
|
+
range = range.cloneRange();
|
389
|
+
range.setStartAfter(lastNode);
|
390
|
+
range.collapse(true);
|
391
|
+
selection.removeAllRanges();
|
392
|
+
selection.addRange(range);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
},
|
396
|
+
|
397
|
+
// TODO: not sure if this should be here
|
398
|
+
setTargetBlank: function (el) {
|
399
|
+
var i;
|
400
|
+
if (el.tagName.toLowerCase() === 'a') {
|
401
|
+
el.target = '_blank';
|
402
|
+
} else {
|
403
|
+
el = el.getElementsByTagName('a');
|
404
|
+
|
405
|
+
for (i = 0; i < el.length; i += 1) {
|
406
|
+
el[i].target = '_blank';
|
407
|
+
}
|
408
|
+
}
|
409
|
+
},
|
410
|
+
|
411
|
+
isListItemChild: function (node) {
|
412
|
+
var parentNode = node.parentNode,
|
413
|
+
tagName = parentNode.tagName.toLowerCase();
|
414
|
+
while (this.parentElements.indexOf(tagName) === -1 && tagName !== 'div') {
|
415
|
+
if (tagName === 'li') {
|
416
|
+
return true;
|
417
|
+
}
|
418
|
+
parentNode = parentNode.parentNode;
|
419
|
+
if (parentNode && parentNode.tagName) {
|
420
|
+
tagName = parentNode.tagName.toLowerCase();
|
421
|
+
} else {
|
422
|
+
return false;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
return false;
|
426
|
+
}
|
427
|
+
};
|
428
|
+
}(window, document));
|
429
|
+
|
430
|
+
var Selection;
|
431
|
+
|
432
|
+
(function (window, document) {
|
433
|
+
'use strict';
|
434
|
+
|
435
|
+
Selection = {
|
436
|
+
// http://stackoverflow.com/questions/1197401/how-can-i-get-the-element-the-caret-is-in-with-javascript-when-using-contentedi
|
437
|
+
// by You
|
438
|
+
getSelectionStart: function (ownerDocument) {
|
439
|
+
var node = ownerDocument.getSelection().anchorNode,
|
440
|
+
startNode = (node && node.nodeType === 3 ? node.parentNode : node);
|
441
|
+
return startNode;
|
442
|
+
},
|
443
|
+
|
444
|
+
findMatchingSelectionParent: function (testElementFunction, contentWindow) {
|
445
|
+
var selection = contentWindow.getSelection(), range, current;
|
446
|
+
|
447
|
+
if (selection.rangeCount === 0) {
|
448
|
+
return false;
|
449
|
+
}
|
450
|
+
|
451
|
+
range = selection.getRangeAt(0);
|
452
|
+
current = range.commonAncestorContainer;
|
453
|
+
|
454
|
+
return Util.traverseUp(current, testElementFunction);
|
455
|
+
},
|
456
|
+
|
457
|
+
getSelectionElement: function (contentWindow) {
|
458
|
+
return this.findMatchingSelectionParent(function (el) {
|
459
|
+
return el.getAttribute('data-medium-element');
|
460
|
+
}, contentWindow);
|
461
|
+
},
|
462
|
+
|
463
|
+
selectionInContentEditableFalse: function (contentWindow) {
|
464
|
+
return this.findMatchingSelectionParent(function (el) {
|
465
|
+
return (el && el.nodeName !== '#text' && el.getAttribute('contenteditable') === 'false');
|
466
|
+
}, contentWindow);
|
467
|
+
},
|
468
|
+
|
469
|
+
// http://stackoverflow.com/questions/4176923/html-of-selected-text
|
470
|
+
// by Tim Down
|
471
|
+
getSelectionHtml: function getSelectionHtml() {
|
472
|
+
var i,
|
473
|
+
html = '',
|
474
|
+
sel,
|
475
|
+
len,
|
476
|
+
container;
|
477
|
+
if (this.options.contentWindow.getSelection !== undefined) {
|
478
|
+
sel = this.options.contentWindow.getSelection();
|
479
|
+
if (sel.rangeCount) {
|
480
|
+
container = this.options.ownerDocument.createElement('div');
|
481
|
+
for (i = 0, len = sel.rangeCount; i < len; i += 1) {
|
482
|
+
container.appendChild(sel.getRangeAt(i).cloneContents());
|
483
|
+
}
|
484
|
+
html = container.innerHTML;
|
485
|
+
}
|
486
|
+
} else if (this.options.ownerDocument.selection !== undefined) {
|
487
|
+
if (this.options.ownerDocument.selection.type === 'Text') {
|
488
|
+
html = this.options.ownerDocument.selection.createRange().htmlText;
|
489
|
+
}
|
490
|
+
}
|
491
|
+
return html;
|
492
|
+
},
|
493
|
+
|
494
|
+
/**
|
495
|
+
* Find the caret position within an element irrespective of any inline tags it may contain.
|
496
|
+
*
|
497
|
+
* @param {DOMElement} An element containing the cursor to find offsets relative to.
|
498
|
+
* @param {Range} A Range representing cursor position. Will window.getSelection if none is passed.
|
499
|
+
* @return {Object} 'left' and 'right' attributes contain offsets from begining and end of Element
|
500
|
+
*/
|
501
|
+
getCaretOffsets: function getCaretOffsets(element, range) {
|
502
|
+
var preCaretRange, postCaretRange;
|
503
|
+
|
504
|
+
if (!range) {
|
505
|
+
range = window.getSelection().getRangeAt(0);
|
506
|
+
}
|
507
|
+
|
508
|
+
preCaretRange = range.cloneRange();
|
509
|
+
postCaretRange = range.cloneRange();
|
510
|
+
|
511
|
+
preCaretRange.selectNodeContents(element);
|
512
|
+
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
513
|
+
|
514
|
+
postCaretRange.selectNodeContents(element);
|
515
|
+
postCaretRange.setStart(range.endContainer, range.endOffset);
|
516
|
+
|
517
|
+
return {
|
518
|
+
left: preCaretRange.toString().length,
|
519
|
+
right: postCaretRange.toString().length
|
520
|
+
};
|
521
|
+
},
|
522
|
+
|
523
|
+
// http://stackoverflow.com/questions/15867542/range-object-get-selection-parent-node-chrome-vs-firefox
|
524
|
+
rangeSelectsSingleNode: function (range) {
|
525
|
+
var startNode = range.startContainer;
|
526
|
+
return startNode === range.endContainer &&
|
527
|
+
startNode.hasChildNodes() &&
|
528
|
+
range.endOffset === range.startOffset + 1;
|
529
|
+
},
|
530
|
+
|
531
|
+
getSelectedParentElement: function (range) {
|
532
|
+
var selectedParentElement = null;
|
533
|
+
if (this.rangeSelectsSingleNode(range) && range.startContainer.childNodes[range.startOffset].nodeType !== 3) {
|
534
|
+
selectedParentElement = range.startContainer.childNodes[range.startOffset];
|
535
|
+
} else if (range.startContainer.nodeType === 3) {
|
536
|
+
selectedParentElement = range.startContainer.parentNode;
|
537
|
+
} else {
|
538
|
+
selectedParentElement = range.startContainer;
|
539
|
+
}
|
540
|
+
return selectedParentElement;
|
541
|
+
},
|
542
|
+
|
543
|
+
getSelectionData: function (el) {
|
544
|
+
var tagName;
|
545
|
+
|
546
|
+
if (el && el.tagName) {
|
547
|
+
tagName = el.tagName.toLowerCase();
|
548
|
+
}
|
549
|
+
|
550
|
+
while (el && Util.parentElements.indexOf(tagName) === -1) {
|
551
|
+
el = el.parentNode;
|
552
|
+
if (el && el.tagName) {
|
553
|
+
tagName = el.tagName.toLowerCase();
|
554
|
+
}
|
555
|
+
}
|
556
|
+
|
557
|
+
return {
|
558
|
+
el: el,
|
559
|
+
tagName: tagName
|
560
|
+
};
|
561
|
+
}
|
562
|
+
};
|
563
|
+
}(document, window));
|
564
|
+
|
565
|
+
var DefaultButton,
|
566
|
+
ButtonsData;
|
567
|
+
|
568
|
+
(function (window, document) {
|
569
|
+
'use strict';
|
570
|
+
|
571
|
+
ButtonsData = {
|
572
|
+
'bold': {
|
573
|
+
name: 'bold',
|
574
|
+
action: 'bold',
|
575
|
+
aria: 'bold',
|
576
|
+
tagNames: ['b', 'strong'],
|
577
|
+
style: {
|
578
|
+
prop: 'font-weight',
|
579
|
+
value: '700|bold'
|
580
|
+
},
|
581
|
+
useQueryState: true,
|
582
|
+
contentDefault: '<b>B</b>',
|
583
|
+
contentFA: '<i class="fa fa-bold"></i>',
|
584
|
+
key: 'b'
|
585
|
+
},
|
586
|
+
'italic': {
|
587
|
+
name: 'italic',
|
588
|
+
action: 'italic',
|
589
|
+
aria: 'italic',
|
590
|
+
tagNames: ['i', 'em'],
|
591
|
+
style: {
|
592
|
+
prop: 'font-style',
|
593
|
+
value: 'italic'
|
594
|
+
},
|
595
|
+
useQueryState: true,
|
596
|
+
contentDefault: '<b><i>I</i></b>',
|
597
|
+
contentFA: '<i class="fa fa-italic"></i>',
|
598
|
+
key: 'i'
|
599
|
+
},
|
600
|
+
'underline': {
|
601
|
+
name: 'underline',
|
602
|
+
action: 'underline',
|
603
|
+
aria: 'underline',
|
604
|
+
tagNames: ['u'],
|
605
|
+
style: {
|
606
|
+
prop: 'text-decoration',
|
607
|
+
value: 'underline'
|
608
|
+
},
|
609
|
+
useQueryState: true,
|
610
|
+
contentDefault: '<b><u>U</u></b>',
|
611
|
+
contentFA: '<i class="fa fa-underline"></i>',
|
612
|
+
key: 'u'
|
613
|
+
},
|
614
|
+
'strikethrough': {
|
615
|
+
name: 'strikethrough',
|
616
|
+
action: 'strikethrough',
|
617
|
+
aria: 'strike through',
|
618
|
+
tagNames: ['strike'],
|
619
|
+
style: {
|
620
|
+
prop: 'text-decoration',
|
621
|
+
value: 'line-through'
|
622
|
+
},
|
623
|
+
useQueryState: true,
|
624
|
+
contentDefault: '<s>A</s>',
|
625
|
+
contentFA: '<i class="fa fa-strikethrough"></i>'
|
626
|
+
},
|
627
|
+
'superscript': {
|
628
|
+
name: 'superscript',
|
629
|
+
action: 'superscript',
|
630
|
+
aria: 'superscript',
|
631
|
+
tagNames: ['sup'],
|
632
|
+
/* firefox doesn't behave the way we want it to, so we CAN'T use queryCommandState for superscript
|
633
|
+
https://github.com/guardian/scribe/blob/master/BROWSERINCONSISTENCIES.md#documentquerycommandstate */
|
634
|
+
// useQueryState: true
|
635
|
+
contentDefault: '<b>x<sup>1</sup></b>',
|
636
|
+
contentFA: '<i class="fa fa-superscript"></i>'
|
637
|
+
},
|
638
|
+
'subscript': {
|
639
|
+
name: 'subscript',
|
640
|
+
action: 'subscript',
|
641
|
+
aria: 'subscript',
|
642
|
+
tagNames: ['sub'],
|
643
|
+
/* firefox doesn't behave the way we want it to, so we CAN'T use queryCommandState for subscript
|
644
|
+
https://github.com/guardian/scribe/blob/master/BROWSERINCONSISTENCIES.md#documentquerycommandstate */
|
645
|
+
// useQueryState: true
|
646
|
+
contentDefault: '<b>x<sub>1</sub></b>',
|
647
|
+
contentFA: '<i class="fa fa-subscript"></i>'
|
648
|
+
},
|
649
|
+
'image': {
|
650
|
+
name: 'image',
|
651
|
+
action: 'image',
|
652
|
+
aria: 'image',
|
653
|
+
tagNames: ['img'],
|
654
|
+
contentDefault: '<b>image</b>',
|
655
|
+
contentFA: '<i class="fa fa-picture-o"></i>'
|
656
|
+
},
|
657
|
+
'quote': {
|
658
|
+
name: 'quote',
|
659
|
+
action: 'append-blockquote',
|
660
|
+
aria: 'blockquote',
|
661
|
+
tagNames: ['blockquote'],
|
662
|
+
contentDefault: '<b>“</b>',
|
663
|
+
contentFA: '<i class="fa fa-quote-right"></i>'
|
664
|
+
},
|
665
|
+
'orderedlist': {
|
666
|
+
name: 'orderedlist',
|
667
|
+
action: 'insertorderedlist',
|
668
|
+
aria: 'ordered list',
|
669
|
+
tagNames: ['ol'],
|
670
|
+
useQueryState: true,
|
671
|
+
contentDefault: '<b>1.</b>',
|
672
|
+
contentFA: '<i class="fa fa-list-ol"></i>'
|
673
|
+
},
|
674
|
+
'unorderedlist': {
|
675
|
+
name: 'unorderedlist',
|
676
|
+
action: 'insertunorderedlist',
|
677
|
+
aria: 'unordered list',
|
678
|
+
tagNames: ['ul'],
|
679
|
+
useQueryState: true,
|
680
|
+
contentDefault: '<b>•</b>',
|
681
|
+
contentFA: '<i class="fa fa-list-ul"></i>'
|
682
|
+
},
|
683
|
+
'pre': {
|
684
|
+
name: 'pre',
|
685
|
+
action: 'append-pre',
|
686
|
+
aria: 'preformatted text',
|
687
|
+
tagNames: ['pre'],
|
688
|
+
contentDefault: '<b>0101</b>',
|
689
|
+
contentFA: '<i class="fa fa-code fa-lg"></i>'
|
690
|
+
},
|
691
|
+
'indent': {
|
692
|
+
name: 'indent',
|
693
|
+
action: 'indent',
|
694
|
+
aria: 'indent',
|
695
|
+
tagNames: [],
|
696
|
+
contentDefault: '<b>→</b>',
|
697
|
+
contentFA: '<i class="fa fa-indent"></i>'
|
698
|
+
},
|
699
|
+
'outdent': {
|
700
|
+
name: 'outdent',
|
701
|
+
action: 'outdent',
|
702
|
+
aria: 'outdent',
|
703
|
+
tagNames: [],
|
704
|
+
contentDefault: '<b>←</b>',
|
705
|
+
contentFA: '<i class="fa fa-outdent"></i>'
|
706
|
+
},
|
707
|
+
'justifyCenter': {
|
708
|
+
name: 'justifyCenter',
|
709
|
+
action: 'justifyCenter',
|
710
|
+
aria: 'center justify',
|
711
|
+
tagNames: [],
|
712
|
+
style: {
|
713
|
+
prop: 'text-align',
|
714
|
+
value: 'center'
|
715
|
+
},
|
716
|
+
useQueryState: true,
|
717
|
+
contentDefault: '<b>C</b>',
|
718
|
+
contentFA: '<i class="fa fa-align-center"></i>'
|
719
|
+
},
|
720
|
+
'justifyFull': {
|
721
|
+
name: 'justifyFull',
|
722
|
+
action: 'justifyFull',
|
723
|
+
aria: 'full justify',
|
724
|
+
tagNames: [],
|
725
|
+
style: {
|
726
|
+
prop: 'text-align',
|
727
|
+
value: 'justify'
|
728
|
+
},
|
729
|
+
useQueryState: true,
|
730
|
+
contentDefault: '<b>J</b>',
|
731
|
+
contentFA: '<i class="fa fa-align-justify"></i>'
|
732
|
+
},
|
733
|
+
'justifyLeft': {
|
734
|
+
name: 'justifyLeft',
|
735
|
+
action: 'justifyLeft',
|
736
|
+
aria: 'left justify',
|
737
|
+
tagNames: [],
|
738
|
+
style: {
|
739
|
+
prop: 'text-align',
|
740
|
+
value: 'left'
|
741
|
+
},
|
742
|
+
useQueryState: true,
|
743
|
+
contentDefault: '<b>L</b>',
|
744
|
+
contentFA: '<i class="fa fa-align-left"></i>'
|
745
|
+
},
|
746
|
+
'justifyRight': {
|
747
|
+
name: 'justifyRight',
|
748
|
+
action: 'justifyRight',
|
749
|
+
aria: 'right justify',
|
750
|
+
tagNames: [],
|
751
|
+
style: {
|
752
|
+
prop: 'text-align',
|
753
|
+
value: 'right'
|
754
|
+
},
|
755
|
+
useQueryState: true,
|
756
|
+
contentDefault: '<b>R</b>',
|
757
|
+
contentFA: '<i class="fa fa-align-right"></i>'
|
758
|
+
},
|
759
|
+
'header1': {
|
760
|
+
name: 'header1',
|
761
|
+
action: function (options) {
|
762
|
+
return 'append-' + options.firstHeader;
|
763
|
+
},
|
764
|
+
aria: function (options) {
|
765
|
+
return options.firstHeader;
|
766
|
+
},
|
767
|
+
tagNames: function (options) {
|
768
|
+
return [options.firstHeader];
|
769
|
+
},
|
770
|
+
contentDefault: '<b>H1</b>'
|
771
|
+
},
|
772
|
+
'header2': {
|
773
|
+
name: 'header2',
|
774
|
+
action: function (options) {
|
775
|
+
return 'append-' + options.secondHeader;
|
776
|
+
},
|
777
|
+
aria: function (options) {
|
778
|
+
return options.secondHeader;
|
779
|
+
},
|
780
|
+
tagNames: function (options) {
|
781
|
+
return [options.secondHeader];
|
782
|
+
},
|
783
|
+
contentDefault: '<b>H2</b>'
|
784
|
+
}
|
785
|
+
};
|
786
|
+
|
787
|
+
DefaultButton = function (options, instance) {
|
788
|
+
this.options = options;
|
789
|
+
this.name = options.name;
|
790
|
+
this.init(instance);
|
791
|
+
};
|
792
|
+
|
793
|
+
DefaultButton.prototype = {
|
794
|
+
init: function (instance) {
|
795
|
+
this.base = instance;
|
796
|
+
|
797
|
+
this.button = this.createButton();
|
798
|
+
this.base.on(this.button, 'click', this.handleClick.bind(this));
|
799
|
+
},
|
800
|
+
getButton: function () {
|
801
|
+
return this.button;
|
802
|
+
},
|
803
|
+
getAction: function () {
|
804
|
+
return (typeof this.options.action === 'function') ? this.options.action(this.base.options) : this.options.action;
|
805
|
+
},
|
806
|
+
getAria: function () {
|
807
|
+
return (typeof this.options.aria === 'function') ? this.options.aria(this.base.options) : this.options.aria;
|
808
|
+
},
|
809
|
+
getTagNames: function () {
|
810
|
+
return (typeof this.options.tagNames === 'function') ? this.options.tagNames(this.base.options) : this.options.tagNames;
|
811
|
+
},
|
812
|
+
createButton: function () {
|
813
|
+
var button = this.base.options.ownerDocument.createElement('button'),
|
814
|
+
content = this.options.contentDefault;
|
815
|
+
button.classList.add('medium-editor-action');
|
816
|
+
button.classList.add('medium-editor-action-' + this.name);
|
817
|
+
button.setAttribute('data-action', this.getAction());
|
818
|
+
button.setAttribute('aria-label', this.getAria());
|
819
|
+
if (this.base.options.buttonLabels) {
|
820
|
+
if (this.base.options.buttonLabels === 'fontawesome' && this.options.contentFA) {
|
821
|
+
content = this.options.contentFA;
|
822
|
+
} else if (typeof this.base.options.buttonLabels === 'object' && this.base.options.buttonLabels[this.name]) {
|
823
|
+
content = this.base.options.buttonLabels[this.options.name];
|
824
|
+
}
|
825
|
+
}
|
826
|
+
button.innerHTML = content;
|
827
|
+
return button;
|
828
|
+
},
|
829
|
+
handleClick: function (evt) {
|
830
|
+
evt.preventDefault();
|
831
|
+
evt.stopPropagation();
|
832
|
+
|
833
|
+
var action = this.getAction();
|
834
|
+
|
835
|
+
if (action) {
|
836
|
+
this.base.execAction(action);
|
837
|
+
}
|
838
|
+
},
|
839
|
+
isActive: function () {
|
840
|
+
return this.button.classList.contains(this.base.options.activeButtonClass);
|
841
|
+
},
|
842
|
+
setInactive: function () {
|
843
|
+
this.button.classList.remove(this.base.options.activeButtonClass);
|
844
|
+
delete this.knownState;
|
845
|
+
},
|
846
|
+
setActive: function () {
|
847
|
+
this.button.classList.add(this.base.options.activeButtonClass);
|
848
|
+
delete this.knownState;
|
849
|
+
},
|
850
|
+
queryCommandState: function () {
|
851
|
+
var queryState = null;
|
852
|
+
if (this.options.useQueryState) {
|
853
|
+
queryState = this.base.queryCommandState(this.getAction());
|
854
|
+
}
|
855
|
+
return queryState;
|
856
|
+
},
|
857
|
+
isAlreadyApplied: function (node) {
|
858
|
+
var isMatch = false,
|
859
|
+
tagNames = this.getTagNames(),
|
860
|
+
styleVals,
|
861
|
+
computedStyle;
|
862
|
+
|
863
|
+
if (this.knownState === false || this.knownState === true) {
|
864
|
+
return this.knownState;
|
865
|
+
}
|
866
|
+
|
867
|
+
if (tagNames && tagNames.length > 0 && node.tagName) {
|
868
|
+
isMatch = tagNames.indexOf(node.tagName.toLowerCase()) !== -1;
|
869
|
+
}
|
870
|
+
|
871
|
+
if (!isMatch && this.options.style) {
|
872
|
+
styleVals = this.options.style.value.split('|');
|
873
|
+
computedStyle = this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.options.style.prop);
|
874
|
+
styleVals.forEach(function (val) {
|
875
|
+
if (!this.knownState) {
|
876
|
+
this.knownState = isMatch = (computedStyle.indexOf(val) !== -1);
|
877
|
+
}
|
878
|
+
}.bind(this));
|
879
|
+
}
|
880
|
+
|
881
|
+
return isMatch;
|
882
|
+
}
|
883
|
+
};
|
884
|
+
}(window, document));
|
885
|
+
|
886
|
+
var pasteHandler;
|
887
|
+
|
888
|
+
(function (window, document) {
|
889
|
+
'use strict';
|
890
|
+
/*jslint regexp: true*/
|
891
|
+
/*
|
892
|
+
jslint does not allow character negation, because the negation
|
893
|
+
will not match any unicode characters. In the regexes in this
|
894
|
+
block, negation is used specifically to match the end of an html
|
895
|
+
tag, and in fact unicode characters *should* be allowed.
|
896
|
+
*/
|
897
|
+
function createReplacements() {
|
898
|
+
return [
|
899
|
+
|
900
|
+
// replace two bogus tags that begin pastes from google docs
|
901
|
+
[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ""],
|
902
|
+
[new RegExp(/<\/b>(<br[^>]*>)?$/gi), ""],
|
903
|
+
|
904
|
+
// un-html spaces and newlines inserted by OS X
|
905
|
+
[new RegExp(/<span class="Apple-converted-space">\s+<\/span>/g), ' '],
|
906
|
+
[new RegExp(/<br class="Apple-interchange-newline">/g), '<br>'],
|
907
|
+
|
908
|
+
// replace google docs italics+bold with a span to be replaced once the html is inserted
|
909
|
+
[new RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi), '<span class="replace-with italic bold">'],
|
910
|
+
|
911
|
+
// replace google docs italics with a span to be replaced once the html is inserted
|
912
|
+
[new RegExp(/<span[^>]*font-style:italic[^>]*>/gi), '<span class="replace-with italic">'],
|
913
|
+
|
914
|
+
//[replace google docs bolds with a span to be replaced once the html is inserted
|
915
|
+
[new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi), '<span class="replace-with bold">'],
|
916
|
+
|
917
|
+
// replace manually entered b/i/a tags with real ones
|
918
|
+
[new RegExp(/<(\/?)(i|b|a)>/gi), '<$1$2>'],
|
919
|
+
|
920
|
+
// replace manually a tags with real ones, converting smart-quotes from google docs
|
921
|
+
[new RegExp(/<a\s+href=("|”|“|“|”)([^&]+)("|”|“|“|”)>/gi), '<a href="$2">']
|
922
|
+
|
923
|
+
];
|
924
|
+
}
|
925
|
+
/*jslint regexp: false*/
|
926
|
+
|
927
|
+
pasteHandler = {
|
928
|
+
handlePaste: function (element, evt, options) {
|
929
|
+
var paragraphs,
|
930
|
+
html = '',
|
931
|
+
p,
|
932
|
+
dataFormatHTML = 'text/html',
|
933
|
+
dataFormatPlain = 'text/plain';
|
934
|
+
|
935
|
+
element.classList.remove('medium-editor-placeholder');
|
936
|
+
if (!options.forcePlainText && !options.cleanPastedHTML) {
|
937
|
+
return element;
|
938
|
+
}
|
939
|
+
|
940
|
+
if (options.contentWindow.clipboardData && evt.clipboardData === undefined) {
|
941
|
+
evt.clipboardData = options.contentWindow.clipboardData;
|
942
|
+
// If window.clipboardData exists, but e.clipboardData doesn't exist,
|
943
|
+
// we're probably in IE. IE only has two possibilities for clipboard
|
944
|
+
// data format: 'Text' and 'URL'.
|
945
|
+
//
|
946
|
+
// Of the two, we want 'Text':
|
947
|
+
dataFormatHTML = 'Text';
|
948
|
+
dataFormatPlain = 'Text';
|
949
|
+
}
|
950
|
+
|
951
|
+
if (evt.clipboardData && evt.clipboardData.getData && !evt.defaultPrevented) {
|
952
|
+
evt.preventDefault();
|
953
|
+
|
954
|
+
if (options.cleanPastedHTML && evt.clipboardData.getData(dataFormatHTML)) {
|
955
|
+
return this.cleanPaste(evt.clipboardData.getData(dataFormatHTML), options);
|
956
|
+
}
|
957
|
+
if (!(options.disableReturn || element.getAttribute('data-disable-return'))) {
|
958
|
+
paragraphs = evt.clipboardData.getData(dataFormatPlain).split(/[\r\n]/g);
|
959
|
+
for (p = 0; p < paragraphs.length; p += 1) {
|
960
|
+
if (paragraphs[p] !== '') {
|
961
|
+
html += '<p>' + Util.htmlEntities(paragraphs[p]) + '</p>';
|
962
|
+
}
|
963
|
+
}
|
964
|
+
Util.insertHTMLCommand(options.ownerDocument, html);
|
965
|
+
} else {
|
966
|
+
html = Util.htmlEntities(evt.clipboardData.getData(dataFormatPlain));
|
967
|
+
Util.insertHTMLCommand(options.ownerDocument, html);
|
968
|
+
}
|
969
|
+
}
|
970
|
+
},
|
971
|
+
|
972
|
+
cleanPaste: function (text, options) {
|
973
|
+
var i, elList, workEl,
|
974
|
+
el = Selection.getSelectionElement(options.contentWindow),
|
975
|
+
multiline = /<p|<br|<div/.test(text),
|
976
|
+
replacements = createReplacements();
|
977
|
+
|
978
|
+
for (i = 0; i < replacements.length; i += 1) {
|
979
|
+
text = text.replace(replacements[i][0], replacements[i][1]);
|
980
|
+
}
|
981
|
+
|
982
|
+
if (multiline) {
|
983
|
+
// double br's aren't converted to p tags, but we want paragraphs.
|
984
|
+
elList = text.split('<br><br>');
|
985
|
+
|
986
|
+
this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>', options.ownerDocument);
|
987
|
+
|
988
|
+
try {
|
989
|
+
options.ownerDocument.execCommand('insertText', false, "\n");
|
990
|
+
} catch (ignore) { }
|
991
|
+
|
992
|
+
// block element cleanup
|
993
|
+
elList = el.querySelectorAll('a,p,div,br');
|
994
|
+
for (i = 0; i < elList.length; i += 1) {
|
995
|
+
workEl = elList[i];
|
996
|
+
|
997
|
+
switch (workEl.tagName.toLowerCase()) {
|
998
|
+
case 'a':
|
999
|
+
if (options.targetBlank) {
|
1000
|
+
Util.setTargetBlank(workEl);
|
1001
|
+
}
|
1002
|
+
break;
|
1003
|
+
case 'p':
|
1004
|
+
case 'div':
|
1005
|
+
this.filterCommonBlocks(workEl);
|
1006
|
+
break;
|
1007
|
+
case 'br':
|
1008
|
+
this.filterLineBreak(workEl);
|
1009
|
+
break;
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
} else {
|
1013
|
+
this.pasteHTML(text, options.ownerDocument);
|
1014
|
+
}
|
1015
|
+
},
|
1016
|
+
|
1017
|
+
pasteHTML: function (html, ownerDocument) {
|
1018
|
+
var elList, workEl, i, fragmentBody, pasteBlock = ownerDocument.createDocumentFragment();
|
1019
|
+
|
1020
|
+
pasteBlock.appendChild(ownerDocument.createElement('body'));
|
1021
|
+
|
1022
|
+
fragmentBody = pasteBlock.querySelector('body');
|
1023
|
+
fragmentBody.innerHTML = html;
|
1024
|
+
|
1025
|
+
this.cleanupSpans(fragmentBody, ownerDocument);
|
1026
|
+
|
1027
|
+
elList = fragmentBody.querySelectorAll('*');
|
1028
|
+
for (i = 0; i < elList.length; i += 1) {
|
1029
|
+
workEl = elList[i];
|
1030
|
+
|
1031
|
+
// delete ugly attributes
|
1032
|
+
workEl.removeAttribute('class');
|
1033
|
+
workEl.removeAttribute('style');
|
1034
|
+
workEl.removeAttribute('dir');
|
1035
|
+
|
1036
|
+
if (workEl.tagName.toLowerCase() === 'meta') {
|
1037
|
+
workEl.parentNode.removeChild(workEl);
|
1038
|
+
}
|
1039
|
+
}
|
1040
|
+
Util.insertHTMLCommand(ownerDocument, fragmentBody.innerHTML.replace(/ /g, ' '));
|
1041
|
+
},
|
1042
|
+
isCommonBlock: function (el) {
|
1043
|
+
return (el && (el.tagName.toLowerCase() === 'p' || el.tagName.toLowerCase() === 'div'));
|
1044
|
+
},
|
1045
|
+
filterCommonBlocks: function (el) {
|
1046
|
+
if (/^\s*$/.test(el.textContent)) {
|
1047
|
+
el.parentNode.removeChild(el);
|
1048
|
+
}
|
1049
|
+
},
|
1050
|
+
filterLineBreak: function (el) {
|
1051
|
+
if (this.isCommonBlock(el.previousElementSibling)) {
|
1052
|
+
// remove stray br's following common block elements
|
1053
|
+
this.removeWithParent(el);
|
1054
|
+
} else if (this.isCommonBlock(el.parentNode) && (el.parentNode.firstChild === el || el.parentNode.lastChild === el)) {
|
1055
|
+
// remove br's just inside open or close tags of a div/p
|
1056
|
+
this.removeWithParent(el);
|
1057
|
+
} else if (el.parentNode.childElementCount === 1 && el.parentNode.textContent === '') {
|
1058
|
+
// and br's that are the only child of elements other than div/p
|
1059
|
+
this.removeWithParent(el);
|
1060
|
+
}
|
1061
|
+
},
|
1062
|
+
|
1063
|
+
// remove an element, including its parent, if it is the only element within its parent
|
1064
|
+
removeWithParent: function (el) {
|
1065
|
+
if (el && el.parentNode) {
|
1066
|
+
if (el.parentNode.parentNode && el.parentNode.childElementCount === 1) {
|
1067
|
+
el.parentNode.parentNode.removeChild(el.parentNode);
|
1068
|
+
} else {
|
1069
|
+
el.parentNode.removeChild(el);
|
1070
|
+
}
|
1071
|
+
}
|
1072
|
+
},
|
15
1073
|
|
16
|
-
|
17
|
-
|
1074
|
+
cleanupSpans: function (container_el, ownerDocument) {
|
1075
|
+
var i,
|
1076
|
+
el,
|
1077
|
+
new_el,
|
1078
|
+
spans = container_el.querySelectorAll('.replace-with'),
|
1079
|
+
isCEF = function (el) {
|
1080
|
+
return (el && el.nodeName !== '#text' && el.getAttribute('contenteditable') === 'false');
|
1081
|
+
};
|
18
1082
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
1083
|
+
for (i = 0; i < spans.length; i += 1) {
|
1084
|
+
el = spans[i];
|
1085
|
+
new_el = ownerDocument.createElement(el.classList.contains('bold') ? 'b' : 'i');
|
1086
|
+
|
1087
|
+
if (el.classList.contains('bold') && el.classList.contains('italic')) {
|
1088
|
+
// add an i tag as well if this has both italics and bold
|
1089
|
+
new_el.innerHTML = '<i>' + el.innerHTML + '</i>';
|
1090
|
+
} else {
|
1091
|
+
new_el.innerHTML = el.innerHTML;
|
1092
|
+
}
|
1093
|
+
el.parentNode.replaceChild(new_el, el);
|
1094
|
+
}
|
1095
|
+
|
1096
|
+
spans = container_el.querySelectorAll('span');
|
1097
|
+
for (i = 0; i < spans.length; i += 1) {
|
1098
|
+
el = spans[i];
|
1099
|
+
|
1100
|
+
// bail if span is in contenteditable = false
|
1101
|
+
if (Util.traverseUp(el, isCEF)) {
|
1102
|
+
return false;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
// remove empty spans, replace others with their contents
|
1106
|
+
if (/^\s*$/.test()) {
|
1107
|
+
el.parentNode.removeChild(el);
|
1108
|
+
} else {
|
1109
|
+
el.parentNode.replaceChild(ownerDocument.createTextNode(el.textContent), el);
|
1110
|
+
}
|
27
1111
|
}
|
28
1112
|
}
|
29
|
-
|
1113
|
+
};
|
1114
|
+
}(window, document));
|
1115
|
+
|
1116
|
+
var AnchorExtension;
|
1117
|
+
|
1118
|
+
(function (window, document) {
|
1119
|
+
'use strict';
|
1120
|
+
|
1121
|
+
function AnchorDerived() {
|
1122
|
+
this.parent = true;
|
1123
|
+
this.options = {
|
1124
|
+
name: 'anchor',
|
1125
|
+
action: 'createLink',
|
1126
|
+
aria: 'link',
|
1127
|
+
tagNames: ['a'],
|
1128
|
+
contentDefault: '<b>#</b>',
|
1129
|
+
contentFA: '<i class="fa fa-link"></i>'
|
1130
|
+
};
|
1131
|
+
this.name = 'anchor';
|
1132
|
+
this.hasForm = true;
|
30
1133
|
}
|
31
1134
|
|
32
|
-
|
33
|
-
var now = Date.now || function () {
|
34
|
-
return new Date().getTime();
|
35
|
-
};
|
1135
|
+
AnchorDerived.prototype = {
|
36
1136
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
previous = 0,
|
45
|
-
later;
|
46
|
-
|
47
|
-
if (!wait && wait !== 0) {
|
48
|
-
wait = THROTTLE_INTERVAL;
|
49
|
-
}
|
1137
|
+
// Button and Extension handling
|
1138
|
+
|
1139
|
+
// Called when the button the toolbar is clicked
|
1140
|
+
// Overrides DefaultButton.handleClick
|
1141
|
+
handleClick: function (evt) {
|
1142
|
+
evt.preventDefault();
|
1143
|
+
evt.stopPropagation();
|
50
1144
|
|
51
|
-
|
52
|
-
|
53
|
-
timeout = null;
|
54
|
-
result = func.apply(context, args);
|
55
|
-
if (!timeout) {
|
56
|
-
context = args = null;
|
1145
|
+
if (!this.base.selection) {
|
1146
|
+
this.base.checkSelection();
|
57
1147
|
}
|
58
|
-
};
|
59
1148
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
args = arguments;
|
65
|
-
if (remaining <= 0 || remaining > wait) {
|
66
|
-
clearTimeout(timeout);
|
67
|
-
timeout = null;
|
68
|
-
previous = currNow;
|
69
|
-
result = func.apply(context, args);
|
70
|
-
if (!timeout) {
|
71
|
-
context = args = null;
|
72
|
-
}
|
73
|
-
} else if (!timeout) {
|
74
|
-
timeout = setTimeout(later, remaining);
|
1149
|
+
var selectedParentElement = Selection.getSelectedParentElement(this.base.selectionRange);
|
1150
|
+
if (selectedParentElement.tagName &&
|
1151
|
+
selectedParentElement.tagName.toLowerCase() === 'a') {
|
1152
|
+
return this.base.execAction('unlink');
|
75
1153
|
}
|
76
|
-
return result;
|
77
|
-
};
|
78
|
-
}
|
79
1154
|
|
80
|
-
|
81
|
-
|
82
|
-
while (node !== null) {
|
83
|
-
if (node === parent) {
|
84
|
-
return true;
|
1155
|
+
if (!this.isDisplayed()) {
|
1156
|
+
this.showForm();
|
85
1157
|
}
|
86
|
-
node = node.parentNode;
|
87
|
-
}
|
88
|
-
return false;
|
89
|
-
}
|
90
1158
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
function findAdjacentTextNodeWithContent(rootNode, targetNode, ownerDocument) {
|
99
|
-
var pastTarget = false,
|
100
|
-
nextNode,
|
101
|
-
nodeIterator = ownerDocument.createNodeIterator(rootNode, NodeFilter.SHOW_TEXT, null, false);
|
102
|
-
|
103
|
-
// Use a native NodeIterator to iterate over all the text nodes that are descendants
|
104
|
-
// of the rootNode. Once past the targetNode, choose the first non-empty text node
|
105
|
-
nextNode = nodeIterator.nextNode();
|
106
|
-
while (nextNode) {
|
107
|
-
if (nextNode === targetNode) {
|
108
|
-
pastTarget = true;
|
109
|
-
} else if (pastTarget) {
|
110
|
-
if (nextNode.nodeType === 3 && nextNode.nodeValue && nextNode.nodeValue.trim().length > 0) {
|
111
|
-
break;
|
112
|
-
}
|
1159
|
+
return false;
|
1160
|
+
},
|
1161
|
+
|
1162
|
+
// Called by medium-editor to append form to the toolbar
|
1163
|
+
getForm: function () {
|
1164
|
+
if (!this.anchorForm) {
|
1165
|
+
this.anchorForm = this.createForm();
|
113
1166
|
}
|
114
|
-
|
115
|
-
}
|
1167
|
+
return this.anchorForm;
|
1168
|
+
},
|
116
1169
|
|
117
|
-
|
118
|
-
|
1170
|
+
// Used by medium-editor when the default toolbar is to be displayed
|
1171
|
+
isDisplayed: function () {
|
1172
|
+
return this.getForm().style.display === 'block';
|
1173
|
+
},
|
119
1174
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
1175
|
+
hideForm: function () {
|
1176
|
+
this.getForm().style.display = 'none';
|
1177
|
+
this.getInput().value = '';
|
1178
|
+
},
|
1179
|
+
|
1180
|
+
showForm: function (link_value) {
|
1181
|
+
var input = this.getInput();
|
1182
|
+
|
1183
|
+
this.base.saveSelection();
|
1184
|
+
this.base.hideToolbarDefaultActions();
|
1185
|
+
this.getForm().style.display = 'block';
|
1186
|
+
this.base.setToolbarPosition();
|
1187
|
+
this.base.keepToolbarAlive = true;
|
1188
|
+
|
1189
|
+
input.value = link_value || '';
|
1190
|
+
input.focus();
|
1191
|
+
},
|
1192
|
+
|
1193
|
+
// Called by core when tearing down medium-editor (deactivate)
|
1194
|
+
deactivate: function () {
|
1195
|
+
if (!this.anchorForm) {
|
1196
|
+
return false;
|
131
1197
|
}
|
132
|
-
return ranges;
|
133
|
-
}
|
134
|
-
return null;
|
135
|
-
}
|
136
1198
|
|
137
|
-
|
138
|
-
|
139
|
-
len,
|
140
|
-
sel = this.options.contentWindow.getSelection();
|
141
|
-
if (savedSel) {
|
142
|
-
sel.removeAllRanges();
|
143
|
-
for (i = 0, len = savedSel.length; i < len; i += 1) {
|
144
|
-
sel.addRange(savedSel[i]);
|
1199
|
+
if (this.anchorForm.parentNode) {
|
1200
|
+
this.anchorForm.parentNode.removeChild(this.anchorForm);
|
145
1201
|
}
|
146
|
-
}
|
147
|
-
}
|
148
1202
|
|
149
|
-
|
150
|
-
|
151
|
-
function getSelectionStart() {
|
152
|
-
var node = this.options.ownerDocument.getSelection().anchorNode,
|
153
|
-
startNode = (node && node.nodeType === 3 ? node.parentNode : node);
|
154
|
-
return startNode;
|
155
|
-
}
|
1203
|
+
delete this.anchorForm;
|
1204
|
+
},
|
156
1205
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
container.appendChild(sel.getRangeAt(i).cloneContents());
|
171
|
-
}
|
172
|
-
html = container.innerHTML;
|
1206
|
+
// core methods
|
1207
|
+
|
1208
|
+
doLinkCreation: function () {
|
1209
|
+
var targetCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-target'),
|
1210
|
+
buttonCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-button'),
|
1211
|
+
opts = {
|
1212
|
+
url: this.getInput().value
|
1213
|
+
};
|
1214
|
+
|
1215
|
+
this.base.restoreSelection();
|
1216
|
+
|
1217
|
+
if (this.base.options.checkLinkFormat) {
|
1218
|
+
opts.url = this.checkLinkFormat(opts.url);
|
173
1219
|
}
|
174
|
-
|
175
|
-
if (
|
176
|
-
|
1220
|
+
|
1221
|
+
if (targetCheckbox && targetCheckbox.checked) {
|
1222
|
+
opts.target = "_blank";
|
1223
|
+
} else {
|
1224
|
+
opts.target = "_self";
|
177
1225
|
}
|
178
|
-
}
|
179
|
-
return html;
|
180
|
-
}
|
181
1226
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
var preCaretRange, postCaretRange;
|
191
|
-
|
192
|
-
if (!range) {
|
193
|
-
range = window.getSelection().getRangeAt(0);
|
194
|
-
}
|
1227
|
+
if (buttonCheckbox && buttonCheckbox.checked) {
|
1228
|
+
opts.buttonClass = this.base.options.anchorButtonClass;
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
this.base.createLink(opts);
|
1232
|
+
this.base.keepToolbarAlive = false;
|
1233
|
+
this.base.checkSelection();
|
1234
|
+
},
|
195
1235
|
|
196
|
-
|
197
|
-
|
1236
|
+
checkLinkFormat: function (value) {
|
1237
|
+
var re = /^(https?|ftps?|rtmpt?):\/\/|mailto:/;
|
1238
|
+
return (re.test(value) ? '' : 'http://') + value;
|
1239
|
+
},
|
198
1240
|
|
199
|
-
|
200
|
-
|
1241
|
+
doFormCancel: function () {
|
1242
|
+
this.base.restoreSelection();
|
1243
|
+
this.base.keepToolbarAlive = false;
|
1244
|
+
this.base.checkSelection();
|
1245
|
+
},
|
201
1246
|
|
202
|
-
|
203
|
-
postCaretRange.setStart(range.endContainer, range.endOffset);
|
1247
|
+
// form creation and event handling
|
204
1248
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
1249
|
+
createForm: function () {
|
1250
|
+
var doc = this.base.options.ownerDocument,
|
1251
|
+
form = doc.createElement('div'),
|
1252
|
+
input = doc.createElement('input'),
|
1253
|
+
close = doc.createElement('a'),
|
1254
|
+
save = doc.createElement('a'),
|
1255
|
+
target,
|
1256
|
+
target_label,
|
1257
|
+
button,
|
1258
|
+
button_label;
|
210
1259
|
|
1260
|
+
// Anchor Form (div)
|
1261
|
+
form.className = 'medium-editor-toolbar-form';
|
1262
|
+
form.id = 'medium-editor-toolbar-form-anchor-' + this.base.id;
|
211
1263
|
|
212
|
-
|
213
|
-
|
214
|
-
return !!(obj && obj.nodeType === 1);
|
215
|
-
}
|
1264
|
+
// Handle clicks on the form itself
|
1265
|
+
this.base.on(form, 'click', this.handleFormClick.bind(this));
|
216
1266
|
|
217
|
-
|
218
|
-
|
219
|
-
|
1267
|
+
// Add url textbox
|
1268
|
+
input.setAttribute('type', 'text');
|
1269
|
+
input.className = 'medium-editor-toolbar-input';
|
1270
|
+
input.setAttribute('placeholder', this.base.options.anchorInputPlaceholder);
|
1271
|
+
form.appendChild(input);
|
220
1272
|
|
221
|
-
|
222
|
-
|
223
|
-
return doc.execCommand('insertHTML', false, html);
|
224
|
-
} catch (ignore) {}
|
225
|
-
}
|
1273
|
+
// Handle typing in the textbox
|
1274
|
+
this.base.on(input, 'keyup', this.handleTextboxKeyup.bind(this));
|
226
1275
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
1276
|
+
// Handle clicks into the textbox
|
1277
|
+
this.base.on(input, 'click', this.handleFormClick.bind(this));
|
1278
|
+
|
1279
|
+
// Add save buton
|
1280
|
+
save.setAttribute('href', '#');
|
1281
|
+
save.className = 'medium-editor-toobar-save';
|
1282
|
+
save.innerHTML = this.base.options.buttonLabels === 'fontawesome' ?
|
1283
|
+
'<i class="fa fa-check"></i>' :
|
1284
|
+
'✓';
|
1285
|
+
form.appendChild(save);
|
1286
|
+
|
1287
|
+
// Handle save button clicks (capture)
|
1288
|
+
this.base.on(save, 'click', this.handleSaveClick.bind(this), true);
|
1289
|
+
|
1290
|
+
// Add close button
|
1291
|
+
close.setAttribute('href', '#');
|
1292
|
+
close.className = 'medium-editor-toobar-close';
|
1293
|
+
close.innerHTML = this.base.options.buttonLabels === 'fontawesome' ?
|
1294
|
+
'<i class="fa fa-times"></i>' :
|
1295
|
+
'×';
|
1296
|
+
form.appendChild(close);
|
1297
|
+
|
1298
|
+
// Handle close button clicks
|
1299
|
+
this.base.on(close, 'click', this.handleCloseClick.bind(this));
|
1300
|
+
|
1301
|
+
// (Optional) Add 'open in new window' checkbox
|
1302
|
+
if (this.base.options.anchorTarget) {
|
1303
|
+
target = doc.createElement('input');
|
1304
|
+
target.setAttribute('type', 'checkbox');
|
1305
|
+
target.className = 'medium-editor-toolbar-anchor-target';
|
1306
|
+
|
1307
|
+
target_label = doc.createElement('label');
|
1308
|
+
target_label.innerHTML = this.base.options.anchorInputCheckboxLabel;
|
1309
|
+
target_label.insertBefore(target, target_label.firstChild);
|
231
1310
|
|
232
|
-
|
233
|
-
el.innerHTML = html;
|
234
|
-
fragment = doc.createDocumentFragment();
|
235
|
-
while (el.firstChild) {
|
236
|
-
node = el.firstChild;
|
237
|
-
lastNode = fragment.appendChild(node);
|
1311
|
+
form.appendChild(target_label);
|
238
1312
|
}
|
239
|
-
range.insertNode(fragment);
|
240
1313
|
|
241
|
-
//
|
242
|
-
if (
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
1314
|
+
// (Optional) Add 'add button class to anchor' checkbox
|
1315
|
+
if (this.base.options.anchorButton) {
|
1316
|
+
button = doc.createElement('input');
|
1317
|
+
button.setAttribute('type', 'checkbox');
|
1318
|
+
button.className = 'medium-editor-toolbar-anchor-button';
|
1319
|
+
|
1320
|
+
button_label = doc.createElement('label');
|
1321
|
+
button_label.innerHTML = "Button";
|
1322
|
+
button_label.insertBefore(button, button_label.firstChild);
|
1323
|
+
|
1324
|
+
form.appendChild(button_label);
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
// Handle click (capture) & focus (capture) outside of the form
|
1328
|
+
this.base.on(doc.body, 'click', this.handleOutsideInteraction.bind(this), true);
|
1329
|
+
this.base.on(doc.body, 'focus', this.handleOutsideInteraction.bind(this), true);
|
1330
|
+
|
1331
|
+
return form;
|
1332
|
+
},
|
1333
|
+
|
1334
|
+
getInput: function () {
|
1335
|
+
return this.getForm().querySelector('input.medium-editor-toolbar-input');
|
1336
|
+
},
|
1337
|
+
|
1338
|
+
handleOutsideInteraction: function (event) {
|
1339
|
+
if (event.target !== this.getForm() &&
|
1340
|
+
!Util.isDescendant(this.getForm(), event.target) &&
|
1341
|
+
!Util.isDescendant(this.base.toolbarActions, event.target)) {
|
1342
|
+
this.base.keepToolbarAlive = false;
|
1343
|
+
this.base.checkSelection();
|
1344
|
+
}
|
1345
|
+
},
|
1346
|
+
|
1347
|
+
handleTextboxKeyup: function (event) {
|
1348
|
+
// For ENTER -> create the anchor
|
1349
|
+
if (event.keyCode === Util.keyCode.ENTER) {
|
1350
|
+
event.preventDefault();
|
1351
|
+
this.doLinkCreation();
|
1352
|
+
return;
|
1353
|
+
}
|
1354
|
+
|
1355
|
+
// For ESCAPE -> close the form
|
1356
|
+
if (event.keyCode === Util.keyCode.ESCAPE) {
|
1357
|
+
event.preventDefault();
|
1358
|
+
this.doFormCancel();
|
248
1359
|
}
|
1360
|
+
},
|
1361
|
+
|
1362
|
+
handleFormClick: function (event) {
|
1363
|
+
// make sure not to hide form when clicking inside the form
|
1364
|
+
event.stopPropagation();
|
1365
|
+
this.base.keepToolbarAlive = true;
|
1366
|
+
},
|
1367
|
+
|
1368
|
+
handleSaveClick: function (event) {
|
1369
|
+
// Clicking Save -> create the anchor
|
1370
|
+
event.preventDefault();
|
1371
|
+
this.doLinkCreation();
|
1372
|
+
},
|
1373
|
+
|
1374
|
+
handleCloseClick: function (event) {
|
1375
|
+
// Click Close -> close the form
|
1376
|
+
event.preventDefault();
|
1377
|
+
this.doFormCancel();
|
249
1378
|
}
|
250
|
-
}
|
1379
|
+
};
|
1380
|
+
|
1381
|
+
AnchorExtension = Util.derives(DefaultButton, AnchorDerived);
|
1382
|
+
}(window, document));
|
1383
|
+
|
1384
|
+
function MediumEditor(elements, options) {
|
1385
|
+
'use strict';
|
1386
|
+
return this.init(elements, options);
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
(function () {
|
1390
|
+
'use strict';
|
1391
|
+
|
1392
|
+
MediumEditor.statics = {
|
1393
|
+
ButtonsData: ButtonsData,
|
1394
|
+
DefaultButton: DefaultButton,
|
1395
|
+
AnchorExtension: AnchorExtension
|
1396
|
+
};
|
251
1397
|
|
252
1398
|
MediumEditor.prototype = {
|
253
1399
|
defaults: {
|
@@ -266,9 +1412,10 @@ if (typeof module === 'object') {
|
|
266
1412
|
disableDoubleReturn: false,
|
267
1413
|
disableToolbar: false,
|
268
1414
|
disableEditing: false,
|
269
|
-
disableAnchorForm: false,
|
270
1415
|
disablePlaceholders: false,
|
1416
|
+
toolbarAlign: 'center',
|
271
1417
|
elementsContainer: false,
|
1418
|
+
imageDragging: true,
|
272
1419
|
standardizeSelectionStart: false,
|
273
1420
|
contentWindow: window,
|
274
1421
|
ownerDocument: document,
|
@@ -286,19 +1433,15 @@ if (typeof module === 'object') {
|
|
286
1433
|
lastButtonClass: 'medium-editor-button-last'
|
287
1434
|
},
|
288
1435
|
|
289
|
-
// http://stackoverflow.com/questions/17907445/how-to-detect-ie11#comment30165888_17907562
|
290
|
-
// by rg89
|
291
|
-
isIE: ((navigator.appName === 'Microsoft Internet Explorer') || ((navigator.appName === 'Netscape') && (new RegExp('Trident/.*rv:([0-9]{1,}[.0-9]{0,})').exec(navigator.userAgent) !== null))),
|
292
|
-
|
293
1436
|
init: function (elements, options) {
|
294
1437
|
var uniqueId = 1;
|
295
1438
|
|
296
|
-
this.options =
|
1439
|
+
this.options = Util.defaults(options, this.defaults);
|
297
1440
|
this.setElementSelection(elements);
|
298
1441
|
if (this.elements.length === 0) {
|
299
1442
|
return;
|
300
1443
|
}
|
301
|
-
|
1444
|
+
|
302
1445
|
if (!this.options.elementsContainer) {
|
303
1446
|
this.options.elementsContainer = this.options.ownerDocument.body;
|
304
1447
|
}
|
@@ -316,13 +1459,14 @@ if (typeof module === 'object') {
|
|
316
1459
|
this.events = [];
|
317
1460
|
this.isActive = true;
|
318
1461
|
this.initThrottledMethods()
|
1462
|
+
.initCommands()
|
319
1463
|
.initElements()
|
320
1464
|
.bindSelect()
|
1465
|
+
.bindDragDrop()
|
321
1466
|
.bindPaste()
|
322
1467
|
.setPlaceholders()
|
323
1468
|
.bindElementActions()
|
324
1469
|
.bindWindowActions();
|
325
|
-
//.passInstance();
|
326
1470
|
},
|
327
1471
|
|
328
1472
|
on: function (target, event, listener, useCapture) {
|
@@ -373,7 +1517,7 @@ if (typeof module === 'object') {
|
|
373
1517
|
// handleResize is throttled because:
|
374
1518
|
// - It will be called when the browser is resizing, which can fire many times very quickly
|
375
1519
|
// - For some event (like resize) a slight lag in UI responsiveness is OK and provides performance benefits
|
376
|
-
this.handleResize = throttle(function () {
|
1520
|
+
this.handleResize = Util.throttle(function () {
|
377
1521
|
if (self.isActive) {
|
378
1522
|
self.positionToolbarIfShown();
|
379
1523
|
}
|
@@ -383,7 +1527,7 @@ if (typeof module === 'object') {
|
|
383
1527
|
// - This method could be called many times due to the type of event handlers that are calling it
|
384
1528
|
// - We want a slight delay so that other events in the stack can run, some of which may
|
385
1529
|
// prevent the toolbar from being hidden (via this.keepToolbarAlive).
|
386
|
-
this.handleBlur = throttle(function () {
|
1530
|
+
this.handleBlur = Util.throttle(function () {
|
387
1531
|
if (self.isActive && !self.keepToolbarAlive) {
|
388
1532
|
self.hideToolbarActions();
|
389
1533
|
}
|
@@ -412,11 +1556,8 @@ if (typeof module === 'object') {
|
|
412
1556
|
}
|
413
1557
|
// Init toolbar
|
414
1558
|
if (addToolbar) {
|
415
|
-
this.
|
416
|
-
.
|
417
|
-
.initToolbar()
|
418
|
-
.bindButtons()
|
419
|
-
.bindAnchorForm()
|
1559
|
+
this.initToolbar()
|
1560
|
+
.setFirstAndLastButtons()
|
420
1561
|
.bindAnchorPreview();
|
421
1562
|
}
|
422
1563
|
return this;
|
@@ -431,7 +1572,7 @@ if (typeof module === 'object') {
|
|
431
1572
|
selector = this.options.ownerDocument.querySelectorAll(selector);
|
432
1573
|
}
|
433
1574
|
// If element, put into array
|
434
|
-
if (isElement(selector)) {
|
1575
|
+
if (Util.isElement(selector)) {
|
435
1576
|
selector = [selector];
|
436
1577
|
}
|
437
1578
|
// Convert NodeList (or other array like object) into an array
|
@@ -442,9 +1583,18 @@ if (typeof module === 'object') {
|
|
442
1583
|
var self = this,
|
443
1584
|
blurFunction = function (e) {
|
444
1585
|
var isDescendantOfEditorElements = false,
|
1586
|
+
selection = self.options.contentWindow.getSelection(),
|
1587
|
+
selRange = selection.isCollapsed ?
|
1588
|
+
null :
|
1589
|
+
Selection.getSelectedParentElement(selection.getRangeAt(0)),
|
445
1590
|
i;
|
1591
|
+
|
1592
|
+
// This control was introduced also to avoid the toolbar
|
1593
|
+
// to disapper when selecting from right to left and
|
1594
|
+
// the selection ends at the beginning of the text.
|
446
1595
|
for (i = 0; i < self.elements.length; i += 1) {
|
447
|
-
if (isDescendant(self.elements[i], e.target)
|
1596
|
+
if (Util.isDescendant(self.elements[i], e.target)
|
1597
|
+
|| Util.isDescendant(self.elements[i], selRange)) {
|
448
1598
|
isDescendantOfEditorElements = true;
|
449
1599
|
break;
|
450
1600
|
}
|
@@ -453,8 +1603,8 @@ if (typeof module === 'object') {
|
|
453
1603
|
if (e.target !== self.toolbar
|
454
1604
|
&& self.elements.indexOf(e.target) === -1
|
455
1605
|
&& !isDescendantOfEditorElements
|
456
|
-
&& !isDescendant(self.toolbar, e.target)
|
457
|
-
&& !isDescendant(self.anchorPreview, e.target)) {
|
1606
|
+
&& !Util.isDescendant(self.toolbar, e.target)
|
1607
|
+
&& !Util.isDescendant(self.anchorPreview, e.target)) {
|
458
1608
|
|
459
1609
|
// Activate the placeholder
|
460
1610
|
if (!self.options.disablePlaceholders) {
|
@@ -507,7 +1657,6 @@ if (typeof module === 'object') {
|
|
507
1657
|
// Bind the return and tab keypress events
|
508
1658
|
this.bindReturn(i)
|
509
1659
|
.bindKeydown(i)
|
510
|
-
.bindBlur()
|
511
1660
|
.bindClick(i);
|
512
1661
|
}
|
513
1662
|
|
@@ -544,6 +1693,60 @@ if (typeof module === 'object') {
|
|
544
1693
|
return content;
|
545
1694
|
},
|
546
1695
|
|
1696
|
+
initExtension: function (extension, name) {
|
1697
|
+
if (extension.parent) {
|
1698
|
+
extension.base = this;
|
1699
|
+
}
|
1700
|
+
if (typeof extension.init === 'function') {
|
1701
|
+
extension.init(this);
|
1702
|
+
}
|
1703
|
+
if (!extension.name) {
|
1704
|
+
extension.name = name;
|
1705
|
+
}
|
1706
|
+
return extension;
|
1707
|
+
},
|
1708
|
+
|
1709
|
+
initCommands: function () {
|
1710
|
+
var buttons = this.options.buttons,
|
1711
|
+
extensions = this.options.extensions,
|
1712
|
+
ext,
|
1713
|
+
name;
|
1714
|
+
this.commands = [];
|
1715
|
+
|
1716
|
+
buttons.forEach(function (buttonName) {
|
1717
|
+
if (extensions[buttonName]) {
|
1718
|
+
ext = this.initExtension(extensions[buttonName], buttonName);
|
1719
|
+
this.commands.push(ext);
|
1720
|
+
} else if (buttonName === 'anchor') {
|
1721
|
+
ext = this.initExtension(new AnchorExtension(), buttonName);
|
1722
|
+
this.commands.push(ext);
|
1723
|
+
} else if (ButtonsData.hasOwnProperty(buttonName)) {
|
1724
|
+
ext = new DefaultButton(ButtonsData[buttonName], this);
|
1725
|
+
this.commands.push(ext);
|
1726
|
+
}
|
1727
|
+
}.bind(this));
|
1728
|
+
|
1729
|
+
for (name in extensions) {
|
1730
|
+
if (extensions.hasOwnProperty(name) && buttons.indexOf(name) === -1) {
|
1731
|
+
ext = this.initExtension(extensions[name], name);
|
1732
|
+
}
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
return this;
|
1736
|
+
},
|
1737
|
+
|
1738
|
+
getExtensionByName: function (name) {
|
1739
|
+
var extension;
|
1740
|
+
if (this.commands && this.commands.length) {
|
1741
|
+
this.commands.forEach(function (ext) {
|
1742
|
+
if (ext.name === name) {
|
1743
|
+
extension = ext;
|
1744
|
+
}
|
1745
|
+
});
|
1746
|
+
}
|
1747
|
+
return extension;
|
1748
|
+
},
|
1749
|
+
|
547
1750
|
/**
|
548
1751
|
* Helper function to call a method with a number of parameters on all registered extensions.
|
549
1752
|
* The function assures that the function exists before calling.
|
@@ -571,36 +1774,13 @@ if (typeof module === 'object') {
|
|
571
1774
|
return this;
|
572
1775
|
},
|
573
1776
|
|
574
|
-
/**
|
575
|
-
* Pass current Medium Editor instance to all extensions
|
576
|
-
* if extension constructor has 'parent' attribute set to 'true'
|
577
|
-
*
|
578
|
-
*/
|
579
|
-
passInstance: function () {
|
580
|
-
var self = this,
|
581
|
-
ext,
|
582
|
-
name;
|
583
|
-
|
584
|
-
for (name in self.options.extensions) {
|
585
|
-
if (self.options.extensions.hasOwnProperty(name)) {
|
586
|
-
ext = self.options.extensions[name];
|
587
|
-
|
588
|
-
if (ext.parent) {
|
589
|
-
ext.base = self;
|
590
|
-
}
|
591
|
-
}
|
592
|
-
}
|
593
|
-
|
594
|
-
return self;
|
595
|
-
},
|
596
|
-
|
597
1777
|
bindParagraphCreation: function (index) {
|
598
1778
|
var self = this;
|
599
1779
|
this.on(this.elements[index], 'keypress', function (e) {
|
600
1780
|
var node,
|
601
1781
|
tagName;
|
602
|
-
if (e.which ===
|
603
|
-
node = getSelectionStart
|
1782
|
+
if (e.which === Util.keyCode.SPACE) {
|
1783
|
+
node = Selection.getSelectionStart(self.options.ownerDocument);
|
604
1784
|
tagName = node.tagName.toLowerCase();
|
605
1785
|
if (tagName === 'a') {
|
606
1786
|
self.options.ownerDocument.execCommand('unlink', false, null);
|
@@ -609,22 +1789,22 @@ if (typeof module === 'object') {
|
|
609
1789
|
});
|
610
1790
|
|
611
1791
|
this.on(this.elements[index], 'keyup', function (e) {
|
612
|
-
var node = getSelectionStart
|
1792
|
+
var node = Selection.getSelectionStart(self.options.ownerDocument),
|
613
1793
|
tagName,
|
614
1794
|
editorElement;
|
615
1795
|
|
616
1796
|
if (node && node.getAttribute('data-medium-element') && node.children.length === 0 && !(self.options.disableReturn || node.getAttribute('data-disable-return'))) {
|
617
1797
|
self.options.ownerDocument.execCommand('formatBlock', false, 'p');
|
618
1798
|
}
|
619
|
-
if (e.which ===
|
620
|
-
node = getSelectionStart
|
1799
|
+
if (e.which === Util.keyCode.ENTER) {
|
1800
|
+
node = Selection.getSelectionStart(self.options.ownerDocument);
|
621
1801
|
tagName = node.tagName.toLowerCase();
|
622
|
-
editorElement =
|
1802
|
+
editorElement = Selection.getSelectionElement(self.options.contentWindow);
|
623
1803
|
|
624
1804
|
if (!(self.options.disableReturn || editorElement.getAttribute('data-disable-return')) &&
|
625
|
-
tagName !== 'li' && !
|
626
|
-
|
627
|
-
|
1805
|
+
tagName !== 'li' && !Util.isListItemChild(node)) {
|
1806
|
+
|
1807
|
+
if (!e.shiftKey && !e.ctrlKey) {
|
628
1808
|
// paragraph creation should not be forced within a header tag
|
629
1809
|
if (!/h\d/.test(tagName)) {
|
630
1810
|
self.options.ownerDocument.execCommand('formatBlock', false, 'p');
|
@@ -639,32 +1819,15 @@ if (typeof module === 'object') {
|
|
639
1819
|
return this;
|
640
1820
|
},
|
641
1821
|
|
642
|
-
isListItemChild: function (node) {
|
643
|
-
var parentNode = node.parentNode,
|
644
|
-
tagName = parentNode.tagName.toLowerCase();
|
645
|
-
while (this.parentElements.indexOf(tagName) === -1 && tagName !== 'div') {
|
646
|
-
if (tagName === 'li') {
|
647
|
-
return true;
|
648
|
-
}
|
649
|
-
parentNode = parentNode.parentNode;
|
650
|
-
if (parentNode && parentNode.tagName) {
|
651
|
-
tagName = parentNode.tagName.toLowerCase();
|
652
|
-
} else {
|
653
|
-
return false;
|
654
|
-
}
|
655
|
-
}
|
656
|
-
return false;
|
657
|
-
},
|
658
|
-
|
659
1822
|
bindReturn: function (index) {
|
660
1823
|
var self = this;
|
661
1824
|
this.on(this.elements[index], 'keypress', function (e) {
|
662
|
-
if (e.which ===
|
1825
|
+
if (e.which === Util.keyCode.ENTER) {
|
663
1826
|
if (self.options.disableReturn || this.getAttribute('data-disable-return')) {
|
664
1827
|
e.preventDefault();
|
665
1828
|
} else if (self.options.disableDoubleReturn || this.getAttribute('data-disable-double-return')) {
|
666
|
-
var node = getSelectionStart
|
667
|
-
if (node && node.textContent === '
|
1829
|
+
var node = Selection.getSelectionStart(self.options.contentWindow);
|
1830
|
+
if (node && node.textContent.trim() === '') {
|
668
1831
|
e.preventDefault();
|
669
1832
|
}
|
670
1833
|
}
|
@@ -676,17 +1839,20 @@ if (typeof module === 'object') {
|
|
676
1839
|
bindKeydown: function (index) {
|
677
1840
|
var self = this;
|
678
1841
|
this.on(this.elements[index], 'keydown', function (e) {
|
1842
|
+
var node, tag, key;
|
679
1843
|
|
680
|
-
if (e.which ===
|
1844
|
+
if (e.which === Util.keyCode.TAB) {
|
681
1845
|
// Override tab only for pre nodes
|
682
|
-
|
1846
|
+
node = Selection.getSelectionStart(self.options.ownerDocument);
|
1847
|
+
tag = node && node.tagName.toLowerCase();
|
1848
|
+
|
683
1849
|
if (tag === 'pre') {
|
684
1850
|
e.preventDefault();
|
685
1851
|
self.options.ownerDocument.execCommand('insertHtml', null, ' ');
|
686
1852
|
}
|
687
1853
|
|
688
1854
|
// Tab to indent list structures!
|
689
|
-
if (tag === 'li') {
|
1855
|
+
if (tag === 'li' || Util.isListItemChild(node)) {
|
690
1856
|
e.preventDefault();
|
691
1857
|
|
692
1858
|
// If Shift is down, outdent, otherwise indent
|
@@ -696,36 +1862,42 @@ if (typeof module === 'object') {
|
|
696
1862
|
self.options.ownerDocument.execCommand('indent', e);
|
697
1863
|
}
|
698
1864
|
}
|
699
|
-
} else if (e.which ===
|
1865
|
+
} else if (e.which === Util.keyCode.BACKSPACE || e.which === Util.keyCode.DELETE || e.which === Util.keyCode.ENTER) {
|
700
1866
|
|
701
1867
|
// Bind keys which can create or destroy a block element: backspace, delete, return
|
702
1868
|
self.onBlockModifier(e);
|
703
1869
|
|
1870
|
+
} else if (e.ctrlKey || e.metaKey) {
|
1871
|
+
key = String.fromCharCode(e.which || e.keyCode).toLowerCase();
|
1872
|
+
self.commands.forEach(function (extension) {
|
1873
|
+
if (extension.options.key && extension.options.key === key) {
|
1874
|
+
extension.handleClick(e);
|
1875
|
+
}
|
1876
|
+
});
|
704
1877
|
}
|
705
1878
|
});
|
706
1879
|
return this;
|
707
1880
|
},
|
708
1881
|
|
709
1882
|
onBlockModifier: function (e) {
|
710
|
-
var range, sel, p, node = getSelectionStart
|
1883
|
+
var range, sel, p, node = Selection.getSelectionStart(this.options.ownerDocument),
|
711
1884
|
tagName = node.tagName.toLowerCase(),
|
712
1885
|
isEmpty = /^(\s+|<br\/?>)?$/i,
|
713
1886
|
isHeader = /h\d/i;
|
714
1887
|
|
715
|
-
|
716
|
-
if ((e.which === 8 || e.which === 13)
|
1888
|
+
if ((e.which === Util.keyCode.BACKSPACE || e.which === Util.keyCode.ENTER)
|
717
1889
|
&& node.previousElementSibling
|
718
1890
|
// in a header
|
719
1891
|
&& isHeader.test(tagName)
|
720
1892
|
// at the very end of the block
|
721
|
-
&& getCaretOffsets(node).left === 0) {
|
722
|
-
if (e.which ===
|
1893
|
+
&& Selection.getCaretOffsets(node).left === 0) {
|
1894
|
+
if (e.which === Util.keyCode.BACKSPACE && isEmpty.test(node.previousElementSibling.innerHTML)) {
|
723
1895
|
// backspacing the begining of a header into an empty previous element will
|
724
1896
|
// change the tagName of the current node to prevent one
|
725
1897
|
// instead delete previous node and cancel the event.
|
726
1898
|
node.previousElementSibling.parentNode.removeChild(node.previousElementSibling);
|
727
1899
|
e.preventDefault();
|
728
|
-
} else if (e.which ===
|
1900
|
+
} else if (e.which === Util.keyCode.ENTER) {
|
729
1901
|
// hitting return in the begining of a header will create empty header elements before the current one
|
730
1902
|
// instead, make "<p><br></p>" element, which are what happens if you hit return in an empty paragraph
|
731
1903
|
p = this.options.ownerDocument.createElement('p');
|
@@ -733,9 +1905,7 @@ if (typeof module === 'object') {
|
|
733
1905
|
node.previousElementSibling.parentNode.insertBefore(p, node);
|
734
1906
|
e.preventDefault();
|
735
1907
|
}
|
736
|
-
|
737
|
-
// delete
|
738
|
-
} else if (e.which === 46
|
1908
|
+
} else if (e.which === Util.keyCode.DELETE
|
739
1909
|
&& node.nextElementSibling
|
740
1910
|
&& node.previousElementSibling
|
741
1911
|
// not in a header
|
@@ -757,100 +1927,12 @@ if (typeof module === 'object') {
|
|
757
1927
|
range.collapse(true);
|
758
1928
|
|
759
1929
|
sel.removeAllRanges();
|
760
|
-
sel.addRange(range);
|
761
|
-
|
762
|
-
node.previousElementSibling.parentNode.removeChild(node);
|
763
|
-
|
764
|
-
e.preventDefault();
|
765
|
-
}
|
766
|
-
|
767
|
-
},
|
1930
|
+
sel.addRange(range);
|
768
1931
|
|
769
|
-
|
770
|
-
var buttonLabels = this.getButtonLabels(this.options.buttonLabels),
|
771
|
-
buttonTemplates = {
|
772
|
-
'bold': '<button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b" aria-label="bold">' + buttonLabels.bold + '</button>',
|
773
|
-
'italic': '<button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i" aria-label="italic">' + buttonLabels.italic + '</button>',
|
774
|
-
'underline': '<button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u" aria-label="underline">' + buttonLabels.underline + '</button>',
|
775
|
-
'strikethrough': '<button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike" aria-label="strike through">' + buttonLabels.strikethrough + '</button>',
|
776
|
-
'superscript': '<button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup" aria-label="superscript">' + buttonLabels.superscript + '</button>',
|
777
|
-
'subscript': '<button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub" aria-label="subscript">' + buttonLabels.subscript + '</button>',
|
778
|
-
'anchor': '<button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a" aria-label="link">' + buttonLabels.anchor + '</button>',
|
779
|
-
'image': '<button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img" aria-label="image">' + buttonLabels.image + '</button>',
|
780
|
-
'header1': '<button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '" aria-label="h1">' + buttonLabels.header1 + '</button>',
|
781
|
-
'header2': '<button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + ' "aria-label="h2">' + buttonLabels.header2 + '</button>',
|
782
|
-
'quote': '<button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote" aria-label="blockquote">' + buttonLabels.quote + '</button>',
|
783
|
-
'orderedlist': '<button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol" aria-label="ordered list">' + buttonLabels.orderedlist + '</button>',
|
784
|
-
'unorderedlist': '<button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul" aria-label="unordered list">' + buttonLabels.unorderedlist + '</button>',
|
785
|
-
'pre': '<button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre" aria-label="preformatted text">' + buttonLabels.pre + '</button>',
|
786
|
-
'indent': '<button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul" aria-label="indent">' + buttonLabels.indent + '</button>',
|
787
|
-
'outdent': '<button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul" aria-label="outdent">' + buttonLabels.outdent + '</button>',
|
788
|
-
'justifyCenter': '<button class="medium-editor-action medium-editor-action-justifyCenter" data-action="justifyCenter" data-element="" aria-label="center justify">' + buttonLabels.justifyCenter + '</button>',
|
789
|
-
'justifyFull': '<button class="medium-editor-action medium-editor-action-justifyFull" data-action="justifyFull" data-element="" aria-label="full justify">' + buttonLabels.justifyFull + '</button>',
|
790
|
-
'justifyLeft': '<button class="medium-editor-action medium-editor-action-justifyLeft" data-action="justifyLeft" data-element="" aria-label="left justify">' + buttonLabels.justifyLeft + '</button>',
|
791
|
-
'justifyRight': '<button class="medium-editor-action medium-editor-action-justifyRight" data-action="justifyRight" data-element="" aria-label="right justify">' + buttonLabels.justifyRight + '</button>'
|
792
|
-
};
|
793
|
-
return buttonTemplates[btnType] || false;
|
794
|
-
},
|
1932
|
+
node.previousElementSibling.parentNode.removeChild(node);
|
795
1933
|
|
796
|
-
|
797
|
-
getButtonLabels: function (buttonLabelType) {
|
798
|
-
var customButtonLabels,
|
799
|
-
attrname,
|
800
|
-
buttonLabels = {
|
801
|
-
'bold': '<b>B</b>',
|
802
|
-
'italic': '<b><i>I</i></b>',
|
803
|
-
'underline': '<b><u>U</u></b>',
|
804
|
-
'strikethrough': '<s>A</s>',
|
805
|
-
'superscript': '<b>x<sup>1</sup></b>',
|
806
|
-
'subscript': '<b>x<sub>1</sub></b>',
|
807
|
-
'anchor': '<b>#</b>',
|
808
|
-
'image': '<b>image</b>',
|
809
|
-
'header1': '<b>H1</b>',
|
810
|
-
'header2': '<b>H2</b>',
|
811
|
-
'quote': '<b>“</b>',
|
812
|
-
'orderedlist': '<b>1.</b>',
|
813
|
-
'unorderedlist': '<b>•</b>',
|
814
|
-
'pre': '<b>0101</b>',
|
815
|
-
'indent': '<b>→</b>',
|
816
|
-
'outdent': '<b>←</b>',
|
817
|
-
'justifyCenter': '<b>C</b>',
|
818
|
-
'justifyFull': '<b>J</b>',
|
819
|
-
'justifyLeft': '<b>L</b>',
|
820
|
-
'justifyRight': '<b>R</b>'
|
821
|
-
};
|
822
|
-
if (buttonLabelType === 'fontawesome') {
|
823
|
-
customButtonLabels = {
|
824
|
-
'bold': '<i class="fa fa-bold"></i>',
|
825
|
-
'italic': '<i class="fa fa-italic"></i>',
|
826
|
-
'underline': '<i class="fa fa-underline"></i>',
|
827
|
-
'strikethrough': '<i class="fa fa-strikethrough"></i>',
|
828
|
-
'superscript': '<i class="fa fa-superscript"></i>',
|
829
|
-
'subscript': '<i class="fa fa-subscript"></i>',
|
830
|
-
'anchor': '<i class="fa fa-link"></i>',
|
831
|
-
'image': '<i class="fa fa-picture-o"></i>',
|
832
|
-
'quote': '<i class="fa fa-quote-right"></i>',
|
833
|
-
'orderedlist': '<i class="fa fa-list-ol"></i>',
|
834
|
-
'unorderedlist': '<i class="fa fa-list-ul"></i>',
|
835
|
-
'pre': '<i class="fa fa-code fa-lg"></i>',
|
836
|
-
'indent': '<i class="fa fa-indent"></i>',
|
837
|
-
'outdent': '<i class="fa fa-outdent"></i>',
|
838
|
-
'justifyCenter': '<i class="fa fa-align-center"></i>',
|
839
|
-
'justifyFull': '<i class="fa fa-align-justify"></i>',
|
840
|
-
'justifyLeft': '<i class="fa fa-align-left"></i>',
|
841
|
-
'justifyRight': '<i class="fa fa-align-right"></i>'
|
842
|
-
};
|
843
|
-
} else if (typeof buttonLabelType === 'object') {
|
844
|
-
customButtonLabels = buttonLabelType;
|
845
|
-
}
|
846
|
-
if (typeof customButtonLabels === 'object') {
|
847
|
-
for (attrname in customButtonLabels) {
|
848
|
-
if (customButtonLabels.hasOwnProperty(attrname)) {
|
849
|
-
buttonLabels[attrname] = customButtonLabels[attrname];
|
850
|
-
}
|
851
|
-
}
|
1934
|
+
e.preventDefault();
|
852
1935
|
}
|
853
|
-
return buttonLabels;
|
854
1936
|
},
|
855
1937
|
|
856
1938
|
initToolbar: function () {
|
@@ -858,17 +1940,10 @@ if (typeof module === 'object') {
|
|
858
1940
|
return this;
|
859
1941
|
}
|
860
1942
|
this.toolbar = this.createToolbar();
|
861
|
-
this.addExtensionForms();
|
862
1943
|
this.keepToolbarAlive = false;
|
863
1944
|
this.toolbarActions = this.toolbar.querySelector('.medium-editor-toolbar-actions');
|
864
1945
|
this.anchorPreview = this.createAnchorPreview();
|
865
1946
|
|
866
|
-
if (!this.options.disableAnchorForm) {
|
867
|
-
this.anchorForm = this.toolbar.querySelector('.medium-editor-toolbar-form');
|
868
|
-
this.anchorInput = this.anchorForm.querySelector('input.medium-editor-toolbar-input');
|
869
|
-
this.anchorTarget = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-target');
|
870
|
-
this.anchorButton = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-button');
|
871
|
-
}
|
872
1947
|
return this;
|
873
1948
|
},
|
874
1949
|
|
@@ -884,145 +1959,127 @@ if (typeof module === 'object') {
|
|
884
1959
|
}
|
885
1960
|
|
886
1961
|
toolbar.appendChild(this.toolbarButtons());
|
887
|
-
|
888
|
-
|
889
|
-
|
1962
|
+
|
1963
|
+
// Add any forms that extensions may have
|
1964
|
+
this.commands.forEach(function (extension) {
|
1965
|
+
if (extension.hasForm) {
|
1966
|
+
toolbar.appendChild(extension.getForm());
|
1967
|
+
}
|
1968
|
+
});
|
1969
|
+
|
890
1970
|
this.options.elementsContainer.appendChild(toolbar);
|
891
1971
|
return toolbar;
|
892
1972
|
},
|
893
1973
|
|
894
1974
|
//TODO: actionTemplate
|
895
1975
|
toolbarButtons: function () {
|
896
|
-
var
|
897
|
-
ul = this.options.ownerDocument.createElement('ul'),
|
1976
|
+
var ul = this.options.ownerDocument.createElement('ul'),
|
898
1977
|
li,
|
899
|
-
|
900
|
-
btn,
|
901
|
-
ext;
|
1978
|
+
btn;
|
902
1979
|
|
903
1980
|
ul.id = 'medium-editor-toolbar-actions' + this.id;
|
904
1981
|
ul.className = 'medium-editor-toolbar-actions clearfix';
|
905
1982
|
|
906
|
-
|
907
|
-
if (
|
908
|
-
|
909
|
-
btn = ext.getButton !== undefined ? ext.getButton(this) : null;
|
910
|
-
if (ext.hasForm) {
|
911
|
-
btn.setAttribute('data-form', 'medium-editor-toolbar-form-' + btns[i] + '-' + this.id);
|
912
|
-
}
|
913
|
-
} else {
|
914
|
-
btn = this.buttonTemplate(btns[i]);
|
915
|
-
}
|
916
|
-
|
917
|
-
if (btn) {
|
1983
|
+
this.commands.forEach(function (extension) {
|
1984
|
+
if (typeof extension.getButton === 'function') {
|
1985
|
+
btn = extension.getButton(this);
|
918
1986
|
li = this.options.ownerDocument.createElement('li');
|
919
|
-
if (isElement(btn)) {
|
1987
|
+
if (Util.isElement(btn)) {
|
920
1988
|
li.appendChild(btn);
|
921
1989
|
} else {
|
922
1990
|
li.innerHTML = btn;
|
923
1991
|
}
|
924
1992
|
ul.appendChild(li);
|
925
1993
|
}
|
926
|
-
}
|
1994
|
+
}.bind(this));
|
927
1995
|
|
928
1996
|
return ul;
|
929
1997
|
},
|
930
1998
|
|
931
|
-
|
932
|
-
var
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
if (ext.hasForm) {
|
942
|
-
form = ext.getForm !== undefined ? ext.getForm() : null;
|
943
|
-
}
|
944
|
-
if (form) {
|
945
|
-
id = 'medium-editor-toolbar-form-' + name + '-' + this.id;
|
946
|
-
form.className = 'medium-editor-toolbar-form';
|
947
|
-
form.id = id;
|
948
|
-
ext.getForm().id = id;
|
949
|
-
this.toolbar.appendChild(form);
|
1999
|
+
bindSelect: function () {
|
2000
|
+
var i,
|
2001
|
+
blurHelper = function (event) {
|
2002
|
+
// Do not close the toolbar when bluring the editable area and clicking into the anchor form
|
2003
|
+
if (event &&
|
2004
|
+
event.type &&
|
2005
|
+
event.type.toLowerCase() === 'blur' &&
|
2006
|
+
event.relatedTarget &&
|
2007
|
+
Util.isDescendant(this.toolbar, event.relatedTarget)) {
|
2008
|
+
return false;
|
950
2009
|
}
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
target_label = this.options.ownerDocument.createElement('label'),
|
959
|
-
target = this.options.ownerDocument.createElement('input'),
|
960
|
-
button_label = this.options.ownerDocument.createElement('label'),
|
961
|
-
button = this.options.ownerDocument.createElement('input'),
|
962
|
-
close = this.options.ownerDocument.createElement('a'),
|
963
|
-
save = this.options.ownerDocument.createElement('a');
|
964
|
-
|
965
|
-
close.setAttribute('href', '#');
|
966
|
-
close.className = 'medium-editor-toobar-close';
|
967
|
-
close.innerHTML = '×';
|
968
|
-
|
969
|
-
save.setAttribute('href', '#');
|
970
|
-
save.className = 'medium-editor-toobar-save';
|
971
|
-
save.innerHTML = '✓';
|
2010
|
+
this.checkSelection();
|
2011
|
+
}.bind(this),
|
2012
|
+
timeoutHelper = function () {
|
2013
|
+
setTimeout(function () {
|
2014
|
+
this.checkSelection();
|
2015
|
+
}.bind(this), 0);
|
2016
|
+
}.bind(this);
|
972
2017
|
|
973
|
-
|
974
|
-
input.className = 'medium-editor-toolbar-input';
|
975
|
-
input.setAttribute('placeholder', this.options.anchorInputPlaceholder);
|
976
|
-
|
977
|
-
|
978
|
-
target.setAttribute('type', 'checkbox');
|
979
|
-
target.className = 'medium-editor-toolbar-anchor-target';
|
980
|
-
target_label.innerHTML = this.options.anchorInputCheckboxLabel;
|
981
|
-
target_label.insertBefore(target, target_label.firstChild);
|
2018
|
+
this.on(this.options.ownerDocument.documentElement, 'mouseup', this.checkSelection.bind(this));
|
982
2019
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
anchor.className = 'medium-editor-toolbar-form';
|
990
|
-
anchor.id = 'medium-editor-toolbar-form-anchor-' + this.id;
|
991
|
-
anchor.appendChild(input);
|
2020
|
+
for (i = 0; i < this.elements.length; i += 1) {
|
2021
|
+
this.on(this.elements[i], 'keyup', this.checkSelection.bind(this));
|
2022
|
+
this.on(this.elements[i], 'blur', blurHelper);
|
2023
|
+
this.on(this.elements[i], 'click', timeoutHelper);
|
2024
|
+
}
|
992
2025
|
|
993
|
-
|
994
|
-
|
2026
|
+
return this;
|
2027
|
+
},
|
995
2028
|
|
996
|
-
|
997
|
-
|
998
|
-
}
|
2029
|
+
bindDragDrop: function () {
|
2030
|
+
var self = this, i, className, onDrag, onDrop, element;
|
999
2031
|
|
1000
|
-
if (
|
1001
|
-
|
2032
|
+
if (!self.options.imageDragging) {
|
2033
|
+
return this;
|
1002
2034
|
}
|
1003
2035
|
|
1004
|
-
|
1005
|
-
},
|
2036
|
+
className = 'medium-editor-dragover';
|
1006
2037
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
2038
|
+
onDrag = function (e) {
|
2039
|
+
e.preventDefault();
|
2040
|
+
e.dataTransfer.dropEffect = "copy";
|
1010
2041
|
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
2042
|
+
if (e.type === "dragover") {
|
2043
|
+
this.classList.add(className);
|
2044
|
+
} else {
|
2045
|
+
this.classList.remove(className);
|
1015
2046
|
}
|
1016
|
-
|
1017
|
-
self.checkSelection();
|
1018
2047
|
};
|
1019
2048
|
|
1020
|
-
|
2049
|
+
onDrop = function (e) {
|
2050
|
+
var files;
|
2051
|
+
e.preventDefault();
|
2052
|
+
e.stopPropagation();
|
2053
|
+
files = Array.prototype.slice.call(e.dataTransfer.files, 0);
|
2054
|
+
files.some(function (file) {
|
2055
|
+
if (file.type.match("image")) {
|
2056
|
+
var fileReader, id;
|
2057
|
+
fileReader = new FileReader();
|
2058
|
+
fileReader.readAsDataURL(file);
|
2059
|
+
|
2060
|
+
id = 'medium-img-' + (+new Date());
|
2061
|
+
Util.insertHTMLCommand(self.options.ownerDocument, '<img class="medium-image-loading" id="' + id + '" />');
|
2062
|
+
|
2063
|
+
fileReader.onload = function () {
|
2064
|
+
var img = document.getElementById(id);
|
2065
|
+
if (img) {
|
2066
|
+
img.removeAttribute('id');
|
2067
|
+
img.removeAttribute('class');
|
2068
|
+
img.src = fileReader.result;
|
2069
|
+
}
|
2070
|
+
};
|
2071
|
+
}
|
2072
|
+
});
|
2073
|
+
this.classList.remove(className);
|
2074
|
+
};
|
1021
2075
|
|
1022
2076
|
for (i = 0; i < this.elements.length; i += 1) {
|
1023
|
-
this.
|
1024
|
-
|
1025
|
-
|
2077
|
+
element = this.elements[i];
|
2078
|
+
|
2079
|
+
|
2080
|
+
this.on(element, 'dragover', onDrag);
|
2081
|
+
this.on(element, 'dragleave', onDrag);
|
2082
|
+
this.on(element, 'drop', onDrop);
|
1026
2083
|
}
|
1027
2084
|
return this;
|
1028
2085
|
},
|
@@ -1045,18 +2102,16 @@ if (typeof module === 'object') {
|
|
1045
2102
|
|
1046
2103
|
newSelection = this.options.contentWindow.getSelection();
|
1047
2104
|
if ((!this.options.updateOnEmptySelection && newSelection.toString().trim() === '') ||
|
1048
|
-
(this.options.allowMultiParagraphSelection === false && this.
|
1049
|
-
|
1050
|
-
|
2105
|
+
(this.options.allowMultiParagraphSelection === false && this.multipleBlockElementsSelected()) ||
|
2106
|
+
Selection.selectionInContentEditableFalse(this.options.contentWindow)) {
|
1051
2107
|
if (!this.options.staticToolbar) {
|
1052
2108
|
this.hideToolbarActions();
|
1053
|
-
} else
|
1054
|
-
this.
|
1055
|
-
this.showToolbarActions();
|
2109
|
+
} else {
|
2110
|
+
this.showAndUpdateToolbar();
|
1056
2111
|
}
|
1057
2112
|
|
1058
2113
|
} else {
|
1059
|
-
selectionElement =
|
2114
|
+
selectionElement = Selection.getSelectionElement(this.options.contentWindow);
|
1060
2115
|
if (!selectionElement || selectionElement.getAttribute('data-disable-toolbar')) {
|
1061
2116
|
if (!this.options.staticToolbar) {
|
1062
2117
|
this.hideToolbarActions();
|
@@ -1069,21 +2124,14 @@ if (typeof module === 'object') {
|
|
1069
2124
|
return this;
|
1070
2125
|
},
|
1071
2126
|
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
return false;
|
1080
|
-
},
|
1081
|
-
|
1082
|
-
hasMultiParagraphs: function () {
|
1083
|
-
var selectionHtml = getSelectionHtml.call(this).replace(/<[\S]+><\/[\S]+>/gim, ''),
|
1084
|
-
hasMultiParagraphs = selectionHtml.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g);
|
2127
|
+
// Checks for existance of multiple block elements in the current selection
|
2128
|
+
multipleBlockElementsSelected: function () {
|
2129
|
+
/*jslint regexp: true*/
|
2130
|
+
var selectionHtml = Selection.getSelectionHtml.call(this).replace(/<[\S]+><\/[\S]+>/gim, ''),
|
2131
|
+
hasMultiParagraphs = selectionHtml.match(/<(p|h[1-6]|blockquote)[^>]*>/g);
|
2132
|
+
/*jslint regexp: false*/
|
1085
2133
|
|
1086
|
-
return
|
2134
|
+
return !!hasMultiParagraphs && hasMultiParagraphs.length > 1;
|
1087
2135
|
},
|
1088
2136
|
|
1089
2137
|
checkSelectionElement: function (newSelection, selectionElement) {
|
@@ -1113,7 +2161,7 @@ if (typeof module === 'object') {
|
|
1113
2161
|
if (this.options.standardizeSelectionStart &&
|
1114
2162
|
this.selectionRange.startContainer.nodeValue &&
|
1115
2163
|
(this.selectionRange.startOffset === this.selectionRange.startContainer.nodeValue.length)) {
|
1116
|
-
adjacentNode = findAdjacentTextNodeWithContent(
|
2164
|
+
adjacentNode = Util.findAdjacentTextNodeWithContent(Selection.getSelectionElement(this.options.contentWindow), this.selectionRange.startContainer, this.options.ownerDocument);
|
1117
2165
|
if (adjacentNode) {
|
1118
2166
|
offset = 0;
|
1119
2167
|
while (adjacentNode.nodeValue.substr(offset, 1).trim().length === 0) {
|
@@ -1130,9 +2178,7 @@ if (typeof module === 'object') {
|
|
1130
2178
|
|
1131
2179
|
for (i = 0; i < this.elements.length; i += 1) {
|
1132
2180
|
if (this.elements[i] === selectionElement) {
|
1133
|
-
this.
|
1134
|
-
.setToolbarPosition()
|
1135
|
-
.showToolbarActions();
|
2181
|
+
this.showAndUpdateToolbar();
|
1136
2182
|
return;
|
1137
2183
|
}
|
1138
2184
|
}
|
@@ -1142,101 +2188,95 @@ if (typeof module === 'object') {
|
|
1142
2188
|
}
|
1143
2189
|
},
|
1144
2190
|
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
return false;
|
1150
|
-
}
|
1151
|
-
|
1152
|
-
range = selection.getRangeAt(0);
|
1153
|
-
current = range.commonAncestorContainer;
|
1154
|
-
|
1155
|
-
do {
|
1156
|
-
if (current.nodeType === 1) {
|
1157
|
-
if (testElementFunction(current)) {
|
1158
|
-
return current;
|
1159
|
-
}
|
1160
|
-
// do not traverse upwards past the nearest containing editor
|
1161
|
-
if (current.getAttribute('data-medium-element')) {
|
1162
|
-
return false;
|
1163
|
-
}
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
current = current.parentNode;
|
1167
|
-
} while (current);
|
1168
|
-
|
1169
|
-
return false;
|
1170
|
-
},
|
1171
|
-
|
1172
|
-
getSelectionElement: function () {
|
1173
|
-
return this.findMatchingSelectionParent(function (el) {
|
1174
|
-
return el.getAttribute('data-medium-element');
|
1175
|
-
});
|
1176
|
-
},
|
1177
|
-
|
1178
|
-
selectionInContentEditableFalse: function () {
|
1179
|
-
return this.findMatchingSelectionParent(function (el) {
|
1180
|
-
return (el && el.nodeName !== '#text' && el.getAttribute('contenteditable') === 'false');
|
1181
|
-
});
|
2191
|
+
showAndUpdateToolbar: function () {
|
2192
|
+
this.setToolbarButtonStates()
|
2193
|
+
.setToolbarPosition()
|
2194
|
+
.showToolbarDefaultActions();
|
1182
2195
|
},
|
1183
2196
|
|
1184
2197
|
setToolbarPosition: function () {
|
1185
2198
|
// document.documentElement for IE 9
|
1186
2199
|
var scrollTop = (this.options.ownerDocument.documentElement && this.options.ownerDocument.documentElement.scrollTop) || this.options.ownerDocument.body.scrollTop,
|
1187
|
-
container = this.elements[0],
|
1188
|
-
containerRect = container.getBoundingClientRect(),
|
1189
|
-
containerTop = containerRect.top + scrollTop,
|
1190
|
-
buttonHeight = 50,
|
1191
2200
|
selection = this.options.contentWindow.getSelection(),
|
2201
|
+
windowWidth = this.options.contentWindow.innerWidth,
|
2202
|
+
container = Selection.getSelectionElement(this.options.contentWindow),
|
2203
|
+
buttonHeight = 50,
|
2204
|
+
toolbarWidth,
|
2205
|
+
toolbarHeight,
|
2206
|
+
halfOffsetWidth,
|
2207
|
+
defaultLeft,
|
2208
|
+
containerRect,
|
2209
|
+
containerTop,
|
2210
|
+
containerCenter,
|
1192
2211
|
range,
|
1193
2212
|
boundary,
|
1194
2213
|
middleBoundary,
|
1195
|
-
|
1196
|
-
halfOffsetWidth = this.toolbar.offsetWidth / 2,
|
1197
|
-
containerCenter = (containerRect.left + (containerRect.width / 2));
|
2214
|
+
targetLeft;
|
1198
2215
|
|
1199
|
-
|
2216
|
+
// If there isn't a valid selection, bail
|
2217
|
+
if (!container || !this.options.contentWindow.getSelection().focusNode) {
|
1200
2218
|
return this;
|
1201
2219
|
}
|
1202
2220
|
|
1203
|
-
this
|
2221
|
+
// If the container isn't part of this medium-editor instance, bail
|
2222
|
+
if (this.elements.indexOf(container) === -1) {
|
2223
|
+
return this;
|
2224
|
+
}
|
2225
|
+
|
2226
|
+
// Calculate container dimensions
|
2227
|
+
containerRect = container.getBoundingClientRect();
|
2228
|
+
containerTop = containerRect.top + scrollTop;
|
2229
|
+
containerCenter = (containerRect.left + (containerRect.width / 2));
|
2230
|
+
|
2231
|
+
// position the toolbar at left 0, so we can get the real width of the toolbar
|
2232
|
+
this.toolbar.style.left = '0';
|
2233
|
+
toolbarWidth = this.toolbar.offsetWidth;
|
2234
|
+
toolbarHeight = this.toolbar.offsetHeight;
|
2235
|
+
halfOffsetWidth = toolbarWidth / 2;
|
2236
|
+
defaultLeft = this.options.diffLeft - halfOffsetWidth;
|
1204
2237
|
|
1205
2238
|
if (this.options.staticToolbar) {
|
2239
|
+
this.showToolbar();
|
1206
2240
|
|
1207
2241
|
if (this.options.stickyToolbar) {
|
1208
|
-
|
1209
2242
|
// If it's beyond the height of the editor, position it at the bottom of the editor
|
1210
|
-
if (scrollTop > (containerTop +
|
1211
|
-
this.toolbar.style.top = (containerTop +
|
2243
|
+
if (scrollTop > (containerTop + container.offsetHeight - toolbarHeight)) {
|
2244
|
+
this.toolbar.style.top = (containerTop + container.offsetHeight - toolbarHeight) + 'px';
|
2245
|
+
this.toolbar.classList.remove('sticky-toolbar');
|
1212
2246
|
|
1213
2247
|
// Stick the toolbar to the top of the window
|
1214
|
-
} else if (scrollTop > (containerTop -
|
2248
|
+
} else if (scrollTop > (containerTop - toolbarHeight)) {
|
1215
2249
|
this.toolbar.classList.add('sticky-toolbar');
|
1216
2250
|
this.toolbar.style.top = "0px";
|
2251
|
+
|
1217
2252
|
// Normal static toolbar position
|
1218
2253
|
} else {
|
1219
2254
|
this.toolbar.classList.remove('sticky-toolbar');
|
1220
|
-
this.toolbar.style.top = containerTop -
|
2255
|
+
this.toolbar.style.top = containerTop - toolbarHeight + "px";
|
1221
2256
|
}
|
1222
|
-
|
1223
2257
|
} else {
|
1224
|
-
this.toolbar.style.top = containerTop -
|
2258
|
+
this.toolbar.style.top = containerTop - toolbarHeight + "px";
|
1225
2259
|
}
|
1226
2260
|
|
1227
|
-
if (this.options.toolbarAlign) {
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
2261
|
+
if (this.options.toolbarAlign === 'left') {
|
2262
|
+
targetLeft = containerRect.left;
|
2263
|
+
} else if (this.options.toolbarAlign === 'center') {
|
2264
|
+
targetLeft = containerCenter - halfOffsetWidth;
|
2265
|
+
} else if (this.options.toolbarAlign === 'right') {
|
2266
|
+
targetLeft = containerRect.right - toolbarWidth;
|
2267
|
+
}
|
2268
|
+
|
2269
|
+
if (targetLeft < 0) {
|
2270
|
+
targetLeft = 0;
|
2271
|
+
} else if ((targetLeft + toolbarWidth) > windowWidth) {
|
2272
|
+
targetLeft = windowWidth - toolbarWidth;
|
1237
2273
|
}
|
1238
2274
|
|
2275
|
+
this.toolbar.style.left = targetLeft + 'px';
|
2276
|
+
|
1239
2277
|
} else if (!selection.isCollapsed) {
|
2278
|
+
this.showToolbar();
|
2279
|
+
|
1240
2280
|
range = selection.getRangeAt(0);
|
1241
2281
|
boundary = range.getBoundingClientRect();
|
1242
2282
|
middleBoundary = (boundary.left + boundary.right) / 2;
|
@@ -1244,16 +2284,16 @@ if (typeof module === 'object') {
|
|
1244
2284
|
if (boundary.top < buttonHeight) {
|
1245
2285
|
this.toolbar.classList.add('medium-toolbar-arrow-over');
|
1246
2286
|
this.toolbar.classList.remove('medium-toolbar-arrow-under');
|
1247
|
-
this.toolbar.style.top = buttonHeight + boundary.bottom - this.options.diffTop + this.options.contentWindow.pageYOffset -
|
2287
|
+
this.toolbar.style.top = buttonHeight + boundary.bottom - this.options.diffTop + this.options.contentWindow.pageYOffset - toolbarHeight + 'px';
|
1248
2288
|
} else {
|
1249
2289
|
this.toolbar.classList.add('medium-toolbar-arrow-under');
|
1250
2290
|
this.toolbar.classList.remove('medium-toolbar-arrow-over');
|
1251
|
-
this.toolbar.style.top = boundary.top + this.options.diffTop + this.options.contentWindow.pageYOffset -
|
2291
|
+
this.toolbar.style.top = boundary.top + this.options.diffTop + this.options.contentWindow.pageYOffset - toolbarHeight + 'px';
|
1252
2292
|
}
|
1253
2293
|
if (middleBoundary < halfOffsetWidth) {
|
1254
2294
|
this.toolbar.style.left = defaultLeft + halfOffsetWidth + 'px';
|
1255
|
-
} else if ((
|
1256
|
-
this.toolbar.style.left =
|
2295
|
+
} else if ((windowWidth - middleBoundary) < halfOffsetWidth) {
|
2296
|
+
this.toolbar.style.left = windowWidth + defaultLeft - halfOffsetWidth + 'px';
|
1257
2297
|
} else {
|
1258
2298
|
this.toolbar.style.left = defaultLeft + middleBoundary + 'px';
|
1259
2299
|
}
|
@@ -1265,21 +2305,57 @@ if (typeof module === 'object') {
|
|
1265
2305
|
},
|
1266
2306
|
|
1267
2307
|
setToolbarButtonStates: function () {
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
}
|
2308
|
+
this.commands.forEach(function (extension) {
|
2309
|
+
if (typeof extension.isActive === 'function') {
|
2310
|
+
extension.setInactive();
|
2311
|
+
}
|
2312
|
+
}.bind(this));
|
1273
2313
|
this.checkActiveButtons();
|
1274
2314
|
return this;
|
1275
2315
|
},
|
1276
2316
|
|
1277
2317
|
checkActiveButtons: function () {
|
1278
2318
|
var elements = Array.prototype.slice.call(this.elements),
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
2319
|
+
manualStateChecks = [],
|
2320
|
+
queryState = null,
|
2321
|
+
parentNode,
|
2322
|
+
checkExtension = function (extension) {
|
2323
|
+
if (typeof extension.checkState === 'function') {
|
2324
|
+
extension.checkState(parentNode);
|
2325
|
+
} else if (typeof extension.isActive === 'function' &&
|
2326
|
+
typeof extension.isAlreadyApplied === 'function') {
|
2327
|
+
if (!extension.isActive() && extension.isAlreadyApplied(parentNode)) {
|
2328
|
+
extension.setActive();
|
2329
|
+
}
|
2330
|
+
}
|
2331
|
+
};
|
2332
|
+
|
2333
|
+
if (!this.selectionRange) {
|
2334
|
+
return;
|
2335
|
+
}
|
2336
|
+
parentNode = Selection.getSelectedParentElement(this.selectionRange);
|
2337
|
+
|
2338
|
+
// Loop through all commands
|
2339
|
+
this.commands.forEach(function (command) {
|
2340
|
+
// For those commands where we can use document.queryCommandState(), do so
|
2341
|
+
if (typeof command.queryCommandState === 'function') {
|
2342
|
+
queryState = command.queryCommandState();
|
2343
|
+
// If queryCommandState returns a valid value, we can trust the browser
|
2344
|
+
// and don't need to do our manual checks
|
2345
|
+
if (queryState !== null) {
|
2346
|
+
if (queryState) {
|
2347
|
+
command.setActive();
|
2348
|
+
}
|
2349
|
+
return;
|
2350
|
+
}
|
2351
|
+
}
|
2352
|
+
// We can't use queryCommandState for this command, so add to manualStateChecks
|
2353
|
+
manualStateChecks.push(command);
|
2354
|
+
});
|
2355
|
+
|
2356
|
+
// Climb up the DOM and do manual checks for whether a certain command is currently enabled for this node
|
2357
|
+
while (parentNode.tagName !== undefined && Util.parentElements.indexOf(parentNode.tagName.toLowerCase) === -1) {
|
2358
|
+
manualStateChecks.forEach(checkExtension.bind(this));
|
1283
2359
|
|
1284
2360
|
// we can abort the search upwards if we leave the contentEditable element
|
1285
2361
|
if (elements.indexOf(parentNode) !== -1) {
|
@@ -1289,45 +2365,8 @@ if (typeof module === 'object') {
|
|
1289
2365
|
}
|
1290
2366
|
},
|
1291
2367
|
|
1292
|
-
|
1293
|
-
var
|
1294
|
-
if (el !== null && el.className.indexOf(this.options.activeButtonClass) === -1) {
|
1295
|
-
el.className += ' ' + this.options.activeButtonClass;
|
1296
|
-
}
|
1297
|
-
},
|
1298
|
-
|
1299
|
-
bindButtons: function () {
|
1300
|
-
var buttons = this.toolbar.querySelectorAll('button'),
|
1301
|
-
i,
|
1302
|
-
self = this,
|
1303
|
-
triggerAction = function (e) {
|
1304
|
-
e.preventDefault();
|
1305
|
-
e.stopPropagation();
|
1306
|
-
if (self.selection === undefined) {
|
1307
|
-
self.checkSelection();
|
1308
|
-
}
|
1309
|
-
if (this.className.indexOf(self.options.activeButtonClass) > -1) {
|
1310
|
-
this.classList.remove(self.options.activeButtonClass);
|
1311
|
-
} else {
|
1312
|
-
this.className += ' ' + self.options.activeButtonClass;
|
1313
|
-
}
|
1314
|
-
if (this.hasAttribute('data-action')) {
|
1315
|
-
self.execAction(this.getAttribute('data-action'), e);
|
1316
|
-
}
|
1317
|
-
// Allows extension buttons to show a form
|
1318
|
-
// TO DO: Improve this
|
1319
|
-
if (this.hasAttribute('data-form')) {
|
1320
|
-
self.showForm(this.getAttribute('data-form'), e);
|
1321
|
-
}
|
1322
|
-
};
|
1323
|
-
for (i = 0; i < buttons.length; i += 1) {
|
1324
|
-
this.on(buttons[i], 'click', triggerAction);
|
1325
|
-
}
|
1326
|
-
this.setFirstAndLastItems(buttons);
|
1327
|
-
return this;
|
1328
|
-
},
|
1329
|
-
|
1330
|
-
setFirstAndLastItems: function (buttons) {
|
2368
|
+
setFirstAndLastButtons: function () {
|
2369
|
+
var buttons = this.toolbar.querySelectorAll('button');
|
1331
2370
|
if (buttons.length > 0) {
|
1332
2371
|
buttons[0].className += ' ' + this.options.firstButtonClass;
|
1333
2372
|
buttons[buttons.length - 1].className += ' ' + this.options.lastButtonClass;
|
@@ -1335,82 +2374,84 @@ if (typeof module === 'object') {
|
|
1335
2374
|
return this;
|
1336
2375
|
},
|
1337
2376
|
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
} else {
|
1350
|
-
this.options.ownerDocument.execCommand(action, false, null);
|
1351
|
-
this.setToolbarPosition();
|
2377
|
+
// Wrapper around document.queryCommandState for checking whether an action has already
|
2378
|
+
// been applied to the current selection
|
2379
|
+
queryCommandState: function (action) {
|
2380
|
+
var fullAction = /^full-(.+)$/gi,
|
2381
|
+
match,
|
2382
|
+
queryState = null;
|
2383
|
+
|
2384
|
+
// Actions starting with 'full-' need to be modified since this is a medium-editor concept
|
2385
|
+
match = fullAction.exec(action);
|
2386
|
+
if (match) {
|
2387
|
+
action = match[1];
|
1352
2388
|
}
|
1353
|
-
},
|
1354
2389
|
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
var form = document.getElementById(formId);
|
1361
|
-
form.style.display = 'block';
|
1362
|
-
this.setToolbarPosition();
|
1363
|
-
this.keepToolbarAlive = true;
|
1364
|
-
},
|
2390
|
+
try {
|
2391
|
+
queryState = this.options.ownerDocument.queryCommandState(action);
|
2392
|
+
} catch (exc) {
|
2393
|
+
queryState = null;
|
2394
|
+
}
|
1365
2395
|
|
1366
|
-
|
1367
|
-
// TO DO: Improve this
|
1368
|
-
hideForm: function (form, e) {
|
1369
|
-
var el = document.getElementById(form.id);
|
1370
|
-
el.style.display = 'none';
|
1371
|
-
this.showToolbarActions();
|
1372
|
-
this.setToolbarPosition();
|
1373
|
-
restoreSelection.call(this, this.savedSelection);
|
2396
|
+
return queryState;
|
1374
2397
|
},
|
1375
2398
|
|
1376
|
-
|
1377
|
-
|
1378
|
-
var
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
},
|
2399
|
+
execAction: function (action, opts) {
|
2400
|
+
/*jslint regexp: true*/
|
2401
|
+
var fullAction = /^full-(.+)$/gi,
|
2402
|
+
match,
|
2403
|
+
result;
|
2404
|
+
/*jslint regexp: false*/
|
1383
2405
|
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
if (
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
2406
|
+
// Actions starting with 'full-' should be applied to to the entire contents of the editable element
|
2407
|
+
// (ie full-bold, full-append-pre, etc.)
|
2408
|
+
match = fullAction.exec(action);
|
2409
|
+
if (match) {
|
2410
|
+
// Store the current selection to be restored after applying the action
|
2411
|
+
this.saveSelection();
|
2412
|
+
// Select all of the contents before calling the action
|
2413
|
+
this.selectAllContents();
|
2414
|
+
result = this.execActionInternal(match[1], opts);
|
2415
|
+
// Restore the previous selection
|
2416
|
+
this.restoreSelection();
|
1391
2417
|
} else {
|
1392
|
-
|
2418
|
+
result = this.execActionInternal(action, opts);
|
1393
2419
|
}
|
1394
|
-
|
2420
|
+
|
2421
|
+
this.checkSelection();
|
2422
|
+
return result;
|
1395
2423
|
},
|
1396
2424
|
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
2425
|
+
execActionInternal: function (action, opts) {
|
2426
|
+
/*jslint regexp: true*/
|
2427
|
+
var appendAction = /^append-(.+)$/gi,
|
2428
|
+
match;
|
2429
|
+
/*jslint regexp: false*/
|
2430
|
+
|
2431
|
+
// Actions starting with 'append-' should attempt to format a block of text ('formatBlock') using a specific
|
2432
|
+
// type of block element (ie append-blockquote, append-h1, append-pre, etc.)
|
2433
|
+
match = appendAction.exec(action);
|
2434
|
+
if (match) {
|
2435
|
+
return this.execFormatBlock(match[1]);
|
1408
2436
|
}
|
1409
|
-
|
2437
|
+
|
2438
|
+
if (action === 'createLink') {
|
2439
|
+
return this.createLink(opts);
|
2440
|
+
}
|
2441
|
+
|
2442
|
+
if (action === 'image') {
|
2443
|
+
return this.options.ownerDocument.execCommand('insertImage', false, this.options.contentWindow.getSelection());
|
2444
|
+
}
|
2445
|
+
|
2446
|
+
return this.options.ownerDocument.execCommand(action, false, null);
|
2447
|
+
},
|
2448
|
+
|
2449
|
+
getSelectedParentElement: function () {
|
2450
|
+
return Selection.getSelectedParentElement();
|
1410
2451
|
},
|
1411
2452
|
|
1412
2453
|
execFormatBlock: function (el) {
|
1413
|
-
var selectionData =
|
2454
|
+
var selectionData = Selection.getSelectionData(this.selection.anchorNode);
|
1414
2455
|
// FF handles blockquote differently on formatBlock
|
1415
2456
|
// allowing nesting, we need to use outdent
|
1416
2457
|
// https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla
|
@@ -1425,7 +2466,7 @@ if (typeof module === 'object') {
|
|
1425
2466
|
// blockquote needs to be called as indent
|
1426
2467
|
// http://stackoverflow.com/questions/10741831/execcommand-formatblock-headings-in-ie
|
1427
2468
|
// http://stackoverflow.com/questions/1816223/rich-text-editor-with-blockquote-function/1821777#1821777
|
1428
|
-
if (
|
2469
|
+
if (Util.isIE) {
|
1429
2470
|
if (el === 'blockquote') {
|
1430
2471
|
return this.options.ownerDocument.execCommand('indent', false, el);
|
1431
2472
|
}
|
@@ -1434,32 +2475,45 @@ if (typeof module === 'object') {
|
|
1434
2475
|
return this.options.ownerDocument.execCommand('formatBlock', false, el);
|
1435
2476
|
},
|
1436
2477
|
|
1437
|
-
|
1438
|
-
|
2478
|
+
isToolbarDefaultActionsShown: function () {
|
2479
|
+
return !!this.toolbarActions && this.toolbarActions.style.display === 'block';
|
2480
|
+
},
|
1439
2481
|
|
1440
|
-
|
1441
|
-
|
2482
|
+
hideToolbarDefaultActions: function () {
|
2483
|
+
if (this.toolbarActions && this.isToolbarDefaultActionsShown()) {
|
2484
|
+
this.commands.forEach(function (extension) {
|
2485
|
+
if (extension.onHide && typeof extension.onHide === 'function') {
|
2486
|
+
extension.onHide();
|
2487
|
+
}
|
2488
|
+
});
|
2489
|
+
this.toolbarActions.style.display = 'none';
|
1442
2490
|
}
|
2491
|
+
},
|
1443
2492
|
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
2493
|
+
showToolbarDefaultActions: function () {
|
2494
|
+
this.hideExtensionForms();
|
2495
|
+
|
2496
|
+
if (this.toolbarActions && !this.isToolbarDefaultActionsShown()) {
|
2497
|
+
this.toolbarActions.style.display = 'block';
|
1449
2498
|
}
|
1450
2499
|
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
2500
|
+
this.keepToolbarAlive = false;
|
2501
|
+
// Using setTimeout + options.delay because:
|
2502
|
+
// We will actually be displaying the toolbar, which should be controlled by options.delay
|
2503
|
+
this.delay(function () {
|
2504
|
+
this.showToolbar();
|
2505
|
+
}.bind(this));
|
2506
|
+
|
2507
|
+
return this;
|
1455
2508
|
},
|
1456
2509
|
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
2510
|
+
hideExtensionForms: function () {
|
2511
|
+
// Hide all extension forms
|
2512
|
+
this.commands.forEach(function (extension) {
|
2513
|
+
if (extension.hasForm && extension.isDisplayed()) {
|
2514
|
+
extension.hideForm();
|
2515
|
+
}
|
2516
|
+
});
|
1463
2517
|
},
|
1464
2518
|
|
1465
2519
|
isToolbarShown: function () {
|
@@ -1469,8 +2523,8 @@ if (typeof module === 'object') {
|
|
1469
2523
|
showToolbar: function () {
|
1470
2524
|
if (this.toolbar && !this.isToolbarShown()) {
|
1471
2525
|
this.toolbar.classList.add('medium-editor-toolbar-active');
|
1472
|
-
if (this.onShowToolbar) {
|
1473
|
-
this.onShowToolbar();
|
2526
|
+
if (typeof this.options.onShowToolbar === 'function') {
|
2527
|
+
this.options.onShowToolbar();
|
1474
2528
|
}
|
1475
2529
|
}
|
1476
2530
|
},
|
@@ -1478,134 +2532,127 @@ if (typeof module === 'object') {
|
|
1478
2532
|
hideToolbar: function () {
|
1479
2533
|
if (this.isToolbarShown()) {
|
1480
2534
|
this.toolbar.classList.remove('medium-editor-toolbar-active');
|
1481
|
-
if (this.onHideToolbar) {
|
1482
|
-
this.onHideToolbar();
|
2535
|
+
if (typeof this.options.onHideToolbar === 'function') {
|
2536
|
+
this.options.onHideToolbar();
|
1483
2537
|
}
|
1484
2538
|
}
|
1485
2539
|
},
|
1486
2540
|
|
1487
2541
|
hideToolbarActions: function () {
|
2542
|
+
this.commands.forEach(function (extension) {
|
2543
|
+
if (extension.onHide && typeof extension.onHide === 'function') {
|
2544
|
+
extension.onHide();
|
2545
|
+
}
|
2546
|
+
});
|
1488
2547
|
this.keepToolbarAlive = false;
|
1489
2548
|
this.hideToolbar();
|
1490
2549
|
},
|
1491
2550
|
|
1492
|
-
|
1493
|
-
var
|
1494
|
-
|
1495
|
-
this.
|
1496
|
-
}
|
1497
|
-
this.toolbarActions.style.display = 'block';
|
1498
|
-
this.keepToolbarAlive = false;
|
1499
|
-
// Using setTimeout + options.delay because:
|
1500
|
-
// We will actually be displaying the toolbar, which should be controlled by options.delay
|
1501
|
-
this.delay(function () {
|
1502
|
-
self.showToolbar();
|
1503
|
-
});
|
1504
|
-
},
|
1505
|
-
|
1506
|
-
saveSelection: function () {
|
1507
|
-
this.savedSelection = saveSelection.call(this);
|
1508
|
-
},
|
1509
|
-
|
1510
|
-
restoreSelection: function () {
|
1511
|
-
restoreSelection.call(this, this.savedSelection);
|
1512
|
-
},
|
1513
|
-
|
1514
|
-
showAnchorForm: function (link_value) {
|
1515
|
-
if (!this.anchorForm) {
|
1516
|
-
return;
|
1517
|
-
}
|
1518
|
-
|
1519
|
-
this.toolbarActions.style.display = 'none';
|
1520
|
-
this.saveSelection();
|
1521
|
-
this.anchorForm.style.display = 'block';
|
1522
|
-
this.setToolbarPosition();
|
1523
|
-
this.keepToolbarAlive = true;
|
1524
|
-
this.anchorInput.focus();
|
1525
|
-
this.anchorInput.value = link_value || '';
|
1526
|
-
},
|
2551
|
+
selectAllContents: function () {
|
2552
|
+
var range = this.options.ownerDocument.createRange(),
|
2553
|
+
sel = this.options.contentWindow.getSelection(),
|
2554
|
+
currNode = Selection.getSelectionElement(this.options.contentWindow);
|
1527
2555
|
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
2556
|
+
if (currNode) {
|
2557
|
+
// Move to the lowest descendant node that still selects all of the contents
|
2558
|
+
while (currNode.children.length === 1) {
|
2559
|
+
currNode = currNode.children[0];
|
2560
|
+
}
|
1532
2561
|
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
2562
|
+
range.selectNodeContents(currNode);
|
2563
|
+
sel.removeAllRanges();
|
2564
|
+
sel.addRange(range);
|
2565
|
+
}
|
2566
|
+
},
|
1536
2567
|
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
2568
|
+
// http://stackoverflow.com/questions/17678843/cant-restore-selection-after-html-modify-even-if-its-the-same-html
|
2569
|
+
// Tim Down
|
2570
|
+
// TODO: move to selection.js and clean up old methods there
|
2571
|
+
saveSelection: function () {
|
2572
|
+
this.selectionState = null;
|
1541
2573
|
|
1542
|
-
this.
|
1543
|
-
|
1544
|
-
|
2574
|
+
var selection = this.options.contentWindow.getSelection(),
|
2575
|
+
range,
|
2576
|
+
preSelectionRange,
|
2577
|
+
start,
|
2578
|
+
editableElementIndex = -1;
|
1545
2579
|
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
target = "_blank";
|
1550
|
-
} else {
|
1551
|
-
target = "_self";
|
1552
|
-
}
|
2580
|
+
if (selection.rangeCount > 0) {
|
2581
|
+
range = selection.getRangeAt(0);
|
2582
|
+
preSelectionRange = range.cloneRange();
|
1553
2583
|
|
1554
|
-
|
1555
|
-
|
2584
|
+
// Find element current selection is inside
|
2585
|
+
this.elements.forEach(function (el, index) {
|
2586
|
+
if (el === range.startContainer || Util.isDescendant(el, range.startContainer)) {
|
2587
|
+
editableElementIndex = index;
|
2588
|
+
return false;
|
1556
2589
|
}
|
2590
|
+
});
|
1557
2591
|
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
restoreSelection.call(self, self.savedSelection);
|
1563
|
-
}
|
1564
|
-
});
|
1565
|
-
|
1566
|
-
this.on(linkSave, 'click', function (e) {
|
1567
|
-
var button = null,
|
1568
|
-
target;
|
1569
|
-
e.preventDefault();
|
1570
|
-
if (self.options.anchorTarget && self.anchorTarget.checked) {
|
1571
|
-
target = "_blank";
|
1572
|
-
} else {
|
1573
|
-
target = "_self";
|
1574
|
-
}
|
2592
|
+
if (editableElementIndex > -1) {
|
2593
|
+
preSelectionRange.selectNodeContents(this.elements[editableElementIndex]);
|
2594
|
+
preSelectionRange.setEnd(range.startContainer, range.startOffset);
|
2595
|
+
start = preSelectionRange.toString().length;
|
1575
2596
|
|
1576
|
-
|
1577
|
-
|
2597
|
+
this.selectionState = {
|
2598
|
+
start: start,
|
2599
|
+
end: start + range.toString().length,
|
2600
|
+
editableElementIndex: editableElementIndex
|
2601
|
+
};
|
1578
2602
|
}
|
2603
|
+
}
|
2604
|
+
},
|
1579
2605
|
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
});
|
2606
|
+
// http://stackoverflow.com/questions/17678843/cant-restore-selection-after-html-modify-even-if-its-the-same-html
|
2607
|
+
// Tim Down
|
2608
|
+
// TODO: move to selection.js and clean up old methods there
|
2609
|
+
restoreSelection: function () {
|
2610
|
+
if (!this.selectionState) {
|
2611
|
+
return;
|
2612
|
+
}
|
1588
2613
|
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
2614
|
+
var editableElement = this.elements[this.selectionState.editableElementIndex],
|
2615
|
+
charIndex = 0,
|
2616
|
+
range = this.options.ownerDocument.createRange(),
|
2617
|
+
nodeStack = [editableElement],
|
2618
|
+
node,
|
2619
|
+
foundStart = false,
|
2620
|
+
stop = false,
|
2621
|
+
i,
|
2622
|
+
sel,
|
2623
|
+
nextCharIndex;
|
2624
|
+
|
2625
|
+
range.setStart(editableElement, 0);
|
2626
|
+
range.collapse(true);
|
2627
|
+
|
2628
|
+
node = nodeStack.pop();
|
2629
|
+
while (!stop && node) {
|
2630
|
+
if (node.nodeType === 3) {
|
2631
|
+
nextCharIndex = charIndex + node.length;
|
2632
|
+
if (!foundStart && this.selectionState.start >= charIndex && this.selectionState.start <= nextCharIndex) {
|
2633
|
+
range.setStart(node, this.selectionState.start - charIndex);
|
2634
|
+
foundStart = true;
|
2635
|
+
}
|
2636
|
+
if (foundStart && this.selectionState.end >= charIndex && this.selectionState.end <= nextCharIndex) {
|
2637
|
+
range.setEnd(node, this.selectionState.end - charIndex);
|
2638
|
+
stop = true;
|
2639
|
+
}
|
2640
|
+
charIndex = nextCharIndex;
|
2641
|
+
} else {
|
2642
|
+
i = node.childNodes.length - 1;
|
2643
|
+
while (i >= 0) {
|
2644
|
+
nodeStack.push(node.childNodes[i]);
|
2645
|
+
i -= 1;
|
2646
|
+
}
|
1594
2647
|
}
|
1595
|
-
|
1596
|
-
|
1597
|
-
if (e.target !== self.anchorForm && !isDescendant(self.anchorForm, e.target) && !isDescendant(self.toolbarActions, e.target)) {
|
1598
|
-
self.keepToolbarAlive = false;
|
1599
|
-
self.checkSelection();
|
2648
|
+
if (!stop) {
|
2649
|
+
node = nodeStack.pop();
|
1600
2650
|
}
|
1601
|
-
}
|
2651
|
+
}
|
1602
2652
|
|
1603
|
-
this.
|
1604
|
-
|
1605
|
-
|
1606
|
-
restoreSelection.call(self, self.savedSelection);
|
1607
|
-
});
|
1608
|
-
return this;
|
2653
|
+
sel = this.options.contentWindow.getSelection();
|
2654
|
+
sel.removeAllRanges();
|
2655
|
+
sel.addRange(range);
|
1609
2656
|
},
|
1610
2657
|
|
1611
2658
|
hideAnchorPreview: function () {
|
@@ -1626,7 +2673,7 @@ if (typeof module === 'object') {
|
|
1626
2673
|
halfOffsetWidth,
|
1627
2674
|
defaultLeft;
|
1628
2675
|
|
1629
|
-
self.anchorPreview.querySelector('i').textContent = anchorEl.href;
|
2676
|
+
self.anchorPreview.querySelector('i').textContent = anchorEl.attributes.href.value;
|
1630
2677
|
halfOffsetWidth = self.anchorPreview.offsetWidth / 2;
|
1631
2678
|
defaultLeft = self.options.diffLeft - halfOffsetWidth;
|
1632
2679
|
|
@@ -1711,25 +2758,26 @@ if (typeof module === 'object') {
|
|
1711
2758
|
'</div>';
|
1712
2759
|
},
|
1713
2760
|
|
1714
|
-
anchorPreviewClickHandler: function (
|
1715
|
-
|
2761
|
+
anchorPreviewClickHandler: function (event) {
|
2762
|
+
var range,
|
2763
|
+
sel,
|
2764
|
+
anchorExtension = this.getExtensionByName('anchor');
|
1716
2765
|
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
2766
|
+
if (anchorExtension && this.activeAnchor) {
|
2767
|
+
range = this.options.ownerDocument.createRange();
|
2768
|
+
range.selectNodeContents(this.activeAnchor);
|
1720
2769
|
|
1721
|
-
|
2770
|
+
sel = this.options.contentWindow.getSelection();
|
1722
2771
|
sel.removeAllRanges();
|
1723
2772
|
sel.addRange(range);
|
1724
2773
|
// Using setTimeout + options.delay because:
|
1725
|
-
// We may actually be displaying the anchor
|
2774
|
+
// We may actually be displaying the anchor form, which should be controlled by options.delay
|
1726
2775
|
this.delay(function () {
|
1727
|
-
if (
|
1728
|
-
|
2776
|
+
if (this.activeAnchor) {
|
2777
|
+
anchorExtension.showForm(this.activeAnchor.attributes.href.value);
|
1729
2778
|
}
|
1730
|
-
|
1731
|
-
});
|
1732
|
-
|
2779
|
+
this.keepToolbarAlive = false;
|
2780
|
+
}.bind(this));
|
1733
2781
|
}
|
1734
2782
|
|
1735
2783
|
this.hideAnchorPreview();
|
@@ -1782,27 +2830,33 @@ if (typeof module === 'object') {
|
|
1782
2830
|
return this;
|
1783
2831
|
},
|
1784
2832
|
|
1785
|
-
|
1786
|
-
var
|
1787
|
-
|
1788
|
-
},
|
2833
|
+
createLink: function (opts) {
|
2834
|
+
var customEvent,
|
2835
|
+
i;
|
1789
2836
|
|
1790
|
-
|
1791
|
-
|
1792
|
-
el = el || getSelectionStart.call(this);
|
1793
|
-
if (el.tagName.toLowerCase() === 'a') {
|
1794
|
-
el.target = '_blank';
|
1795
|
-
} else {
|
1796
|
-
el = el.getElementsByTagName('a');
|
2837
|
+
if (opts.url && opts.url.trim().length > 0) {
|
2838
|
+
this.options.ownerDocument.execCommand('createLink', false, opts.url);
|
1797
2839
|
|
1798
|
-
|
1799
|
-
|
2840
|
+
if (this.options.targetBlank || opts.target === '_blank') {
|
2841
|
+
Util.setTargetBlank(Selection.getSelectionStart(this.options.ownerDocument));
|
2842
|
+
}
|
2843
|
+
|
2844
|
+
if (opts.buttonClass) {
|
2845
|
+
this.setButtonClass(opts.buttonClass);
|
2846
|
+
}
|
2847
|
+
}
|
2848
|
+
|
2849
|
+
if (this.options.targetBlank || opts.target === "_blank" || opts.buttonClass) {
|
2850
|
+
customEvent = this.options.ownerDocument.createEvent("HTMLEvents");
|
2851
|
+
customEvent.initEvent("input", true, true, this.options.contentWindow);
|
2852
|
+
for (i = 0; i < this.elements.length; i += 1) {
|
2853
|
+
this.elements[i].dispatchEvent(customEvent);
|
1800
2854
|
}
|
1801
2855
|
}
|
1802
2856
|
},
|
1803
2857
|
|
1804
2858
|
setButtonClass: function (buttonClass) {
|
1805
|
-
var el = getSelectionStart
|
2859
|
+
var el = Selection.getSelectionStart(this.options.ownerDocument),
|
1806
2860
|
classes = buttonClass.split(' '),
|
1807
2861
|
i,
|
1808
2862
|
j;
|
@@ -1820,47 +2874,6 @@ if (typeof module === 'object') {
|
|
1820
2874
|
}
|
1821
2875
|
},
|
1822
2876
|
|
1823
|
-
createLink: function (input, target, buttonClass) {
|
1824
|
-
var i, event;
|
1825
|
-
|
1826
|
-
this.createLinkInternal(input.value, target, buttonClass);
|
1827
|
-
|
1828
|
-
if (this.options.targetBlank || target === "_blank" || buttonClass) {
|
1829
|
-
event = this.options.ownerDocument.createEvent("HTMLEvents");
|
1830
|
-
event.initEvent("input", true, true, this.options.contentWindow);
|
1831
|
-
for (i = 0; i < this.elements.length; i += 1) {
|
1832
|
-
this.elements[i].dispatchEvent(event);
|
1833
|
-
}
|
1834
|
-
}
|
1835
|
-
|
1836
|
-
this.checkSelection();
|
1837
|
-
this.showToolbarActions();
|
1838
|
-
input.value = '';
|
1839
|
-
},
|
1840
|
-
|
1841
|
-
createLinkInternal: function (url, target, buttonClass) {
|
1842
|
-
if (!url || url.trim().length === 0) {
|
1843
|
-
this.hideToolbarActions();
|
1844
|
-
return;
|
1845
|
-
}
|
1846
|
-
|
1847
|
-
restoreSelection.call(this, this.savedSelection);
|
1848
|
-
|
1849
|
-
if (this.options.checkLinkFormat) {
|
1850
|
-
url = this.checkLinkFormat(url);
|
1851
|
-
}
|
1852
|
-
|
1853
|
-
this.options.ownerDocument.execCommand('createLink', false, url);
|
1854
|
-
|
1855
|
-
if (this.options.targetBlank || target === "_blank") {
|
1856
|
-
this.setTargetBlank();
|
1857
|
-
}
|
1858
|
-
|
1859
|
-
if (buttonClass) {
|
1860
|
-
this.setButtonClass(buttonClass);
|
1861
|
-
}
|
1862
|
-
},
|
1863
|
-
|
1864
2877
|
positionToolbarIfShown: function () {
|
1865
2878
|
if (this.isToolbarShown()) {
|
1866
2879
|
this.setToolbarPosition();
|
@@ -1881,6 +2894,9 @@ if (typeof module === 'object') {
|
|
1881
2894
|
this.on(this.options.contentWindow, 'resize', function () {
|
1882
2895
|
self.handleResize();
|
1883
2896
|
});
|
2897
|
+
|
2898
|
+
this.bindBlur();
|
2899
|
+
|
1884
2900
|
return this;
|
1885
2901
|
},
|
1886
2902
|
|
@@ -1912,59 +2928,19 @@ if (typeof module === 'object') {
|
|
1912
2928
|
this.elements[i].removeAttribute('data-medium-element');
|
1913
2929
|
}
|
1914
2930
|
|
1915
|
-
this.
|
1916
|
-
|
2931
|
+
this.commands.forEach(function (extension) {
|
2932
|
+
if (typeof extension.deactivate === 'function') {
|
2933
|
+
extension.deactivate();
|
2934
|
+
}
|
2935
|
+
}.bind(this));
|
1917
2936
|
|
1918
|
-
|
1919
|
-
// converts special characters (like <) into their escaped/encoded values (like <).
|
1920
|
-
// This allows you to show to display the string without the browser reading it as HTML.
|
1921
|
-
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
2937
|
+
this.removeAllEvents();
|
1922
2938
|
},
|
1923
2939
|
|
1924
2940
|
bindPaste: function () {
|
1925
2941
|
var i, self = this;
|
1926
2942
|
this.pasteWrapper = function (e) {
|
1927
|
-
|
1928
|
-
html = '',
|
1929
|
-
p,
|
1930
|
-
dataFormatHTML = 'text/html',
|
1931
|
-
dataFormatPlain = 'text/plain';
|
1932
|
-
|
1933
|
-
this.classList.remove('medium-editor-placeholder');
|
1934
|
-
if (!self.options.forcePlainText && !self.options.cleanPastedHTML) {
|
1935
|
-
return this;
|
1936
|
-
}
|
1937
|
-
|
1938
|
-
if (self.options.contentWindow.clipboardData && e.clipboardData === undefined) {
|
1939
|
-
e.clipboardData = self.options.contentWindow.clipboardData;
|
1940
|
-
// If window.clipboardData exists, but e.clipboardData doesn't exist,
|
1941
|
-
// we're probably in IE. IE only has two possibilities for clipboard
|
1942
|
-
// data format: 'Text' and 'URL'.
|
1943
|
-
//
|
1944
|
-
// Of the two, we want 'Text':
|
1945
|
-
dataFormatHTML = 'Text';
|
1946
|
-
dataFormatPlain = 'Text';
|
1947
|
-
}
|
1948
|
-
|
1949
|
-
if (e.clipboardData && e.clipboardData.getData && !e.defaultPrevented) {
|
1950
|
-
e.preventDefault();
|
1951
|
-
|
1952
|
-
if (self.options.cleanPastedHTML && e.clipboardData.getData(dataFormatHTML)) {
|
1953
|
-
return self.cleanPaste(e.clipboardData.getData(dataFormatHTML));
|
1954
|
-
}
|
1955
|
-
if (!(self.options.disableReturn || this.getAttribute('data-disable-return'))) {
|
1956
|
-
paragraphs = e.clipboardData.getData(dataFormatPlain).split(/[\r\n]/g);
|
1957
|
-
for (p = 0; p < paragraphs.length; p += 1) {
|
1958
|
-
if (paragraphs[p] !== '') {
|
1959
|
-
html += '<p>' + self.htmlEntities(paragraphs[p]) + '</p>';
|
1960
|
-
}
|
1961
|
-
}
|
1962
|
-
insertHTMLCommand(self.options.ownerDocument, html);
|
1963
|
-
} else {
|
1964
|
-
html = self.htmlEntities(e.clipboardData.getData(dataFormatPlain));
|
1965
|
-
insertHTMLCommand(self.options.ownerDocument, html);
|
1966
|
-
}
|
1967
|
-
}
|
2943
|
+
pasteHandler.handlePaste(this, e, self.options);
|
1968
2944
|
};
|
1969
2945
|
for (i = 0; i < this.elements.length; i += 1) {
|
1970
2946
|
this.on(this.elements[i], 'paste', this.pasteWrapper);
|
@@ -1985,197 +2961,15 @@ if (typeof module === 'object') {
|
|
1985
2961
|
},
|
1986
2962
|
|
1987
2963
|
cleanPaste: function (text) {
|
1988
|
-
|
1989
|
-
/*jslint regexp: true*/
|
1990
|
-
/*
|
1991
|
-
jslint does not allow character negation, because the negation
|
1992
|
-
will not match any unicode characters. In the regexes in this
|
1993
|
-
block, negation is used specifically to match the end of an html
|
1994
|
-
tag, and in fact unicode characters *should* be allowed.
|
1995
|
-
*/
|
1996
|
-
var i, elList, workEl,
|
1997
|
-
el = this.getSelectionElement(),
|
1998
|
-
multiline = /<p|<br|<div/.test(text),
|
1999
|
-
replacements = [
|
2000
|
-
|
2001
|
-
// replace two bogus tags that begin pastes from google docs
|
2002
|
-
[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ""],
|
2003
|
-
[new RegExp(/<\/b>(<br[^>]*>)?$/gi), ""],
|
2004
|
-
|
2005
|
-
// un-html spaces and newlines inserted by OS X
|
2006
|
-
[new RegExp(/<span class="Apple-converted-space">\s+<\/span>/g), ' '],
|
2007
|
-
[new RegExp(/<br class="Apple-interchange-newline">/g), '<br>'],
|
2008
|
-
|
2009
|
-
// replace google docs italics+bold with a span to be replaced once the html is inserted
|
2010
|
-
[new RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi), '<span class="replace-with italic bold">'],
|
2011
|
-
|
2012
|
-
// replace google docs italics with a span to be replaced once the html is inserted
|
2013
|
-
[new RegExp(/<span[^>]*font-style:italic[^>]*>/gi), '<span class="replace-with italic">'],
|
2014
|
-
|
2015
|
-
//[replace google docs bolds with a span to be replaced once the html is inserted
|
2016
|
-
[new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi), '<span class="replace-with bold">'],
|
2017
|
-
|
2018
|
-
// replace manually entered b/i/a tags with real ones
|
2019
|
-
[new RegExp(/<(\/?)(i|b|a)>/gi), '<$1$2>'],
|
2020
|
-
|
2021
|
-
// replace manually a tags with real ones, converting smart-quotes from google docs
|
2022
|
-
[new RegExp(/<a\s+href=("|”|“|“|”)([^&]+)("|”|“|“|”)>/gi), '<a href="$2">']
|
2023
|
-
|
2024
|
-
];
|
2025
|
-
/*jslint regexp: false*/
|
2026
|
-
|
2027
|
-
for (i = 0; i < replacements.length; i += 1) {
|
2028
|
-
text = text.replace(replacements[i][0], replacements[i][1]);
|
2029
|
-
}
|
2030
|
-
|
2031
|
-
if (multiline) {
|
2032
|
-
|
2033
|
-
// double br's aren't converted to p tags, but we want paragraphs.
|
2034
|
-
elList = text.split('<br><br>');
|
2035
|
-
|
2036
|
-
this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>');
|
2037
|
-
this.options.ownerDocument.execCommand('insertText', false, "\n");
|
2038
|
-
|
2039
|
-
// block element cleanup
|
2040
|
-
elList = el.querySelectorAll('a,p,div,br');
|
2041
|
-
for (i = 0; i < elList.length; i += 1) {
|
2042
|
-
|
2043
|
-
workEl = elList[i];
|
2044
|
-
|
2045
|
-
switch (workEl.tagName.toLowerCase()) {
|
2046
|
-
case 'a':
|
2047
|
-
if (this.options.targetBlank) {
|
2048
|
-
this.setTargetBlank(workEl);
|
2049
|
-
}
|
2050
|
-
break;
|
2051
|
-
case 'p':
|
2052
|
-
case 'div':
|
2053
|
-
this.filterCommonBlocks(workEl);
|
2054
|
-
break;
|
2055
|
-
case 'br':
|
2056
|
-
this.filterLineBreak(workEl);
|
2057
|
-
break;
|
2058
|
-
}
|
2059
|
-
|
2060
|
-
}
|
2061
|
-
|
2062
|
-
|
2063
|
-
} else {
|
2064
|
-
|
2065
|
-
this.pasteHTML(text);
|
2066
|
-
|
2067
|
-
}
|
2068
|
-
|
2964
|
+
pasteHandler.cleanPaste(text, this.options);
|
2069
2965
|
},
|
2070
2966
|
|
2071
2967
|
pasteHTML: function (html) {
|
2072
|
-
|
2073
|
-
|
2074
|
-
pasteBlock.appendChild(this.options.ownerDocument.createElement('body'));
|
2075
|
-
|
2076
|
-
fragmentBody = pasteBlock.querySelector('body');
|
2077
|
-
fragmentBody.innerHTML = html;
|
2078
|
-
|
2079
|
-
this.cleanupSpans(fragmentBody);
|
2080
|
-
|
2081
|
-
elList = fragmentBody.querySelectorAll('*');
|
2082
|
-
for (i = 0; i < elList.length; i += 1) {
|
2083
|
-
|
2084
|
-
workEl = elList[i];
|
2085
|
-
|
2086
|
-
// delete ugly attributes
|
2087
|
-
workEl.removeAttribute('class');
|
2088
|
-
workEl.removeAttribute('style');
|
2089
|
-
workEl.removeAttribute('dir');
|
2090
|
-
|
2091
|
-
if (workEl.tagName.toLowerCase() === 'meta') {
|
2092
|
-
workEl.parentNode.removeChild(workEl);
|
2093
|
-
}
|
2094
|
-
|
2095
|
-
}
|
2096
|
-
insertHTMLCommand(this.options.ownerDocument, fragmentBody.innerHTML.replace(/ /g, ' '));
|
2097
|
-
},
|
2098
|
-
isCommonBlock: function (el) {
|
2099
|
-
return (el && (el.tagName.toLowerCase() === 'p' || el.tagName.toLowerCase() === 'div'));
|
2100
|
-
},
|
2101
|
-
filterCommonBlocks: function (el) {
|
2102
|
-
if (/^\s*$/.test(el.textContent)) {
|
2103
|
-
el.parentNode.removeChild(el);
|
2104
|
-
}
|
2105
|
-
},
|
2106
|
-
filterLineBreak: function (el) {
|
2107
|
-
if (this.isCommonBlock(el.previousElementSibling)) {
|
2108
|
-
|
2109
|
-
// remove stray br's following common block elements
|
2110
|
-
el.parentNode.removeChild(el);
|
2111
|
-
|
2112
|
-
} else if (this.isCommonBlock(el.parentNode) && (el.parentNode.firstChild === el || el.parentNode.lastChild === el)) {
|
2113
|
-
|
2114
|
-
// remove br's just inside open or close tags of a div/p
|
2115
|
-
el.parentNode.removeChild(el);
|
2116
|
-
|
2117
|
-
} else if (el.parentNode.childElementCount === 1) {
|
2118
|
-
|
2119
|
-
// and br's that are the only child of a div/p
|
2120
|
-
this.removeWithParent(el);
|
2121
|
-
|
2122
|
-
}
|
2123
|
-
|
2124
|
-
},
|
2125
|
-
|
2126
|
-
// remove an element, including its parent, if it is the only element within its parent
|
2127
|
-
removeWithParent: function (el) {
|
2128
|
-
if (el && el.parentNode) {
|
2129
|
-
if (el.parentNode.parentNode && el.parentNode.childElementCount === 1) {
|
2130
|
-
el.parentNode.parentNode.removeChild(el.parentNode);
|
2131
|
-
} else {
|
2132
|
-
el.parentNode.removeChild(el.parentNode);
|
2133
|
-
}
|
2134
|
-
}
|
2135
|
-
},
|
2136
|
-
|
2137
|
-
cleanupSpans: function (container_el) {
|
2138
|
-
|
2139
|
-
var i,
|
2140
|
-
el,
|
2141
|
-
new_el,
|
2142
|
-
spans = container_el.querySelectorAll('.replace-with');
|
2143
|
-
|
2144
|
-
for (i = 0; i < spans.length; i += 1) {
|
2145
|
-
|
2146
|
-
el = spans[i];
|
2147
|
-
new_el = this.options.ownerDocument.createElement(el.classList.contains('bold') ? 'b' : 'i');
|
2148
|
-
|
2149
|
-
if (el.classList.contains('bold') && el.classList.contains('italic')) {
|
2150
|
-
|
2151
|
-
// add an i tag as well if this has both italics and bold
|
2152
|
-
new_el.innerHTML = '<i>' + el.innerHTML + '</i>';
|
2153
|
-
|
2154
|
-
} else {
|
2155
|
-
|
2156
|
-
new_el.innerHTML = el.innerHTML;
|
2157
|
-
|
2158
|
-
}
|
2159
|
-
el.parentNode.replaceChild(new_el, el);
|
2160
|
-
|
2161
|
-
}
|
2162
|
-
|
2163
|
-
spans = container_el.querySelectorAll('span');
|
2164
|
-
for (i = 0; i < spans.length; i += 1) {
|
2165
|
-
|
2166
|
-
el = spans[i];
|
2167
|
-
|
2168
|
-
// remove empty spans, replace others with their contents
|
2169
|
-
if (/^\s*$/.test()) {
|
2170
|
-
el.parentNode.removeChild(el);
|
2171
|
-
} else {
|
2172
|
-
el.parentNode.replaceChild(this.options.ownerDocument.createTextNode(el.textContent), el);
|
2173
|
-
}
|
2174
|
-
|
2175
|
-
}
|
2176
|
-
|
2968
|
+
pasteHandler.pasteHTML(html, this.options.ownerDocument);
|
2177
2969
|
}
|
2178
|
-
|
2179
2970
|
};
|
2180
2971
|
|
2181
|
-
}(
|
2972
|
+
}());
|
2973
|
+
|
2974
|
+
return MediumEditor;
|
2975
|
+
}()));
|