From ebe149110be982eae4fea481f3dabd6de492674d Mon Sep 17 00:00:00 2001 From: did Date: Mon, 16 Jan 2012 23:59:59 +0100 Subject: [PATCH] first draft of the new inline editing toolbar --- Gemfile | 4 +- .../locomotive/inline_editor.js.coffee | 20 + .../javascripts/locomotive/utils/core_ext.js | 20 + .../inline_editor/application_view.js.coffee | 133 + .../inline_editor/toolbar_view.js.coffee | 43 + .../views/pages/_form_view.js.coffee | 2 + app/assets/stylesheets/locomotive.css | 2 +- .../locomotive/{ => backoffice}/_box.css.scss | 0 .../{ => backoffice}/_buttons.css.scss | 0 .../{ => backoffice}/_helpers.css.scss | 0 .../{ => backoffice}/_picker.css.scss | 0 .../{ => backoffice}/application.css.scss | 0 .../codemirror_changes.css.scss | 0 .../{ => backoffice}/content_assets.css.scss | 0 .../content_locale_picker.css.scss | 0 .../{ => backoffice}/datepicker.css.scss | 0 .../{ => backoffice}/dialog_changes.css.scss | 0 .../editable_elements.css.scss | 0 .../formtastic_changes.css.scss | 0 .../{ => backoffice}/installation.css.scss | 0 .../{ => backoffice}/layout.css.scss | 0 .../locomotive/{ => backoffice}/menu.css | 0 .../{ => backoffice}/menu/_colors.css.scss | 0 .../{ => backoffice}/menu/_helpers.css.scss | 0 .../{ => backoffice}/menu/_icons.css.scss | 0 .../{ => backoffice}/menu/default.css.scss | 0 .../{ => backoffice}/menu/main.css.scss | 0 .../{ => backoffice}/menu/sub.css.scss | 0 .../{ => backoffice}/not_logged_in.css | 0 .../{ => backoffice}/simple.css.scss | 0 .../{ => backoffice}/sites_picker.css.scss | 0 .../stylesheets/locomotive/inline_editor.css | 8 + .../locomotive/inline_editor/layout.css.scss | 16 + .../locomotive/inline_editor/toolbar.css.scss | 67 + ...ring_controller.rb => pages_controller.rb} | 12 +- .../locomotive/inline_editor_middleware.rb | 34 + app/presenters/locomotive/page_presenter.rb | 4 +- .../locomotive/public/pages/edit.html.haml | 50 + config/routes.rb | 9 +- lib/locomotive/liquid/tags/inline_editor.rb | 84 +- lib/locomotive/render.rb | 7 +- spec/dummy/config/application.rb | 2 + .../locomotive/aloha/css/aloha-core.css | 44 + .../locomotive/aloha/css/aloha-sidebar.css | 284 + .../locomotive/aloha/css/aloha.css | 7774 ++ .../locomotive/aloha/css/ext-aloha-reset.css | 33 + .../locomotive/aloha/css/ext-aloha.css | 357 + .../locomotive/aloha/img/arrow-down.png | Bin 0 -> 770 bytes .../locomotive/aloha/img/arrow-left.png | Bin 0 -> 790 bytes .../locomotive/aloha/img/arrow.png | Bin 0 -> 719 bytes .../locomotive/aloha/img/base-big.png | Bin 0 -> 1428 bytes .../locomotive/aloha/img/base-multi.png | Bin 0 -> 2636 bytes .../javascripts/locomotive/aloha/img/base.png | Bin 0 -> 5408 bytes .../javascripts/locomotive/aloha/img/bg.png | Bin 0 -> 520969 bytes .../aloha/img/breadcrumb-divider.png | Bin 0 -> 330 bytes .../locomotive/aloha/img/fade-in.png | Bin 0 -> 278 bytes .../locomotive/aloha/img/fade-out.png | Bin 0 -> 292 bytes .../locomotive/aloha/img/gentics-logo.png | Bin 0 -> 2094 bytes .../locomotive/aloha/img/grabhandle.png | Bin 0 -> 112 bytes .../locomotive/aloha/img/maximize.png | Bin 0 -> 123 bytes .../locomotive/aloha/img/multisplit-base.jpg | Bin 0 -> 929 bytes .../locomotive/aloha/img/multisplit-close.gif | Bin 0 -> 211 bytes .../locomotive/aloha/img/multisplit-open.gif | Bin 0 -> 211 bytes .../javascripts/locomotive/aloha/img/pin.png | Bin 0 -> 564 bytes .../locomotive/aloha/img/removeformat.png | Bin 0 -> 193 bytes .../locomotive/aloha/img/text_indent.png | Bin 0 -> 353 bytes .../aloha/img/text_indent_remove.png | Bin 0 -> 351 bytes .../locomotive/aloha/lib/aloha-bootstrap.js | 27566 +++++ .../javascripts/locomotive/aloha/lib/aloha.js | 88671 ++++++++++++++++ .../locomotive/aloha/lib/aloha/command.js | 246 + .../locomotive/aloha/lib/aloha/console.js | 330 + .../aloha/lib/aloha/contenthandlermanager.js | 65 + .../locomotive/aloha/lib/aloha/core.js | 560 + .../locomotive/aloha/lib/aloha/ecma5.js | 194 + .../locomotive/aloha/lib/aloha/ecma5shims.js | 280 + .../locomotive/aloha/lib/aloha/editable.js | 878 + .../locomotive/aloha/lib/aloha/engine.js | 8306 ++ .../aloha/lib/aloha/ext-alohaproxy.js | 86 + .../aloha/lib/aloha/ext-alohareader.js | 50 + .../aloha/lib/aloha/ext-alohatreeloader.js | 77 + .../locomotive/aloha/lib/aloha/ext.js | 32 + .../aloha/lib/aloha/floatingmenu.js | 1286 + .../locomotive/aloha/lib/aloha/ierange-m2.js | 546 + .../aloha/lib/aloha/jquery.aloha.js | 324 + .../locomotive/aloha/lib/aloha/jquery.js | 24 + .../aloha/lib/aloha/jquery.patch.js | 115 + .../locomotive/aloha/lib/aloha/markup.js | 898 + .../locomotive/aloha/lib/aloha/message.js | 115 + .../locomotive/aloha/lib/aloha/nls/de/i18n.js | 10 + .../locomotive/aloha/lib/aloha/nls/i18n.js | 20 + .../locomotive/aloha/lib/aloha/observable.js | 106 + .../locomotive/aloha/lib/aloha/plugin.js | 276 + .../aloha/lib/aloha/pluginmanager.js | 146 + .../locomotive/aloha/lib/aloha/rangy-core.js | 3242 + .../locomotive/aloha/lib/aloha/registry.js | 59 + .../locomotive/aloha/lib/aloha/repository.js | 241 + .../aloha/lib/aloha/repositorymanager.js | 571 + .../aloha/lib/aloha/repositoryobjects.js | 146 + .../locomotive/aloha/lib/aloha/selection.js | 2082 + .../locomotive/aloha/lib/aloha/sidebar.js | 1133 + .../aloha/lib/aloha/ui-attributefield.js | 524 + .../locomotive/aloha/lib/aloha/ui-browser.js | 214 + .../locomotive/aloha/lib/aloha/ui.js | 889 + .../javascripts/locomotive/aloha/lib/css.js | 313 + .../javascripts/locomotive/aloha/lib/i18n.js | 153 + .../locomotive/aloha/lib/jquery-plugin.js | 46 + .../javascripts/locomotive/aloha/lib/order.js | 140 + .../locomotive/aloha/lib/require.js | 2013 + .../javascripts/locomotive/aloha/lib/text.js | 262 + .../locomotive/aloha/lib/util/class.js | 80 + .../locomotive/aloha/lib/util/dom.js | 1673 + .../locomotive/aloha/lib/util/json2.js | 481 + .../locomotive/aloha/lib/util/lang.js | 66 + .../locomotive/aloha/lib/util/position.js | 158 + .../locomotive/aloha/lib/util/range.js | 923 + .../jquery/ext-jquery-adapter-debug.js | 2470 + .../adapter/jquery/ext-jquery-adapter.js | 7 + .../lib/vendor/ext-3.2.1/ext-all-debug.js | 47684 +++++++++ .../aloha/lib/vendor/ext-3.2.1/ext-all.js | 13 + .../aloha/lib/vendor/ext-3.2.1/gpl-3.0.txt | 674 + .../aloha/lib/vendor/ext-3.2.1/license.txt | 42 + .../lib/vendor/ext-3.2.1/resources/charts.swf | Bin 0 -> 81768 bytes .../ext-3.2.1/resources/css/ext-all.css | 5903 + .../ext-3.2.1/resources/css/ext-all.less | 6795 ++ .../ext-3.2.1/resources/css/xtheme-gray.css | 1692 + .../ext-3.2.1/resources/expressinstall.swf | Bin 0 -> 4823 bytes .../images/default/box/corners-blue.gif | Bin 0 -> 1010 bytes .../resources/images/default/box/corners.gif | Bin 0 -> 1005 bytes .../resources/images/default/box/l-blue.gif | Bin 0 -> 810 bytes .../resources/images/default/box/l.gif | Bin 0 -> 810 bytes .../resources/images/default/box/r-blue.gif | Bin 0 -> 810 bytes .../resources/images/default/box/r.gif | Bin 0 -> 810 bytes .../resources/images/default/box/tb-blue.gif | Bin 0 -> 851 bytes .../resources/images/default/box/tb.gif | Bin 0 -> 839 bytes .../resources/images/default/button/arrow.gif | Bin 0 -> 828 bytes .../resources/images/default/button/btn.gif | Bin 0 -> 4298 bytes .../images/default/button/group-cs.gif | Bin 0 -> 2459 bytes .../images/default/button/group-lr.gif | Bin 0 -> 861 bytes .../images/default/button/group-tb.gif | Bin 0 -> 846 bytes .../default/button/s-arrow-b-noline.gif | Bin 0 -> 898 bytes .../images/default/button/s-arrow-b.gif | Bin 0 -> 937 bytes .../images/default/button/s-arrow-bo.gif | Bin 0 -> 139 bytes .../images/default/button/s-arrow-noline.gif | Bin 0 -> 863 bytes .../images/default/button/s-arrow-o.gif | Bin 0 -> 937 bytes .../images/default/button/s-arrow.gif | Bin 0 -> 937 bytes .../resources/images/default/dd/drop-add.gif | Bin 0 -> 1001 bytes .../resources/images/default/dd/drop-no.gif | Bin 0 -> 949 bytes .../resources/images/default/dd/drop-yes.gif | Bin 0 -> 1016 bytes .../images/default/editor/tb-sprite.gif | Bin 0 -> 2072 bytes .../images/default/form/checkbox.gif | Bin 0 -> 2061 bytes .../images/default/form/clear-trigger.gif | Bin 0 -> 1988 bytes .../images/default/form/clear-trigger.psd | Bin 0 -> 11804 bytes .../images/default/form/date-trigger.gif | Bin 0 -> 1603 bytes .../images/default/form/date-trigger.psd | Bin 0 -> 12377 bytes .../images/default/form/error-tip-corners.gif | Bin 0 -> 4183 bytes .../images/default/form/exclamation.gif | Bin 0 -> 996 bytes .../resources/images/default/form/radio.gif | Bin 0 -> 1746 bytes .../images/default/form/search-trigger.gif | Bin 0 -> 2182 bytes .../images/default/form/search-trigger.psd | Bin 0 -> 15601 bytes .../resources/images/default/form/text-bg.gif | Bin 0 -> 819 bytes .../images/default/form/trigger-square.gif | Bin 0 -> 1810 bytes .../images/default/form/trigger-square.psd | Bin 0 -> 36542 bytes .../images/default/form/trigger-tpl.gif | Bin 0 -> 1487 bytes .../resources/images/default/form/trigger.gif | Bin 0 -> 1816 bytes .../resources/images/default/form/trigger.psd | Bin 0 -> 37599 bytes .../resources/images/default/gradient-bg.gif | Bin 0 -> 1472 bytes .../images/default/grid/arrow-left-white.gif | Bin 0 -> 825 bytes .../images/default/grid/arrow-right-white.gif | Bin 0 -> 825 bytes .../images/default/grid/col-move-bottom.gif | Bin 0 -> 868 bytes .../images/default/grid/col-move-top.gif | Bin 0 -> 869 bytes .../resources/images/default/grid/columns.gif | Bin 0 -> 962 bytes .../resources/images/default/grid/dirty.gif | Bin 0 -> 832 bytes .../resources/images/default/grid/done.gif | Bin 0 -> 133 bytes .../resources/images/default/grid/drop-no.gif | Bin 0 -> 947 bytes .../images/default/grid/drop-yes.gif | Bin 0 -> 860 bytes .../images/default/grid/footer-bg.gif | Bin 0 -> 834 bytes .../images/default/grid/grid-blue-hd.gif | Bin 0 -> 829 bytes .../images/default/grid/grid-blue-split.gif | Bin 0 -> 817 bytes .../images/default/grid/grid-hrow.gif | Bin 0 -> 855 bytes .../images/default/grid/grid-loading.gif | Bin 0 -> 701 bytes .../images/default/grid/grid-split.gif | Bin 0 -> 817 bytes .../images/default/grid/grid-vista-hd.gif | Bin 0 -> 829 bytes .../images/default/grid/grid3-hd-btn.gif | Bin 0 -> 1229 bytes .../images/default/grid/grid3-hrow-over.gif | Bin 0 -> 823 bytes .../images/default/grid/grid3-hrow.gif | Bin 0 -> 836 bytes .../default/grid/grid3-special-col-bg.gif | Bin 0 -> 837 bytes .../default/grid/grid3-special-col-sel-bg.gif | Bin 0 -> 843 bytes .../images/default/grid/group-by.gif | Bin 0 -> 917 bytes .../images/default/grid/group-collapse.gif | Bin 0 -> 881 bytes .../default/grid/group-expand-sprite.gif | Bin 0 -> 955 bytes .../images/default/grid/group-expand.gif | Bin 0 -> 884 bytes .../resources/images/default/grid/hd-pop.gif | Bin 0 -> 839 bytes .../images/default/grid/hmenu-asc.gif | Bin 0 -> 931 bytes .../images/default/grid/hmenu-desc.gif | Bin 0 -> 930 bytes .../images/default/grid/hmenu-lock.gif | Bin 0 -> 955 bytes .../images/default/grid/hmenu-lock.png | Bin 0 -> 648 bytes .../images/default/grid/hmenu-unlock.gif | Bin 0 -> 971 bytes .../images/default/grid/hmenu-unlock.png | Bin 0 -> 697 bytes .../images/default/grid/invalid_line.gif | Bin 0 -> 815 bytes .../resources/images/default/grid/loading.gif | Bin 0 -> 771 bytes .../resources/images/default/grid/mso-hd.gif | Bin 0 -> 875 bytes .../resources/images/default/grid/nowait.gif | Bin 0 -> 884 bytes .../default/grid/page-first-disabled.gif | Bin 0 -> 925 bytes .../images/default/grid/page-first.gif | Bin 0 -> 925 bytes .../default/grid/page-last-disabled.gif | Bin 0 -> 923 bytes .../images/default/grid/page-last.gif | Bin 0 -> 923 bytes .../default/grid/page-next-disabled.gif | Bin 0 -> 875 bytes .../images/default/grid/page-next.gif | Bin 0 -> 875 bytes .../default/grid/page-prev-disabled.gif | Bin 0 -> 879 bytes .../images/default/grid/page-prev.gif | Bin 0 -> 879 bytes .../images/default/grid/pick-button.gif | Bin 0 -> 1036 bytes .../resources/images/default/grid/refresh.gif | Bin 0 -> 977 bytes .../images/default/grid/row-check-sprite.gif | Bin 0 -> 1083 bytes .../images/default/grid/row-expand-sprite.gif | Bin 0 -> 955 bytes .../images/default/grid/row-over.gif | Bin 0 -> 823 bytes .../resources/images/default/grid/row-sel.gif | Bin 0 -> 823 bytes .../resources/images/default/grid/sort-hd.gif | Bin 0 -> 1473 bytes .../images/default/grid/sort_asc.gif | Bin 0 -> 830 bytes .../images/default/grid/sort_desc.gif | Bin 0 -> 833 bytes .../resources/images/default/grid/wait.gif | Bin 0 -> 1100 bytes .../images/default/layout/collapse.gif | Bin 0 -> 842 bytes .../images/default/layout/expand.gif | Bin 0 -> 842 bytes .../images/default/layout/gradient-bg.gif | Bin 0 -> 1472 bytes .../images/default/layout/mini-bottom.gif | Bin 0 -> 856 bytes .../images/default/layout/mini-left.gif | Bin 0 -> 871 bytes .../images/default/layout/mini-right.gif | Bin 0 -> 872 bytes .../images/default/layout/mini-top.gif | Bin 0 -> 856 bytes .../images/default/layout/ns-collapse.gif | Bin 0 -> 842 bytes .../images/default/layout/ns-expand.gif | Bin 0 -> 843 bytes .../images/default/layout/panel-close.gif | Bin 0 -> 829 bytes .../images/default/layout/panel-title-bg.gif | Bin 0 -> 838 bytes .../default/layout/panel-title-light-bg.gif | Bin 0 -> 835 bytes .../resources/images/default/layout/stick.gif | Bin 0 -> 874 bytes .../resources/images/default/layout/stuck.gif | Bin 0 -> 92 bytes .../images/default/layout/tab-close-on.gif | Bin 0 -> 880 bytes .../images/default/layout/tab-close.gif | Bin 0 -> 859 bytes .../resources/images/default/menu/checked.gif | Bin 0 -> 959 bytes .../images/default/menu/group-checked.gif | Bin 0 -> 891 bytes .../images/default/menu/item-over.gif | Bin 0 -> 820 bytes .../images/default/menu/menu-parent.gif | Bin 0 -> 854 bytes .../resources/images/default/menu/menu.gif | Bin 0 -> 834 bytes .../images/default/menu/unchecked.gif | Bin 0 -> 941 bytes .../images/default/panel/corners-sprite.gif | Bin 0 -> 1418 bytes .../images/default/panel/left-right.gif | Bin 0 -> 815 bytes .../images/default/panel/light-hd.gif | Bin 0 -> 827 bytes .../images/default/panel/tool-sprite-tpl.gif | Bin 0 -> 971 bytes .../images/default/panel/tool-sprites.gif | Bin 0 -> 4392 bytes .../default/panel/tools-sprites-trans.gif | Bin 0 -> 2843 bytes .../images/default/panel/top-bottom.gif | Bin 0 -> 875 bytes .../images/default/panel/top-bottom.png | Bin 0 -> 218 bytes .../default/panel/white-corners-sprite.gif | Bin 0 -> 1366 bytes .../images/default/panel/white-left-right.gif | Bin 0 -> 815 bytes .../images/default/panel/white-top-bottom.gif | Bin 0 -> 872 bytes .../images/default/progress/progress-bg.gif | Bin 0 -> 834 bytes .../resources/images/default/qtip/bg.gif | Bin 0 -> 1091 bytes .../resources/images/default/qtip/close.gif | Bin 0 -> 972 bytes .../images/default/qtip/tip-anchor-sprite.gif | Bin 0 -> 951 bytes .../images/default/qtip/tip-sprite.gif | Bin 0 -> 4271 bytes .../ext-3.2.1/resources/images/default/s.gif | Bin 0 -> 43 bytes .../resources/images/default/shadow-c.png | Bin 0 -> 118 bytes .../resources/images/default/shadow-lr.png | Bin 0 -> 135 bytes .../resources/images/default/shadow.png | Bin 0 -> 311 bytes .../images/default/shared/blue-loading.gif | Bin 0 -> 3236 bytes .../images/default/shared/calendar.gif | Bin 0 -> 979 bytes .../images/default/shared/glass-bg.gif | Bin 0 -> 873 bytes .../images/default/shared/hd-sprite.gif | Bin 0 -> 1099 bytes .../images/default/shared/large-loading.gif | Bin 0 -> 3236 bytes .../images/default/shared/left-btn.gif | Bin 0 -> 870 bytes .../images/default/shared/loading-balls.gif | Bin 0 -> 2118 bytes .../images/default/shared/right-btn.gif | Bin 0 -> 871 bytes .../images/default/shared/warning.gif | Bin 0 -> 960 bytes .../images/default/sizer/e-handle-dark.gif | Bin 0 -> 1062 bytes .../images/default/sizer/e-handle.gif | Bin 0 -> 1586 bytes .../images/default/sizer/ne-handle-dark.gif | Bin 0 -> 839 bytes .../images/default/sizer/ne-handle.gif | Bin 0 -> 854 bytes .../images/default/sizer/nw-handle-dark.gif | Bin 0 -> 839 bytes .../images/default/sizer/nw-handle.gif | Bin 0 -> 853 bytes .../images/default/sizer/s-handle-dark.gif | Bin 0 -> 1060 bytes .../images/default/sizer/s-handle.gif | Bin 0 -> 1318 bytes .../images/default/sizer/se-handle-dark.gif | Bin 0 -> 838 bytes .../images/default/sizer/se-handle.gif | Bin 0 -> 853 bytes .../resources/images/default/sizer/square.gif | Bin 0 -> 864 bytes .../images/default/sizer/sw-handle-dark.gif | Bin 0 -> 839 bytes .../images/default/sizer/sw-handle.gif | Bin 0 -> 855 bytes .../images/default/slider/slider-bg.png | Bin 0 -> 300 bytes .../images/default/slider/slider-thumb.png | Bin 0 -> 933 bytes .../images/default/slider/slider-v-bg.png | Bin 0 -> 288 bytes .../images/default/slider/slider-v-thumb.png | Bin 0 -> 883 bytes .../images/default/tabs/scroll-left.gif | Bin 0 -> 1295 bytes .../images/default/tabs/scroll-right.gif | Bin 0 -> 1300 bytes .../images/default/tabs/scroller-bg.gif | Bin 0 -> 1100 bytes .../default/tabs/tab-btm-inactive-left-bg.gif | Bin 0 -> 886 bytes .../tabs/tab-btm-inactive-right-bg.gif | Bin 0 -> 1386 bytes .../images/default/tabs/tab-btm-left-bg.gif | Bin 0 -> 1402 bytes .../default/tabs/tab-btm-over-left-bg.gif | Bin 0 -> 191 bytes .../default/tabs/tab-btm-over-right-bg.gif | Bin 0 -> 638 bytes .../images/default/tabs/tab-btm-right-bg.gif | Bin 0 -> 863 bytes .../images/default/tabs/tab-close.gif | Bin 0 -> 896 bytes .../images/default/tabs/tab-strip-bg.gif | Bin 0 -> 835 bytes .../images/default/tabs/tab-strip-bg.png | Bin 0 -> 259 bytes .../images/default/tabs/tab-strip-btm-bg.gif | Bin 0 -> 826 bytes .../images/default/tabs/tabs-sprite.gif | Bin 0 -> 2120 bytes .../resources/images/default/toolbar/bg.gif | Bin 0 -> 904 bytes .../default/toolbar/btn-arrow-light.gif | Bin 0 -> 916 bytes .../images/default/toolbar/btn-arrow.gif | Bin 0 -> 919 bytes .../images/default/toolbar/btn-over-bg.gif | Bin 0 -> 837 bytes .../images/default/toolbar/gray-bg.gif | Bin 0 -> 832 bytes .../resources/images/default/toolbar/more.gif | Bin 0 -> 845 bytes .../images/default/toolbar/tb-bg.gif | Bin 0 -> 862 bytes .../images/default/toolbar/tb-btn-sprite.gif | Bin 0 -> 1127 bytes .../default/toolbar/tb-xl-btn-sprite.gif | Bin 0 -> 1663 bytes .../images/default/toolbar/tb-xl-sep.gif | Bin 0 -> 810 bytes .../resources/images/default/tree/arrows.gif | Bin 0 -> 617 bytes .../images/default/tree/drop-add.gif | Bin 0 -> 1001 bytes .../images/default/tree/drop-between.gif | Bin 0 -> 907 bytes .../resources/images/default/tree/drop-no.gif | Bin 0 -> 949 bytes .../images/default/tree/drop-over.gif | Bin 0 -> 911 bytes .../images/default/tree/drop-under.gif | Bin 0 -> 911 bytes .../images/default/tree/drop-yes.gif | Bin 0 -> 1016 bytes .../default/tree/elbow-end-minus-nl.gif | Bin 0 -> 898 bytes .../images/default/tree/elbow-end-minus.gif | Bin 0 -> 905 bytes .../images/default/tree/elbow-end-plus-nl.gif | Bin 0 -> 900 bytes .../images/default/tree/elbow-end-plus.gif | Bin 0 -> 907 bytes .../images/default/tree/elbow-end.gif | Bin 0 -> 844 bytes .../images/default/tree/elbow-line.gif | Bin 0 -> 846 bytes .../images/default/tree/elbow-minus-nl.gif | Bin 0 -> 898 bytes .../images/default/tree/elbow-minus.gif | Bin 0 -> 908 bytes .../images/default/tree/elbow-plus-nl.gif | Bin 0 -> 900 bytes .../images/default/tree/elbow-plus.gif | Bin 0 -> 910 bytes .../resources/images/default/tree/elbow.gif | Bin 0 -> 850 bytes .../images/default/tree/folder-open.gif | Bin 0 -> 956 bytes .../resources/images/default/tree/folder.gif | Bin 0 -> 952 bytes .../resources/images/default/tree/leaf.gif | Bin 0 -> 945 bytes .../resources/images/default/tree/loading.gif | Bin 0 -> 771 bytes .../resources/images/default/tree/s.gif | Bin 0 -> 43 bytes .../images/default/window/icon-error.gif | Bin 0 -> 1669 bytes .../images/default/window/icon-info.gif | Bin 0 -> 1586 bytes .../images/default/window/icon-question.gif | Bin 0 -> 1607 bytes .../images/default/window/icon-warning.gif | Bin 0 -> 1483 bytes .../images/default/window/left-corners.png | Bin 0 -> 200 bytes .../images/default/window/left-corners.psd | Bin 0 -> 15576 bytes .../images/default/window/left-right.png | Bin 0 -> 152 bytes .../images/default/window/left-right.psd | Bin 0 -> 24046 bytes .../images/default/window/right-corners.png | Bin 0 -> 256 bytes .../images/default/window/right-corners.psd | Bin 0 -> 15530 bytes .../images/default/window/top-bottom.png | Bin 0 -> 180 bytes .../images/default/window/top-bottom.psd | Bin 0 -> 32128 bytes .../images/gray/button/btn-arrow.gif | Bin 0 -> 870 bytes .../images/gray/button/btn-sprite.gif | Bin 0 -> 1222 bytes .../resources/images/gray/button/btn.gif | Bin 0 -> 3319 bytes .../resources/images/gray/button/group-cs.gif | Bin 0 -> 2459 bytes .../resources/images/gray/button/group-lr.gif | Bin 0 -> 861 bytes .../resources/images/gray/button/group-tb.gif | Bin 0 -> 846 bytes .../images/gray/button/s-arrow-bo.gif | Bin 0 -> 123 bytes .../images/gray/button/s-arrow-o.gif | Bin 0 -> 139 bytes .../images/gray/form/clear-trigger.gif | Bin 0 -> 1425 bytes .../images/gray/form/date-trigger.gif | Bin 0 -> 929 bytes .../images/gray/form/search-trigger.gif | Bin 0 -> 2220 bytes .../images/gray/form/trigger-square.gif | Bin 0 -> 1071 bytes .../resources/images/gray/form/trigger.gif | Bin 0 -> 1080 bytes .../resources/images/gray/gradient-bg.gif | Bin 0 -> 1472 bytes .../images/gray/grid/col-move-bottom.gif | Bin 0 -> 177 bytes .../images/gray/grid/col-move-top.gif | Bin 0 -> 178 bytes .../images/gray/grid/grid3-hd-btn.gif | Bin 0 -> 482 bytes .../images/gray/grid/grid3-hrow-over.gif | Bin 0 -> 56 bytes .../images/gray/grid/grid3-hrow-over2.gif | Bin 0 -> 107 bytes .../resources/images/gray/grid/grid3-hrow.gif | Bin 0 -> 836 bytes .../images/gray/grid/grid3-hrow2.gif | Bin 0 -> 107 bytes .../images/gray/grid/grid3-special-col-bg.gif | Bin 0 -> 158 bytes .../gray/grid/grid3-special-col-bg2.gif | Bin 0 -> 158 bytes .../gray/grid/grid3-special-col-sel-bg.gif | Bin 0 -> 158 bytes .../images/gray/grid/group-collapse.gif | Bin 0 -> 136 bytes .../images/gray/grid/group-expand-sprite.gif | Bin 0 -> 196 bytes .../images/gray/grid/group-expand.gif | Bin 0 -> 138 bytes .../resources/images/gray/grid/page-first.gif | Bin 0 -> 327 bytes .../resources/images/gray/grid/page-last.gif | Bin 0 -> 325 bytes .../resources/images/gray/grid/page-next.gif | Bin 0 -> 183 bytes .../resources/images/gray/grid/page-prev.gif | Bin 0 -> 186 bytes .../resources/images/gray/grid/refresh.gif | Bin 0 -> 570 bytes .../images/gray/grid/row-expand-sprite.gif | Bin 0 -> 196 bytes .../resources/images/gray/grid/sort_asc.gif | Bin 0 -> 59 bytes .../resources/images/gray/grid/sort_desc.gif | Bin 0 -> 59 bytes .../images/gray/menu/group-checked.gif | Bin 0 -> 295 bytes .../images/gray/menu/item-over-disabled.gif | Bin 0 -> 49 bytes .../resources/images/gray/menu/item-over.gif | Bin 0 -> 850 bytes .../images/gray/menu/menu-parent.gif | Bin 0 -> 165 bytes .../images/gray/panel/corners-sprite.gif | Bin 0 -> 1402 bytes .../images/gray/panel/left-right.gif | Bin 0 -> 815 bytes .../resources/images/gray/panel/light-hd.gif | Bin 0 -> 827 bytes .../images/gray/panel/tool-sprite-tpl.gif | Bin 0 -> 971 bytes .../images/gray/panel/tool-sprites.gif | Bin 0 -> 4464 bytes .../images/gray/panel/tools-sprites-trans.gif | Bin 0 -> 1981 bytes .../images/gray/panel/top-bottom.gif | Bin 0 -> 871 bytes .../images/gray/panel/top-bottom.png | Bin 0 -> 218 bytes .../gray/panel/white-corners-sprite.gif | Bin 0 -> 1365 bytes .../images/gray/panel/white-left-right.gif | Bin 0 -> 815 bytes .../images/gray/panel/white-top-bottom.gif | Bin 0 -> 860 bytes .../images/gray/progress/progress-bg.gif | Bin 0 -> 107 bytes .../resources/images/gray/qtip/bg.gif | Bin 0 -> 1024 bytes .../resources/images/gray/qtip/close.gif | Bin 0 -> 972 bytes .../images/gray/qtip/tip-anchor-sprite.gif | Bin 0 -> 164 bytes .../resources/images/gray/qtip/tip-sprite.gif | Bin 0 -> 3241 bytes .../ext-3.2.1/resources/images/gray/s.gif | Bin 0 -> 43 bytes .../images/gray/shared/hd-sprite.gif | Bin 0 -> 305 bytes .../resources/images/gray/shared/left-btn.gif | Bin 0 -> 106 bytes .../images/gray/shared/right-btn.gif | Bin 0 -> 107 bytes .../resources/images/gray/sizer/e-handle.gif | Bin 0 -> 753 bytes .../resources/images/gray/sizer/ne-handle.gif | Bin 0 -> 128 bytes .../resources/images/gray/sizer/nw-handle.gif | Bin 0 -> 114 bytes .../resources/images/gray/sizer/s-handle.gif | Bin 0 -> 494 bytes .../resources/images/gray/sizer/se-handle.gif | Bin 0 -> 114 bytes .../resources/images/gray/sizer/square.gif | Bin 0 -> 123 bytes .../resources/images/gray/sizer/sw-handle.gif | Bin 0 -> 116 bytes .../images/gray/slider/slider-thumb.png | Bin 0 -> 675 bytes .../images/gray/slider/slider-v-thumb.png | Bin 0 -> 632 bytes .../images/gray/tabs/scroll-left.gif | Bin 0 -> 1260 bytes .../images/gray/tabs/scroll-right.gif | Bin 0 -> 1269 bytes .../images/gray/tabs/scroller-bg.gif | Bin 0 -> 1090 bytes .../gray/tabs/tab-btm-inactive-left-bg.gif | Bin 0 -> 881 bytes .../gray/tabs/tab-btm-inactive-right-bg.gif | Bin 0 -> 1383 bytes .../images/gray/tabs/tab-btm-left-bg.gif | Bin 0 -> 1402 bytes .../images/gray/tabs/tab-btm-over-left-bg.gif | Bin 0 -> 189 bytes .../gray/tabs/tab-btm-over-right-bg.gif | Bin 0 -> 635 bytes .../images/gray/tabs/tab-btm-right-bg.gif | Bin 0 -> 863 bytes .../resources/images/gray/tabs/tab-close.gif | Bin 0 -> 896 bytes .../images/gray/tabs/tab-strip-bg.gif | Bin 0 -> 835 bytes .../images/gray/tabs/tab-strip-bg.png | Bin 0 -> 259 bytes .../images/gray/tabs/tab-strip-btm-bg.gif | Bin 0 -> 826 bytes .../images/gray/tabs/tabs-sprite.gif | Bin 0 -> 2109 bytes .../resources/images/gray/toolbar/bg.gif | Bin 0 -> 854 bytes .../images/gray/toolbar/btn-arrow-light.gif | Bin 0 -> 916 bytes .../images/gray/toolbar/btn-arrow.gif | Bin 0 -> 919 bytes .../images/gray/toolbar/btn-over-bg.gif | Bin 0 -> 837 bytes .../resources/images/gray/toolbar/gray-bg.gif | Bin 0 -> 815 bytes .../resources/images/gray/toolbar/more.gif | Bin 0 -> 67 bytes .../resources/images/gray/toolbar/tb-bg.gif | Bin 0 -> 862 bytes .../images/gray/toolbar/tb-btn-sprite.gif | Bin 0 -> 1021 bytes .../resources/images/gray/tree/arrows.gif | Bin 0 -> 407 bytes .../images/gray/tree/elbow-end-minus-nl.gif | Bin 0 -> 149 bytes .../images/gray/tree/elbow-end-minus.gif | Bin 0 -> 154 bytes .../images/gray/tree/elbow-end-plus-nl.gif | Bin 0 -> 151 bytes .../images/gray/tree/elbow-end-plus.gif | Bin 0 -> 156 bytes .../images/gray/window/icon-error.gif | Bin 0 -> 1669 bytes .../images/gray/window/icon-info.gif | Bin 0 -> 1586 bytes .../images/gray/window/icon-question.gif | Bin 0 -> 1607 bytes .../images/gray/window/icon-warning.gif | Bin 0 -> 1483 bytes .../images/gray/window/left-corners.png | Bin 0 -> 325 bytes .../images/gray/window/left-corners.pspimage | Bin 0 -> 4385 bytes .../images/gray/window/left-right.png | Bin 0 -> 2815 bytes .../images/gray/window/right-corners.png | Bin 0 -> 344 bytes .../images/gray/window/top-bottom.png | Bin 0 -> 2860 bytes .../vendor/ext-3.2.1/resources/resources.jsb | 507 + .../aloha/lib/vendor/jquery-1.5.1.js | 8316 ++ .../aloha/lib/vendor/jquery-1.6.1.js | 8936 ++ .../locomotive/aloha/lib/vendor/jquery-1.6.js | 8865 ++ .../aloha/lib/vendor/jquery.json-2.2.min.js | 33 + .../aloha/lib/vendor/jquery.store.js | 446 + .../locomotive/aloha/lib/vendor/sanitize.js | 267 + .../javascripts/locomotive/aloha/package.json | 49 + .../aloha/plugins/common/abbr/css/abbr.css | 0 .../plugins/common/abbr/lib/abbr-plugin.js | 293 + .../aloha/plugins/common/abbr/nls/de/i18n.js | 1 + .../aloha/plugins/common/abbr/nls/i18n.js | 4 + .../aloha/plugins/common/abbr/package.json | 1 + .../aloha/plugins/common/align/LICENSE | 166 + .../aloha/plugins/common/align/README | 12 + .../aloha/plugins/common/align/css/align.css | 19 + .../aloha/plugins/common/align/img/align.png | Bin 0 -> 210 bytes .../plugins/common/align/lib/align-plugin.js | 345 + .../aloha/plugins/common/align/nls/en/i18n.js | 1 + .../aloha/plugins/common/align/nls/fr/i18n.js | 1 + .../aloha/plugins/common/align/nls/i18n.js | 6 + .../aloha/plugins/common/align/package.json | 2 + .../aloha/plugins/common/block/README | 0 .../aloha/plugins/common/block/css/block.css | 51 + .../common/block/img/toolbar-draghandle.gif | Bin 0 -> 178 bytes .../plugins/common/block/lib/block-plugin.js | 104 + .../aloha/plugins/common/block/lib/block.js | 442 + .../common/block/lib/blockcontenthandler.js | 58 + .../plugins/common/block/lib/blockmanager.js | 242 + .../aloha/plugins/common/block/lib/editor.js | 209 + .../plugins/common/block/lib/editormanager.js | 34 + .../block/lib/sidebarattributeeditor.js | 119 + .../aloha/plugins/common/block/package.json | 11 + .../characterpicker/css/characterpicker.css | 38 + .../common/characterpicker/img/icon.png | Bin 0 -> 2968 bytes .../lib/characterpicker-plugin.js | 227 + .../common/characterpicker/nls/de/i18n.js | 1 + .../common/characterpicker/nls/i18n.js | 4 + .../plugins/common/commands/css/abbr.css | 0 .../common/commands/lib/commands-plugin.js | 15 + .../plugins/common/commands/lib/inserthtml.js | 107 + .../plugins/common/commands/package.json | 1 + .../plugins/common/contenthandler/README.md | 0 .../lib/contenthandler-plugin.js | 54 + .../lib/genericcontenthandler.js | 255 + .../lib/oembedcontenthandler.js | 276 + .../lib/sanitizecontenthandler.js | 136 + .../contenthandler/lib/wordcontenthandler.js | 279 + .../common/contenthandler/package.json | 1 + .../dom-to-xhtml/lib/dom-to-xhtml-plugin.js | 29 + .../common/dom-to-xhtml/lib/dom-to-xhtml.js | 344 + .../plugins/common/format/css/format.css | 8 + .../aloha/plugins/common/format/img/em.png | Bin 0 -> 277 bytes .../plugins/common/format/img/strong.png | Bin 0 -> 334 bytes .../common/format/lib/format-plugin.js | 303 + .../plugins/common/format/nls/de/i18n.js | 1 + .../plugins/common/format/nls/eo/i18n.js | 1 + .../plugins/common/format/nls/fi/i18n.js | 1 + .../plugins/common/format/nls/fr/i18n.js | 1 + .../aloha/plugins/common/format/nls/i18n.js | 10 + .../plugins/common/format/nls/it/i18n.js | 1 + .../plugins/common/format/nls/pl/i18n.js | 1 + .../plugins/common/format/nls/ru/i18n.js | 1 + .../css/highlighteditables.css | 14 + .../lib/highlighteditables-plugin.js | 72 + .../common/highlighteditables/package.json | 1 + .../horizontalruler/css/horizontalruler.css | 4 + .../common/horizontalruler/img/icon.png | Bin 0 -> 2864 bytes .../lib/horizontalruler-plugin.js | 55 + .../common/horizontalruler/nls/de/i18n.js | 1 + .../common/horizontalruler/nls/i18n.js | 4 + .../aloha/plugins/common/image/AGPL3 | 661 + .../aloha/plugins/common/image/LICENSE | 25 + .../aloha/plugins/common/image/README.md | 83 + .../aloha/plugins/common/image/css/image.css | 124 + .../aloha/plugins/common/image/demo/crop.html | 76 + .../aloha/plugins/common/image/demo/crop.php | 21 + .../plugins/common/image/demo/cropnresize.jpg | Bin 0 -> 76312 bytes .../plugins/common/image/demo/index.html | 120 + .../aloha/plugins/common/image/img/blank.jpg | Bin 0 -> 685 bytes .../plugins/common/image/img/cropnresize.png | Bin 0 -> 1981 bytes .../plugins/common/image/img/handle-sw.png | Bin 0 -> 728 bytes .../common/image/img/image-align-left.png | Bin 0 -> 6702 bytes .../common/image/img/image-align-none.png | Bin 0 -> 6653 bytes .../common/image/img/image-align-right.png | Bin 0 -> 6719 bytes .../plugins/common/image/img/image-border.png | Bin 0 -> 6233 bytes .../plugins/common/image/img/image-title.png | Bin 0 -> 6597 bytes .../aloha/plugins/common/image/img/image.gif | Bin 0 -> 621 bytes .../common/image/img/padding-decrease.gif | Bin 0 -> 359 bytes .../common/image/img/padding-increase.gif | Bin 0 -> 358 bytes .../aloha/plugins/common/image/img/page.png | Bin 0 -> 635 bytes .../common/image/img/size-decrease.gif | Bin 0 -> 346 bytes .../common/image/img/size-increase.gif | Bin 0 -> 345 bytes .../plugins/common/image/lib/image-plugin.js | 1615 + .../aloha/plugins/common/image/nls/cz/i18n.js | 16 + .../aloha/plugins/common/image/nls/de/i18n.js | 1 + .../aloha/plugins/common/image/nls/fr/i18n.js | 1 + .../aloha/plugins/common/image/nls/i18n.js | 7 + .../aloha/plugins/common/image/nls/ru/i18n.js | 16 + .../aloha/plugins/common/image/package.json | 1 + .../aloha/plugins/common/image/test/test.css | 12 + .../aloha/plugins/common/image/test/test.html | 40 + .../common/image/vendor/jcrop/jcrop.gif | Bin 0 -> 329 bytes .../image/vendor/jcrop/jquery.jcrop.css | 35 + .../image/vendor/jcrop/jquery.jcrop.min.js | 163 + .../image/vendor/mousewheel/mousewheel.js | 60 + .../vendor/ui/jquery-ui-1.8.10.custom.min.js | 97 + .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 0 -> 260 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 0 -> 251 bytes .../images/ui-bg_flat_10_000000_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 0 -> 104 bytes .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 0 -> 125 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 0 -> 3762 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 0 -> 90 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 0 -> 129 bytes .../images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_228ef1_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffd27a_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffffff_256x240.png | Bin 0 -> 4369 bytes .../jquery-ui-1.8.10.cropnresize.css | 33 + .../ui-lightness/jquery-ui-1.8.10.custom.css | 314 + .../aloha/plugins/common/link/css/link.css | 55 + .../plugins/common/link/demo/background.png | Bin 0 -> 251 bytes .../link/demo/external-link-ltr-icon.png | Bin 0 -> 279 bytes .../aloha/plugins/common/link/demo/index.css | 91 + .../aloha/plugins/common/link/demo/index.html | 91 + .../plugins/common/link/extra/delicious.js | 246 + .../plugins/common/link/extra/linklist.js | 222 + .../plugins/common/link/extra/slowlinklist.js | 228 + .../plugins/common/link/lib/link-plugin.js | 759 + .../aloha/plugins/common/link/nls/de/i18n.js | 13 + .../aloha/plugins/common/link/nls/fr/i18n.js | 6 + .../aloha/plugins/common/link/nls/i18n.js | 9 + .../aloha/plugins/common/link/nls/pl/i18n.js | 6 + .../aloha/plugins/common/link/nls/ru/i18n.js | 6 + .../plugins/common/list/lib/list-plugin.js | 849 + .../aloha/plugins/common/list/nls/de/i18n.js | 1 + .../aloha/plugins/common/list/nls/eo/i18n.js | 1 + .../aloha/plugins/common/list/nls/fi/i18n.js | 1 + .../aloha/plugins/common/list/nls/fr/i18n.js | 1 + .../aloha/plugins/common/list/nls/i18n.js | 9 + .../aloha/plugins/common/list/nls/it/i18n.js | 1 + .../aloha/plugins/common/list/nls/ru/i18n.js | 1 + .../aloha/plugins/common/list/package.json | 1 + .../aloha/plugins/common/paste/README.md | 3 + .../plugins/common/paste/lib/paste-plugin.js | 221 + .../aloha/plugins/common/paste/package.json | 8 + .../aloha/plugins/common/table/css/table.css | 160 + .../aloha/plugins/common/table/img/down.cur | Bin 0 -> 183 bytes .../aloha/plugins/common/table/img/left.cur | Bin 0 -> 55 bytes .../plugins/common/table/img/table_layout.png | Bin 0 -> 76050 bytes .../plugins/common/table/img/wai-green.png | Bin 0 -> 51404 bytes .../plugins/common/table/img/wai-red.png | Bin 0 -> 48696 bytes .../plugins/common/table/lib/table-cell.js | 463 + .../common/table/lib/table-create-layer.js | 210 + .../common/table/lib/table-plugin-utils.js | 355 + .../plugins/common/table/lib/table-plugin.js | 1498 + .../common/table/lib/table-selection.js | 374 + .../aloha/plugins/common/table/lib/table.js | 1529 + .../aloha/plugins/common/table/nls/de/i18n.js | 1 + .../aloha/plugins/common/table/nls/eo/i18n.js | 1 + .../aloha/plugins/common/table/nls/fi/i18n.js | 1 + .../aloha/plugins/common/table/nls/fr/i18n.js | 1 + .../aloha/plugins/common/table/nls/i18n.js | 11 + .../aloha/plugins/common/table/nls/it/i18n.js | 1 + .../aloha/plugins/common/table/nls/pl/i18n.js | 1 + .../aloha/plugins/common/table/nls/ru/i18n.js | 1 + .../aloha/plugins/common/table/package.json | 1 + .../aloha/plugins/common/undo/demo/index.css | 49 + .../aloha/plugins/common/undo/demo/index.html | 85 + .../plugins/common/undo/lib/undo-plugin.js | 134 + .../aloha/plugins/common/undo/package.json | 7 + .../vendor/diff_match_patch_uncompressed.js | 2155 + .../aloha/plugins/common/undo/vendor/undo.js | 119 + .../aloha/plugins/extra/attributes/README | 0 .../extra/attributes/css/attributes.css | 12 + .../extra/attributes/lib/attributes-plugin.js | 217 + .../plugins/extra/attributes/nls/de/i18n.js | 1 + .../plugins/extra/attributes/nls/en/i18n.js | 1 + .../plugins/extra/attributes/nls/i18n.js | 5 + .../aloha/plugins/extra/browser/README | 0 .../plugins/extra/browser/css/browser.css | 360 + .../extra/browser/css/browser.jqgrid.css | 374 + .../extra/browser/css/browsercombined.css | 752 + .../browser/css/browsercombined.css.backup | 883 + .../css/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 111 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../css/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../css/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../css/images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../css/images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../css/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes .../browser/css/jquery-ui-1.8.13.custom.css | 319 + .../plugins/extra/browser/css/jstree.css | 88 + .../plugins/extra/browser/css/throbber.gif | Bin 0 -> 1849 bytes .../plugins/extra/browser/css/ui.jqgrid.css | 148 + .../extra/browser/img/arrow-000-medium.png | Bin 0 -> 485 bytes .../plugins/extra/browser/img/arrow-180.png | Bin 0 -> 589 bytes .../extra/browser/img/arrow-315-medium.png | Bin 0 -> 482 bytes .../extra/browser/img/arrow-stop-180.png | Bin 0 -> 658 bytes .../plugins/extra/browser/img/arrow-stop.png | Bin 0 -> 665 bytes .../aloha/plugins/extra/browser/img/arrow.png | Bin 0 -> 590 bytes .../browser/img/control-stop-square-small.png | Bin 0 -> 326 bytes .../browser/img/folder-horizontal-open.png | Bin 0 -> 511 bytes .../plugins/extra/browser/img/folder-open.png | Bin 0 -> 647 bytes .../browser/img/gcn-icons/gcn-icon-file.gif | Bin 0 -> 601 bytes .../browser/img/gcn-icons/gcn-icon-image.gif | Bin 0 -> 1096 bytes .../browser/img/gcn-icons/gcn-icon-page.gif | Bin 0 -> 1055 bytes .../extra/browser/img/magnifier-left.png | Bin 0 -> 736 bytes .../aloha/plugins/extra/browser/img/page.png | Bin 0 -> 635 bytes .../plugins/extra/browser/img/picture.png | Bin 0 -> 606 bytes .../browser/img/sort-alphabet-descending.png | Bin 0 -> 594 bytes .../extra/browser/img/sort-alphabet.png | Bin 0 -> 599 bytes .../plugins/extra/browser/img/throbber.gif | Bin 0 -> 1849 bytes .../extra/browser/lib/browser-plugin.js | 10 + .../plugins/extra/browser/lib/browser.js | 1103 + .../aloha/plugins/extra/browser/lib/locale.js | 26 + .../aloha/plugins/extra/browser/nls/de.json | 1 + .../plugins/extra/browser/nls/de/i18n.js | 18 + .../aloha/plugins/extra/browser/nls/en.json | 1 + .../plugins/extra/browser/nls/en/i18n.js | 18 + .../aloha/plugins/extra/browser/nls/i18n.js | 4 + .../extra/browser/vendor/grid.locale.de.js | 134 + .../extra/browser/vendor/grid.locale.en.js | 129 + .../extra/browser/vendor/jquery.jqGrid.js | 467 + .../extra/browser/vendor/jquery.jstree.js | 4544 + .../plugins/extra/browser/vendor/jquery.ui.js | 756 + .../plugins/extra/browser/vendor/ui-layout.js | 108 + .../aloha/plugins/extra/cite/README | 0 .../aloha/plugins/extra/cite/css/cite.css | 49 + .../plugins/extra/cite/img/blockquote.png | Bin 0 -> 1533 bytes .../plugins/extra/cite/img/icon_cite.png | Bin 0 -> 1610 bytes .../plugins/extra/cite/lib/cite-plugin.js | 539 + .../aloha/plugins/extra/cite/nls/de/i18n.js | 1 + .../aloha/plugins/extra/cite/nls/en/i18n.js | 1 + .../aloha/plugins/extra/cite/nls/i18n.js | 4 + .../aloha/plugins/extra/cite/package.json | 1 + .../plugins/extra/comments/img/add-icon.png | Bin 0 -> 11957 bytes .../aloha/plugins/extra/comments/img/add.png | Bin 0 -> 2736 bytes .../plugins/extra/comments/img/comments.png | Bin 0 -> 1055 bytes .../aloha/plugins/extra/comments/img/hr.png | Bin 0 -> 115 bytes .../plugins/extra/comments/img/textbox.png | Bin 0 -> 9439 bytes .../aloha/plugins/extra/comments/package.json | 1 + .../plugins/extra/comments/src/comments.css | 442 + .../plugins/extra/comments/src/comments.js | 669 + .../plugins/extra/draganddropfiles/AGPL3 | 661 + .../plugins/extra/draganddropfiles/LICENSE | 25 + .../plugins/extra/draganddropfiles/README.md | 5 + .../plugins/extra/draganddropfiles/TODO.md | 2 + .../extra/draganddropfiles/demo/index.css | 47 + .../extra/draganddropfiles/demo/index.html | 101 + .../draganddropfiles/demo/migration/index.css | 189 + .../demo/migration/index.html | 321 + .../demo/specs/DragnDropnImage.graphml | 677 + .../extra/draganddropfiles/demo/style.css | 47 + .../extra/draganddropfiles/demo/upload.php | 26 + .../extra/draganddropfiles/i18n/en.json | 1 + .../extra/draganddropfiles/i18n/fr.json | 1 + .../extra/draganddropfiles/img/cross.png | Bin 0 -> 655 bytes .../extra/draganddropfiles/img/hourglass.png | Bin 0 -> 744 bytes .../extra/draganddropfiles/img/loading.gif | Bin 0 -> 771 bytes .../extra/draganddropfiles/img/page.png | Bin 0 -> 635 bytes .../extra/draganddropfiles/img/tick.png | Bin 0 -> 537 bytes .../lib/draganddropfiles-plugin.js | 4 + .../draganddropfiles/lib/dragndropfiles.css | 110 + .../draganddropfiles/lib/dragndropfiles.js | 349 + .../lib/dropfilesrepository.js | 365 + .../extra/draganddropfiles/package.json | 1 + .../plugins/extra/flag-icons/img/flags/aa.png | Bin 0 -> 339 bytes .../plugins/extra/flag-icons/img/flags/ab.png | Bin 0 -> 434 bytes .../plugins/extra/flag-icons/img/flags/ad.png | Bin 0 -> 643 bytes .../plugins/extra/flag-icons/img/flags/ae.png | Bin 0 -> 408 bytes .../plugins/extra/flag-icons/img/flags/af.png | Bin 0 -> 604 bytes .../plugins/extra/flag-icons/img/flags/ag.png | Bin 0 -> 591 bytes .../plugins/extra/flag-icons/img/flags/ai.png | Bin 0 -> 643 bytes .../plugins/extra/flag-icons/img/flags/ak.png | Bin 0 -> 269 bytes .../plugins/extra/flag-icons/img/flags/al.png | Bin 0 -> 600 bytes .../plugins/extra/flag-icons/img/flags/am.png | Bin 0 -> 497 bytes .../plugins/extra/flag-icons/img/flags/an.png | Bin 0 -> 488 bytes .../plugins/extra/flag-icons/img/flags/ao.png | Bin 0 -> 428 bytes .../plugins/extra/flag-icons/img/flags/ar.png | Bin 0 -> 506 bytes .../plugins/extra/flag-icons/img/flags/as.png | Bin 0 -> 647 bytes .../plugins/extra/flag-icons/img/flags/at.png | Bin 0 -> 403 bytes .../plugins/extra/flag-icons/img/flags/au.png | Bin 0 -> 673 bytes .../plugins/extra/flag-icons/img/flags/av.png | Bin 0 -> 211 bytes .../plugins/extra/flag-icons/img/flags/aw.png | Bin 0 -> 524 bytes .../plugins/extra/flag-icons/img/flags/ax.png | Bin 0 -> 663 bytes .../plugins/extra/flag-icons/img/flags/ay.png | Bin 0 -> 700 bytes .../plugins/extra/flag-icons/img/flags/az.png | Bin 0 -> 589 bytes .../plugins/extra/flag-icons/img/flags/ba.png | Bin 0 -> 593 bytes .../plugins/extra/flag-icons/img/flags/bb.png | Bin 0 -> 585 bytes .../plugins/extra/flag-icons/img/flags/bd.png | Bin 0 -> 504 bytes .../plugins/extra/flag-icons/img/flags/be.png | Bin 0 -> 449 bytes .../plugins/extra/flag-icons/img/flags/bf.png | Bin 0 -> 497 bytes .../plugins/extra/flag-icons/img/flags/bg.png | Bin 0 -> 462 bytes .../plugins/extra/flag-icons/img/flags/bh.png | Bin 0 -> 457 bytes .../plugins/extra/flag-icons/img/flags/bi.png | Bin 0 -> 675 bytes .../plugins/extra/flag-icons/img/flags/bj.png | Bin 0 -> 486 bytes .../plugins/extra/flag-icons/img/flags/bm.png | Bin 0 -> 611 bytes .../plugins/extra/flag-icons/img/flags/bn.png | Bin 0 -> 639 bytes .../plugins/extra/flag-icons/img/flags/bo.png | Bin 0 -> 500 bytes .../plugins/extra/flag-icons/img/flags/br.png | Bin 0 -> 593 bytes .../plugins/extra/flag-icons/img/flags/bs.png | Bin 0 -> 526 bytes .../plugins/extra/flag-icons/img/flags/bt.png | Bin 0 -> 631 bytes .../plugins/extra/flag-icons/img/flags/bv.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/bw.png | Bin 0 -> 443 bytes .../plugins/extra/flag-icons/img/flags/by.png | Bin 0 -> 514 bytes .../plugins/extra/flag-icons/img/flags/bz.png | Bin 0 -> 600 bytes .../plugins/extra/flag-icons/img/flags/ca.png | Bin 0 -> 628 bytes .../extra/flag-icons/img/flags/catalonia.png | Bin 0 -> 398 bytes .../plugins/extra/flag-icons/img/flags/cc.png | Bin 0 -> 625 bytes .../plugins/extra/flag-icons/img/flags/cd.png | Bin 0 -> 528 bytes .../plugins/extra/flag-icons/img/flags/ce.png | Bin 0 -> 200 bytes .../plugins/extra/flag-icons/img/flags/cf.png | Bin 0 -> 614 bytes .../plugins/extra/flag-icons/img/flags/cg.png | Bin 0 -> 521 bytes .../plugins/extra/flag-icons/img/flags/ch.png | Bin 0 -> 367 bytes .../plugins/extra/flag-icons/img/flags/ci.png | Bin 0 -> 453 bytes .../plugins/extra/flag-icons/img/flags/ck.png | Bin 0 -> 586 bytes .../plugins/extra/flag-icons/img/flags/cl.png | Bin 0 -> 450 bytes .../plugins/extra/flag-icons/img/flags/cm.png | Bin 0 -> 525 bytes .../plugins/extra/flag-icons/img/flags/cn.png | Bin 0 -> 472 bytes .../plugins/extra/flag-icons/img/flags/co.png | Bin 0 -> 483 bytes .../plugins/extra/flag-icons/img/flags/cr.png | Bin 0 -> 477 bytes .../plugins/extra/flag-icons/img/flags/cs.png | Bin 0 -> 439 bytes .../plugins/extra/flag-icons/img/flags/cu.png | Bin 0 -> 563 bytes .../plugins/extra/flag-icons/img/flags/cv.png | Bin 0 -> 529 bytes .../plugins/extra/flag-icons/img/flags/cx.png | Bin 0 -> 608 bytes .../plugins/extra/flag-icons/img/flags/cy.png | Bin 0 -> 428 bytes .../plugins/extra/flag-icons/img/flags/cz.png | Bin 0 -> 476 bytes .../plugins/extra/flag-icons/img/flags/da.png | Bin 0 -> 495 bytes .../plugins/extra/flag-icons/img/flags/de.png | Bin 0 -> 545 bytes .../plugins/extra/flag-icons/img/flags/dj.png | Bin 0 -> 572 bytes .../plugins/extra/flag-icons/img/flags/dk.png | Bin 0 -> 495 bytes .../plugins/extra/flag-icons/img/flags/dm.png | Bin 0 -> 620 bytes .../plugins/extra/flag-icons/img/flags/do.png | Bin 0 -> 508 bytes .../plugins/extra/flag-icons/img/flags/dv.png | Bin 0 -> 272 bytes .../plugins/extra/flag-icons/img/flags/dz.png | Bin 0 -> 582 bytes .../plugins/extra/flag-icons/img/flags/ec.png | Bin 0 -> 500 bytes .../plugins/extra/flag-icons/img/flags/ee.png | Bin 0 -> 429 bytes .../plugins/extra/flag-icons/img/flags/eg.png | Bin 0 -> 465 bytes .../plugins/extra/flag-icons/img/flags/eh.png | Bin 0 -> 508 bytes .../plugins/extra/flag-icons/img/flags/el.png | Bin 0 -> 487 bytes .../plugins/extra/flag-icons/img/flags/en.png | Bin 0 -> 496 bytes .../plugins/extra/flag-icons/img/flags/eo.png | Bin 0 -> 255 bytes .../plugins/extra/flag-icons/img/flags/er.png | Bin 0 -> 653 bytes .../plugins/extra/flag-icons/img/flags/es.png | Bin 0 -> 469 bytes .../plugins/extra/flag-icons/img/flags/et.png | Bin 0 -> 592 bytes .../plugins/extra/flag-icons/img/flags/eu.png | Bin 0 -> 335 bytes .../flag-icons/img/flags/europeanunion.png | Bin 0 -> 479 bytes .../plugins/extra/flag-icons/img/flags/fa.png | Bin 0 -> 268 bytes .../extra/flag-icons/img/flags/fam.png | Bin 0 -> 532 bytes .../plugins/extra/flag-icons/img/flags/ff.png | Bin 0 -> 303 bytes .../plugins/extra/flag-icons/img/flags/fi.png | Bin 0 -> 489 bytes .../plugins/extra/flag-icons/img/flags/fj.png | Bin 0 -> 610 bytes .../plugins/extra/flag-icons/img/flags/fk.png | Bin 0 -> 648 bytes .../plugins/extra/flag-icons/img/flags/fm.png | Bin 0 -> 552 bytes .../plugins/extra/flag-icons/img/flags/fo.png | Bin 0 -> 474 bytes .../plugins/extra/flag-icons/img/flags/fr.png | Bin 0 -> 545 bytes .../plugins/extra/flag-icons/img/flags/fy.png | Bin 0 -> 704 bytes .../plugins/extra/flag-icons/img/flags/ga.png | Bin 0 -> 489 bytes .../plugins/extra/flag-icons/img/flags/gb.png | Bin 0 -> 599 bytes .../plugins/extra/flag-icons/img/flags/gd.png | Bin 0 -> 637 bytes .../plugins/extra/flag-icons/img/flags/ge.png | Bin 0 -> 594 bytes .../plugins/extra/flag-icons/img/flags/gf.png | Bin 0 -> 545 bytes .../plugins/extra/flag-icons/img/flags/gh.png | Bin 0 -> 490 bytes .../plugins/extra/flag-icons/img/flags/gi.png | Bin 0 -> 463 bytes .../plugins/extra/flag-icons/img/flags/gl.png | Bin 0 -> 470 bytes .../plugins/extra/flag-icons/img/flags/gm.png | Bin 0 -> 493 bytes .../plugins/extra/flag-icons/img/flags/gn.png | Bin 0 -> 480 bytes .../plugins/extra/flag-icons/img/flags/gp.png | Bin 0 -> 488 bytes .../plugins/extra/flag-icons/img/flags/gq.png | Bin 0 -> 537 bytes .../plugins/extra/flag-icons/img/flags/gr.png | Bin 0 -> 487 bytes .../plugins/extra/flag-icons/img/flags/gs.png | Bin 0 -> 630 bytes .../plugins/extra/flag-icons/img/flags/gt.png | Bin 0 -> 493 bytes .../plugins/extra/flag-icons/img/flags/gu.png | Bin 0 -> 509 bytes .../plugins/extra/flag-icons/img/flags/gv.png | Bin 0 -> 320 bytes .../plugins/extra/flag-icons/img/flags/gw.png | Bin 0 -> 516 bytes .../plugins/extra/flag-icons/img/flags/gy.png | Bin 0 -> 645 bytes .../plugins/extra/flag-icons/img/flags/ha.png | Bin 0 -> 497 bytes .../plugins/extra/flag-icons/img/flags/he.png | Bin 0 -> 272 bytes .../plugins/extra/flag-icons/img/flags/hi.png | Bin 0 -> 503 bytes .../plugins/extra/flag-icons/img/flags/hk.png | Bin 0 -> 527 bytes .../plugins/extra/flag-icons/img/flags/hm.png | Bin 0 -> 673 bytes .../plugins/extra/flag-icons/img/flags/hn.png | Bin 0 -> 537 bytes .../plugins/extra/flag-icons/img/flags/ho.png | Bin 0 -> 454 bytes .../plugins/extra/flag-icons/img/flags/hr.png | Bin 0 -> 524 bytes .../plugins/extra/flag-icons/img/flags/ht.png | Bin 0 -> 487 bytes .../plugins/extra/flag-icons/img/flags/hu.png | Bin 0 -> 432 bytes .../plugins/extra/flag-icons/img/flags/hy.png | Bin 0 -> 253 bytes .../plugins/extra/flag-icons/img/flags/hz.png | Bin 0 -> 202 bytes .../plugins/extra/flag-icons/img/flags/id.png | Bin 0 -> 430 bytes .../plugins/extra/flag-icons/img/flags/ie.png | Bin 0 -> 481 bytes .../plugins/extra/flag-icons/img/flags/ig.png | Bin 0 -> 195 bytes .../plugins/extra/flag-icons/img/flags/ii.png | Bin 0 -> 472 bytes .../plugins/extra/flag-icons/img/flags/il.png | Bin 0 -> 431 bytes .../plugins/extra/flag-icons/img/flags/in.png | Bin 0 -> 503 bytes .../plugins/extra/flag-icons/img/flags/io.png | Bin 0 -> 658 bytes .../plugins/extra/flag-icons/img/flags/iq.png | Bin 0 -> 515 bytes .../plugins/extra/flag-icons/img/flags/ir.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/is.png | Bin 0 -> 532 bytes .../plugins/extra/flag-icons/img/flags/it.png | Bin 0 -> 420 bytes .../plugins/extra/flag-icons/img/flags/ja.png | Bin 0 -> 420 bytes .../plugins/extra/flag-icons/img/flags/jm.png | Bin 0 -> 637 bytes .../plugins/extra/flag-icons/img/flags/jo.png | Bin 0 -> 473 bytes .../plugins/extra/flag-icons/img/flags/jp.png | Bin 0 -> 420 bytes .../plugins/extra/flag-icons/img/flags/jv.png | Bin 0 -> 313 bytes .../plugins/extra/flag-icons/img/flags/ka.png | Bin 0 -> 282 bytes .../plugins/extra/flag-icons/img/flags/ke.png | Bin 0 -> 569 bytes .../plugins/extra/flag-icons/img/flags/kg.png | Bin 0 -> 510 bytes .../plugins/extra/flag-icons/img/flags/kh.png | Bin 0 -> 549 bytes .../plugins/extra/flag-icons/img/flags/ki.png | Bin 0 -> 641 bytes .../plugins/extra/flag-icons/img/flags/kk.png | Bin 0 -> 330 bytes .../plugins/extra/flag-icons/img/flags/kl.png | Bin 0 -> 363 bytes .../plugins/extra/flag-icons/img/flags/km.png | Bin 0 -> 577 bytes .../plugins/extra/flag-icons/img/flags/kn.png | Bin 0 -> 604 bytes .../plugins/extra/flag-icons/img/flags/ko.png | Bin 0 -> 592 bytes .../plugins/extra/flag-icons/img/flags/kp.png | Bin 0 -> 561 bytes .../plugins/extra/flag-icons/img/flags/kr.png | Bin 0 -> 592 bytes .../plugins/extra/flag-icons/img/flags/ks.png | Bin 0 -> 341 bytes .../plugins/extra/flag-icons/img/flags/ku.png | Bin 0 -> 306 bytes .../plugins/extra/flag-icons/img/flags/kv.png | Bin 0 -> 208 bytes .../plugins/extra/flag-icons/img/flags/kw.png | Bin 0 -> 486 bytes .../plugins/extra/flag-icons/img/flags/ky.png | Bin 0 -> 643 bytes .../plugins/extra/flag-icons/img/flags/kz.png | Bin 0 -> 616 bytes .../plugins/extra/flag-icons/img/flags/la.png | Bin 0 -> 363 bytes .../plugins/extra/flag-icons/img/flags/lb.png | Bin 0 -> 517 bytes .../plugins/extra/flag-icons/img/flags/lc.png | Bin 0 -> 520 bytes .../plugins/extra/flag-icons/img/flags/lg.png | Bin 0 -> 287 bytes .../plugins/extra/flag-icons/img/flags/li.png | Bin 0 -> 537 bytes .../plugins/extra/flag-icons/img/flags/lk.png | Bin 0 -> 627 bytes .../plugins/extra/flag-icons/img/flags/ln.png | Bin 0 -> 359 bytes .../plugins/extra/flag-icons/img/flags/lo.png | Bin 0 -> 269 bytes .../plugins/extra/flag-icons/img/flags/lr.png | Bin 0 -> 466 bytes .../plugins/extra/flag-icons/img/flags/ls.png | Bin 0 -> 628 bytes .../plugins/extra/flag-icons/img/flags/lt.png | Bin 0 -> 508 bytes .../plugins/extra/flag-icons/img/flags/lu.png | Bin 0 -> 481 bytes .../plugins/extra/flag-icons/img/flags/lv.png | Bin 0 -> 465 bytes .../plugins/extra/flag-icons/img/flags/ly.png | Bin 0 -> 419 bytes .../plugins/extra/flag-icons/img/flags/ma.png | Bin 0 -> 432 bytes .../plugins/extra/flag-icons/img/flags/mc.png | Bin 0 -> 380 bytes .../plugins/extra/flag-icons/img/flags/md.png | Bin 0 -> 566 bytes .../plugins/extra/flag-icons/img/flags/me.png | Bin 0 -> 448 bytes .../plugins/extra/flag-icons/img/flags/mg.png | Bin 0 -> 453 bytes .../plugins/extra/flag-icons/img/flags/mh.png | Bin 0 -> 628 bytes .../plugins/extra/flag-icons/img/flags/mi.png | Bin 0 -> 417 bytes .../plugins/extra/flag-icons/img/flags/mk.png | Bin 0 -> 664 bytes .../plugins/extra/flag-icons/img/flags/ml.png | Bin 0 -> 474 bytes .../plugins/extra/flag-icons/img/flags/mm.png | Bin 0 -> 483 bytes .../plugins/extra/flag-icons/img/flags/mn.png | Bin 0 -> 492 bytes .../plugins/extra/flag-icons/img/flags/mo.png | Bin 0 -> 588 bytes .../plugins/extra/flag-icons/img/flags/mp.png | Bin 0 -> 597 bytes .../plugins/extra/flag-icons/img/flags/mq.png | Bin 0 -> 655 bytes .../plugins/extra/flag-icons/img/flags/mr.png | Bin 0 -> 569 bytes .../plugins/extra/flag-icons/img/flags/ms.png | Bin 0 -> 614 bytes .../plugins/extra/flag-icons/img/flags/mt.png | Bin 0 -> 420 bytes .../plugins/extra/flag-icons/img/flags/mu.png | Bin 0 -> 496 bytes .../plugins/extra/flag-icons/img/flags/mv.png | Bin 0 -> 542 bytes .../plugins/extra/flag-icons/img/flags/mw.png | Bin 0 -> 529 bytes .../plugins/extra/flag-icons/img/flags/mx.png | Bin 0 -> 574 bytes .../plugins/extra/flag-icons/img/flags/my.png | Bin 0 -> 571 bytes .../plugins/extra/flag-icons/img/flags/mz.png | Bin 0 -> 584 bytes .../plugins/extra/flag-icons/img/flags/na.png | Bin 0 -> 647 bytes .../plugins/extra/flag-icons/img/flags/nb.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/nc.png | Bin 0 -> 591 bytes .../plugins/extra/flag-icons/img/flags/nd.png | Bin 0 -> 641 bytes .../plugins/extra/flag-icons/img/flags/ne.png | Bin 0 -> 537 bytes .../plugins/extra/flag-icons/img/flags/nf.png | Bin 0 -> 602 bytes .../plugins/extra/flag-icons/img/flags/ng.png | Bin 0 -> 482 bytes .../plugins/extra/flag-icons/img/flags/ni.png | Bin 0 -> 508 bytes .../plugins/extra/flag-icons/img/flags/nl.png | Bin 0 -> 453 bytes .../plugins/extra/flag-icons/img/flags/nn.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/no.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/np.png | Bin 0 -> 443 bytes .../plugins/extra/flag-icons/img/flags/nr.png | Bin 0 -> 527 bytes .../plugins/extra/flag-icons/img/flags/nu.png | Bin 0 -> 572 bytes .../plugins/extra/flag-icons/img/flags/nv.png | Bin 0 -> 547 bytes .../plugins/extra/flag-icons/img/flags/ny.png | Bin 0 -> 342 bytes .../plugins/extra/flag-icons/img/flags/nz.png | Bin 0 -> 639 bytes .../plugins/extra/flag-icons/img/flags/oc.png | Bin 0 -> 545 bytes .../plugins/extra/flag-icons/img/flags/om.png | Bin 0 -> 478 bytes .../plugins/extra/flag-icons/img/flags/or.png | Bin 0 -> 503 bytes .../plugins/extra/flag-icons/img/flags/os.png | Bin 0 -> 211 bytes .../plugins/extra/flag-icons/img/flags/pa.png | Bin 0 -> 519 bytes .../plugins/extra/flag-icons/img/flags/pe.png | Bin 0 -> 397 bytes .../plugins/extra/flag-icons/img/flags/pf.png | Bin 0 -> 498 bytes .../plugins/extra/flag-icons/img/flags/pg.png | Bin 0 -> 593 bytes .../plugins/extra/flag-icons/img/flags/ph.png | Bin 0 -> 538 bytes .../plugins/extra/flag-icons/img/flags/pk.png | Bin 0 -> 569 bytes .../plugins/extra/flag-icons/img/flags/pl.png | Bin 0 -> 374 bytes .../plugins/extra/flag-icons/img/flags/pm.png | Bin 0 -> 689 bytes .../plugins/extra/flag-icons/img/flags/pn.png | Bin 0 -> 657 bytes .../plugins/extra/flag-icons/img/flags/pr.png | Bin 0 -> 556 bytes .../plugins/extra/flag-icons/img/flags/ps.png | Bin 0 -> 472 bytes .../plugins/extra/flag-icons/img/flags/pt.png | Bin 0 -> 554 bytes .../plugins/extra/flag-icons/img/flags/pw.png | Bin 0 -> 550 bytes .../plugins/extra/flag-icons/img/flags/py.png | Bin 0 -> 473 bytes .../plugins/extra/flag-icons/img/flags/qa.png | Bin 0 -> 450 bytes .../plugins/extra/flag-icons/img/flags/re.png | Bin 0 -> 545 bytes .../plugins/extra/flag-icons/img/flags/rm.png | Bin 0 -> 495 bytes .../plugins/extra/flag-icons/img/flags/rn.png | Bin 0 -> 479 bytes .../plugins/extra/flag-icons/img/flags/ro.png | Bin 0 -> 495 bytes .../plugins/extra/flag-icons/img/flags/rs.png | Bin 0 -> 423 bytes .../plugins/extra/flag-icons/img/flags/ru.png | Bin 0 -> 420 bytes .../plugins/extra/flag-icons/img/flags/rw.png | Bin 0 -> 533 bytes .../plugins/extra/flag-icons/img/flags/sa.png | Bin 0 -> 551 bytes .../plugins/extra/flag-icons/img/flags/sb.png | Bin 0 -> 624 bytes .../plugins/extra/flag-icons/img/flags/sc.png | Bin 0 -> 608 bytes .../extra/flag-icons/img/flags/scotland.png | Bin 0 -> 649 bytes .../plugins/extra/flag-icons/img/flags/sd.png | Bin 0 -> 492 bytes .../plugins/extra/flag-icons/img/flags/se.png | Bin 0 -> 542 bytes .../plugins/extra/flag-icons/img/flags/sg.png | Bin 0 -> 468 bytes .../plugins/extra/flag-icons/img/flags/sh.png | Bin 0 -> 645 bytes .../plugins/extra/flag-icons/img/flags/si.png | Bin 0 -> 510 bytes .../plugins/extra/flag-icons/img/flags/sj.png | Bin 0 -> 512 bytes .../plugins/extra/flag-icons/img/flags/sk.png | Bin 0 -> 562 bytes .../plugins/extra/flag-icons/img/flags/sl.png | Bin 0 -> 436 bytes .../plugins/extra/flag-icons/img/flags/sm.png | Bin 0 -> 502 bytes .../plugins/extra/flag-icons/img/flags/sn.png | Bin 0 -> 532 bytes .../plugins/extra/flag-icons/img/flags/so.png | Bin 0 -> 527 bytes .../plugins/extra/flag-icons/img/flags/sq.png | Bin 0 -> 397 bytes .../plugins/extra/flag-icons/img/flags/sr.png | Bin 0 -> 513 bytes .../plugins/extra/flag-icons/img/flags/ss.png | Bin 0 -> 371 bytes .../plugins/extra/flag-icons/img/flags/st.png | Bin 0 -> 584 bytes .../plugins/extra/flag-icons/img/flags/su.png | Bin 0 -> 197 bytes .../plugins/extra/flag-icons/img/flags/sv.png | Bin 0 -> 501 bytes .../plugins/extra/flag-icons/img/flags/sw.png | Bin 0 -> 460 bytes .../plugins/extra/flag-icons/img/flags/sy.png | Bin 0 -> 422 bytes .../plugins/extra/flag-icons/img/flags/sz.png | Bin 0 -> 643 bytes .../plugins/extra/flag-icons/img/flags/ta.png | Bin 0 -> 392 bytes .../plugins/extra/flag-icons/img/flags/tc.png | Bin 0 -> 624 bytes .../plugins/extra/flag-icons/img/flags/td.png | Bin 0 -> 570 bytes .../plugins/extra/flag-icons/img/flags/te.png | Bin 0 -> 503 bytes .../plugins/extra/flag-icons/img/flags/tf.png | Bin 0 -> 527 bytes .../plugins/extra/flag-icons/img/flags/tg.png | Bin 0 -> 273 bytes .../plugins/extra/flag-icons/img/flags/th.png | Bin 0 -> 452 bytes .../plugins/extra/flag-icons/img/flags/ti.png | Bin 0 -> 456 bytes .../plugins/extra/flag-icons/img/flags/tj.png | Bin 0 -> 496 bytes .../plugins/extra/flag-icons/img/flags/tk.png | Bin 0 -> 638 bytes .../plugins/extra/flag-icons/img/flags/tl.png | Bin 0 -> 514 bytes .../plugins/extra/flag-icons/img/flags/tm.png | Bin 0 -> 593 bytes .../plugins/extra/flag-icons/img/flags/tn.png | Bin 0 -> 495 bytes .../plugins/extra/flag-icons/img/flags/to.png | Bin 0 -> 426 bytes .../plugins/extra/flag-icons/img/flags/tr.png | Bin 0 -> 492 bytes .../plugins/extra/flag-icons/img/flags/tt.png | Bin 0 -> 617 bytes .../plugins/extra/flag-icons/img/flags/tv.png | Bin 0 -> 536 bytes .../plugins/extra/flag-icons/img/flags/tw.png | Bin 0 -> 465 bytes .../plugins/extra/flag-icons/img/flags/ty.png | Bin 0 -> 301 bytes .../plugins/extra/flag-icons/img/flags/tz.png | Bin 0 -> 642 bytes .../plugins/extra/flag-icons/img/flags/ua.png | Bin 0 -> 446 bytes .../plugins/extra/flag-icons/img/flags/ug.png | Bin 0 -> 531 bytes .../plugins/extra/flag-icons/img/flags/uk.png | Bin 0 -> 434 bytes .../plugins/extra/flag-icons/img/flags/um.png | Bin 0 -> 571 bytes .../plugins/extra/flag-icons/img/flags/ur.png | Bin 0 -> 317 bytes .../plugins/extra/flag-icons/img/flags/us.png | Bin 0 -> 609 bytes .../plugins/extra/flag-icons/img/flags/uy.png | Bin 0 -> 532 bytes .../plugins/extra/flag-icons/img/flags/uz.png | Bin 0 -> 515 bytes .../plugins/extra/flag-icons/img/flags/va.png | Bin 0 -> 553 bytes .../plugins/extra/flag-icons/img/flags/vc.png | Bin 0 -> 577 bytes .../plugins/extra/flag-icons/img/flags/ve.png | Bin 0 -> 528 bytes .../plugins/extra/flag-icons/img/flags/vg.png | Bin 0 -> 630 bytes .../plugins/extra/flag-icons/img/flags/vi.png | Bin 0 -> 616 bytes .../plugins/extra/flag-icons/img/flags/vn.png | Bin 0 -> 474 bytes .../plugins/extra/flag-icons/img/flags/vo.png | Bin 0 -> 620 bytes .../plugins/extra/flag-icons/img/flags/vu.png | Bin 0 -> 604 bytes .../plugins/extra/flag-icons/img/flags/wa.png | Bin 0 -> 449 bytes .../extra/flag-icons/img/flags/wales.png | Bin 0 -> 652 bytes .../plugins/extra/flag-icons/img/flags/wf.png | Bin 0 -> 554 bytes .../plugins/extra/flag-icons/img/flags/wo.png | Bin 0 -> 532 bytes .../plugins/extra/flag-icons/img/flags/ws.png | Bin 0 -> 476 bytes .../plugins/extra/flag-icons/img/flags/xh.png | Bin 0 -> 269 bytes .../plugins/extra/flag-icons/img/flags/ye.png | Bin 0 -> 413 bytes .../plugins/extra/flag-icons/img/flags/yt.png | Bin 0 -> 593 bytes .../plugins/extra/flag-icons/img/flags/za.png | Bin 0 -> 642 bytes .../plugins/extra/flag-icons/img/flags/zh.png | Bin 0 -> 472 bytes .../plugins/extra/flag-icons/img/flags/zm.png | Bin 0 -> 500 bytes .../plugins/extra/flag-icons/img/flags/zw.png | Bin 0 -> 574 bytes .../extra/flag-icons/lib/flag-icons-plugin.js | 10 + .../plugins/extra/formatlesspaste/README.md | 3 + .../extra/formatlesspaste/css/formatless.css | 7 + .../extra/formatlesspaste/img/button.png | Bin 0 -> 384 bytes .../formatlesspaste/lib/formatlesshandler.js | 67 + .../lib/formatlesspaste-plugin.js | 103 + .../extra/formatlesspaste/nls/de/i18n.js | 1 + .../plugins/extra/formatlesspaste/nls/i18n.js | 7 + .../extra/formatlesspaste/package.json | 8 + .../plugins/extra/googletranslate/README.md | 22 + .../googletranslate/css/googletranslate.css | 14 + .../plugins/extra/googletranslate/img/ad.png | Bin 0 -> 643 bytes .../plugins/extra/googletranslate/img/ae.png | Bin 0 -> 408 bytes .../plugins/extra/googletranslate/img/af.png | Bin 0 -> 604 bytes .../plugins/extra/googletranslate/img/ag.png | Bin 0 -> 591 bytes .../plugins/extra/googletranslate/img/ai.png | Bin 0 -> 643 bytes .../plugins/extra/googletranslate/img/al.png | Bin 0 -> 600 bytes .../plugins/extra/googletranslate/img/am.png | Bin 0 -> 497 bytes .../plugins/extra/googletranslate/img/an.png | Bin 0 -> 488 bytes .../plugins/extra/googletranslate/img/ao.png | Bin 0 -> 428 bytes .../plugins/extra/googletranslate/img/ar.png | Bin 0 -> 506 bytes .../plugins/extra/googletranslate/img/as.png | Bin 0 -> 647 bytes .../plugins/extra/googletranslate/img/at.png | Bin 0 -> 403 bytes .../plugins/extra/googletranslate/img/au.png | Bin 0 -> 673 bytes .../plugins/extra/googletranslate/img/aw.png | Bin 0 -> 524 bytes .../plugins/extra/googletranslate/img/ax.png | Bin 0 -> 663 bytes .../plugins/extra/googletranslate/img/az.png | Bin 0 -> 589 bytes .../plugins/extra/googletranslate/img/ba.png | Bin 0 -> 593 bytes .../plugins/extra/googletranslate/img/bb.png | Bin 0 -> 585 bytes .../plugins/extra/googletranslate/img/bd.png | Bin 0 -> 504 bytes .../plugins/extra/googletranslate/img/be.png | Bin 0 -> 449 bytes .../plugins/extra/googletranslate/img/bf.png | Bin 0 -> 497 bytes .../plugins/extra/googletranslate/img/bg.png | Bin 0 -> 462 bytes .../plugins/extra/googletranslate/img/bh.png | Bin 0 -> 457 bytes .../plugins/extra/googletranslate/img/bi.png | Bin 0 -> 675 bytes .../plugins/extra/googletranslate/img/bj.png | Bin 0 -> 486 bytes .../plugins/extra/googletranslate/img/bm.png | Bin 0 -> 611 bytes .../plugins/extra/googletranslate/img/bn.png | Bin 0 -> 639 bytes .../plugins/extra/googletranslate/img/bo.png | Bin 0 -> 500 bytes .../plugins/extra/googletranslate/img/br.png | Bin 0 -> 593 bytes .../plugins/extra/googletranslate/img/bs.png | Bin 0 -> 526 bytes .../plugins/extra/googletranslate/img/bt.png | Bin 0 -> 631 bytes .../plugins/extra/googletranslate/img/bv.png | Bin 0 -> 512 bytes .../plugins/extra/googletranslate/img/bw.png | Bin 0 -> 443 bytes .../plugins/extra/googletranslate/img/by.png | Bin 0 -> 514 bytes .../plugins/extra/googletranslate/img/bz.png | Bin 0 -> 600 bytes .../plugins/extra/googletranslate/img/ca.png | Bin 0 -> 628 bytes .../extra/googletranslate/img/catalonia.png | Bin 0 -> 398 bytes .../plugins/extra/googletranslate/img/cc.png | Bin 0 -> 625 bytes .../plugins/extra/googletranslate/img/cd.png | Bin 0 -> 528 bytes .../plugins/extra/googletranslate/img/cf.png | Bin 0 -> 614 bytes .../plugins/extra/googletranslate/img/cg.png | Bin 0 -> 521 bytes .../plugins/extra/googletranslate/img/ch.png | Bin 0 -> 367 bytes .../plugins/extra/googletranslate/img/ci.png | Bin 0 -> 453 bytes .../plugins/extra/googletranslate/img/ck.png | Bin 0 -> 586 bytes .../plugins/extra/googletranslate/img/cl.png | Bin 0 -> 450 bytes .../plugins/extra/googletranslate/img/cm.png | Bin 0 -> 525 bytes .../plugins/extra/googletranslate/img/cn.png | Bin 0 -> 472 bytes .../plugins/extra/googletranslate/img/co.png | Bin 0 -> 483 bytes .../plugins/extra/googletranslate/img/cr.png | Bin 0 -> 477 bytes .../plugins/extra/googletranslate/img/cs.png | Bin 0 -> 439 bytes .../plugins/extra/googletranslate/img/cu.png | Bin 0 -> 563 bytes .../plugins/extra/googletranslate/img/cv.png | Bin 0 -> 529 bytes .../plugins/extra/googletranslate/img/cx.png | Bin 0 -> 608 bytes .../plugins/extra/googletranslate/img/cy.png | Bin 0 -> 428 bytes .../plugins/extra/googletranslate/img/cz.png | Bin 0 -> 476 bytes .../plugins/extra/googletranslate/img/de.png | Bin 0 -> 545 bytes .../plugins/extra/googletranslate/img/dj.png | Bin 0 -> 572 bytes .../plugins/extra/googletranslate/img/dk.png | Bin 0 -> 495 bytes .../plugins/extra/googletranslate/img/dm.png | Bin 0 -> 620 bytes .../plugins/extra/googletranslate/img/do.png | Bin 0 -> 508 bytes .../plugins/extra/googletranslate/img/dz.png | Bin 0 -> 582 bytes .../plugins/extra/googletranslate/img/ec.png | Bin 0 -> 500 bytes .../plugins/extra/googletranslate/img/ee.png | Bin 0 -> 429 bytes .../plugins/extra/googletranslate/img/eg.png | Bin 0 -> 465 bytes .../plugins/extra/googletranslate/img/eh.png | Bin 0 -> 508 bytes .../plugins/extra/googletranslate/img/en.png | Bin 0 -> 496 bytes .../plugins/extra/googletranslate/img/er.png | Bin 0 -> 653 bytes .../plugins/extra/googletranslate/img/es.png | Bin 0 -> 469 bytes .../plugins/extra/googletranslate/img/et.png | Bin 0 -> 592 bytes .../googletranslate/img/europeanunion.png | Bin 0 -> 479 bytes .../plugins/extra/googletranslate/img/fam.png | Bin 0 -> 532 bytes .../plugins/extra/googletranslate/img/fi.png | Bin 0 -> 489 bytes .../plugins/extra/googletranslate/img/fj.png | Bin 0 -> 610 bytes .../plugins/extra/googletranslate/img/fk.png | Bin 0 -> 648 bytes .../plugins/extra/googletranslate/img/fm.png | Bin 0 -> 552 bytes .../plugins/extra/googletranslate/img/fo.png | Bin 0 -> 474 bytes .../plugins/extra/googletranslate/img/fr.png | Bin 0 -> 545 bytes .../plugins/extra/googletranslate/img/ga.png | Bin 0 -> 489 bytes .../plugins/extra/googletranslate/img/gb.png | Bin 0 -> 599 bytes .../plugins/extra/googletranslate/img/gd.png | Bin 0 -> 637 bytes .../plugins/extra/googletranslate/img/ge.png | Bin 0 -> 594 bytes .../plugins/extra/googletranslate/img/gf.png | Bin 0 -> 545 bytes .../plugins/extra/googletranslate/img/gh.png | Bin 0 -> 490 bytes .../plugins/extra/googletranslate/img/gi.png | Bin 0 -> 463 bytes .../plugins/extra/googletranslate/img/gl.png | Bin 0 -> 470 bytes .../plugins/extra/googletranslate/img/gm.png | Bin 0 -> 493 bytes .../plugins/extra/googletranslate/img/gn.png | Bin 0 -> 480 bytes .../plugins/extra/googletranslate/img/gp.png | Bin 0 -> 488 bytes .../plugins/extra/googletranslate/img/gq.png | Bin 0 -> 537 bytes .../plugins/extra/googletranslate/img/gr.png | Bin 0 -> 487 bytes .../plugins/extra/googletranslate/img/gs.png | Bin 0 -> 630 bytes .../plugins/extra/googletranslate/img/gt.png | Bin 0 -> 493 bytes .../plugins/extra/googletranslate/img/gu.png | Bin 0 -> 509 bytes .../plugins/extra/googletranslate/img/gw.png | Bin 0 -> 516 bytes .../plugins/extra/googletranslate/img/gy.png | Bin 0 -> 645 bytes .../plugins/extra/googletranslate/img/hk.png | Bin 0 -> 527 bytes .../plugins/extra/googletranslate/img/hm.png | Bin 0 -> 673 bytes .../plugins/extra/googletranslate/img/hn.png | Bin 0 -> 537 bytes .../plugins/extra/googletranslate/img/hr.png | Bin 0 -> 524 bytes .../plugins/extra/googletranslate/img/ht.png | Bin 0 -> 487 bytes .../plugins/extra/googletranslate/img/hu.png | Bin 0 -> 432 bytes .../plugins/extra/googletranslate/img/id.png | Bin 0 -> 430 bytes .../plugins/extra/googletranslate/img/ie.png | Bin 0 -> 481 bytes .../plugins/extra/googletranslate/img/il.png | Bin 0 -> 431 bytes .../plugins/extra/googletranslate/img/in.png | Bin 0 -> 503 bytes .../plugins/extra/googletranslate/img/io.png | Bin 0 -> 658 bytes .../plugins/extra/googletranslate/img/iq.png | Bin 0 -> 515 bytes .../plugins/extra/googletranslate/img/ir.png | Bin 0 -> 512 bytes .../plugins/extra/googletranslate/img/is.png | Bin 0 -> 532 bytes .../plugins/extra/googletranslate/img/it.png | Bin 0 -> 420 bytes .../plugins/extra/googletranslate/img/jm.png | Bin 0 -> 637 bytes .../plugins/extra/googletranslate/img/jo.png | Bin 0 -> 473 bytes .../plugins/extra/googletranslate/img/jp.png | Bin 0 -> 420 bytes .../plugins/extra/googletranslate/img/ke.png | Bin 0 -> 569 bytes .../plugins/extra/googletranslate/img/kg.png | Bin 0 -> 510 bytes .../plugins/extra/googletranslate/img/kh.png | Bin 0 -> 549 bytes .../plugins/extra/googletranslate/img/ki.png | Bin 0 -> 656 bytes .../plugins/extra/googletranslate/img/km.png | Bin 0 -> 577 bytes .../plugins/extra/googletranslate/img/kn.png | Bin 0 -> 604 bytes .../plugins/extra/googletranslate/img/kp.png | Bin 0 -> 561 bytes .../plugins/extra/googletranslate/img/kr.png | Bin 0 -> 592 bytes .../plugins/extra/googletranslate/img/kw.png | Bin 0 -> 486 bytes .../plugins/extra/googletranslate/img/ky.png | Bin 0 -> 643 bytes .../plugins/extra/googletranslate/img/kz.png | Bin 0 -> 616 bytes .../plugins/extra/googletranslate/img/la.png | Bin 0 -> 563 bytes .../plugins/extra/googletranslate/img/lb.png | Bin 0 -> 517 bytes .../plugins/extra/googletranslate/img/lc.png | Bin 0 -> 520 bytes .../plugins/extra/googletranslate/img/li.png | Bin 0 -> 537 bytes .../plugins/extra/googletranslate/img/lk.png | Bin 0 -> 627 bytes .../plugins/extra/googletranslate/img/lr.png | Bin 0 -> 466 bytes .../plugins/extra/googletranslate/img/ls.png | Bin 0 -> 628 bytes .../plugins/extra/googletranslate/img/lt.png | Bin 0 -> 508 bytes .../plugins/extra/googletranslate/img/lu.png | Bin 0 -> 481 bytes .../plugins/extra/googletranslate/img/lv.png | Bin 0 -> 465 bytes .../plugins/extra/googletranslate/img/ly.png | Bin 0 -> 419 bytes .../plugins/extra/googletranslate/img/ma.png | Bin 0 -> 432 bytes .../plugins/extra/googletranslate/img/mc.png | Bin 0 -> 380 bytes .../plugins/extra/googletranslate/img/md.png | Bin 0 -> 566 bytes .../plugins/extra/googletranslate/img/me.png | Bin 0 -> 448 bytes .../plugins/extra/googletranslate/img/mg.png | Bin 0 -> 453 bytes .../plugins/extra/googletranslate/img/mh.png | Bin 0 -> 628 bytes .../plugins/extra/googletranslate/img/mk.png | Bin 0 -> 664 bytes .../plugins/extra/googletranslate/img/ml.png | Bin 0 -> 474 bytes .../plugins/extra/googletranslate/img/mm.png | Bin 0 -> 483 bytes .../plugins/extra/googletranslate/img/mn.png | Bin 0 -> 492 bytes .../plugins/extra/googletranslate/img/mo.png | Bin 0 -> 588 bytes .../plugins/extra/googletranslate/img/mp.png | Bin 0 -> 597 bytes .../plugins/extra/googletranslate/img/mq.png | Bin 0 -> 655 bytes .../plugins/extra/googletranslate/img/mr.png | Bin 0 -> 569 bytes .../plugins/extra/googletranslate/img/ms.png | Bin 0 -> 614 bytes .../plugins/extra/googletranslate/img/mt.png | Bin 0 -> 420 bytes .../plugins/extra/googletranslate/img/mu.png | Bin 0 -> 496 bytes .../plugins/extra/googletranslate/img/mv.png | Bin 0 -> 542 bytes .../plugins/extra/googletranslate/img/mw.png | Bin 0 -> 529 bytes .../plugins/extra/googletranslate/img/mx.png | Bin 0 -> 574 bytes .../plugins/extra/googletranslate/img/my.png | Bin 0 -> 571 bytes .../plugins/extra/googletranslate/img/mz.png | Bin 0 -> 584 bytes .../plugins/extra/googletranslate/img/na.png | Bin 0 -> 647 bytes .../plugins/extra/googletranslate/img/nc.png | Bin 0 -> 591 bytes .../plugins/extra/googletranslate/img/ne.png | Bin 0 -> 537 bytes .../plugins/extra/googletranslate/img/nf.png | Bin 0 -> 602 bytes .../plugins/extra/googletranslate/img/ng.png | Bin 0 -> 482 bytes .../plugins/extra/googletranslate/img/ni.png | Bin 0 -> 508 bytes .../plugins/extra/googletranslate/img/nl.png | Bin 0 -> 453 bytes .../plugins/extra/googletranslate/img/no.png | Bin 0 -> 512 bytes .../plugins/extra/googletranslate/img/np.png | Bin 0 -> 443 bytes .../plugins/extra/googletranslate/img/nr.png | Bin 0 -> 527 bytes .../plugins/extra/googletranslate/img/nu.png | Bin 0 -> 572 bytes .../plugins/extra/googletranslate/img/nz.png | Bin 0 -> 639 bytes .../plugins/extra/googletranslate/img/om.png | Bin 0 -> 478 bytes .../plugins/extra/googletranslate/img/pa.png | Bin 0 -> 519 bytes .../plugins/extra/googletranslate/img/pe.png | Bin 0 -> 397 bytes .../plugins/extra/googletranslate/img/pf.png | Bin 0 -> 498 bytes .../plugins/extra/googletranslate/img/pg.png | Bin 0 -> 593 bytes .../plugins/extra/googletranslate/img/ph.png | Bin 0 -> 538 bytes .../plugins/extra/googletranslate/img/pk.png | Bin 0 -> 569 bytes .../plugins/extra/googletranslate/img/pl.png | Bin 0 -> 374 bytes .../plugins/extra/googletranslate/img/pm.png | Bin 0 -> 689 bytes .../plugins/extra/googletranslate/img/pn.png | Bin 0 -> 657 bytes .../plugins/extra/googletranslate/img/pr.png | Bin 0 -> 556 bytes .../plugins/extra/googletranslate/img/ps.png | Bin 0 -> 472 bytes .../plugins/extra/googletranslate/img/pt.png | Bin 0 -> 554 bytes .../plugins/extra/googletranslate/img/pw.png | Bin 0 -> 550 bytes .../plugins/extra/googletranslate/img/py.png | Bin 0 -> 473 bytes .../plugins/extra/googletranslate/img/qa.png | Bin 0 -> 450 bytes .../plugins/extra/googletranslate/img/re.png | Bin 0 -> 545 bytes .../plugins/extra/googletranslate/img/ro.png | Bin 0 -> 495 bytes .../plugins/extra/googletranslate/img/rs.png | Bin 0 -> 423 bytes .../plugins/extra/googletranslate/img/ru.png | Bin 0 -> 420 bytes .../plugins/extra/googletranslate/img/rw.png | Bin 0 -> 533 bytes .../plugins/extra/googletranslate/img/sa.png | Bin 0 -> 551 bytes .../plugins/extra/googletranslate/img/sb.png | Bin 0 -> 624 bytes .../plugins/extra/googletranslate/img/sc.png | Bin 0 -> 608 bytes .../extra/googletranslate/img/scotland.png | Bin 0 -> 649 bytes .../plugins/extra/googletranslate/img/sd.png | Bin 0 -> 492 bytes .../plugins/extra/googletranslate/img/se.png | Bin 0 -> 542 bytes .../plugins/extra/googletranslate/img/sg.png | Bin 0 -> 468 bytes .../plugins/extra/googletranslate/img/sh.png | Bin 0 -> 645 bytes .../plugins/extra/googletranslate/img/si.png | Bin 0 -> 510 bytes .../plugins/extra/googletranslate/img/sj.png | Bin 0 -> 512 bytes .../plugins/extra/googletranslate/img/sk.png | Bin 0 -> 562 bytes .../plugins/extra/googletranslate/img/sl.png | Bin 0 -> 436 bytes .../plugins/extra/googletranslate/img/sm.png | Bin 0 -> 502 bytes .../plugins/extra/googletranslate/img/sn.png | Bin 0 -> 532 bytes .../plugins/extra/googletranslate/img/so.png | Bin 0 -> 527 bytes .../plugins/extra/googletranslate/img/sr.png | Bin 0 -> 513 bytes .../plugins/extra/googletranslate/img/st.png | Bin 0 -> 584 bytes .../plugins/extra/googletranslate/img/sv.png | Bin 0 -> 501 bytes .../plugins/extra/googletranslate/img/sy.png | Bin 0 -> 422 bytes .../plugins/extra/googletranslate/img/sz.png | Bin 0 -> 643 bytes .../plugins/extra/googletranslate/img/tc.png | Bin 0 -> 624 bytes .../plugins/extra/googletranslate/img/td.png | Bin 0 -> 570 bytes .../plugins/extra/googletranslate/img/tf.png | Bin 0 -> 527 bytes .../plugins/extra/googletranslate/img/tg.png | Bin 0 -> 562 bytes .../plugins/extra/googletranslate/img/th.png | Bin 0 -> 452 bytes .../plugins/extra/googletranslate/img/tj.png | Bin 0 -> 496 bytes .../plugins/extra/googletranslate/img/tk.png | Bin 0 -> 638 bytes .../plugins/extra/googletranslate/img/tl.png | Bin 0 -> 514 bytes .../plugins/extra/googletranslate/img/tm.png | Bin 0 -> 593 bytes .../plugins/extra/googletranslate/img/tn.png | Bin 0 -> 495 bytes .../plugins/extra/googletranslate/img/to.png | Bin 0 -> 426 bytes .../plugins/extra/googletranslate/img/tr.png | Bin 0 -> 492 bytes .../plugins/extra/googletranslate/img/tt.png | Bin 0 -> 617 bytes .../plugins/extra/googletranslate/img/tv.png | Bin 0 -> 536 bytes .../plugins/extra/googletranslate/img/tw.png | Bin 0 -> 465 bytes .../plugins/extra/googletranslate/img/tz.png | Bin 0 -> 642 bytes .../plugins/extra/googletranslate/img/ua.png | Bin 0 -> 446 bytes .../plugins/extra/googletranslate/img/ug.png | Bin 0 -> 531 bytes .../plugins/extra/googletranslate/img/um.png | Bin 0 -> 571 bytes .../plugins/extra/googletranslate/img/us.png | Bin 0 -> 609 bytes .../plugins/extra/googletranslate/img/uy.png | Bin 0 -> 532 bytes .../plugins/extra/googletranslate/img/uz.png | Bin 0 -> 515 bytes .../plugins/extra/googletranslate/img/va.png | Bin 0 -> 553 bytes .../plugins/extra/googletranslate/img/vc.png | Bin 0 -> 577 bytes .../plugins/extra/googletranslate/img/ve.png | Bin 0 -> 528 bytes .../plugins/extra/googletranslate/img/vg.png | Bin 0 -> 630 bytes .../plugins/extra/googletranslate/img/vi.png | Bin 0 -> 616 bytes .../plugins/extra/googletranslate/img/vn.png | Bin 0 -> 474 bytes .../plugins/extra/googletranslate/img/vu.png | Bin 0 -> 604 bytes .../extra/googletranslate/img/wales.png | Bin 0 -> 652 bytes .../plugins/extra/googletranslate/img/wf.png | Bin 0 -> 554 bytes .../plugins/extra/googletranslate/img/ws.png | Bin 0 -> 476 bytes .../plugins/extra/googletranslate/img/ye.png | Bin 0 -> 413 bytes .../plugins/extra/googletranslate/img/yt.png | Bin 0 -> 593 bytes .../plugins/extra/googletranslate/img/za.png | Bin 0 -> 642 bytes .../plugins/extra/googletranslate/img/zm.png | Bin 0 -> 500 bytes .../plugins/extra/googletranslate/img/zw.png | Bin 0 -> 574 bytes .../lib/googletranslate-plugin.js | 182 + .../extra/googletranslate/package.json | 1 + .../aloha/plugins/extra/headerids/README | 0 .../plugins/extra/headerids/css/headerids.css | 8 + .../extra/headerids/lib/headerids-plugin.js | 127 + .../plugins/extra/headerids/nls/de/i18n.js | 1 + .../plugins/extra/headerids/nls/en/i18n.js | 1 + .../aloha/plugins/extra/headerids/nls/i18n.js | 5 + .../extra/hints/dep/jquery.poshytip.js | 470 + .../aloha/plugins/extra/hints/i18n/de.json | 1 + .../aloha/plugins/extra/hints/i18n/en.json | 1 + .../extra/hints/img/tip-twitter_arrows.gif | Bin 0 -> 87 bytes .../aloha/plugins/extra/hints/package.json | 9 + .../aloha/plugins/extra/hints/src/hints.css | 61 + .../aloha/plugins/extra/hints/src/hints.js | 49 + .../aloha/plugins/extra/linkbrowser/README | 0 .../extra/linkbrowser/img/flags/ad.png | Bin 0 -> 643 bytes .../extra/linkbrowser/img/flags/ae.png | Bin 0 -> 408 bytes .../extra/linkbrowser/img/flags/af.png | Bin 0 -> 604 bytes .../extra/linkbrowser/img/flags/ag.png | Bin 0 -> 591 bytes .../extra/linkbrowser/img/flags/ai.png | Bin 0 -> 643 bytes .../extra/linkbrowser/img/flags/al.png | Bin 0 -> 600 bytes .../extra/linkbrowser/img/flags/am.png | Bin 0 -> 497 bytes .../extra/linkbrowser/img/flags/an.png | Bin 0 -> 488 bytes .../extra/linkbrowser/img/flags/ao.png | Bin 0 -> 428 bytes .../extra/linkbrowser/img/flags/ar.png | Bin 0 -> 506 bytes .../extra/linkbrowser/img/flags/as.png | Bin 0 -> 647 bytes .../extra/linkbrowser/img/flags/at.png | Bin 0 -> 403 bytes .../extra/linkbrowser/img/flags/au.png | Bin 0 -> 673 bytes .../extra/linkbrowser/img/flags/aw.png | Bin 0 -> 524 bytes .../extra/linkbrowser/img/flags/ax.png | Bin 0 -> 663 bytes .../extra/linkbrowser/img/flags/az.png | Bin 0 -> 589 bytes .../extra/linkbrowser/img/flags/ba.png | Bin 0 -> 593 bytes .../extra/linkbrowser/img/flags/bb.png | Bin 0 -> 585 bytes .../extra/linkbrowser/img/flags/bd.png | Bin 0 -> 504 bytes .../extra/linkbrowser/img/flags/be.png | Bin 0 -> 449 bytes .../extra/linkbrowser/img/flags/bf.png | Bin 0 -> 497 bytes .../extra/linkbrowser/img/flags/bg.png | Bin 0 -> 462 bytes .../extra/linkbrowser/img/flags/bh.png | Bin 0 -> 457 bytes .../extra/linkbrowser/img/flags/bi.png | Bin 0 -> 675 bytes .../extra/linkbrowser/img/flags/bj.png | Bin 0 -> 486 bytes .../extra/linkbrowser/img/flags/bm.png | Bin 0 -> 611 bytes .../extra/linkbrowser/img/flags/bn.png | Bin 0 -> 639 bytes .../extra/linkbrowser/img/flags/bo.png | Bin 0 -> 500 bytes .../extra/linkbrowser/img/flags/br.png | Bin 0 -> 593 bytes .../extra/linkbrowser/img/flags/bs.png | Bin 0 -> 526 bytes .../extra/linkbrowser/img/flags/bt.png | Bin 0 -> 631 bytes .../extra/linkbrowser/img/flags/bv.png | Bin 0 -> 512 bytes .../extra/linkbrowser/img/flags/bw.png | Bin 0 -> 443 bytes .../extra/linkbrowser/img/flags/by.png | Bin 0 -> 514 bytes .../extra/linkbrowser/img/flags/bz.png | Bin 0 -> 600 bytes .../extra/linkbrowser/img/flags/ca.png | Bin 0 -> 628 bytes .../extra/linkbrowser/img/flags/catalonia.png | Bin 0 -> 398 bytes .../extra/linkbrowser/img/flags/cc.png | Bin 0 -> 625 bytes .../extra/linkbrowser/img/flags/cd.png | Bin 0 -> 528 bytes .../extra/linkbrowser/img/flags/cf.png | Bin 0 -> 614 bytes .../extra/linkbrowser/img/flags/cg.png | Bin 0 -> 521 bytes .../extra/linkbrowser/img/flags/ch.png | Bin 0 -> 367 bytes .../extra/linkbrowser/img/flags/ci.png | Bin 0 -> 453 bytes .../extra/linkbrowser/img/flags/ck.png | Bin 0 -> 586 bytes .../extra/linkbrowser/img/flags/cl.png | Bin 0 -> 450 bytes .../extra/linkbrowser/img/flags/cm.png | Bin 0 -> 525 bytes .../extra/linkbrowser/img/flags/cn.png | Bin 0 -> 472 bytes .../extra/linkbrowser/img/flags/co.png | Bin 0 -> 483 bytes .../extra/linkbrowser/img/flags/cr.png | Bin 0 -> 477 bytes .../extra/linkbrowser/img/flags/cs.png | Bin 0 -> 439 bytes .../extra/linkbrowser/img/flags/cu.png | Bin 0 -> 563 bytes .../extra/linkbrowser/img/flags/cv.png | Bin 0 -> 529 bytes .../extra/linkbrowser/img/flags/cx.png | Bin 0 -> 608 bytes .../extra/linkbrowser/img/flags/cy.png | Bin 0 -> 428 bytes .../extra/linkbrowser/img/flags/cz.png | Bin 0 -> 476 bytes .../extra/linkbrowser/img/flags/de.png | Bin 0 -> 545 bytes .../extra/linkbrowser/img/flags/dj.png | Bin 0 -> 572 bytes .../extra/linkbrowser/img/flags/dk.png | Bin 0 -> 495 bytes .../extra/linkbrowser/img/flags/dm.png | Bin 0 -> 620 bytes .../extra/linkbrowser/img/flags/do.png | Bin 0 -> 508 bytes .../extra/linkbrowser/img/flags/dz.png | Bin 0 -> 582 bytes .../extra/linkbrowser/img/flags/ec.png | Bin 0 -> 500 bytes .../extra/linkbrowser/img/flags/ee.png | Bin 0 -> 429 bytes .../extra/linkbrowser/img/flags/eg.png | Bin 0 -> 465 bytes .../extra/linkbrowser/img/flags/eh.png | Bin 0 -> 508 bytes .../extra/linkbrowser/img/flags/en.png | Bin 0 -> 496 bytes .../extra/linkbrowser/img/flags/er.png | Bin 0 -> 653 bytes .../extra/linkbrowser/img/flags/es.png | Bin 0 -> 469 bytes .../extra/linkbrowser/img/flags/et.png | Bin 0 -> 592 bytes .../linkbrowser/img/flags/europeanunion.png | Bin 0 -> 479 bytes .../extra/linkbrowser/img/flags/fam.png | Bin 0 -> 532 bytes .../extra/linkbrowser/img/flags/fi.png | Bin 0 -> 489 bytes .../extra/linkbrowser/img/flags/fj.png | Bin 0 -> 610 bytes .../extra/linkbrowser/img/flags/fk.png | Bin 0 -> 648 bytes .../extra/linkbrowser/img/flags/fm.png | Bin 0 -> 552 bytes .../extra/linkbrowser/img/flags/fo.png | Bin 0 -> 474 bytes .../extra/linkbrowser/img/flags/fr.png | Bin 0 -> 545 bytes .../extra/linkbrowser/img/flags/ga.png | Bin 0 -> 489 bytes .../extra/linkbrowser/img/flags/gb.png | Bin 0 -> 599 bytes .../extra/linkbrowser/img/flags/gd.png | Bin 0 -> 637 bytes .../extra/linkbrowser/img/flags/ge.png | Bin 0 -> 594 bytes .../extra/linkbrowser/img/flags/gf.png | Bin 0 -> 545 bytes .../extra/linkbrowser/img/flags/gh.png | Bin 0 -> 490 bytes .../extra/linkbrowser/img/flags/gi.png | Bin 0 -> 463 bytes .../extra/linkbrowser/img/flags/gl.png | Bin 0 -> 470 bytes .../extra/linkbrowser/img/flags/gm.png | Bin 0 -> 493 bytes .../extra/linkbrowser/img/flags/gn.png | Bin 0 -> 480 bytes .../extra/linkbrowser/img/flags/gp.png | Bin 0 -> 488 bytes .../extra/linkbrowser/img/flags/gq.png | Bin 0 -> 537 bytes .../extra/linkbrowser/img/flags/gr.png | Bin 0 -> 487 bytes .../extra/linkbrowser/img/flags/gs.png | Bin 0 -> 630 bytes .../extra/linkbrowser/img/flags/gt.png | Bin 0 -> 493 bytes .../extra/linkbrowser/img/flags/gu.png | Bin 0 -> 509 bytes .../extra/linkbrowser/img/flags/gw.png | Bin 0 -> 516 bytes .../extra/linkbrowser/img/flags/gy.png | Bin 0 -> 645 bytes .../extra/linkbrowser/img/flags/hk.png | Bin 0 -> 527 bytes .../extra/linkbrowser/img/flags/hm.png | Bin 0 -> 673 bytes .../extra/linkbrowser/img/flags/hn.png | Bin 0 -> 537 bytes .../extra/linkbrowser/img/flags/hr.png | Bin 0 -> 524 bytes .../extra/linkbrowser/img/flags/ht.png | Bin 0 -> 487 bytes .../extra/linkbrowser/img/flags/hu.png | Bin 0 -> 432 bytes .../extra/linkbrowser/img/flags/id.png | Bin 0 -> 430 bytes .../extra/linkbrowser/img/flags/ie.png | Bin 0 -> 481 bytes .../extra/linkbrowser/img/flags/il.png | Bin 0 -> 431 bytes .../extra/linkbrowser/img/flags/in.png | Bin 0 -> 503 bytes .../extra/linkbrowser/img/flags/io.png | Bin 0 -> 658 bytes .../extra/linkbrowser/img/flags/iq.png | Bin 0 -> 515 bytes .../extra/linkbrowser/img/flags/ir.png | Bin 0 -> 512 bytes .../extra/linkbrowser/img/flags/is.png | Bin 0 -> 532 bytes .../extra/linkbrowser/img/flags/it.png | Bin 0 -> 420 bytes .../extra/linkbrowser/img/flags/jm.png | Bin 0 -> 637 bytes .../extra/linkbrowser/img/flags/jo.png | Bin 0 -> 473 bytes .../extra/linkbrowser/img/flags/jp.png | Bin 0 -> 420 bytes .../extra/linkbrowser/img/flags/ke.png | Bin 0 -> 569 bytes .../extra/linkbrowser/img/flags/kg.png | Bin 0 -> 510 bytes .../extra/linkbrowser/img/flags/kh.png | Bin 0 -> 549 bytes .../extra/linkbrowser/img/flags/ki.png | Bin 0 -> 656 bytes .../extra/linkbrowser/img/flags/km.png | Bin 0 -> 577 bytes .../extra/linkbrowser/img/flags/kn.png | Bin 0 -> 604 bytes .../extra/linkbrowser/img/flags/kp.png | Bin 0 -> 561 bytes .../extra/linkbrowser/img/flags/kr.png | Bin 0 -> 592 bytes .../extra/linkbrowser/img/flags/kw.png | Bin 0 -> 486 bytes .../extra/linkbrowser/img/flags/ky.png | Bin 0 -> 643 bytes .../extra/linkbrowser/img/flags/kz.png | Bin 0 -> 616 bytes .../extra/linkbrowser/img/flags/la.png | Bin 0 -> 563 bytes .../extra/linkbrowser/img/flags/lb.png | Bin 0 -> 517 bytes .../extra/linkbrowser/img/flags/lc.png | Bin 0 -> 520 bytes .../extra/linkbrowser/img/flags/li.png | Bin 0 -> 537 bytes .../extra/linkbrowser/img/flags/lk.png | Bin 0 -> 627 bytes .../extra/linkbrowser/img/flags/lr.png | Bin 0 -> 466 bytes .../extra/linkbrowser/img/flags/ls.png | Bin 0 -> 628 bytes .../extra/linkbrowser/img/flags/lt.png | Bin 0 -> 508 bytes .../extra/linkbrowser/img/flags/lu.png | Bin 0 -> 481 bytes .../extra/linkbrowser/img/flags/lv.png | Bin 0 -> 465 bytes .../extra/linkbrowser/img/flags/ly.png | Bin 0 -> 419 bytes .../extra/linkbrowser/img/flags/ma.png | Bin 0 -> 432 bytes .../extra/linkbrowser/img/flags/mc.png | Bin 0 -> 380 bytes .../extra/linkbrowser/img/flags/md.png | Bin 0 -> 566 bytes .../extra/linkbrowser/img/flags/me.png | Bin 0 -> 448 bytes .../extra/linkbrowser/img/flags/mg.png | Bin 0 -> 453 bytes .../extra/linkbrowser/img/flags/mh.png | Bin 0 -> 628 bytes .../extra/linkbrowser/img/flags/mk.png | Bin 0 -> 664 bytes .../extra/linkbrowser/img/flags/ml.png | Bin 0 -> 474 bytes .../extra/linkbrowser/img/flags/mm.png | Bin 0 -> 483 bytes .../extra/linkbrowser/img/flags/mn.png | Bin 0 -> 492 bytes .../extra/linkbrowser/img/flags/mo.png | Bin 0 -> 588 bytes .../extra/linkbrowser/img/flags/mp.png | Bin 0 -> 597 bytes .../extra/linkbrowser/img/flags/mq.png | Bin 0 -> 655 bytes .../extra/linkbrowser/img/flags/mr.png | Bin 0 -> 569 bytes .../extra/linkbrowser/img/flags/ms.png | Bin 0 -> 614 bytes .../extra/linkbrowser/img/flags/mt.png | Bin 0 -> 420 bytes .../extra/linkbrowser/img/flags/mu.png | Bin 0 -> 496 bytes .../extra/linkbrowser/img/flags/mv.png | Bin 0 -> 542 bytes .../extra/linkbrowser/img/flags/mw.png | Bin 0 -> 529 bytes .../extra/linkbrowser/img/flags/mx.png | Bin 0 -> 574 bytes .../extra/linkbrowser/img/flags/my.png | Bin 0 -> 571 bytes .../extra/linkbrowser/img/flags/mz.png | Bin 0 -> 584 bytes .../extra/linkbrowser/img/flags/na.png | Bin 0 -> 647 bytes .../extra/linkbrowser/img/flags/nc.png | Bin 0 -> 591 bytes .../extra/linkbrowser/img/flags/ne.png | Bin 0 -> 537 bytes .../extra/linkbrowser/img/flags/nf.png | Bin 0 -> 602 bytes .../extra/linkbrowser/img/flags/ng.png | Bin 0 -> 482 bytes .../extra/linkbrowser/img/flags/ni.png | Bin 0 -> 508 bytes .../extra/linkbrowser/img/flags/nl.png | Bin 0 -> 453 bytes .../extra/linkbrowser/img/flags/no.png | Bin 0 -> 512 bytes .../extra/linkbrowser/img/flags/np.png | Bin 0 -> 443 bytes .../extra/linkbrowser/img/flags/nr.png | Bin 0 -> 527 bytes .../extra/linkbrowser/img/flags/nu.png | Bin 0 -> 572 bytes .../extra/linkbrowser/img/flags/nz.png | Bin 0 -> 639 bytes .../extra/linkbrowser/img/flags/om.png | Bin 0 -> 478 bytes .../extra/linkbrowser/img/flags/pa.png | Bin 0 -> 519 bytes .../extra/linkbrowser/img/flags/pe.png | Bin 0 -> 397 bytes .../extra/linkbrowser/img/flags/pf.png | Bin 0 -> 498 bytes .../extra/linkbrowser/img/flags/pg.png | Bin 0 -> 593 bytes .../extra/linkbrowser/img/flags/ph.png | Bin 0 -> 538 bytes .../extra/linkbrowser/img/flags/pk.png | Bin 0 -> 569 bytes .../extra/linkbrowser/img/flags/pl.png | Bin 0 -> 374 bytes .../extra/linkbrowser/img/flags/pm.png | Bin 0 -> 689 bytes .../extra/linkbrowser/img/flags/pn.png | Bin 0 -> 657 bytes .../extra/linkbrowser/img/flags/pr.png | Bin 0 -> 556 bytes .../extra/linkbrowser/img/flags/ps.png | Bin 0 -> 472 bytes .../extra/linkbrowser/img/flags/pt.png | Bin 0 -> 554 bytes .../extra/linkbrowser/img/flags/pw.png | Bin 0 -> 550 bytes .../extra/linkbrowser/img/flags/py.png | Bin 0 -> 473 bytes .../extra/linkbrowser/img/flags/qa.png | Bin 0 -> 450 bytes .../extra/linkbrowser/img/flags/re.png | Bin 0 -> 545 bytes .../extra/linkbrowser/img/flags/ro.png | Bin 0 -> 495 bytes .../extra/linkbrowser/img/flags/rs.png | Bin 0 -> 423 bytes .../extra/linkbrowser/img/flags/ru.png | Bin 0 -> 420 bytes .../extra/linkbrowser/img/flags/rw.png | Bin 0 -> 533 bytes .../extra/linkbrowser/img/flags/sa.png | Bin 0 -> 551 bytes .../extra/linkbrowser/img/flags/sb.png | Bin 0 -> 624 bytes .../extra/linkbrowser/img/flags/sc.png | Bin 0 -> 608 bytes .../extra/linkbrowser/img/flags/scotland.png | Bin 0 -> 649 bytes .../extra/linkbrowser/img/flags/sd.png | Bin 0 -> 492 bytes .../extra/linkbrowser/img/flags/se.png | Bin 0 -> 542 bytes .../extra/linkbrowser/img/flags/sg.png | Bin 0 -> 468 bytes .../extra/linkbrowser/img/flags/sh.png | Bin 0 -> 645 bytes .../extra/linkbrowser/img/flags/si.png | Bin 0 -> 510 bytes .../extra/linkbrowser/img/flags/sj.png | Bin 0 -> 512 bytes .../extra/linkbrowser/img/flags/sk.png | Bin 0 -> 562 bytes .../extra/linkbrowser/img/flags/sl.png | Bin 0 -> 436 bytes .../extra/linkbrowser/img/flags/sm.png | Bin 0 -> 502 bytes .../extra/linkbrowser/img/flags/sn.png | Bin 0 -> 532 bytes .../extra/linkbrowser/img/flags/so.png | Bin 0 -> 527 bytes .../extra/linkbrowser/img/flags/sr.png | Bin 0 -> 513 bytes .../extra/linkbrowser/img/flags/st.png | Bin 0 -> 584 bytes .../extra/linkbrowser/img/flags/sv.png | Bin 0 -> 501 bytes .../extra/linkbrowser/img/flags/sy.png | Bin 0 -> 422 bytes .../extra/linkbrowser/img/flags/sz.png | Bin 0 -> 643 bytes .../extra/linkbrowser/img/flags/tc.png | Bin 0 -> 624 bytes .../extra/linkbrowser/img/flags/td.png | Bin 0 -> 570 bytes .../extra/linkbrowser/img/flags/tf.png | Bin 0 -> 527 bytes .../extra/linkbrowser/img/flags/tg.png | Bin 0 -> 562 bytes .../extra/linkbrowser/img/flags/th.png | Bin 0 -> 452 bytes .../extra/linkbrowser/img/flags/tj.png | Bin 0 -> 496 bytes .../extra/linkbrowser/img/flags/tk.png | Bin 0 -> 638 bytes .../extra/linkbrowser/img/flags/tl.png | Bin 0 -> 514 bytes .../extra/linkbrowser/img/flags/tm.png | Bin 0 -> 593 bytes .../extra/linkbrowser/img/flags/tn.png | Bin 0 -> 495 bytes .../extra/linkbrowser/img/flags/to.png | Bin 0 -> 426 bytes .../extra/linkbrowser/img/flags/tr.png | Bin 0 -> 492 bytes .../extra/linkbrowser/img/flags/tt.png | Bin 0 -> 617 bytes .../extra/linkbrowser/img/flags/tv.png | Bin 0 -> 536 bytes .../extra/linkbrowser/img/flags/tw.png | Bin 0 -> 465 bytes .../extra/linkbrowser/img/flags/tz.png | Bin 0 -> 642 bytes .../extra/linkbrowser/img/flags/ua.png | Bin 0 -> 446 bytes .../extra/linkbrowser/img/flags/ug.png | Bin 0 -> 531 bytes .../extra/linkbrowser/img/flags/um.png | Bin 0 -> 571 bytes .../extra/linkbrowser/img/flags/us.png | Bin 0 -> 609 bytes .../extra/linkbrowser/img/flags/uy.png | Bin 0 -> 532 bytes .../extra/linkbrowser/img/flags/uz.png | Bin 0 -> 515 bytes .../extra/linkbrowser/img/flags/va.png | Bin 0 -> 553 bytes .../extra/linkbrowser/img/flags/vc.png | Bin 0 -> 577 bytes .../extra/linkbrowser/img/flags/ve.png | Bin 0 -> 528 bytes .../extra/linkbrowser/img/flags/vg.png | Bin 0 -> 630 bytes .../extra/linkbrowser/img/flags/vi.png | Bin 0 -> 616 bytes .../extra/linkbrowser/img/flags/vn.png | Bin 0 -> 474 bytes .../extra/linkbrowser/img/flags/vu.png | Bin 0 -> 604 bytes .../extra/linkbrowser/img/flags/wales.png | Bin 0 -> 652 bytes .../extra/linkbrowser/img/flags/wf.png | Bin 0 -> 554 bytes .../extra/linkbrowser/img/flags/ws.png | Bin 0 -> 476 bytes .../extra/linkbrowser/img/flags/ye.png | Bin 0 -> 413 bytes .../extra/linkbrowser/img/flags/yt.png | Bin 0 -> 593 bytes .../extra/linkbrowser/img/flags/za.png | Bin 0 -> 642 bytes .../extra/linkbrowser/img/flags/zm.png | Bin 0 -> 500 bytes .../extra/linkbrowser/img/flags/zw.png | Bin 0 -> 574 bytes .../linkbrowser/lib/linkbrowser-plugin.js | 153 + .../plugins/extra/linkbrowser/nls/de/i18n.js | 1 + .../plugins/extra/linkbrowser/nls/fr/i18n.js | 1 + .../plugins/extra/linkbrowser/nls/i18n.js | 7 + .../plugins/extra/linkbrowser/nls/pl/i18n.js | 1 + .../plugins/extra/linkbrowser/nls/ru/i18n.js | 1 + .../plugins/extra/linkchecker/demo/index.css | 49 + .../plugins/extra/linkchecker/demo/index.html | 82 + .../plugins/extra/linkchecker/i18n/en.json | 1 + .../plugins/extra/linkchecker/package.json | 1 + .../aloha/plugins/extra/linkchecker/proxy.php | 244 + .../extra/linkchecker/src/linkchecker.css | 14 + .../extra/linkchecker/src/linkchecker.js | 256 + .../listenforcer/lib/listenforcer-plugin.js | 165 + .../aloha/plugins/extra/metaview/README | 0 .../plugins/extra/metaview/css/metaview.css | 86 + .../plugins/extra/metaview/img/anchor.png | Bin 0 -> 1271 bytes .../plugins/extra/metaview/img/blockquote.png | Bin 0 -> 196 bytes .../plugins/extra/metaview/img/button.png | Bin 0 -> 228 bytes .../plugins/extra/metaview/img/caption.png | Bin 0 -> 248 bytes .../aloha/plugins/extra/metaview/img/cite.png | Bin 0 -> 571 bytes .../aloha/plugins/extra/metaview/img/dd.png | Bin 0 -> 178 bytes .../aloha/plugins/extra/metaview/img/div.png | Bin 0 -> 201 bytes .../aloha/plugins/extra/metaview/img/dl.png | Bin 0 -> 181 bytes .../aloha/plugins/extra/metaview/img/dt.png | Bin 0 -> 180 bytes .../aloha/plugins/extra/metaview/img/h1.png | Bin 0 -> 166 bytes .../aloha/plugins/extra/metaview/img/h2.png | Bin 0 -> 172 bytes .../aloha/plugins/extra/metaview/img/h3.png | Bin 0 -> 170 bytes .../aloha/plugins/extra/metaview/img/h4.png | Bin 0 -> 172 bytes .../aloha/plugins/extra/metaview/img/h5.png | Bin 0 -> 172 bytes .../aloha/plugins/extra/metaview/img/h6.png | Bin 0 -> 171 bytes .../plugins/extra/metaview/img/icon_cite.png | Bin 0 -> 1610 bytes .../aloha/plugins/extra/metaview/img/p.png | Bin 0 -> 3607 bytes .../aloha/plugins/extra/metaview/img/pre.png | Bin 0 -> 177 bytes .../plugins/extra/metaview/img/table.png | Bin 0 -> 247 bytes .../aloha/plugins/extra/metaview/img/td.png | Bin 0 -> 181 bytes .../aloha/plugins/extra/metaview/img/th.png | Bin 0 -> 188 bytes .../extra/metaview/lib/metaview-plugin.js | 82 + .../aloha/plugins/extra/metaview/nls/de.json | 1 + .../plugins/extra/metaview/nls/de/i18n.js | 1 + .../aloha/plugins/extra/metaview/nls/en.json | 1 + .../plugins/extra/metaview/nls/en/i18n.js | 1 + .../aloha/plugins/extra/metaview/nls/i18n.js | 5 + .../plugins/extra/numerated-headers/README | 0 .../css/numerated-headers.css | 7 + .../extra/numerated-headers/demo/index.css | 189 + .../extra/numerated-headers/demo/index.html | 139 + .../numerated-headers/demo/js/aloha-config.js | 115 + .../extra/numerated-headers/img/headers.png | Bin 0 -> 252 bytes .../lib/numerated-headers-plugin.js | 233 + .../extra/numerated-headers/nls/de/i18n.js | 1 + .../extra/numerated-headers/nls/en/i18n.js | 1 + .../extra/numerated-headers/nls/i18n.js | 5 + .../aloha/plugins/extra/ribbon/LICENSE.md | 662 + .../aloha/plugins/extra/ribbon/README.md | 8 + .../aloha/plugins/extra/ribbon/css/ribbon.css | 10 + .../plugins/extra/ribbon/lib/ribbon-plugin.js | 186 + .../aloha/plugins/extra/ribbon/package.json | 1 + .../aloha/plugins/extra/speak/README | 0 .../aloha/plugins/extra/speak/css/speak.css | 3 + .../aloha/plugins/extra/speak/img/speaker.png | Bin 0 -> 2035 bytes .../plugins/extra/speak/lib/speak-plugin.js | 44 + .../aloha/plugins/extra/speak/lib/speak.js | 3 + .../aloha/plugins/extra/speak/package.json | 1 + .../aloha/plugins/extra/toc/i18n/de.json | 1 + .../aloha/plugins/extra/toc/i18n/en.json | 1 + .../aloha/plugins/extra/toc/package.json | 1 + .../aloha/plugins/extra/toc/src/toc.js | 350 + .../aloha/plugins/extra/vie/LICENSE | 22 + .../aloha/plugins/extra/vie/README.markdown | 65 + .../aloha/plugins/extra/vie/demo/index.html | 93 + .../vie/img/cms-decoupled-communications.png | Bin 0 -> 10283 bytes .../aloha/plugins/extra/vie/package.json | 1 + .../plugins/extra/vie/src/backbone-min.js | 27 + .../plugins/extra/vie/src/underscore-min.js | 25 + .../aloha/plugins/extra/vie/src/vie-aloha.js | 74 + .../extra/vie/src/vie-collectionmanager.js | 70 + .../extra/vie/src/vie-containermanager.js | 263 + .../aloha/plugins/extra/vie/src/vie.js | 20 + .../aloha/plugins/extra/wai-lang/README.md | 11 + .../plugins/extra/wai-lang/css/wai-lang.css | 30 + .../plugins/extra/wai-lang/img/button.png | Bin 0 -> 930 bytes .../extra/wai-lang/img/remove-button.png | Bin 0 -> 949 bytes .../extra/wai-lang/lib/language-codes.json | 682 + .../plugins/extra/wai-lang/lib/languages.js | 105 + .../extra/wai-lang/lib/wai-lang-plugin.js | 378 + .../plugins/extra/wai-lang/nls/de/i18n.js | 1 + .../plugins/extra/wai-lang/nls/en/i18n.js | 1 + .../aloha/plugins/extra/wai-lang/nls/i18n.js | 5 + .../aloha/plugins/extra/zemanta/README | 5 + .../css/zemanta-widget-alohaeditor.css | 24 + .../extra/zemanta/img/zemanta-mini-logo.png | Bin 0 -> 3517 bytes .../extra/zemanta/lib/zemanta-plugin.js | 241 + .../aloha/plugins/extra/zemanta/nls/i18n.js | 8 + .../locomotive/backbone.modelbinding.js | 1 + .../assets/javascripts/locomotive/resize.js | 9 + .../assets/javascripts/locomotive/toggle.js | 11 +- .../locomotive/toggle/toggle_handle-bg.png | Bin 355 -> 0 bytes .../toggle/toggle_handle_left-bg.png | Bin 698 -> 0 bytes .../toggle/toggle_handle_right-bg.png | Bin 727 -> 0 bytes .../locomotive/toggle/toggle_shadow-bg.png | Bin 344 -> 0 bytes .../assets/javascripts/locomotive/vendor.js | 2 +- .../{toggle.scss => toggle.css.scss} | 0 1659 files changed, 287704 insertions(+), 58 deletions(-) create mode 100644 app/assets/javascripts/locomotive/inline_editor.js.coffee create mode 100644 app/assets/javascripts/locomotive/views/inline_editor/application_view.js.coffee create mode 100644 app/assets/javascripts/locomotive/views/inline_editor/toolbar_view.js.coffee rename app/assets/stylesheets/locomotive/{ => backoffice}/_box.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/_buttons.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/_helpers.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/_picker.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/application.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/codemirror_changes.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/content_assets.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/content_locale_picker.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/datepicker.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/dialog_changes.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/editable_elements.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/formtastic_changes.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/installation.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/layout.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu.css (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/_colors.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/_helpers.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/_icons.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/default.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/main.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/menu/sub.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/not_logged_in.css (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/simple.css.scss (100%) rename app/assets/stylesheets/locomotive/{ => backoffice}/sites_picker.css.scss (100%) create mode 100644 app/assets/stylesheets/locomotive/inline_editor.css create mode 100644 app/assets/stylesheets/locomotive/inline_editor/layout.css.scss create mode 100644 app/assets/stylesheets/locomotive/inline_editor/toolbar.css.scss rename app/controllers/locomotive/public/{rendering_controller.rb => pages_controller.rb} (53%) create mode 100644 app/middlewares/locomotive/inline_editor_middleware.rb create mode 100644 app/views/locomotive/public/pages/edit.html.haml create mode 100644 vendor/assets/javascripts/locomotive/aloha/css/aloha-core.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/css/aloha-sidebar.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/css/aloha.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/css/ext-aloha-reset.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/css/ext-aloha.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/arrow-down.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/arrow-left.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/arrow.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/base-big.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/base-multi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/base.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/breadcrumb-divider.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/fade-in.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/fade-out.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/gentics-logo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/grabhandle.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/maximize.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/multisplit-base.jpg create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/multisplit-close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/multisplit-open.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/pin.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/removeformat.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/text_indent.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/img/text_indent_remove.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha-bootstrap.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/command.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/console.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/contenthandlermanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/core.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ecma5.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ecma5shims.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/editable.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/engine.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ext-alohaproxy.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ext-alohareader.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ext-alohatreeloader.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ext.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/floatingmenu.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ierange-m2.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/jquery.aloha.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/jquery.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/jquery.patch.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/markup.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/message.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/observable.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/pluginmanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/rangy-core.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/registry.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/repository.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/repositorymanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/repositoryobjects.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/selection.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/sidebar.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ui-attributefield.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ui-browser.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/aloha/ui.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/css.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/jquery-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/order.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/require.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/text.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/class.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/dom.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/json2.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/lang.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/position.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/util/range.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/adapter/jquery/ext-jquery-adapter-debug.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/adapter/jquery/ext-jquery-adapter.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/ext-all-debug.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/ext-all.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/gpl-3.0.txt create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/license.txt create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/charts.swf create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/css/ext-all.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/css/ext-all.less create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/css/xtheme-gray.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/expressinstall.swf create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/corners-blue.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/l-blue.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/l.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/r-blue.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/r.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/tb-blue.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/arrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/group-cs.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/group-lr.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/group-tb.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b-noline.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-bo.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-noline.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-o.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/dd/drop-add.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/dd/drop-no.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/dd/drop-yes.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/checkbox.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/clear-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/clear-trigger.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/date-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/date-trigger.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/error-tip-corners.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/exclamation.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/radio.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/search-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/search-trigger.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/text-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/trigger-square.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/trigger-square.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/trigger-tpl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/form/trigger.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/gradient-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/arrow-left-white.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/arrow-right-white.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/col-move-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/col-move-top.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/columns.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/dirty.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/done.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/drop-no.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/drop-yes.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/footer-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-blue-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-blue-split.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-hrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-split.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid-vista-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hd-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-sel-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/group-by.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/group-collapse.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/group-expand-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/group-expand.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hd-pop.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-asc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-desc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-lock.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-lock.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-unlock.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-unlock.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/mso-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/nowait.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-first-disabled.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-first.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-last-disabled.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-last.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-next-disabled.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-next.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-prev-disabled.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/page-prev.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/pick-button.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/refresh.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/row-check-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/row-expand-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/row-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/row-sel.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/sort-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/sort_asc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/sort_desc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/grid/wait.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/collapse.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/expand.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/gradient-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/mini-left.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/mini-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/ns-collapse.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/ns-expand.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/panel-close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/panel-title-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/panel-title-light-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/stick.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/stuck.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/tab-close-on.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/layout/tab-close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/checked.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/group-checked.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/item-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/menu-parent.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/menu.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/menu/unchecked.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/corners-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/left-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/light-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/tool-sprite-tpl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/tool-sprites.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/tools-sprites-trans.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/top-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/top-bottom.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/white-corners-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/white-left-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/panel/white-top-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/progress/progress-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/qtip/bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/qtip/close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/qtip/tip-anchor-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/qtip/tip-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/s.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shadow-c.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shadow-lr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shadow.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/blue-loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/calendar.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/hd-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/large-loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/left-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/loading-balls.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/right-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/shared/warning.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/e-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/e-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/ne-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/ne-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/nw-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/nw-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/s-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/s-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/se-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/se-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/square.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/sw-handle-dark.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/sizer/sw-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/slider/slider-bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/slider/slider-thumb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/slider/slider-v-bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/slider/slider-v-thumb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/scroll-left.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/scroll-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/scroller-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-inactive-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-inactive-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-over-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-over-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-strip-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-strip-bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-strip-btm-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tabs/tabs-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/btn-arrow-light.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/btn-arrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/btn-over-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/gray-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/more.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/tb-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/tb-btn-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/tb-xl-btn-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/toolbar/tb-xl-sep.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/arrows.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-add.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-between.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-no.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-under.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/drop-yes.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-minus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-minus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-plus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-plus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-line.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/elbow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/folder-open.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/folder.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/leaf.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/tree/s.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/icon-error.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/icon-info.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/icon-question.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/icon-warning.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/left-corners.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/left-corners.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/left-right.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/left-right.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/right-corners.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/right-corners.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/top-bottom.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/default/window/top-bottom.psd create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/btn-arrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/btn-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/group-cs.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/group-lr.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/group-tb.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-bo.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-o.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/form/clear-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/form/date-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/form/search-trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/form/trigger-square.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/form/trigger.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/gradient-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/col-move-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/col-move-top.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hd-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow-over2.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow2.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-special-col-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-special-col-bg2.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-special-col-sel-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/group-collapse.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/group-expand-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/group-expand.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/page-first.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/page-last.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/page-next.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/page-prev.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/refresh.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/row-expand-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/sort_asc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/grid/sort_desc.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/menu/group-checked.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/menu/item-over-disabled.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/menu/item-over.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/menu/menu-parent.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/corners-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/left-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/light-hd.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/tool-sprite-tpl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/tool-sprites.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/tools-sprites-trans.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/top-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/top-bottom.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/white-corners-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/white-left-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/progress/progress-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/qtip/bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/qtip/close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/qtip/tip-anchor-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/qtip/tip-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/s.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/shared/hd-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/shared/left-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/shared/right-btn.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/e-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/ne-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/nw-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/s-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/se-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/square.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/sizer/sw-handle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/slider/slider-thumb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/slider/slider-v-thumb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/scroll-left.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/scroll-right.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/scroller-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-inactive-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-inactive-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-over-left-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-over-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-right-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-close.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-strip-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-strip-bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-strip-btm-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tabs/tabs-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/btn-arrow-light.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/btn-arrow.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/btn-over-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/gray-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/more.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/tb-bg.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/toolbar/tb-btn-sprite.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tree/arrows.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-minus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-minus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-plus-nl.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-plus.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/icon-error.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/icon-info.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/icon-question.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/icon-warning.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/left-corners.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/left-corners.pspimage create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/left-right.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/right-corners.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/images/gray/window/top-bottom.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/ext-3.2.1/resources/resources.jsb create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/jquery-1.5.1.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/jquery-1.6.1.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/jquery-1.6.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/jquery.json-2.2.min.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/jquery.store.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/lib/vendor/sanitize.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/abbr/css/abbr.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/abbr/lib/abbr-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/abbr/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/abbr/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/abbr/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/LICENSE create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/css/align.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/img/align.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/lib/align-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/align/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/css/block.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/img/toolbar-draghandle.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/block-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/block.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/blockcontenthandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/blockmanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/editor.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/editormanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/lib/sidebarattributeeditor.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/block/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/characterpicker/css/characterpicker.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/characterpicker/img/icon.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/characterpicker/lib/characterpicker-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/characterpicker/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/characterpicker/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/commands/css/abbr.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/commands/lib/commands-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/commands/lib/inserthtml.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/commands/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/lib/contenthandler-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/lib/genericcontenthandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/lib/oembedcontenthandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/lib/sanitizecontenthandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/lib/wordcontenthandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/contenthandler/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/dom-to-xhtml/lib/dom-to-xhtml.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/css/format.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/img/em.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/img/strong.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/lib/format-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/eo/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/fi/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/it/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/pl/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/format/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/highlighteditables/css/highlighteditables.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/highlighteditables/lib/highlighteditables-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/highlighteditables/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/horizontalruler/css/horizontalruler.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/horizontalruler/img/icon.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/horizontalruler/lib/horizontalruler-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/horizontalruler/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/horizontalruler/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/AGPL3 create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/LICENSE create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/css/image.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/crop.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/crop.php create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/cropnresize.jpg create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/blank.jpg create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/cropnresize.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/handle-sw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-align-left.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-align-none.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-align-right.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-border.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-title.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/padding-decrease.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/padding-increase.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/page.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/size-decrease.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/size-increase.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/lib/image-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/nls/cz/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/test/test.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/test/test.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jcrop.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.min.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/mousewheel/mousewheel.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/jquery-ui-1.8.10.custom.min.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_flat_10_000000_40x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_222222_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_228ef1_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ef8c08_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ffd27a_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ffffff_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.cropnresize.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.custom.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/css/link.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/background.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/external-link-ltr-icon.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/delicious.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/linklist.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/slowlinklist.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/lib/link-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/pl/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/lib/list-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/eo/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fi/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/it/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/list/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/lib/paste-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/css/table.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/down.cur create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/left.cur create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/table_layout.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-green.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-red.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-cell.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-create-layer.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin-utils.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-selection.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/eo/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/fi/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/it/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/pl/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/table/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/demo/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/lib/undo-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/vendor/diff_match_patch_uncompressed.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/common/undo/vendor/undo.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/css/attributes.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/lib/attributes-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/attributes/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/browser.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/browser.jqgrid.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/browsercombined.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/browsercombined.css.backup create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-icons_222222_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-icons_2e83ff_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-icons_454545_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-icons_888888_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/images/ui-icons_cd0a0a_256x240.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/jquery-ui-1.8.13.custom.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/jstree.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/throbber.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/css/ui.jqgrid.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow-000-medium.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow-180.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow-315-medium.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow-stop-180.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow-stop.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/arrow.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/control-stop-square-small.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/folder-horizontal-open.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/folder-open.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/gcn-icons/gcn-icon-file.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/gcn-icons/gcn-icon-image.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/gcn-icons/gcn-icon-page.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/magnifier-left.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/page.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/picture.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/sort-alphabet-descending.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/sort-alphabet.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/img/throbber.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/lib/browser-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/lib/browser.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/lib/locale.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/nls/de.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/nls/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/grid.locale.de.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/grid.locale.en.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/jquery.jqGrid.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/jquery.jstree.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/jquery.ui.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/ui-layout.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/css/cite.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/blockquote.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/icon_cite.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/lib/cite-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/add-icon.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/add.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/comments.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/hr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/textbox.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/src/comments.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/src/comments.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/AGPL3 create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/LICENSE create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/TODO.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/specs/DragnDropnImage.graphml create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/style.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/upload.php create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/fr.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/cross.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/hourglass.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/loading.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/page.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/tick.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/lib/draganddropfiles-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/lib/dragndropfiles.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/lib/dragndropfiles.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/lib/dropfilesrepository.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/aa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ab.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ad.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ae.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/af.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ag.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ai.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ak.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/al.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/am.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/an.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ao.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ar.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/as.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/at.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/au.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/av.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/aw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ax.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ay.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/az.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ba.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/be.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/br.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/by.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/bz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ca.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/catalonia.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ce.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ch.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ci.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ck.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/co.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/cz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/da.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/de.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/dj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/dk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/dm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/do.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/dv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/dz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ec.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ee.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/eg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/eh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/el.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/en.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/eo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/er.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/es.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/et.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/eu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/europeanunion.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fam.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ff.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/fy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ga.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ge.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/gy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ha.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/he.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ho.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ht.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/hz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/id.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ie.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ig.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ii.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/il.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/in.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/io.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/iq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ir.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/is.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/it.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ja.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/jm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/jo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/jp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/jv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ka.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ke.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ki.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/km.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ko.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ks.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ku.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ky.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/kz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/la.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/li.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ln.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ls.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/lv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ly.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ma.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/md.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/me.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ml.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ms.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/my.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/mz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/na.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ne.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ng.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ni.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/no.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/np.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ny.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/nz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/oc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/om.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/or.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/os.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pe.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ph.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ps.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/pw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/py.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/qa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/re.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/rm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/rn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ro.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/rs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ru.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/rw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/scotland.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/se.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/si.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/so.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ss.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/st.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/su.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/sz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ta.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/td.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/te.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/th.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ti.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/to.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ty.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/tz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ua.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ug.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/uk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/um.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ur.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/us.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/uy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/uz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/va.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ve.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/vu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/wa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/wales.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/wf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/wo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ws.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/xh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/ye.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/yt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/za.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/zh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/zm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/img/flags/zw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/flag-icons/lib/flag-icons-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/css/formatless.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/img/button.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/lib/formatlesshandler.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/lib/formatlesspaste-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/formatlesspaste/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/css/googletranslate.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ad.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ae.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/af.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ag.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ai.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/al.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/am.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/an.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ao.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ar.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/as.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/at.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/au.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/aw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ax.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/az.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ba.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/be.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/br.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/by.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/bz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ca.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/catalonia.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ch.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ci.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ck.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/co.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/cz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/de.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/dj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/dk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/dm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/do.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/dz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ec.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ee.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/eg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/eh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/en.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/er.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/es.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/et.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/europeanunion.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fam.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/fr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ga.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ge.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/gy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/hk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/hm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/hn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/hr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ht.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/hu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/id.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ie.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/il.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/in.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/io.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/iq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ir.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/is.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/it.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/jm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/jo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/jp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ke.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ki.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/km.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ky.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/kz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/la.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/li.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ls.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/lv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ly.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ma.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/md.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/me.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ml.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ms.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/my.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/mz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/na.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ne.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ng.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ni.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/no.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/np.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/nz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/om.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pe.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ph.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ps.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/pw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/py.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/qa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/re.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ro.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/rs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ru.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/rw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/scotland.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/se.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/si.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/so.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/st.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/sz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/td.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/th.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/to.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/tz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ua.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ug.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/um.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/us.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/uy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/uz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/va.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/vc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ve.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/vg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/vi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/vn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/vu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/wales.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/wf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ws.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/ye.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/yt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/za.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/zm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/img/zw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/lib/googletranslate-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/googletranslate/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/css/headerids.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/lib/headerids-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/headerids/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/dep/jquery.poshytip.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/i18n/de.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/i18n/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/img/tip-twitter_arrows.gif create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/src/hints.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/hints/src/hints.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ad.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ae.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/af.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ag.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ai.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/al.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/am.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/an.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ao.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ar.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/as.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/at.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/au.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/aw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ax.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/az.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ba.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/be.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/br.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/by.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/bz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ca.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/catalonia.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ch.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ci.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ck.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/co.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/cz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/de.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/dj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/dk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/dm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/do.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/dz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ec.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ee.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/eg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/eh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/en.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/er.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/es.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/et.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/europeanunion.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fam.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/fr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ga.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ge.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/gy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/hk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/hm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/hn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/hr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ht.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/hu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/id.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ie.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/il.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/in.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/io.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/iq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ir.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/is.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/it.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/jm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/jo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/jp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ke.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ki.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/km.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ky.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/kz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/la.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/li.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ls.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/lv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ly.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ma.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/md.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/me.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ml.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mp.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mq.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ms.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mx.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/my.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/mz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/na.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ne.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ng.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ni.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/no.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/np.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/nz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/om.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pe.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ph.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ps.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/pw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/py.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/qa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/re.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ro.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/rs.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ru.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/rw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sa.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sb.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/scotland.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/se.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sh.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/si.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/so.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/st.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/sz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/td.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/th.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tj.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tk.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/to.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tr.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tv.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/tz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ua.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ug.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/um.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/us.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/uy.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/uz.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/va.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/vc.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ve.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/vg.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/vi.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/vn.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/vu.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/wales.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/wf.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ws.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/ye.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/yt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/za.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/zm.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/img/flags/zw.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/lib/linkbrowser-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/nls/fr/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/nls/pl/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkbrowser/nls/ru/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/demo/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/i18n/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/proxy.php create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/src/linkchecker.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/linkchecker/src/linkchecker.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/listenforcer/lib/listenforcer-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/css/metaview.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/anchor.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/blockquote.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/button.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/caption.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/cite.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/dd.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/div.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/dl.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/dt.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h1.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h2.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h3.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h4.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h5.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/h6.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/icon_cite.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/p.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/pre.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/table.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/td.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/img/th.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/lib/metaview-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/nls/de.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/nls/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/metaview/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/css/numerated-headers.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/demo/index.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/demo/js/aloha-config.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/img/headers.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/lib/numerated-headers-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/numerated-headers/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/ribbon/LICENSE.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/ribbon/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/ribbon/css/ribbon.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/ribbon/lib/ribbon-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/ribbon/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/css/speak.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/img/speaker.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/lib/speak-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/lib/speak.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/speak/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/toc/i18n/de.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/toc/i18n/en.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/toc/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/toc/src/toc.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/LICENSE create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/README.markdown create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/demo/index.html create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/img/cms-decoupled-communications.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/package.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/backbone-min.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/underscore-min.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/vie-aloha.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/vie-collectionmanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/vie-containermanager.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/vie/src/vie.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/README.md create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/css/wai-lang.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/img/button.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/img/remove-button.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/lib/language-codes.json create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/lib/languages.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/lib/wai-lang-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/nls/de/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/nls/en/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/wai-lang/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/zemanta/README create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/zemanta/css/zemanta-widget-alohaeditor.css create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/zemanta/img/zemanta-mini-logo.png create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/zemanta/lib/zemanta-plugin.js create mode 100644 vendor/assets/javascripts/locomotive/aloha/plugins/extra/zemanta/nls/i18n.js create mode 100644 vendor/assets/javascripts/locomotive/resize.js delete mode 100644 vendor/assets/javascripts/locomotive/toggle/toggle_handle-bg.png delete mode 100644 vendor/assets/javascripts/locomotive/toggle/toggle_handle_left-bg.png delete mode 100644 vendor/assets/javascripts/locomotive/toggle/toggle_handle_right-bg.png delete mode 100644 vendor/assets/javascripts/locomotive/toggle/toggle_shadow-bg.png rename vendor/assets/stylesheets/locomotive/{toggle.scss => toggle.css.scss} (100%) diff --git a/Gemfile b/Gemfile index bed5e274..bae7eb59 100644 --- a/Gemfile +++ b/Gemfile @@ -13,8 +13,8 @@ gem 'mongo', '~> 1.5.2' gem 'bson_ext', '~> 1.5.2' gem 'mongoid', '~> 2.4.0' gem 'locomotive_mongoid_acts_as_tree', :git => 'git@github.com:locomotivecms/mongoid_acts_as_tree.git' -# gem 'custom_fields', :path => '../gems/custom_fields' # DEV -gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental' +gem 'custom_fields', :path => '../gems/custom_fields' # DEV +# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental' gem 'kaminari' gem 'haml', '~> 3.1.3' diff --git a/app/assets/javascripts/locomotive/inline_editor.js.coffee b/app/assets/javascripts/locomotive/inline_editor.js.coffee new file mode 100644 index 00000000..f4be6dd3 --- /dev/null +++ b/app/assets/javascripts/locomotive/inline_editor.js.coffee @@ -0,0 +1,20 @@ +#= require jquery +#= require jquery-ui +#= require jquery_ujs +#= require underscore +#= require backbone +#= require locomotive/growl +#= require locomotive/handlebars +#= require locomotive/ICanHandlebarz +#= require locomotive/resize +#= require locomotive/toggle +#= require_self +#= require_tree ./utils +#= require_tree ./models +#= require_tree ./views/inline_editor + +window.Locomotive = + mounted_on: '/locomotive' # default path + Models: {} + Collections: {} + Views: {} \ No newline at end of file diff --git a/app/assets/javascripts/locomotive/utils/core_ext.js b/app/assets/javascripts/locomotive/utils/core_ext.js index 2f372ef4..faf01845 100644 --- a/app/assets/javascripts/locomotive/utils/core_ext.js +++ b/app/assets/javascripts/locomotive/utils/core_ext.js @@ -43,5 +43,25 @@ //this will reload the page, it's likely better to store this until finished document.location.search = kvp.join('&'); } + + window.addJavascript = function(doc, src, options) { + var script = doc.createElement('script'); + script.type = 'text/javascript'; + script.src = src; + for (var key in options) { + script.setAttribute(key, options[key]); + } + doc.body.appendChild(script); + } + + window.addStylesheet = function(doc, src, options) { + var stylesheet = doc.createElement('link'); + stylesheet.style = 'text/css'; + stylesheet.href = src; + stylesheet.media = 'screen'; + stylesheet.rel = 'stylesheet'; + doc.head.appendChild(stylesheet); + } + })(); diff --git a/app/assets/javascripts/locomotive/views/inline_editor/application_view.js.coffee b/app/assets/javascripts/locomotive/views/inline_editor/application_view.js.coffee new file mode 100644 index 00000000..fbc245b3 --- /dev/null +++ b/app/assets/javascripts/locomotive/views/inline_editor/application_view.js.coffee @@ -0,0 +1,133 @@ +Locomotive.Views.InlinEditor ||= {} + +#= require ./toolbar_view + +class Locomotive.Views.InlinEditor.ApplicationView extends Backbone.View + + el: 'body' + + initialize: -> + super + + @iframe = @$('#page iframe') + + @toolbar_view = new Locomotive.Views.InlinEditor.ToolbarView(target: @iframe) + + render: -> + super + + @decorate_iframe() + + set_page: (attributes) -> + @page = new Locomotive.Models.Page(attributes) + window.foo = @page + + @toolbar_view.model = @page + + @$('#toolbar .inner').html(@toolbar_view.refresh().render().el) + + decorate_iframe: -> + console.log('decorating iframe') + + iframe = @iframe + iframe.load => + # add js / css + doc = iframe[0].contentWindow.document + window.addJavascript doc, '/assets/locomotive/aloha/lib/aloha.js', + 'data-aloha-plugins': 'common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste' + window.addStylesheet doc, '/assets/locomotive/aloha/css/aloha.css' + + # bind the resize event. When the iFrame's size changes, update its height + iframe_content = iframe.contents().find('body') + iframe_content.resize -> + elem = $(this) + + if elem.outerHeight(true) > $('body').outerHeight(true) # Resize the iFrame. + iframe.css height: elem.outerHeight(true) + + # Resize the iFrame immediately. + iframe_content.resize() + + # render: -> + # super + # + # console.log('rendering') + # + # @enable_iframe_auto_height() + # + # @foo() + # + # @toolbar_view = new Locomotive.Views. + # + # set_page: (attributes) -> + # @page = new Locomotive.Models.Page(attributes) + # + # window.foo = @page + # + # @$('#toolbar .inner').html(ich.toolbar(@page.toJSON())) + # + # enable_iframe_auto_height: -> + # console.log('decorating iframe') + # + # console.log(@$('#page iframe html')) + # + # # @$('#page iframe').iframeAutoHeight + # # debug: true + # # callback: (callbackObject) => + # # $('body').css('overflow': 'visible') + # + # iframe = @$('#page iframe') + # iframe.load => + # iframe_content = iframe.contents().find('body') + # + # # Bind the resize event. When the iframe's size changes, update its height as + # # well as the corresponding info div. + # iframe_content.resize -> + # elem = $(this) + # + # # Resize the IFrame. + # if elem.outerHeight(true) > $('body').outerHeight(true) + # iframe.css height: elem.outerHeight(true) + # + # # Update the info div width and height. + # # $('#iframe-info').text( 'IFRAME width: ' + elem.width() + ', height: ' + elem.height() ); + # + # # Resize the Iframe and update the info div immediately. + # iframe_content.resize() + # + # foo: -> + # @$('#page iframe').load => + # # console.log 'iframe loaded' + # doc = @$('#page iframe')[0].contentWindow.document + # + # script = doc.createElement('script') + # script.type = 'text/javascript' + # script.src = '/assets/locomotive/aloha/lib/aloha.js' + # script.setAttribute('data-aloha-plugins', 'common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste') + # doc.body.appendChild(script) + # + # stylesheet = doc.createElement('link') + # stylesheet.style = 'text/css' + # stylesheet.href = '/assets/locomotive/aloha/css/aloha.css' + # stylesheet.media = 'screen' + # stylesheet.rel = 'stylesheet' + # doc.head.appendChild(stylesheet) + # + # # + # # {{ '/assets/locomotive/aloha/css/aloha.css' | stylesheet_tag }} + # + # # $("body", doc).append(script) + # + # # $('body', doc).append('') + # + # # + # # $('body', doc).append('

Hello world

'); + # + # + # # register_page_content: (iframe) -> + # # + # # + # # console.log 'he he' + # + # + # diff --git a/app/assets/javascripts/locomotive/views/inline_editor/toolbar_view.js.coffee b/app/assets/javascripts/locomotive/views/inline_editor/toolbar_view.js.coffee new file mode 100644 index 00000000..5a7b2f88 --- /dev/null +++ b/app/assets/javascripts/locomotive/views/inline_editor/toolbar_view.js.coffee @@ -0,0 +1,43 @@ +Locomotive.Views.InlinEditor ||= {} + +class Locomotive.Views.InlinEditor.ToolbarView extends Backbone.View + + tagName: 'div' + + className: 'toolbar-view' + + events: + 'change .edit input[type=checkbox]': 'toggle_inline_editing' + + initialize: -> + super + + render: -> + super + $(@el).html(ich.toolbar(@model.toJSON())) + + @enable_edit_checkbox() + + @ + + toggle_inline_editing: (event) -> + console.log('toggle_inline_editing !!!') + if $(event.target).is(':checked') + @editable_elements().aloha() + else + @editable_elements().removeClass('aloha-editable-highlight').mahalo() + + editable_elements: -> + @options.target[0].contentWindow.Aloha.jQuery('.editable-long-text, .editable-short-text') + + enable_edit_checkbox: -> + @$('.edit input[type=checkbox]').checkToggle + on_label_color: '#fff' + off_label_color: '#bbb' + + refresh: -> + console.log('refreshing...') + @ + + remove: -> + super \ No newline at end of file diff --git a/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee b/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee index ebb7fbc1..b56f753f 100644 --- a/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee +++ b/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee @@ -16,6 +16,8 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView @model = new Locomotive.Models.Page(@options.page) + window.foo = @model + @touched_url = false @image_picker_view = new Locomotive.Views.ThemeAssets.ImagePickerView diff --git a/app/assets/stylesheets/locomotive.css b/app/assets/stylesheets/locomotive.css index 3f715097..26071544 100644 --- a/app/assets/stylesheets/locomotive.css +++ b/app/assets/stylesheets/locomotive.css @@ -10,5 +10,5 @@ *= require codemirror/themes/default *= require locomotive/toggle.css *= require locomotive/liquid_mode.css - *= require_tree ./locomotive + *= require_tree ./locomotive/backoffice */ diff --git a/app/assets/stylesheets/locomotive/_box.css.scss b/app/assets/stylesheets/locomotive/backoffice/_box.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/_box.css.scss rename to app/assets/stylesheets/locomotive/backoffice/_box.css.scss diff --git a/app/assets/stylesheets/locomotive/_buttons.css.scss b/app/assets/stylesheets/locomotive/backoffice/_buttons.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/_buttons.css.scss rename to app/assets/stylesheets/locomotive/backoffice/_buttons.css.scss diff --git a/app/assets/stylesheets/locomotive/_helpers.css.scss b/app/assets/stylesheets/locomotive/backoffice/_helpers.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/_helpers.css.scss rename to app/assets/stylesheets/locomotive/backoffice/_helpers.css.scss diff --git a/app/assets/stylesheets/locomotive/_picker.css.scss b/app/assets/stylesheets/locomotive/backoffice/_picker.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/_picker.css.scss rename to app/assets/stylesheets/locomotive/backoffice/_picker.css.scss diff --git a/app/assets/stylesheets/locomotive/application.css.scss b/app/assets/stylesheets/locomotive/backoffice/application.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/application.css.scss rename to app/assets/stylesheets/locomotive/backoffice/application.css.scss diff --git a/app/assets/stylesheets/locomotive/codemirror_changes.css.scss b/app/assets/stylesheets/locomotive/backoffice/codemirror_changes.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/codemirror_changes.css.scss rename to app/assets/stylesheets/locomotive/backoffice/codemirror_changes.css.scss diff --git a/app/assets/stylesheets/locomotive/content_assets.css.scss b/app/assets/stylesheets/locomotive/backoffice/content_assets.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/content_assets.css.scss rename to app/assets/stylesheets/locomotive/backoffice/content_assets.css.scss diff --git a/app/assets/stylesheets/locomotive/content_locale_picker.css.scss b/app/assets/stylesheets/locomotive/backoffice/content_locale_picker.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/content_locale_picker.css.scss rename to app/assets/stylesheets/locomotive/backoffice/content_locale_picker.css.scss diff --git a/app/assets/stylesheets/locomotive/datepicker.css.scss b/app/assets/stylesheets/locomotive/backoffice/datepicker.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/datepicker.css.scss rename to app/assets/stylesheets/locomotive/backoffice/datepicker.css.scss diff --git a/app/assets/stylesheets/locomotive/dialog_changes.css.scss b/app/assets/stylesheets/locomotive/backoffice/dialog_changes.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/dialog_changes.css.scss rename to app/assets/stylesheets/locomotive/backoffice/dialog_changes.css.scss diff --git a/app/assets/stylesheets/locomotive/editable_elements.css.scss b/app/assets/stylesheets/locomotive/backoffice/editable_elements.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/editable_elements.css.scss rename to app/assets/stylesheets/locomotive/backoffice/editable_elements.css.scss diff --git a/app/assets/stylesheets/locomotive/formtastic_changes.css.scss b/app/assets/stylesheets/locomotive/backoffice/formtastic_changes.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/formtastic_changes.css.scss rename to app/assets/stylesheets/locomotive/backoffice/formtastic_changes.css.scss diff --git a/app/assets/stylesheets/locomotive/installation.css.scss b/app/assets/stylesheets/locomotive/backoffice/installation.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/installation.css.scss rename to app/assets/stylesheets/locomotive/backoffice/installation.css.scss diff --git a/app/assets/stylesheets/locomotive/layout.css.scss b/app/assets/stylesheets/locomotive/backoffice/layout.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/layout.css.scss rename to app/assets/stylesheets/locomotive/backoffice/layout.css.scss diff --git a/app/assets/stylesheets/locomotive/menu.css b/app/assets/stylesheets/locomotive/backoffice/menu.css similarity index 100% rename from app/assets/stylesheets/locomotive/menu.css rename to app/assets/stylesheets/locomotive/backoffice/menu.css diff --git a/app/assets/stylesheets/locomotive/menu/_colors.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/_colors.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/_colors.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/_colors.css.scss diff --git a/app/assets/stylesheets/locomotive/menu/_helpers.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/_helpers.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/_helpers.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/_helpers.css.scss diff --git a/app/assets/stylesheets/locomotive/menu/_icons.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/_icons.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/_icons.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/_icons.css.scss diff --git a/app/assets/stylesheets/locomotive/menu/default.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/default.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/default.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/default.css.scss diff --git a/app/assets/stylesheets/locomotive/menu/main.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/main.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/main.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/main.css.scss diff --git a/app/assets/stylesheets/locomotive/menu/sub.css.scss b/app/assets/stylesheets/locomotive/backoffice/menu/sub.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/menu/sub.css.scss rename to app/assets/stylesheets/locomotive/backoffice/menu/sub.css.scss diff --git a/app/assets/stylesheets/locomotive/not_logged_in.css b/app/assets/stylesheets/locomotive/backoffice/not_logged_in.css similarity index 100% rename from app/assets/stylesheets/locomotive/not_logged_in.css rename to app/assets/stylesheets/locomotive/backoffice/not_logged_in.css diff --git a/app/assets/stylesheets/locomotive/simple.css.scss b/app/assets/stylesheets/locomotive/backoffice/simple.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/simple.css.scss rename to app/assets/stylesheets/locomotive/backoffice/simple.css.scss diff --git a/app/assets/stylesheets/locomotive/sites_picker.css.scss b/app/assets/stylesheets/locomotive/backoffice/sites_picker.css.scss similarity index 100% rename from app/assets/stylesheets/locomotive/sites_picker.css.scss rename to app/assets/stylesheets/locomotive/backoffice/sites_picker.css.scss diff --git a/app/assets/stylesheets/locomotive/inline_editor.css b/app/assets/stylesheets/locomotive/inline_editor.css new file mode 100644 index 00000000..40a51811 --- /dev/null +++ b/app/assets/stylesheets/locomotive/inline_editor.css @@ -0,0 +1,8 @@ +/* + * This is a manifest file that'll automatically include all the stylesheets available in this directory + * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at + * the top of the compiled file, but it's generally better to create a new file per style scope. + *= require locomotive/blueprint/screen.css + *= require locomotive/toggle.css + *= require_tree ./inline_editor +*/ \ No newline at end of file diff --git a/app/assets/stylesheets/locomotive/inline_editor/layout.css.scss b/app/assets/stylesheets/locomotive/inline_editor/layout.css.scss new file mode 100644 index 00000000..dc4d3ed4 --- /dev/null +++ b/app/assets/stylesheets/locomotive/inline_editor/layout.css.scss @@ -0,0 +1,16 @@ +body { + position: relative; + background: transparent; + // overflow: hidden; +} + +#page { + position: relative; + padding-top: 50px; + + iframe { + width: 100%; + height: 100%; + display: block; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/locomotive/inline_editor/toolbar.css.scss b/app/assets/stylesheets/locomotive/inline_editor/toolbar.css.scss new file mode 100644 index 00000000..7ee9c83f --- /dev/null +++ b/app/assets/stylesheets/locomotive/inline_editor/toolbar.css.scss @@ -0,0 +1,67 @@ +@import "compass/css3/images"; +@import "compass/css3/opacity"; +@import "compass/css3/box-shadow"; +@import "compass/css3/text-shadow"; + +#toolbar { + position: fixed; + top: 0px; + left: 0px; + + height: 50px; + width: 100%; + + .background { + z-index: 100; + position: absolute; + top: 0px; + left: 0px; + + height: 100%; + width: 100%; + + @include background-image(linear-gradient(#303138, #23242B)); + @include box-shadow(rgba(0, 0, 0, 0.6) 0px -1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 4px 6px 4px, rgba(255, 255, 255, 0.4) 0 1px 0 0 inset); + @include opacity(0.95); + } + + .inner { + position: relative; + height: 100%; + z-index: 200; + color: #fff; + + h1 { + float: left; + margin: 0 0 0 10px; + + position: relative; + top: -2px; + + width: 200px; + + line-height: 50px; + font-size: 18px; + font-weight: bold; + color: #fff; + @include single-text-shadow(#000, 0px, 1px, 0px); + } + + .edit { + float: right; + margin-right: 10px; + line-height: 50px; + + .toggleSwitch { + position: relative; + top: 0px; + margin-left: 3px; + display: inline-block; + + div.switchArea { + @include box-shadow(rgba(0, 0, 0, 0.8) 0px 1px 0px 0px); + } + } + } + } +} \ No newline at end of file diff --git a/app/controllers/locomotive/public/rendering_controller.rb b/app/controllers/locomotive/public/pages_controller.rb similarity index 53% rename from app/controllers/locomotive/public/rendering_controller.rb rename to app/controllers/locomotive/public/pages_controller.rb index 705355ff..f45d7bb2 100644 --- a/app/controllers/locomotive/public/rendering_controller.rb +++ b/app/controllers/locomotive/public/pages_controller.rb @@ -1,6 +1,6 @@ module Locomotive module Public - class RenderingController < ApplicationController + class PagesController < ApplicationController include Locomotive::Routing::SiteDispatcher @@ -8,7 +8,7 @@ module Locomotive before_filter :require_site - before_filter :authenticate_admin!, :only => [:edit] + before_filter :authenticate_locomotive_account!, :only => [:edit] before_filter :validate_site_membership, :only => [:edit] @@ -17,8 +17,12 @@ module Locomotive end def edit - @editing = true - render_locomotive_page + if params[:noiframe] + @editing = true + render_locomotive_page + else + render :layout => false + end end end diff --git a/app/middlewares/locomotive/inline_editor_middleware.rb b/app/middlewares/locomotive/inline_editor_middleware.rb new file mode 100644 index 00000000..8c7034cc --- /dev/null +++ b/app/middlewares/locomotive/inline_editor_middleware.rb @@ -0,0 +1,34 @@ +module Locomotive + class InlineEditorMiddleware + + def initialize(app, opts = {}) + @app = app + end + + def call(env) + response = @app.call(env) + + # if env['warden'].authenticated?(:locomotive_account) && + # !env['PATH_INFO'].starts_with?("/assets") && + # !env['PATH_INFO'].starts_with?("/#{Locomotive.mounted_on}/") && + # !env['PATH_INFO'].ends_with?("/edit") + + Rails.logger.debug "headers = #{response[1].inspect}" + + unless response[1]['Editable'].blank? + Rails.logger.debug "==> #{ENV['PATH_INFO'].inspect}, warden ? #{env['warden'].inspect} /#{env['warden'].user} / #{env['warden'].authenticated?(:locomotive_account)}" + + html = response.last.body.to_s.gsub '', %( + Edit + + ) + + [response[0], response[1], [html]] + else + response + end + end + + end + +end diff --git a/app/presenters/locomotive/page_presenter.rb b/app/presenters/locomotive/page_presenter.rb index 1fe9c363..339dc2de 100644 --- a/app/presenters/locomotive/page_presenter.rb +++ b/app/presenters/locomotive/page_presenter.rb @@ -1,7 +1,7 @@ module Locomotive class PagePresenter < BasePresenter - delegate :title, :slug, :fullpath, :raw_template, :published, :template_changed, :cache_strategy, :to => :source + delegate :title, :slug, :fullpath, :raw_template, :published, :listed, :templatized, :redirect, :redirect_url, :template_changed, :cache_strategy, :to => :source def escaped_raw_template h(self.source.raw_template) @@ -12,7 +12,7 @@ module Locomotive end def included_methods - super + %w(title slug fullpath raw_template published published cache_strategy template_changed editable_elements) + super + %w(title slug fullpath raw_template published listed templatized redirect redirect_url cache_strategy template_changed editable_elements) end def as_json_for_html_view diff --git a/app/views/locomotive/public/pages/edit.html.haml b/app/views/locomotive/public/pages/edit.html.haml new file mode 100644 index 00000000..d620a938 --- /dev/null +++ b/app/views/locomotive/public/pages/edit.html.haml @@ -0,0 +1,50 @@ +!!! XML +!!! +%html{ :xmlns => 'http://www.w3.org/1999/xhtml' } + %head + %title Locomotive + + = csrf_meta_tag + + - key = Rails.application.config.session_options[:key] + + %meta{ :name => 'key-param', :content => Rails.application.config.session_options[:key] } + %meta{ :name => 'key-token', :content => cookies[key] } + + = stylesheet_link_tag 'locomotive/inline_editor', :media => 'screen' + = javascript_include_tag 'locomotive/inline_editor' + + %script{ :type => 'text/javascript' } + :plain + window.locale = '#{I18n.locale}'; + + Locomotive.mounted_on = '#{Locomotive.mounted_on}'; + Locomotive.current_site = new Locomotive.Models.Site(#{current_site.to_json}); + Locomotive.current_account = new Locomotive.Models.Account(#{current_locomotive_account.to_json}); + + $(document).ready(function() { + + window.application_view = new Locomotive.Views.InlinEditor.ApplicationView({ + flash: #{flash.to_json} + }); + window.application_view.render(); + + }); + + %script{ :type => 'text/html', :id => 'toolbar' } + + %h1 {{title}} + + .edit + %label Editing mode: + = check_box_tag 'edit', '1', false + + %body + #page + %iframe{ :src => %(#{request.fullpath}?noiframe=true') , :scrolling => 'no', :frameborder => '0' } + + #toolbar + .background + .inner + + diff --git a/config/routes.rb b/config/routes.rb index 976cc3b9..2c485634 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -65,7 +65,10 @@ Rails.application.routes.draw do resources :locomotive_entry_submissions, :controller => 'locomotive/public/content_entries', :path => 'entry_submissions/:slug' # magic urls - match '/' => 'locomotive/public/rendering#show' - match '*path/edit' => 'locomotive/public/rendering#edit' - match '*path' => 'locomotive/public/rendering#show' + # match '/editable' => 'locomotive/public/rendering#edit', :path => '/' + match '/' => 'locomotive/public/pages#show' + match '/edit' => 'locomotive/public/pages#edit' + match '*path/edit' => 'locomotive/public/pages#edit' + # match '_/*path' => 'locomotive/public/rendering#show' + match '*path' => 'locomotive/public/pages#show' end \ No newline at end of file diff --git a/lib/locomotive/liquid/tags/inline_editor.rb b/lib/locomotive/liquid/tags/inline_editor.rb index 68d121f6..927b0b12 100644 --- a/lib/locomotive/liquid/tags/inline_editor.rb +++ b/lib/locomotive/liquid/tags/inline_editor.rb @@ -4,45 +4,55 @@ module Liquid class InlineEditor < ::Liquid::Tag def render(context) - if context.registers[:current_locomotive_account] - output = %{ - - - - } - - if context.registers[:inline_editor] - controller = context.registers[:controller] - - output << %{ - - - - - - - - - - } - - if controller.send(:protect_against_forgery?) - output << %(\n).html_safe - end - else - output << %{ - - - } - end - - output << %{ - - - - + if context.registers[:current_locomotive_account] && context.registers[:inline_editor] + %{ + } + else + '' end + + # if context.registers[:current_locomotive_account] + # output = %{ + # + # + # + # } + # + # if context.registers[:inline_editor] + # controller = context.registers[:controller] + # + # output << %{ + # + # + # + # + # + # + # + # + # + # } + # + # if controller.send(:protect_against_forgery?) + # output << %(\n).html_safe + # end + # else + # output << %{ + # + # + # } + # end + # + # output << %{ + # + # + # + # + # } + # end end end diff --git a/lib/locomotive/render.rb b/lib/locomotive/render.rb index 0967a94a..557fd6bd 100644 --- a/lib/locomotive/render.rb +++ b/lib/locomotive/render.rb @@ -33,7 +33,7 @@ module Locomotive path.gsub!(/\.[a-zA-Z][a-zA-Z0-9]{2,}$/, '') # remove the page extension path.gsub!(/^\//, '') # remove the leading slash - path = 'index' if path.blank? + path = 'index' if path.blank? || path == 'edit' if path != 'index' dirname = File.dirname(path).gsub(/^\.$/, '') # also look for templatized page path @@ -73,8 +73,6 @@ module Locomotive assigns.merge!(Locomotive.config.context_assign_extensions) - Rails.logger.debug flash.to_hash.stringify_keys.inspect - assigns.merge!(flash.to_hash.stringify_keys) # data from public submissions if @page.templatized? # add instance from content type @@ -96,7 +94,8 @@ module Locomotive def prepare_and_set_response(output) flash.discard - response.headers['Content-Type'] = 'text/html; charset=utf-8' + response.headers['Content-Type'] = 'text/html; charset=utf-8' + response.headers['Editable'] = 'true' unless self.editing_page? if @page.with_cache? fresh_when :etag => @page, :last_modified => @page.updated_at.utc, :public => true diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index a6a2df39..433c536b 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -43,6 +43,8 @@ module Dummy # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' + + config.middleware.use 'Locomotive::InlineEditorMiddleware' end end diff --git a/vendor/assets/javascripts/locomotive/aloha/css/aloha-core.css b/vendor/assets/javascripts/locomotive/aloha/css/aloha-core.css new file mode 100644 index 00000000..7085cd8e --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/css/aloha-core.css @@ -0,0 +1,44 @@ +.aloha-editable { + min-height: 1.2em; + outline: none; +} +.aloha-editable ::selection, +.aloha-editable ::-moz-selection { + background: #80B5F2; + color: white; +} +.aloha-editable-zerowidthfix { + padding: 0px 5px 0px 5px !important; +} + + + +.aloha-logo { + width:37px !important; + height:25px !important; + background-image: url('../img/gentics-logo.png') !important; +} +.aloha-maximize { + background-image: url('../img/gentics-logo.png') !important; +} +.aloha-fade-out { + background-image: url('../img/fade-out.png') !important; + width:20px !important; + height:20px !important; +} +.aloha-fade-in { + background-image: url('../img/fade-in.png') !important; + width:20px !important; + height:20px !important; +} +.aloha-maximize { + width:20px !important; + height:20px !important; + background-image: url('../img/maximize.png') !important; +} +.aloha-textarea { + overflow: hidden; + border:1px solid #ccc; + padding:6px; + overflow:auto; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/css/aloha-sidebar.css b/vendor/assets/javascripts/locomotive/aloha/css/aloha-sidebar.css new file mode 100644 index 00000000..fce32af7 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/css/aloha-sidebar.css @@ -0,0 +1,284 @@ +.aloha-sidebar-bar { + z-index: 999999999; + position: fixed; + top: 0; + left: 0; + text-align: left; + font-family: Arial, sans-serif; + font-size: 12px; + border-right: 1px solid #888; + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + +} +.aloha-sidebar-bar.aloha-sidebar-right { + left: auto; + right: 0; + border-right-width: 0; + border-left: 1px solid #888; +} +.aloha-sidebar-inner { + position: relative; + background-color: #ccc; + background-image: -webkit-radial-gradient( + rgba(0, 0, 0, 0.0) 20%, + rgba(0, 0, 0, 0.2) 80%, + rgba(0, 0, 0, 0.3) 100% + ); + background-image: -moz-radial-gradient( + rgba(0, 0, 0, 0.0) 20%, + rgba(0, 0, 0, 0.2) 80%, + rgba(0, 0, 0, 0.3) 100% + ); +} +.aloha-sidebar-panels { + margin: 0; + padding: 15px 0; +} +.aloha-sidebar-panels li { + overflow: hidden; + margin: 0; + padding: 0 15px; +} +.aloha-sidebar-panel-top { + -webkit-border-top-left-radius: 5px; + -webkit-border-top-right-radius: 5px; + -moz-border-radius-topleft: 5px; + -moz-border-radius-topright: 5px; +} +.aloha-sidebar-panel-content.aloha-sidebar-panel-bottom { + padding-bottom: 0; + -webkit-border-bottom-left-radius: 5px; + -webkit-border-bottom-right-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -moz-border-radius-bottomright: 5px; + border-bottom-width: 1px; +} +.aloha-sidebar-panel-title { + position: relative; + overflow: hidden; + padding: 8px 0 0 8px; + border: 1px solid rgba(0, 0, 0, 0.3); + border-bottom-width: 0; + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + color: #ccc; + cursor: pointer; + font-size: 13px; + font-weight: bold; + line-height: 1.5em; + text-shadow: 0 0 6px #23262b; +} +.aloha-sidebar-panel-title:hover { + color: #fff; +} +.aloha-sidebar-panel-title-arrow { + position: absolute; + top: 8px; + left: 8px; + width: 16px; + height: 16px; + background: url(../img/arrow.png) no-repeat center center; + opacity: 0.3; + +} +.aloha-sidebar-panel-title:hover .aloha-sidebar-panel-title-arrow { + opacity: 0.9; + +} +.aloha-sidebar-panel-title .aloha-sidebar-panel-title-arrow.aloha-sidebar-panel-title-arrow-down { + background-image: url(../img/arrow-down.png); +} +.aloha-sidebar-panel-title-text { + margin-left: 24px; + white-space: nowrap; +} +.aloha-sidebar-panel-content { + overflow: hidden; + height: 5px; + background: #303539; +} +.aloha-sidebar-panel-content-inner { + margin: 5px 0 0; + padding: 0; + color: #888; + background: #fff; + background-image: -webkit-radial-gradient( + rgba(0, 0, 0, 0.0) 50%, + rgba(0, 0, 0, 0.1) 90%, + rgba(0, 0, 0, 0.2) 100% + ); + background-image: -moz-radial-gradient( + rgba(0, 0, 0, 0.0) 50%, + rgba(0, 0, 0, 0.1) 90%, + rgba(0, 0, 0, 0.2) 100% + ); +} +.aloha-sidebar-panel-content input { + margin: 5px; + padding: 5px; +} +.aloha-sidebar-handle { + position: absolute; + top: 30px; + right: -30px; + width: 40px; + height: 30px; + overflow: hidden; + + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + + cursor: pointer; + + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + -moz-border-radius-topright: 5px; + -moz-border-radius-bottomright: 5px; + -webkit-border-top-right-radius: 5px; + -webkit-border-bottom-right-radius: 5px; +} +.aloha-sidebar-right .aloha-sidebar-handle { + left: -30px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + -moz-border-radius-topright: 0px; + -moz-border-radius-bottomright: 0px; + -webkit-border-top-right-radius: 0px; + -webkit-border-bottom-right-radius: 0px; + + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + -moz-border-radius-topleft: 5px; + -moz-border-radius-bottomleft: 5px; + -webkit-border-top-left-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} +.aloha-sidebar-handle-icon { + display: block; + position: absolute; + top: 5px; + right: 5px; + background: url(../img/arrow.png) no-repeat center center; + width: 20px; + height: 20px; + opacity: 0.5; + +} +.aloha-sidebar-right .aloha-sidebar-handle-icon { + left: 5px; + right: auto; +} +.aloha-sidebar-handle-icon.aloha-sidebar-handle-icon-left { + background-image: url(../img/arrow-left.png); +} +.aloha-sidebar-panel-parent-path { + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + color: #fff; + cursor: pointer; + font-size: 12px; + text-shadow: 0 0 6px #23262b; + white-space: nowrap; + line-height: 1em; +} +.aloha-sidebar-panel-parent-path:hover { + opacity: 0.9; + +} +.aloha-sidebar-panel-parent-path span { + display: inline-block; + padding: 0 10px 0 5px; + background: url(../img/breadcrumb-divider.png) no-repeat right center; + opacity: 0.25; + + line-height: 1.6em; +} +.aloha-sidebar-panel-parent-path span:first-child { + font-weight: bold; + opacity: 0.8; + +} +.aloha-sidebar-panel-parent-path span:last-child { + background: none; +} +.aloha-sidebar-panel-parent-content { + padding: 4px; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.0, rgba(0, 0, 0, 0.25)), + color-stop(0.05, rgba(0, 0, 0, 0.0)) + ); + background-image: -moz-linear-gradient( + center top, + rgba(0, 0, 0, 0.25) 0%, + rgba(0, 0, 0, 0.0) 5% + ); +} diff --git a/vendor/assets/javascripts/locomotive/aloha/css/aloha.css b/vendor/assets/javascripts/locomotive/aloha/css/aloha.css new file mode 100644 index 00000000..377172ee --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/css/aloha.css @@ -0,0 +1,7774 @@ +.aloha-floatingmenu table, .aloha-floatingmenu tr, .aloha-floatingmenu td, +.ext-root table, .ext-root tr, .ext-root td, +table.x-layer, .x-layer tr, .x-layer td, +table.x-window, .x-window tr, .x-window td, +table.x-toolbar-ct, .x-toolbar-ct tr, .x-toolbar-ct td, +table.x-toolbar-left, .x-toolbar-left tr, .x-toolbar-left td, +table.x-table-layout, .x-table-layout tr, .x-table-layout td, +table.x-toolbar-ct table, .x-toolbar-cell td, .x-table-layout-cell td { + width: 0 !important; + height: 0 !important; + border: 0 !important; + padding: 0 !important; + margin: 0 !important; + background-color: transparent !important; +} +div.aloha-floatingmenu, div.aloha-shadow { + min-width: 0px; +} +.ext-root tr:nth-child(2n), .ext-root tr:nth-child(3n), .ext-root tr:nth-child(4n), .ext-root tr:nth-child(5n) { + width: 0 !important; + height: 0 !important; + border: 0 !important; + padding: 0 !important; + margin: 0 !important; + background-color: transparent !important; +} +.ext-root ol, .ext-root ul, .x-menu ul, .x-menu ol { + list-style:none; + margin:0; + padding:0; +} +.aloha-floatingmenu { + +} +.aloha-floatingmenu html, +.aloha-floatingmenu body, +.aloha-floatingmenu div, +.aloha-floatingmenu dl, +.aloha-floatingmenu dt, +.aloha-floatingmenu dd, +.aloha-floatingmenu ul, +.aloha-floatingmenu ol, +.aloha-floatingmenu li, +.aloha-floatingmenu h1, +.aloha-floatingmenu h2, +.aloha-floatingmenu h3, +.aloha-floatingmenu h4, +.aloha-floatingmenu h5, +.aloha-floatingmenu h6, +.aloha-floatingmenu pre, +.aloha-floatingmenu form, +.aloha-floatingmenu fieldset, +.aloha-floatingmenu input, +.aloha-floatingmenu p, +.aloha-floatingmenu blockquote, +.aloha-floatingmenu th, +.aloha-floatingmenu td { + margin: 0; + padding: 0; +} +.aloha-floatingmenu img, .aloha-floatingmenu body, .aloha-floatingmenu html { + border: 0; +} +.aloha-floatingmenu address, +.aloha-floatingmenu caption, +.aloha-floatingmenu cite, +.aloha-floatingmenu code, +.aloha-floatingmenu dfn, +.aloha-floatingmenu em, +.aloha-floatingmenu strong, +.aloha-floatingmenu th, +.aloha-floatingmenu var { + font-style: normal; + font-weight: normal; +} +.aloha-floatingmenu ol, .aloha-floatingmenu ul { + list-style: none; +} +.aloha-floatingmenu caption, .aloha-floatingmenu th { + text-align: left; +} +.aloha-floatingmenu h1, +.aloha-floatingmenu h2, +.aloha-floatingmenu h3, +.aloha-floatingmenu h4, +.aloha-floatingmenu h5, +.aloha-floatingmenu h6 { + font-size: 100%; +} +.aloha-floatingmenu q:before, .aloha-floatingmenu q:after { + content: ''; +} +.ext-el-mask { + z-index: 100; + position: absolute; + top: 0; + left: 0; + -moz-opacity: 0.5; + opacity: .50; + filter: alpha(opacity=50); + width: 100%; + height: 100%; + zoom: 1; +} +.ext-el-mask-msg { + z-index: 20001; + position: absolute; + top: 0; + left: 0; + border: 1px solid; + background: repeat-x 0 -16px; + padding: 2px; +} +.ext-el-mask-msg div { + padding: 5px 10px 5px 10px; + border: 1px solid; + cursor: wait; +} +.ext-shim { + position: absolute; + visibility: hidden; + left: 0; + top: 0; + overflow: hidden; +} +.ext-ie .ext-shim { + filter: alpha(opacity=0); +} +.ext-ie6 .ext-shim { + margin-left: 5px; + margin-top: 3px; +} +.x-mask-loading div { + padding: 5px 10px 5px 25px; + background: no-repeat 5px 5px; + line-height: 16px; +} +.x-hidden, .x-hide-offsets { + position: absolute !important; + left: -10000px; + top: -10000px; + visibility: hidden; +} +.x-hide-display { + display: none !important; +} +.x-hide-visibility { + visibility: hidden !important; +} +.x-masked { + overflow: hidden !important; +} +.x-masked-relative { + position: relative !important; +} +.x-masked select, .x-masked object, .x-masked embed { + visibility: hidden; +} +.x-layer { + visibility: hidden; +} +.x-unselectable, .x-unselectable * { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-repaint { + zoom: 1; + background-color: transparent; + -moz-outline: none; + outline: none; +} +.x-item-disabled { + cursor: default; + opacity: .6; + -moz-opacity: .6; + filter: alpha(opacity=60); +} +.x-item-disabled * { + cursor: default !important; +} +.x-form-radio-group .x-item-disabled { + filter: none; +} +.x-splitbar-proxy { + position: absolute; + visibility: hidden; + z-index: 20001; + zoom: 1; + line-height: 1px; + font-size: 1px; + overflow: hidden; +} +.x-splitbar-h, .x-splitbar-proxy-h { + cursor: e-resize; + cursor: col-resize; +} +.x-splitbar-v, .x-splitbar-proxy-v { + cursor: s-resize; + cursor: row-resize; +} +.x-color-palette { + width: 150px; + height: 92px; + cursor: pointer; +} +.x-color-palette a { + border: 1px solid; + float: left; + padding: 2px; + text-decoration: none; + -moz-outline: 0 none; + outline: 0 none; + cursor: pointer; +} +.x-color-palette a:hover, .x-color-palette a.x-color-palette-sel { + border: 1px solid; +} +.x-color-palette em { + display: block; + border: 1px solid; +} +.x-color-palette em span { + cursor: pointer; + display: block; + height: 10px; + line-height: 10px; + width: 10px; +} +.x-ie-shadow { + display: none; + position: absolute; + overflow: hidden; + left: 0; + top: 0; + zoom: 1; +} +.x-shadow { + display: none; + position: absolute; + overflow: hidden; + left: 0; + top: 0; +} +.x-shadow * { + overflow: hidden; +} +.x-shadow * { + padding: 0; + border: 0; + margin: 0; + clear: none; + zoom: 1; +} +.x-shadow .xstc, .x-shadow .xsbc { + height: 6px; + float: left; +} +.x-shadow .xstl, +.x-shadow .xstr, +.x-shadow .xsbl, +.x-shadow .xsbr { + width: 6px; + height: 6px; + float: left; +} +.x-shadow .xsc { + width: 100%; +} +.x-shadow .xsml, .x-shadow .xsmr { + width: 6px; + float: left; + height: 100%; +} +.x-shadow .xsmc { + float: left; + height: 100%; + background: transparent; +} +.x-shadow .xst, .x-shadow .xsb { + height: 6px; + overflow: hidden; + width: 100%; +} +.x-shadow .xsml { + background: transparent repeat-y 0 0; +} +.x-shadow .xsmr { + background: transparent repeat-y -6px 0; +} +.x-shadow .xstl { + background: transparent no-repeat 0 0; +} +.x-shadow .xstc { + background: transparent repeat-x 0 -30px; +} +.x-shadow .xstr { + background: transparent repeat-x 0 -18px; +} +.x-shadow .xsbl { + background: transparent no-repeat 0 -12px; +} +.x-shadow .xsbc { + background: transparent repeat-x 0 -36px; +} +.x-shadow .xsbr { + background: transparent repeat-x 0 -6px; +} +.loading-indicator { + background: no-repeat left; + padding-left: 20px; + line-height: 16px; + margin: 3px; +} +.x-text-resize { + position: absolute; + left: -1000px; + top: -1000px; + visibility: hidden; + zoom: 1; +} +.x-drag-overlay { + width: 100%; + height: 100%; + display: none; + position: absolute; + left: 0; + top: 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/s.gif); + z-index: 20000; +} +.x-clear { + clear: both; + height: 0; + overflow: hidden; + line-height: 0; + font-size: 0; +} +.x-spotlight { + z-index: 8999; + position: absolute; + top: 0; + left: 0; + -moz-opacity: 0.5; + opacity: .50; + filter: alpha(opacity=50); + width: 0; + height: 0; + zoom: 1; +} +#x-history-frame { + position: absolute; + top: -1px; + left: 0; + width: 1px; + height: 1px; + visibility: hidden; +} +#x-history-field { + position: absolute; + top: 0; + left: -1px; + width: 1px; + height: 1px; + visibility: hidden; +} +.x-resizable-handle { + position: absolute; + z-index: 100; + + font-size: 1px; + line-height: 6px; + overflow: hidden; + filter: alpha(opacity=0); + opacity: 0; + zoom: 1; +} +.x-resizable-handle-east { + width: 6px; + cursor: e-resize; + right: 0; + top: 0; + height: 100%; +} +.ext-ie .x-resizable-handle-east { + margin-right: -1px; + +} +.x-resizable-handle-south { + width: 100%; + cursor: s-resize; + left: 0; + bottom: 0; + height: 6px; +} +.ext-ie .x-resizable-handle-south { + margin-bottom: -1px; + +} +.x-resizable-handle-west { + width: 6px; + cursor: w-resize; + left: 0; + top: 0; + height: 100%; +} +.x-resizable-handle-north { + width: 100%; + cursor: n-resize; + left: 0; + top: 0; + height: 6px; +} +.x-resizable-handle-southeast { + width: 6px; + cursor: se-resize; + right: 0; + bottom: 0; + height: 6px; + z-index: 101; +} +.x-resizable-handle-northwest { + width: 6px; + cursor: nw-resize; + left: 0; + top: 0; + height: 6px; + z-index: 101; +} +.x-resizable-handle-northeast { + width: 6px; + cursor: ne-resize; + right: 0; + top: 0; + height: 6px; + z-index: 101; +} +.x-resizable-handle-southwest { + width: 6px; + cursor: sw-resize; + left: 0; + bottom: 0; + height: 6px; + z-index: 101; +} +.x-resizable-over .x-resizable-handle, .x-resizable-pinned .x-resizable-handle { + filter: alpha(opacity=100); + opacity: 1; +} +.x-resizable-over .x-resizable-handle-east, +.x-resizable-pinned .x-resizable-handle-east, +.x-resizable-over .x-resizable-handle-west, +.x-resizable-pinned .x-resizable-handle-west { + background-position: left; +} +.x-resizable-over .x-resizable-handle-south, +.x-resizable-pinned .x-resizable-handle-south, +.x-resizable-over .x-resizable-handle-north, +.x-resizable-pinned .x-resizable-handle-north { + background-position: top; +} +.x-resizable-over .x-resizable-handle-southeast, .x-resizable-pinned .x-resizable-handle-southeast { + background-position: top left; +} +.x-resizable-over .x-resizable-handle-northwest, .x-resizable-pinned .x-resizable-handle-northwest { + background-position: bottom right; +} +.x-resizable-over .x-resizable-handle-northeast, .x-resizable-pinned .x-resizable-handle-northeast { + background-position: bottom left; +} +.x-resizable-over .x-resizable-handle-southwest, .x-resizable-pinned .x-resizable-handle-southwest { + background-position: top right; +} +.x-resizable-proxy { + border: 1px dashed; + position: absolute; + overflow: hidden; + display: none; + left: 0; + top: 0; + z-index: 50000; +} +.x-resizable-overlay { + width: 100%; + height: 100%; + display: none; + position: absolute; + left: 0; + top: 0; + z-index: 200000; + -moz-opacity: 0; + opacity: 0; + filter: alpha(opacity=0); +} +.x-tab-panel { + overflow: hidden; +} +.x-tab-panel-header, .x-tab-panel-footer { + border: 1px solid; + overflow: hidden; + zoom: 1; +} +.x-tab-panel-header { + border: 1px solid; + padding-bottom: 2px; +} +.x-tab-panel-footer { + border: 1px solid; + padding-top: 2px; +} +.x-tab-strip-wrap { + width: 100%; + overflow: hidden; + position: relative; + zoom: 1; +} +ul.x-tab-strip { + display: block; + width: 5000px; + zoom: 1; +} +ul.x-tab-strip-top { + padding-top: 1px; + background: repeat-x bottom; + border-bottom: 1px solid; +} +ul.x-tab-strip-bottom { + padding-bottom: 1px; + background: repeat-x top; + border-top: 1px solid; + border-bottom: 0 none; +} +.x-tab-panel-header-plain .x-tab-strip-top { + background: transparent !important; + padding-top: 0 !important; +} +.x-tab-panel-header-plain { + background: transparent !important; + border-width: 0 !important; + padding-bottom: 0 !important; +} +.x-tab-panel-header-plain .x-tab-strip-spacer, .x-tab-panel-footer-plain .x-tab-strip-spacer { + border: 1px solid; + height: 2px; + font-size: 1px; + line-height: 1px; +} +.x-tab-panel-header-plain .x-tab-strip-spacer { + border-top: 0 none; +} +.x-tab-panel-footer-plain .x-tab-strip-spacer { + border-bottom: 0 none; +} +.x-tab-panel-footer-plain .x-tab-strip-bottom { + background: transparent !important; + padding-bottom: 0 !important; +} +.x-tab-panel-footer-plain { + background: transparent !important; + border-width: 0 !important; + padding-top: 0 !important; +} +.ext-border-box .x-tab-panel-header-plain .x-tab-strip-spacer, .ext-border-box .x-tab-panel-footer-plain .x-tab-strip-spacer { + height: 3px; +} +ul.x-tab-strip li { + float: left; + margin-left: 2px; +} +ul.x-tab-strip li.x-tab-edge { + float: left; + margin: 0 !important; + padding: 0 !important; + border: 0 none !important; + font-size: 1px !important; + line-height: 1px !important; + overflow: hidden; + zoom: 1; + background: transparent !important; + width: 1px; +} +.x-tab-strip a, .x-tab-strip span, .x-tab-strip em { + display: block; +} +.x-tab-strip a { + text-decoration: none !important; + -moz-outline: none; + outline: none; + cursor: pointer; +} +.x-tab-strip-inner { + overflow: hidden; + text-overflow: ellipsis; +} +.x-tab-strip span.x-tab-strip-text { + white-space: nowrap; + cursor: pointer; + padding: 4px 0; +} +.x-tab-strip-top .x-tab-with-icon .x-tab-right { + padding-left: 6px; +} +.x-tab-strip .x-tab-with-icon span.x-tab-strip-text { + padding-left: 20px; + background-position: 0 3px; + background-repeat: no-repeat; +} +.x-tab-strip-active, .x-tab-strip-active a.x-tab-right { + cursor: default; +} +.x-tab-strip-active span.x-tab-strip-text { + cursor: default; +} +.x-tab-strip-disabled .x-tabs-text { + cursor: default; +} +.x-tab-panel-body { + overflow: hidden; +} +.x-tab-panel-bwrap { + overflow: hidden; +} +.ext-ie .x-tab-strip .x-tab-right { + position: relative; +} +.x-tab-strip-top .x-tab-strip-active .x-tab-right { + margin-bottom: -1px; +} +.ext-ie8 ul.x-tab-strip li { + position: relative; +} +.ext-ie8 .x-tab-strip .x-tab-right { + margin-bottom: 0 !important; + top: 1px; +} +.ext-ie8 ul.x-tab-strip-top { + padding-top: 0; +} +.ext-ie8 .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { + top: 4px; +} +.ext-ie8 .x-tab-strip-bottom .x-tab-right { + top: 0; +} +.x-tab-strip-top .x-tab-strip-active .x-tab-right span.x-tab-strip-text { + padding-bottom: 5px; +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-right { + margin-top: -1px; +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-right span.x-tab-strip-text { + padding-top: 5px; +} +.x-tab-strip-top .x-tab-right { + background: transparent no-repeat 0 -51px; + padding-left: 10px; +} +.x-tab-strip-top .x-tab-left { + background: transparent no-repeat right -351px; + padding-right: 10px; +} +.x-tab-strip-top .x-tab-strip-inner { + background: transparent repeat-x 0 -201px; +} +.x-tab-strip-top .x-tab-strip-over .x-tab-right { + background-position: 0 -101px; +} +.x-tab-strip-top .x-tab-strip-over .x-tab-left { + background-position: right -401px; +} +.x-tab-strip-top .x-tab-strip-over .x-tab-strip-inner { + background-position: 0 -251px; +} +.x-tab-strip-top .x-tab-strip-active .x-tab-right { + background-position: 0 0; +} +.x-tab-strip-top .x-tab-strip-active .x-tab-left { + background-position: right -301px; +} +.x-tab-strip-top .x-tab-strip-active .x-tab-strip-inner { + background-position: 0 -151px; +} +.x-tab-strip-bottom .x-tab-right { + background: no-repeat bottom right; +} +.x-tab-strip-bottom .x-tab-left { + background: no-repeat bottom left; +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-right { + background: no-repeat bottom right; +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-left { + background: no-repeat bottom left; +} +.x-tab-strip-bottom .x-tab-left { + margin-right: 3px; + padding: 0 10px; +} +.x-tab-strip-bottom .x-tab-right { + padding: 0; +} +.x-tab-strip .x-tab-strip-close { + display: none; +} +.x-tab-strip-closable { + position: relative; +} +.x-tab-strip-closable .x-tab-left { + padding-right: 19px; +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { + opacity: .6; + -moz-opacity: .6; + background-repeat: no-repeat; + display: block; + width: 11px; + height: 11px; + position: absolute; + top: 3px; + right: 3px; + cursor: pointer; + z-index: 2; +} +.x-tab-strip .x-tab-strip-active a.x-tab-strip-close { + opacity: .8; + -moz-opacity: .8; +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close:hover { + opacity: 1; + -moz-opacity: 1; +} +.x-tab-panel-body { + border: 1px solid; +} +.x-tab-panel-body-top { + border-top: 0 none; +} +.x-tab-panel-body-bottom { + border-bottom: 0 none; +} +.x-tab-scroller-left { + background: transparent no-repeat -18px 0; + border-bottom: 1px solid; + width: 18px; + position: absolute; + left: 0; + top: 0; + z-index: 10; + cursor: pointer; +} +.x-tab-scroller-left-over { + background-position: 0 0; +} +.x-tab-scroller-left-disabled { + background-position: -18px 0; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); + cursor: default; +} +.x-tab-scroller-right { + background: transparent no-repeat 0 0; + border-bottom: 1px solid; + width: 18px; + position: absolute; + right: 0; + top: 0; + z-index: 10; + cursor: pointer; +} +.x-tab-scroller-right-over { + background-position: -18px 0; +} +.x-tab-scroller-right-disabled { + background-position: 0 0; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); + cursor: default; +} +.x-tab-scrolling-bottom .x-tab-scroller-left, .x-tab-scrolling-bottom .x-tab-scroller-right { + margin-top: 1px; +} +.x-tab-scrolling .x-tab-strip-wrap { + margin-left: 18px; + margin-right: 18px; +} +.x-tab-scrolling { + position: relative; +} +.x-tab-panel-bbar .x-toolbar { + border: 1px solid; + border-top: 0 none; + overflow: hidden; + padding: 2px; +} +.x-tab-panel-tbar .x-toolbar { + border: 1px solid; + border-top: 0 none; + overflow: hidden; + padding: 2px; +} +.x-form-field { + margin: 0 0 0 0; +} +.ext-webkit *:focus { + outline: none !important; +} +.x-form-text, textarea.x-form-field { + padding: 1px 3px; + background: repeat-x 0 0; + border: 1px solid; +} +textarea.x-form-field { + padding: 2px 3px; +} +.x-form-text, .ext-ie .x-form-file { + height: 22px; + line-height: 18px; + vertical-align: middle; +} +.ext-ie6 .x-form-text, .ext-ie7 .x-form-text { + margin: -1px 0; + + height: 22px; + + line-height: 18px; +} +.ext-ie6 textarea.x-form-field, .ext-ie7 textarea.x-form-field { + margin: -1px 0; + +} +.ext-strict .x-form-text { + height: 18px; +} +.ext-safari.ext-mac textarea.x-form-field { + margin-bottom: -2px; + +} +.ext-strict .ext-ie8 .x-form-text, .ext-strict .ext-ie8 textarea.x-form-field { + margin-bottom: 1px; +} +.ext-gecko .x-form-text, .ext-ie8 .x-form-text { + padding-top: 2px; + + padding-bottom: 0; +} +.ext-ie6 .x-form-composite .x-form-text.x-box-item, .ext-ie7 .x-form-composite .x-form-text.x-box-item { + margin: 0 !important; + +} +textarea { + resize: none; + +} +.x-form-select-one { + height: 20px; + line-height: 18px; + vertical-align: middle; + border: 1px solid; +} +.x-form-check-wrap { + line-height: 18px; + height: auto; +} +.ext-ie .x-form-check-wrap input { + width: 15px; + height: 15px; +} +.x-form-check-wrap input { + vertical-align: bottom; +} +.x-editor .x-form-check-wrap { + padding: 3px; +} +.x-editor .x-form-checkbox { + height: 13px; +} +.x-form-check-group-label { + border-bottom: 1px solid; + margin-bottom: 5px; + padding-left: 3px !important; + float: none !important; +} +.x-form-field-wrap .x-form-trigger { + width: 17px; + height: 21px; + border: 0; + background: transparent no-repeat 0 0; + cursor: pointer; + border-bottom: 1px solid; + position: absolute; + top: 0; +} +.x-form-field-wrap .x-form-date-trigger, .x-form-field-wrap .x-form-clear-trigger, .x-form-field-wrap .x-form-search-trigger { + cursor: pointer; +} +.x-form-field-wrap .x-form-twin-triggers .x-form-trigger { + position: static; + top: auto; + vertical-align: top; +} +.x-form-field-wrap { + position: relative; + left: 0; + top: 0; + text-align: left; + zoom: 1; + white-space: nowrap; +} +.ext-strict .ext-ie8 .x-toolbar-cell .x-form-field-trigger-wrap .x-form-trigger { + right: 0; + +} +.x-form-field-wrap .x-form-trigger-over { + background-position: -17px 0; +} +.x-form-field-wrap .x-form-trigger-click { + background-position: -34px 0; +} +.x-trigger-wrap-focus .x-form-trigger { + background-position: -51px 0; +} +.x-trigger-wrap-focus .x-form-trigger-over { + background-position: -68px 0; +} +.x-trigger-wrap-focus .x-form-trigger-click { + background-position: -85px 0; +} +.x-trigger-wrap-focus .x-form-trigger { + border-bottom: 1px solid; +} +.x-item-disabled .x-form-trigger-over { + background-position: 0 0 !important; + border-bottom: 1px solid; +} +.x-item-disabled .x-form-trigger-click { + background-position: 0 0 !important; + border-bottom: 1px solid; +} +.x-trigger-noedit { + cursor: pointer; +} +.x-form-focus, textarea.x-form-focus { + border: 1px solid; +} +.x-form-invalid, textarea.x-form-invalid { + background: repeat-x bottom; + border: 1px solid; +} +.x-form-inner-invalid, textarea.x-form-inner-invalid { + background: repeat-x bottom; +} +.x-editor { + visibility: hidden; + padding: 0; + margin: 0; +} +.x-form-grow-sizer { + left: -10000px; + padding: 8px 3px; + position: absolute; + visibility: hidden; + top: -10000px; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + word-wrap: break-word; + zoom: 1; +} +.x-form-grow-sizer p { + margin: 0 !important; + border: 0 none !important; + padding: 0 !important; +} +.x-form-item { + display: block; + margin-bottom: 4px; + zoom: 1; +} +.x-form-item label.x-form-item-label { + display: block; + float: left; + width: 100px; + padding: 3px; + padding-left: 0; + clear: left; + z-index: 2; + position: relative; +} +.x-form-element { + padding-left: 105px; + position: relative; +} +.x-form-invalid-msg { + padding: 2px; + padding-left: 18px; + background: transparent no-repeat 0 2px; + line-height: 16px; + width: 200px; +} +.x-form-label-left label.x-form-item-label { + text-align: left; +} +.x-form-label-right label.x-form-item-label { + text-align: right; +} +.x-form-label-top .x-form-item label.x-form-item-label { + width: auto; + float: none; + clear: none; + display: inline; + margin-bottom: 4px; + position: static; +} +.x-form-label-top .x-form-element { + padding-left: 0; + padding-top: 4px; +} +.x-form-label-top .x-form-item { + padding-bottom: 4px; +} +.x-small-editor .x-form-text { + height: 20px; + line-height: 16px; + vertical-align: middle; +} +.ext-ie6 .x-small-editor .x-form-text, .ext-ie7 .x-small-editor .x-form-text { + margin-top: -1px !important; + + margin-bottom: -1px !important; + height: 20px !important; + + line-height: 16px !important; +} +.ext-strict .x-small-editor .x-form-text { + height: 16px !important; +} +.ext-ie6 .x-small-editor .x-form-text, .ext-ie7 .x-small-editor .x-form-text { + height: 20px; + line-height: 16px; +} +.ext-border-box .x-small-editor .x-form-text { + height: 20px; +} +.x-small-editor .x-form-select-one { + height: 20px; + line-height: 16px; + vertical-align: middle; +} +.x-small-editor .x-form-num-field { + text-align: right; +} +.x-small-editor .x-form-field-wrap .x-form-trigger { + height: 19px; +} +.ext-webkit .x-small-editor .x-form-text { + padding-top: 3px; + font-size: 100%; +} +.x-form-clear { + clear: both; + height: 0; + overflow: hidden; + line-height: 0; + font-size: 0; +} +.x-form-clear-left { + clear: left; + height: 0; + overflow: hidden; + line-height: 0; + font-size: 0; +} +.ext-ie6 .x-form-check-wrap input, .ext-border-box .x-form-check-wrap input { + margin-top: 3px; +} +.x-form-cb-label { + position: relative; + margin-left: 4px; + top: 2px; +} +.ext-ie .x-form-cb-label { + top: 1px; +} +.ext-ie6 .x-form-cb-label, .ext-border-box .x-form-cb-label { + top: 3px; +} +.x-form-display-field { + padding-top: 2px; +} +.ext-gecko .x-form-display-field, .ext-strict .ext-ie7 .x-form-display-field { + padding-top: 1px; +} +.ext-ie .x-form-display-field { + padding-top: 3px; +} +.ext-strict .ext-ie8 .x-form-display-field { + padding-top: 0; +} +.x-form-column { + float: left; + padding: 0; + margin: 0; + width: 48%; + overflow: hidden; + zoom: 1; +} +.x-form .x-form-btns-ct .x-btn { + float: right; + clear: none; +} +.x-form .x-form-btns-ct .x-form-btns td { + border: 0; + padding: 0; +} +.x-form .x-form-btns-ct .x-form-btns-right table { + float: right; + clear: none; +} +.x-form .x-form-btns-ct .x-form-btns-left table { + float: left; + clear: none; +} +.x-form .x-form-btns-ct .x-form-btns-center { + text-align: center; + +} +.x-form .x-form-btns-ct .x-form-btns-center table { + margin: 0 auto; + +} +.x-form .x-form-btns-ct table td.x-form-btn-td { + padding: 3px; +} +.x-form .x-form-btns-ct .x-btn-focus .x-btn-left { + background-position: 0 -147px; +} +.x-form .x-form-btns-ct .x-btn-focus .x-btn-right { + background-position: 0 -168px; +} +.x-form .x-form-btns-ct .x-btn-focus .x-btn-center { + background-position: 0 -189px; +} +.x-form .x-form-btns-ct .x-btn-click .x-btn-center { + background-position: 0 -126px; +} +.x-form .x-form-btns-ct .x-btn-click .x-btn-right { + background-position: 0 -84px; +} +.x-form .x-form-btns-ct .x-btn-click .x-btn-left { + background-position: 0 -63px; +} +.x-form-invalid-icon { + width: 16px; + height: 18px; + visibility: hidden; + position: absolute; + left: 0; + top: 0; + display: block; + background: transparent no-repeat 0 2px; +} +.x-fieldset { + border: 1px solid; + padding: 10px; + margin-bottom: 10px; + display: block; + +} +.ext-webkit .x-fieldset-header { + padding-top: 1px; +} +.ext-ie .x-fieldset legend { + margin-bottom: 10px; +} +.ext-ie .x-fieldset { + padding-top: 0; + padding-bottom: 10px; +} +.x-fieldset legend .x-tool-toggle { + margin-right: 3px; + margin-left: 0; + float: left !important; +} +.x-fieldset legend input { + margin-right: 3px; + float: left !important; + height: 13px; + width: 13px; +} +fieldset.x-panel-collapsed { + padding-bottom: 0 !important; + border-width: 1px 1px 0 1px !important; + border-left-color: transparent; + border-right-color: transparent; +} +.ext-ie6 fieldset.x-panel-collapsed { + padding-bottom: 0 !important; + border-width: 1px 0 0 0 !important; + margin-left: 1px; + margin-right: 1px; +} +fieldset.x-panel-collapsed .x-fieldset-bwrap { + visibility: hidden; + position: absolute; + left: -1000px; + top: -1000px; +} +.ext-ie .x-fieldset-bwrap { + zoom: 1; +} +.x-fieldset-noborder { + border: 0px none transparent; +} +.x-fieldset-noborder legend { + margin-left: -3px; +} +.ext-ie .x-fieldset-noborder legend { + position: relative; + margin-bottom: 23px; +} +.ext-ie .x-fieldset-noborder legend span { + position: absolute; + left: 16px; +} +.ext-gecko .x-window-body .x-form-item { + -moz-outline: none; + outline: none; + overflow: auto; +} +.ext-gecko .x-form-item { + -moz-outline: none; + outline: none; +} +.x-hide-label label.x-form-item-label { + display: none; +} +.x-hide-label .x-form-element { + padding-left: 0 !important; +} +.x-form-label-top .x-hide-label label.x-form-item-label { + display: none; +} +.x-fieldset { + overflow: hidden; +} +.x-fieldset-bwrap { + overflow: hidden; + zoom: 1; +} +.x-fieldset-body { + overflow: hidden; +} +.x-btn { + cursor: pointer; + white-space: nowrap; +} +.x-btn button { + border: 0 none; + background: transparent; + padding-left: 3px; + padding-right: 3px; + cursor: pointer; + margin: 0; + overflow: visible; + width: auto; + -moz-outline: 0 none; + outline: 0 none; +} +* html .ext-ie .x-btn button { + width: 1px; +} +.ext-gecko .x-btn button, .ext-webkit .x-btn button { + padding-left: 0; + padding-right: 0; +} +.ext-gecko .x-btn button::-moz-focus-inner { + padding: 0; +} +.ext-ie .x-btn button { + padding-top: 2px; +} +.x-btn td { + padding: 0 !important; +} +.x-btn-text { + cursor: pointer; + white-space: nowrap; + padding: 0; +} +.x-btn-noicon .x-btn-small .x-btn-text { + height: 16px; +} +.x-btn-noicon .x-btn-medium .x-btn-text { + height: 24px; +} +.x-btn-noicon .x-btn-large .x-btn-text { + height: 32px; +} +.x-btn-icon .x-btn-text { + background-position: center; + background-repeat: no-repeat; +} +.x-btn-icon .x-btn-small .x-btn-text { + height: 16px; + width: 16px; +} +.x-btn-icon .x-btn-medium .x-btn-text { + height: 24px; + width: 24px; +} +.x-btn-icon .x-btn-large .x-btn-text { + height: 32px; + width: 32px; +} +.x-btn-text-icon .x-btn-icon-small-left .x-btn-text { + background-position: 0 center; + background-repeat: no-repeat; + padding-left: 18px; + height: 16px; +} +.x-btn-text-icon .x-btn-icon-medium-left .x-btn-text { + background-position: 0 center; + background-repeat: no-repeat; + padding-left: 26px; + height: 24px; +} +.x-btn-text-icon .x-btn-icon-large-left .x-btn-text { + background-position: 0 center; + background-repeat: no-repeat; + padding-left: 34px; + height: 32px; +} +.x-btn-text-icon .x-btn-icon-small-top .x-btn-text { + background-position: center 0; + background-repeat: no-repeat; + padding-top: 18px; +} +.x-btn-text-icon .x-btn-icon-medium-top .x-btn-text { + background-position: center 0; + background-repeat: no-repeat; + padding-top: 26px; +} +.x-btn-text-icon .x-btn-icon-large-top .x-btn-text { + background-position: center 0; + background-repeat: no-repeat; + padding-top: 34px; +} +.x-btn-text-icon .x-btn-icon-small-right .x-btn-text { + background-position: right center; + background-repeat: no-repeat; + padding-right: 18px; + height: 16px; +} +.x-btn-text-icon .x-btn-icon-medium-right .x-btn-text { + background-position: right center; + background-repeat: no-repeat; + padding-right: 26px; + height: 24px; +} +.x-btn-text-icon .x-btn-icon-large-right .x-btn-text { + background-position: right center; + background-repeat: no-repeat; + padding-right: 34px; + height: 32px; +} +.x-btn-text-icon .x-btn-icon-small-bottom .x-btn-text { + background-position: center bottom; + background-repeat: no-repeat; + padding-bottom: 18px; +} +.x-btn-text-icon .x-btn-icon-medium-bottom .x-btn-text { + background-position: center bottom; + background-repeat: no-repeat; + padding-bottom: 26px; +} +.x-btn-text-icon .x-btn-icon-large-bottom .x-btn-text { + background-position: center bottom; + background-repeat: no-repeat; + padding-bottom: 34px; +} +.x-btn-tr i, +.x-btn-tl i, +.x-btn-mr i, +.x-btn-ml i, +.x-btn-br i, +.x-btn-bl i { + font-size: 1px; + line-height: 1px; + width: 3px; + display: block; + overflow: hidden; +} +.x-btn-tr i, +.x-btn-tl i, +.x-btn-br i, +.x-btn-bl i { + height: 3px; +} +.x-btn-tl { + width: 3px; + height: 3px; + background: no-repeat 0 0; +} +.x-btn-tr { + width: 3px; + height: 3px; + background: no-repeat -3px 0; +} +.x-btn-tc { + height: 3px; + background: repeat-x 0 -6px; +} +.x-btn-ml { + width: 3px; + background: no-repeat 0 -24px; +} +.x-btn-mr { + width: 3px; + background: no-repeat -3px -24px; +} +.x-btn-mc { + background: repeat-x 0 -1096px; + vertical-align: middle; + text-align: center; + padding: 0 5px; + cursor: pointer; + white-space: nowrap; +} +.ext-strict .ext-ie6 .x-btn-mc, .ext-strict .ext-ie7 .x-btn-mc { + height: 100%; +} +.x-btn-bl { + width: 3px; + height: 3px; + background: no-repeat 0 -3px; +} +.x-btn-br { + width: 3px; + height: 3px; + background: no-repeat -3px -3px; +} +.x-btn-bc { + height: 3px; + background: repeat-x 0 -15px; +} +.x-btn-over .x-btn-tl { + background-position: -6px 0; +} +.x-btn-over .x-btn-tr { + background-position: -9px 0; +} +.x-btn-over .x-btn-tc { + background-position: 0 -9px; +} +.x-btn-over .x-btn-ml { + background-position: -6px -24px; +} +.x-btn-over .x-btn-mr { + background-position: -9px -24px; +} +.x-btn-over .x-btn-mc { + background-position: 0 -2168px; +} +.x-btn-over .x-btn-bl { + background-position: -6px -3px; +} +.x-btn-over .x-btn-br { + background-position: -9px -3px; +} +.x-btn-over .x-btn-bc { + background-position: 0 -18px; +} +.x-btn-click .x-btn-tl, .x-btn-menu-active .x-btn-tl, .x-btn-pressed .x-btn-tl { + background-position: -12px 0; +} +.x-btn-click .x-btn-tr, .x-btn-menu-active .x-btn-tr, .x-btn-pressed .x-btn-tr { + background-position: -15px 0; +} +.x-btn-click .x-btn-tc, .x-btn-menu-active .x-btn-tc, .x-btn-pressed .x-btn-tc { + background-position: 0 -12px; +} +.x-btn-click .x-btn-ml, .x-btn-menu-active .x-btn-ml, .x-btn-pressed .x-btn-ml { + background-position: -12px -24px; +} +.x-btn-click .x-btn-mr, .x-btn-menu-active .x-btn-mr, .x-btn-pressed .x-btn-mr { + background-position: -15px -24px; +} +.x-btn-click .x-btn-mc, .x-btn-menu-active .x-btn-mc, .x-btn-pressed .x-btn-mc { + background-position: 0 -3240px; +} +.x-btn-click .x-btn-bl, .x-btn-menu-active .x-btn-bl, .x-btn-pressed .x-btn-bl { + background-position: -12px -3px; +} +.x-btn-click .x-btn-br, .x-btn-menu-active .x-btn-br, .x-btn-pressed .x-btn-br { + background-position: -15px -3px; +} +.x-btn-click .x-btn-bc, .x-btn-menu-active .x-btn-bc, .x-btn-pressed .x-btn-bc { + background-position: 0 -21px; +} +.x-btn-disabled * { + cursor: default !important; +} +.x-btn-mc em.x-btn-arrow { + display: block; + background: transparent no-repeat right center; + padding-right: 10px; +} +.x-btn-mc em.x-btn-split { + display: block; + background: transparent no-repeat right center; + padding-right: 14px; +} +.x-btn-mc em.x-btn-arrow-bottom { + display: block; + background: transparent no-repeat center bottom; + padding-bottom: 14px; +} +.x-btn-mc em.x-btn-split-bottom { + display: block; + background: transparent no-repeat center bottom; + padding-bottom: 14px; +} +.x-btn-as-arrow .x-btn-mc em { + display: block; + background: transparent; + padding-bottom: 14px; +} +.x-btn-group { + padding: 1px; +} +.x-btn-group-header { + padding: 2px; + text-align: center; +} +.x-btn-group-tc { + background: transparent repeat-x 0 0; + overflow: hidden; +} +.x-btn-group-tl { + background: transparent no-repeat 0 0; + padding-left: 3px; + zoom: 1; +} +.x-btn-group-tr { + background: transparent no-repeat right 0; + zoom: 1; + padding-right: 3px; +} +.x-btn-group-bc { + background: transparent repeat-x 0 bottom; + zoom: 1; +} +.x-btn-group-bc .x-panel-footer { + zoom: 1; +} +.x-btn-group-bl { + background: transparent no-repeat 0 bottom; + padding-left: 3px; + zoom: 1; +} +.x-btn-group-br { + background: transparent no-repeat right bottom; + padding-right: 3px; + zoom: 1; +} +.x-btn-group-mc { + border: 0 none; + padding: 1px 0 0 0; + margin: 0; +} +.x-btn-group-mc .x-btn-group-body { + background: transparent; + border: 0 none; +} +.x-btn-group-ml { + background: transparent repeat-y 0 0; + padding-left: 3px; + zoom: 1; +} +.x-btn-group-mr { + background: transparent repeat-y right 0; + padding-right: 3px; + zoom: 1; +} +.x-btn-group-bc .x-btn-group-footer { + padding-bottom: 6px; +} +.x-panel-nofooter .x-btn-group-bc { + height: 3px; + font-size: 0; + line-height: 0; +} +.x-btn-group-bwrap { + overflow: hidden; + zoom: 1; +} +.x-btn-group-body { + overflow: hidden; + zoom: 1; +} +.x-btn-group-notitle .x-btn-group-tc { + background: transparent repeat-x 0 0; + overflow: hidden; + height: 2px; +} +.x-toolbar { + border-style: solid; + border-width: 0 0 1px 0; + display: block; + padding: 2px; + background: repeat-x top left; + position: relative; + left: 0; + top: 0; + zoom: 1; + overflow: hidden; +} +.x-toolbar-left { + width: 100%; +} +.x-toolbar .x-item-disabled .x-btn-icon { + opacity: .35; + -moz-opacity: .35; + filter: alpha(opacity=35); +} +.x-toolbar td { + vertical-align: middle; +} +.x-toolbar td, +.x-toolbar span, +.x-toolbar input, +.x-toolbar div, +.x-toolbar select, +.x-toolbar label { + white-space: nowrap; +} +.x-toolbar .x-item-disabled { + cursor: default; + opacity: .6; + -moz-opacity: .6; + filter: alpha(opacity=60); +} +.x-toolbar .x-item-disabled * { + cursor: default; +} +.x-toolbar .x-toolbar-cell { + vertical-align: middle; +} +.x-toolbar .x-btn-tl, +.x-toolbar .x-btn-tr, +.x-toolbar .x-btn-tc, +.x-toolbar .x-btn-ml, +.x-toolbar .x-btn-mr, +.x-toolbar .x-btn-mc, +.x-toolbar .x-btn-bl, +.x-toolbar .x-btn-br, +.x-toolbar .x-btn-bc { + background-position: 500px 500px; +} +.x-toolbar .x-btn-over .x-btn-tl { + background-position: -6px 0; +} +.x-toolbar .x-btn-over .x-btn-tr { + background-position: -9px 0; +} +.x-toolbar .x-btn-over .x-btn-tc { + background-position: 0 -9px; +} +.x-toolbar .x-btn-over .x-btn-ml { + background-position: -6px -24px; +} +.x-toolbar .x-btn-over .x-btn-mr { + background-position: -9px -24px; +} +.x-toolbar .x-btn-over .x-btn-mc { + background-position: 0 -2168px; +} +.x-toolbar .x-btn-over .x-btn-bl { + background-position: -6px -3px; +} +.x-toolbar .x-btn-over .x-btn-br { + background-position: -9px -3px; +} +.x-toolbar .x-btn-over .x-btn-bc { + background-position: 0 -18px; +} +.x-toolbar .x-btn-click .x-btn-tl, .x-toolbar .x-btn-menu-active .x-btn-tl, .x-toolbar .x-btn-pressed .x-btn-tl { + background-position: -12px 0; +} +.x-toolbar .x-btn-click .x-btn-tr, .x-toolbar .x-btn-menu-active .x-btn-tr, .x-toolbar .x-btn-pressed .x-btn-tr { + background-position: -15px 0; +} +.x-toolbar .x-btn-click .x-btn-tc, .x-toolbar .x-btn-menu-active .x-btn-tc, .x-toolbar .x-btn-pressed .x-btn-tc { + background-position: 0 -12px; +} +.x-toolbar .x-btn-click .x-btn-ml, .x-toolbar .x-btn-menu-active .x-btn-ml, .x-toolbar .x-btn-pressed .x-btn-ml { + background-position: -12px -24px; +} +.x-toolbar .x-btn-click .x-btn-mr, .x-toolbar .x-btn-menu-active .x-btn-mr, .x-toolbar .x-btn-pressed .x-btn-mr { + background-position: -15px -24px; +} +.x-toolbar .x-btn-click .x-btn-mc, .x-toolbar .x-btn-menu-active .x-btn-mc, .x-toolbar .x-btn-pressed .x-btn-mc { + background-position: 0 -3240px; +} +.x-toolbar .x-btn-click .x-btn-bl, .x-toolbar .x-btn-menu-active .x-btn-bl, .x-toolbar .x-btn-pressed .x-btn-bl { + background-position: -12px -3px; +} +.x-toolbar .x-btn-click .x-btn-br, .x-toolbar .x-btn-menu-active .x-btn-br, .x-toolbar .x-btn-pressed .x-btn-br { + background-position: -15px -3px; +} +.x-toolbar .x-btn-click .x-btn-bc, .x-toolbar .x-btn-menu-active .x-btn-bc, .x-toolbar .x-btn-pressed .x-btn-bc { + background-position: 0 -21px; +} +.x-toolbar div.xtb-text { + padding: 2px 2px 0; + line-height: 16px; + display: block; +} +.x-toolbar .xtb-sep { + background-position: center; + background-repeat: no-repeat; + display: block; + font-size: 1px; + height: 16px; + width: 4px; + overflow: hidden; + cursor: default; + margin: 0 2px 0; + border: 0; +} +.x-toolbar .xtb-spacer { + width: 2px; +} +.x-tbar-page-number { + width: 30px; + height: 14px; +} +.ext-ie .x-tbar-page-number { + margin-top: 2px; +} +.x-paging-info { + position: absolute; + top: 5px; + right: 8px; +} +.x-toolbar-ct { + width: 100%; +} +.x-toolbar-right td { + text-align: center; +} +.x-panel-tbar, +.x-panel-bbar, +.x-window-tbar, +.x-window-bbar, +.x-tab-panel-tbar, +.x-tab-panel-bbar, +.x-plain-tbar, +.x-plain-bbar { + overflow: hidden; + zoom: 1; +} +.x-toolbar-more .x-btn-small .x-btn-text { + height: 16px; + width: 12px; +} +.x-toolbar-more em.x-btn-arrow { + display: inline; + background: transparent; + padding-right: 0; +} +.x-toolbar-more .x-btn-mc em.x-btn-arrow { + background-image: none; +} +div.x-toolbar-no-items { + color: gray !important; + padding: 5px 10px !important; +} +.ext-border-box .x-toolbar-cell .x-form-text { + margin-bottom: -1px !important; +} +.ext-border-box .x-toolbar-cell .x-form-field-wrap .x-form-text { + margin: 0 !important; +} +.ext-ie .x-toolbar-cell .x-form-field-wrap { + height: 21px; +} +.ext-ie .x-toolbar-cell .x-form-text { + position: relative; + top: -1px; +} +.ext-strict .ext-ie8 .x-toolbar-cell .x-form-field-trigger-wrap .x-form-text, .ext-strict .ext-ie .x-toolbar-cell .x-form-text { + top: 0px; +} +.x-toolbar-right td .x-form-field-trigger-wrap { + text-align: left; +} +.x-toolbar-cell .x-form-checkbox, .x-toolbar-cell .x-form-radio { + margin-top: 5px; +} +.x-toolbar-cell .x-form-cb-label { + vertical-align: bottom; + top: 1px; +} +.ext-ie .x-toolbar-cell .x-form-checkbox, .ext-ie .x-toolbar-cell .x-form-radio { + margin-top: 4px; +} +.ext-ie .x-toolbar-cell .x-form-cb-label { + top: 0; +} +.x-grid3 { + position: relative; + overflow: hidden; +} +.x-grid-panel .x-panel-body { + overflow: hidden !important; +} +.x-grid-panel .x-panel-mc .x-panel-body { + border: 1px solid; +} +.x-grid3 table { + table-layout: fixed; +} +.x-grid3-viewport { + overflow: hidden; +} +.x-grid3-hd-row td, .x-grid3-row td, .x-grid3-summary-row td { + -moz-outline: none; + outline: none; + -moz-user-focus: normal; +} +.x-grid3-row td, .x-grid3-summary-row td { + line-height: 13px; + vertical-align: top; + padding-left: 1px; + padding-right: 1px; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-grid3-cell { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-grid3-hd-row td { + line-height: 15px; + vertical-align: middle; + border-left: 1px solid; + border-right: 1px solid; +} +.x-grid3-hd-row .x-grid3-marker-hd { + padding: 3px; +} +.x-grid3-row .x-grid3-marker { + padding: 3px; +} +.x-grid3-cell-inner, .x-grid3-hd-inner { + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + padding: 3px 3px 3px 5px; + white-space: nowrap; +} +.x-grid3-hd-inner { + position: relative; + cursor: inherit; + padding: 4px 3px 4px 5px; +} +.x-grid3-row-body { + white-space: normal; +} +.x-grid3-body-cell { + -moz-outline: 0 none; + outline: 0 none; +} +.ext-ie .x-grid3-cell-inner, .ext-ie .x-grid3-hd-inner { + width: 100%; +} +.ext-strict .x-grid3-cell-inner, .ext-strict .x-grid3-hd-inner { + width: auto; +} +.x-grid-row-loading { + background: no-repeat center center; +} +.x-grid-page { + overflow: hidden; +} +.x-grid3-row { + cursor: default; + border: 1px solid; + width: 100%; +} +.x-grid3-row-over { + border: 1px solid; + background: repeat-x left top; +} +.x-grid3-resize-proxy { + width: 1px; + left: 0; + cursor: e-resize; + cursor: col-resize; + position: absolute; + top: 0; + height: 100px; + overflow: hidden; + visibility: hidden; + border: 0 none; + z-index: 7; +} +.x-grid3-resize-marker { + width: 1px; + left: 0; + position: absolute; + top: 0; + height: 100px; + overflow: hidden; + visibility: hidden; + border: 0 none; + z-index: 7; +} +.x-grid3-focus { + position: absolute; + left: 0; + top: 0; + width: 1px; + height: 1px; + line-height: 1px; + font-size: 1px; + -moz-outline: 0 none; + outline: 0 none; + -moz-user-select: text; + -khtml-user-select: text; + -webkit-user-select: ignore; +} +.x-grid3-header { + background: repeat-x 0 bottom; + cursor: default; + zoom: 1; + padding: 1px 0 0 0; +} +.x-grid3-header-pop { + border-left: 1px solid; + float: right; + clear: none; +} +.x-grid3-header-pop-inner { + border-left: 1px solid; + width: 14px; + height: 19px; + background: transparent no-repeat center center; +} +.ext-ie .x-grid3-header-pop-inner { + width: 15px; +} +.ext-strict .x-grid3-header-pop-inner { + width: 14px; +} +.x-grid3-header-inner { + overflow: hidden; + zoom: 1; + float: left; +} +.x-grid3-header-offset { + padding-left: 1px; + text-align: left; +} +td.x-grid3-hd-over, +td.sort-desc, +td.sort-asc, +td.x-grid3-hd-menu-open { + border-left: 1px solid; + border-right: 1px solid; +} +td.x-grid3-hd-over .x-grid3-hd-inner, +td.sort-desc .x-grid3-hd-inner, +td.sort-asc .x-grid3-hd-inner, +td.x-grid3-hd-menu-open .x-grid3-hd-inner { + background: repeat-x left bottom; +} +.x-grid3-sort-icon { + background-repeat: no-repeat; + display: none; + height: 4px; + width: 13px; + margin-left: 3px; + vertical-align: middle; +} +.sort-asc .x-grid3-sort-icon, .sort-desc .x-grid3-sort-icon { + display: inline; +} +.ext-strict .ext-ie .x-grid3-header-inner, .ext-strict .ext-ie6 .x-grid3-hd { + position: relative; +} +.ext-strict .ext-ie6 .x-grid3-hd-inner { + position: static; +} +.x-grid3-body { + zoom: 1; +} +.x-grid3-scroller { + overflow: auto; + zoom: 1; + position: relative; +} +.x-grid3-cell-text, .x-grid3-hd-text { + display: block; + padding: 3px 5px 3px 5px; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-grid3-split { + background-position: center; + background-repeat: no-repeat; + cursor: e-resize; + cursor: col-resize; + display: block; + font-size: 1px; + height: 16px; + overflow: hidden; + position: absolute; + top: 2px; + width: 6px; + z-index: 3; +} +.x-dd-drag-proxy .x-grid3-hd-inner { + background: repeat-x left bottom; + width: 120px; + padding: 3px; + border: 1px solid; + overflow: hidden; +} +.col-move-top, .col-move-bottom { + width: 9px; + height: 9px; + position: absolute; + top: 0; + line-height: 1px; + font-size: 1px; + overflow: hidden; + visibility: hidden; + z-index: 20000; + background: transparent no-repeat left top; +} +.x-grid3-row-selected { + border: 1px dotted; +} +.x-grid3-locked td.x-grid3-row-marker, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker { + background: repeat-x 0 bottom !important; + vertical-align: middle !important; + padding: 0; + border-top: 1px solid; + border-bottom: none !important; + border-right: 1px solid !important; + text-align: center; +} +.x-grid3-locked td.x-grid3-row-marker div, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker div { + padding: 0 4px; + text-align: center; +} +.x-grid3-dirty-cell { + background: transparent no-repeat 0 0; +} +.x-grid3-topbar, .x-grid3-bottombar { + overflow: hidden; + display: none; + zoom: 1; + position: relative; +} +.x-grid3-topbar .x-toolbar { + border-right: 0 none; +} +.x-grid3-bottombar .x-toolbar { + border-right: 0 none; + border-bottom: 0 none; + border-top: 1px solid; +} +.x-props-grid .x-grid3-cell { + padding: 1px; +} +.x-props-grid .x-grid3-td-name .x-grid3-cell-inner { + background: transparent repeat-y -16px !important; + padding-left: 12px; +} +.x-props-grid .x-grid3-body .x-grid3-td-name { + padding: 1px; + padding-right: 0; + border: 0 none; + border-right: 1px solid; +} +.x-grid3-col-dd { + border: 0 none; + padding: 0; + background: transparent; +} +.x-dd-drag-ghost .x-grid3-dd-wrap { + padding: 1px 3px 3px 1px; +} +.x-grid3-hd { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-grid3-hd-btn { + display: none; + position: absolute; + width: 14px; + background: no-repeat left center; + right: 0; + top: 0; + z-index: 2; + cursor: pointer; +} +.x-grid3-hd-over .x-grid3-hd-btn, .x-grid3-hd-menu-open .x-grid3-hd-btn { + display: block; +} +a.x-grid3-hd-btn:hover { + background-position: -14px center; +} +.x-grid3-body .x-grid3-td-expander { + background: transparent repeat-y right; +} +.x-grid3-body .x-grid3-td-expander .x-grid3-cell-inner { + padding: 0 !important; + height: 100%; +} +.x-grid3-row-expander { + width: 100%; + height: 18px; + background-position: 4px 2px; + background-repeat: no-repeat; + background-color: transparent; +} +.x-grid3-row-collapsed .x-grid3-row-expander { + background-position: 4px 2px; +} +.x-grid3-row-expanded .x-grid3-row-expander { + background-position: -21px 2px; +} +.x-grid3-row-collapsed .x-grid3-row-body { + display: none !important; +} +.x-grid3-row-expanded .x-grid3-row-body { + display: block !important; +} +.x-grid3-body .x-grid3-td-checker { + background: transparent repeat-y right; +} +.x-grid3-body .x-grid3-td-checker .x-grid3-cell-inner, .x-grid3-header .x-grid3-td-checker .x-grid3-hd-inner { + padding: 0 !important; + height: 100%; +} +.x-grid3-row-checker, .x-grid3-hd-checker { + width: 100%; + height: 18px; + background-position: 2px 2px; + background-repeat: no-repeat; + background-color: transparent; +} +.x-grid3-row .x-grid3-row-checker { + background-position: 2px 2px; +} +.x-grid3-row-selected .x-grid3-row-checker, .x-grid3-hd-checker-on .x-grid3-hd-checker, .x-grid3-row-checked .x-grid3-row-checker { + background-position: -23px 2px; +} +.x-grid3-hd-checker { + background-position: 2px 1px; +} +.ext-border-box .x-grid3-hd-checker { + background-position: 2px 3px; +} +.x-grid3-hd-checker-on .x-grid3-hd-checker { + background-position: -23px 1px; +} +.ext-border-box .x-grid3-hd-checker-on .x-grid3-hd-checker { + background-position: -23px 3px; +} +.x-grid3-body .x-grid3-td-numberer { + background: transparent repeat-y right; +} +.x-grid3-body .x-grid3-td-numberer .x-grid3-cell-inner { + padding: 3px 5px 0 0 !important; + text-align: right; +} +.x-grid3-body .x-grid3-td-row-icon { + background: transparent repeat-y right; + vertical-align: top; + text-align: center; +} +.x-grid3-body .x-grid3-td-row-icon .x-grid3-cell-inner { + padding: 0 !important; + background-position: center center; + background-repeat: no-repeat; + width: 16px; + height: 16px; + margin-left: 2px; + margin-top: 3px; +} +.x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, .x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, .x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { + background: transparent repeat-y right; +} +.x-grid3-body .x-grid3-check-col-td .x-grid3-cell-inner { + padding: 1px 0 0 0 !important; +} +.x-grid3-check-col { + width: 100%; + height: 16px; + background-position: center center; + background-repeat: no-repeat; + background-color: transparent; +} +.x-grid3-check-col-on { + width: 100%; + height: 16px; + background-position: center center; + background-repeat: no-repeat; + background-color: transparent; +} +.x-grid-group, .x-grid-group-body, .x-grid-group-hd { + zoom: 1; +} +.x-grid-group-hd { + border-bottom: 2px solid; + cursor: pointer; + padding-top: 6px; +} +.x-grid-group-hd div.x-grid-group-title { + background: transparent no-repeat 3px 3px; + padding: 4px 4px 4px 17px; +} +.x-grid-group-collapsed .x-grid-group-body { + display: none; +} +.ext-ie6 .x-grid3 .x-editor .x-form-text, .ext-ie7 .x-grid3 .x-editor .x-form-text { + position: relative; + top: -1px; +} +.ext-ie .x-props-grid .x-editor .x-form-text { + position: static; + top: 0; +} +.x-grid-empty { + padding: 10px; +} +.ext-ie7 .x-grid-panel .x-panel-bbar { + position: relative; +} +.ext-ie7 .x-grid-panel .x-panel-mc .x-panel-bbar { + position: static; +} +.ext-ie6 .x-grid3-header { + position: relative; +} +.ext-webkit .x-grid-panel .x-panel-bwrap { + -webkit-user-select: none; +} +.ext-webkit .x-tbar-page-number { + -webkit-user-select: ignore; +} +.x-grid-with-col-lines .x-grid3-row td.x-grid3-cell { + padding-right: 0; + border-right: 1px solid; +} +.x-dd-drag-proxy { + position: absolute; + left: 0; + top: 0; + visibility: hidden; + z-index: 15000; +} +.x-dd-drag-ghost { + -moz-opacity: 0.85; + opacity: .85; + filter: alpha(opacity=85); + border: 1px solid; + padding: 3px; + padding-left: 20px; + white-space: nowrap; +} +.x-dd-drag-repair .x-dd-drag-ghost { + -moz-opacity: 0.4; + opacity: .4; + filter: alpha(opacity=40); + border: 0 none; + padding: 0; + background-color: transparent; +} +.x-dd-drag-repair .x-dd-drop-icon { + visibility: hidden; +} +.x-dd-drop-icon { + position: absolute; + top: 3px; + left: 3px; + display: block; + width: 16px; + height: 16px; + background-color: transparent; + background-position: center; + background-repeat: no-repeat; + z-index: 1; +} +.x-view-selector { + position: absolute; + left: 0; + top: 0; + width: 0; + border: 1px dotted; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); + zoom: 1; +} +.ext-strict .ext-ie .x-tree .x-panel-bwrap { + position: relative; + overflow: hidden; +} +.x-tree-icon, +.x-tree-ec-icon, +.x-tree-elbow-line, +.x-tree-elbow, +.x-tree-elbow-end, +.x-tree-elbow-plus, +.x-tree-elbow-minus, +.x-tree-elbow-end-plus, +.x-tree-elbow-end-minus { + border: 0 none; + height: 18px; + margin: 0; + padding: 0; + vertical-align: top; + width: 16px; + background-repeat: no-repeat; +} +.x-tree-node-collapsed .x-tree-node-icon, .x-tree-node-expanded .x-tree-node-icon, .x-tree-node-leaf .x-tree-node-icon { + border: 0 none; + height: 18px; + margin: 0; + padding: 0; + vertical-align: top; + width: 16px; + background-position: center; + background-repeat: no-repeat; +} +.ext-ie .x-tree-node-indent img, .ext-ie .x-tree-node-icon, .ext-ie .x-tree-ec-icon { + vertical-align: middle !important; +} +.ext-strict .ext-ie8 .x-tree-node-indent img, .ext-strict .ext-ie8 .x-tree-node-icon, .ext-strict .ext-ie8 .x-tree-ec-icon { + vertical-align: top !important; +} +input.x-tree-node-cb { + margin-left: 1px; + height: 19px; + vertical-align: bottom; +} +.ext-ie input.x-tree-node-cb { + margin-left: 0; + margin-top: 1px; + width: 16px; + height: 16px; + vertical-align: middle; +} +.ext-strict .ext-ie8 input.x-tree-node-cb { + margin: 1px 1px; + height: 14px; + vertical-align: bottom; +} +.ext-strict .ext-ie8 input.x-tree-node-cb + a { + vertical-align: bottom; +} +.ext-opera input.x-tree-node-cb { + height: 14px; + vertical-align: middle; +} +.x-tree-noicon .x-tree-node-icon { + width: 0; + height: 0; +} +.x-tree-no-lines .x-tree-elbow { + background: transparent; +} +.x-tree-no-lines .x-tree-elbow-end { + background: transparent; +} +.x-tree-no-lines .x-tree-elbow-line { + background: transparent; +} +.x-tree-arrows .x-tree-elbow { + background: transparent; +} +.x-tree-arrows .x-tree-elbow-plus { + background: transparent no-repeat 0 0; +} +.x-tree-arrows .x-tree-elbow-minus { + background: transparent no-repeat -16px 0; +} +.x-tree-arrows .x-tree-elbow-end { + background: transparent; +} +.x-tree-arrows .x-tree-elbow-end-plus { + background: transparent no-repeat 0 0; +} +.x-tree-arrows .x-tree-elbow-end-minus { + background: transparent no-repeat -16px 0; +} +.x-tree-arrows .x-tree-elbow-line { + background: transparent; +} +.x-tree-arrows .x-tree-ec-over .x-tree-elbow-plus { + background-position: -32px 0; +} +.x-tree-arrows .x-tree-ec-over .x-tree-elbow-minus { + background-position: -48px 0; +} +.x-tree-arrows .x-tree-ec-over .x-tree-elbow-end-plus { + background-position: -32px 0; +} +.x-tree-arrows .x-tree-ec-over .x-tree-elbow-end-minus { + background-position: -48px 0; +} +.x-tree-elbow-plus, +.x-tree-elbow-minus, +.x-tree-elbow-end-plus, +.x-tree-elbow-end-minus { + cursor: pointer; +} +.ext-ie ul.x-tree-node-ct { + font-size: 0; + line-height: 0; + zoom: 1; +} +.x-tree-node { + white-space: nowrap; +} +.x-tree-node-el { + line-height: 18px; + cursor: pointer; +} +.x-tree-node a, .x-dd-drag-ghost a { + text-decoration: none; + -khtml-user-select: none; + -moz-user-select: none; + -webkit-user-select: ignore; + -kthml-user-focus: normal; + -moz-user-focus: normal; + -moz-outline: 0 none; + outline: 0 none; +} +.x-tree-node a span, .x-dd-drag-ghost a span { + text-decoration: none; + padding: 1px 3px 1px 2px; +} +.x-tree-node .x-tree-node-disabled .x-tree-node-icon { + -moz-opacity: 0.5; + opacity: .5; + filter: alpha(opacity=50); +} +.x-tree-node .x-tree-node-inline-icon { + background: transparent; +} +.x-tree-node a:hover, .x-dd-drag-ghost a:hover { + text-decoration: none; +} +.x-tree-node div.x-tree-drag-insert-below { + border-bottom: 1px dotted; +} +.x-tree-node div.x-tree-drag-insert-above { + border-top: 1px dotted; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below { + border-bottom: 0 none; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above { + border-top: 0 none; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below a { + border-bottom: 2px solid; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above a { + border-top: 2px solid; +} +.x-tree-node .x-tree-drag-append a span { + border: 1px dotted; +} +.x-dd-drag-ghost .x-tree-node-indent, .x-dd-drag-ghost .x-tree-ec-icon { + display: none !important; +} +.x-tree-root-ct { + zoom: 1; +} +.x-date-picker { + border: 1px solid; + border-top: 0 none; + position: relative; +} +.x-date-picker a { + -moz-outline: 0 none; + outline: 0 none; +} +.x-date-inner, .x-date-inner td, .x-date-inner th { + border-collapse: separate; +} +.x-date-middle, .x-date-left, .x-date-right { + background: repeat-x 0 -83px; + overflow: hidden; +} +.x-date-middle .x-btn-tc, +.x-date-middle .x-btn-tl, +.x-date-middle .x-btn-tr, +.x-date-middle .x-btn-mc, +.x-date-middle .x-btn-ml, +.x-date-middle .x-btn-mr, +.x-date-middle .x-btn-bc, +.x-date-middle .x-btn-bl, +.x-date-middle .x-btn-br { + background: transparent !important; + vertical-align: middle; +} +.x-date-middle .x-btn-mc em.x-btn-arrow { + background: transparent no-repeat right 0; +} +.x-date-right, .x-date-left { + width: 18px; +} +.x-date-right { + text-align: right; +} +.x-date-middle { + padding-top: 2px; + padding-bottom: 2px; + width: 130px; + +} +.x-date-right a, .x-date-left a { + display: block; + width: 16px; + height: 16px; + background-position: center; + background-repeat: no-repeat; + cursor: pointer; + -moz-opacity: 0.6; + opacity: .6; + filter: alpha(opacity=60); +} +.x-date-right a:hover, .x-date-left a:hover { + -moz-opacity: 1; + opacity: 1; + filter: alpha(opacity=100); +} +.x-item-disabled .x-date-right a:hover, .x-item-disabled .x-date-left a:hover { + -moz-opacity: 0.6; + opacity: .6; + filter: alpha(opacity=60); +} +.x-date-right a { + margin-right: 2px; + text-decoration: none !important; +} +.x-date-left a { + margin-left: 2px; + text-decoration: none !important; +} +table.x-date-inner { + width: 100%; + table-layout: fixed; +} +.ext-webkit table.x-date-inner { + + width: 175px; +} +.x-date-inner th { + width: 25px; +} +.x-date-inner th { + background: repeat-x left top; + text-align: right !important; + border-bottom: 1px solid; + cursor: default; + padding: 0; + border-collapse: separate; +} +.x-date-inner th span { + display: block; + padding: 2px; + padding-right: 7px; +} +.x-date-inner td { + border: 1px solid; + text-align: right; + padding: 0; +} +.x-date-inner a { + padding: 2px 5px; + display: block; + text-decoration: none; + text-align: right; + zoom: 1; +} +.x-date-inner .x-date-active { + cursor: pointer; + color: black; +} +.x-date-inner .x-date-selected a { + background: repeat-x left top; + border: 1px solid; + padding: 1px 4px; +} +.x-date-inner .x-date-today a { + border: 1px solid; + padding: 1px 4px; +} +.x-date-inner .x-date-prevday a, .x-date-inner .x-date-nextday a { + text-decoration: none !important; +} +.x-date-bottom { + padding: 4px; + border-top: 1px solid; + background: repeat-x left top; +} +.x-date-inner a:hover, .x-date-inner .x-date-disabled a:hover { + text-decoration: none !important; +} +.x-item-disabled .x-date-inner a:hover { + background: none; +} +.x-date-inner .x-date-disabled a { + cursor: default; +} +.x-date-menu .x-menu-item { + padding: 1px 24px 1px 4px; + white-space: nowrap; +} +.x-date-menu .x-menu-item .x-menu-item-icon { + width: 10px; + height: 10px; + margin-right: 5px; + background-position: center -4px !important; +} +.x-date-mp { + position: absolute; + left: 0; + top: 0; + display: none; +} +.x-date-mp td { + padding: 2px; + font: normal 11px arial, helvetica, tahoma, sans-serif; +} +td.x-date-mp-month, td.x-date-mp-year, td.x-date-mp-ybtn { + border: 0 none; + text-align: center; + vertical-align: middle; + width: 25%; +} +.x-date-mp-ok { + margin-right: 3px; +} +.x-date-mp-btns button { + text-decoration: none; + text-align: center; + text-decoration: none !important; + border: 1px solid; + padding: 1px 3px 1px; + cursor: pointer; +} +.x-date-mp-btns { + background: repeat-x left top; +} +.x-date-mp-btns td { + border-top: 1px solid; + text-align: center; +} +td.x-date-mp-month a, td.x-date-mp-year a { + display: block; + padding: 2px 4px; + text-decoration: none; + text-align: center; +} +td.x-date-mp-month a:hover, td.x-date-mp-year a:hover { + text-decoration: none; + cursor: pointer; +} +td.x-date-mp-sel a { + padding: 1px 3px; + background: repeat-x left top; + border: 1px solid; +} +.x-date-mp-ybtn a { + overflow: hidden; + width: 15px; + height: 15px; + cursor: pointer; + background: transparent no-repeat; + display: block; + margin: 0 auto; +} +.x-date-mp-ybtn a.x-date-mp-next { + background-position: 0 -120px; +} +.x-date-mp-ybtn a.x-date-mp-next:hover { + background-position: -15px -120px; +} +.x-date-mp-ybtn a.x-date-mp-prev { + background-position: 0 -105px; +} +.x-date-mp-ybtn a.x-date-mp-prev:hover { + background-position: -15px -105px; +} +.x-date-mp-ybtn { + text-align: center; +} +td.x-date-mp-sep { + border-right: 1px solid; +} +.x-tip { + position: absolute; + top: 0; + left: 0; + visibility: hidden; + z-index: 20002; + border: 0 none; +} +.x-tip .x-tip-close { + height: 15px; + float: right; + width: 15px; + margin: 0 0 2px 2px; + cursor: pointer; + display: none; +} +.x-tip .x-tip-tc { + background: transparent no-repeat 0 -62px; + padding-top: 3px; + overflow: hidden; + zoom: 1; +} +.x-tip .x-tip-tl { + background: transparent no-repeat 0 0; + padding-left: 6px; + overflow: hidden; + zoom: 1; +} +.x-tip .x-tip-tr { + background: transparent no-repeat right 0; + padding-right: 6px; + overflow: hidden; + zoom: 1; +} +.x-tip .x-tip-bc { + background: transparent no-repeat 0 -121px; + height: 3px; + overflow: hidden; +} +.x-tip .x-tip-bl { + background: transparent no-repeat 0 -59px; + padding-left: 6px; + zoom: 1; +} +.x-tip .x-tip-br { + background: transparent no-repeat right -59px; + padding-right: 6px; + zoom: 1; +} +.x-tip .x-tip-mc { + border: 0 none; +} +.x-tip .x-tip-ml { + background: no-repeat 0 -124px; + padding-left: 6px; + zoom: 1; +} +.x-tip .x-tip-mr { + background: transparent no-repeat right -124px; + padding-right: 6px; + zoom: 1; +} +.ext-ie .x-tip .x-tip-header, .ext-ie .x-tip .x-tip-tc { + font-size: 0; + line-height: 0; +} +.ext-border-box .x-tip .x-tip-header, .ext-border-box .x-tip .x-tip-tc { + line-height: 1px; +} +.x-tip .x-tip-header-text { + padding: 0; + margin: 0 0 2px 0; +} +.x-tip .x-tip-body { + margin: 0 !important; + line-height: 14px; + padding: 0; +} +.x-tip .x-tip-body .loading-indicator { + margin: 0; +} +.x-tip-draggable .x-tip-header, .x-tip-draggable .x-tip-header-text { + cursor: move; +} +.x-form-invalid-tip .x-tip-tc { + background: repeat-x 0 -12px; + padding-top: 6px; +} +.x-form-invalid-tip .x-tip-bc { + background: repeat-x 0 -18px; + height: 6px; +} +.x-form-invalid-tip .x-tip-bl { + background: no-repeat 0 -6px; +} +.x-form-invalid-tip .x-tip-br { + background: no-repeat right -6px; +} +.x-form-invalid-tip .x-tip-body { + padding: 2px; +} +.x-form-invalid-tip .x-tip-body { + padding-left: 24px; + background: transparent no-repeat 2px 2px; +} +.x-tip-anchor { + position: absolute; + width: 9px; + height: 10px; + overflow: hidden; + background: transparent no-repeat 0 0; + zoom: 1; +} +.x-tip-anchor-bottom { + background-position: -9px 0; +} +.x-tip-anchor-right { + background-position: -18px 0; + width: 10px; +} +.x-tip-anchor-left { + background-position: -28px 0; + width: 10px; +} +.x-menu { + z-index: 15000; + zoom: 1; + background: repeat-y; +} +.x-menu-floating { + border: 1px solid; +} +.x-menu a { + text-decoration: none !important; +} +.ext-ie .x-menu { + zoom: 1; + overflow: hidden; +} +.x-menu-list { + padding: 2px; + background: transparent; + border: 0 none; + overflow: hidden; + overflow-y: hidden; +} +.ext-strict .ext-ie .x-menu-list { + position: relative; +} +.x-menu li { + line-height: 100%; +} +.x-menu li.x-menu-sep-li { + font-size: 1px; + line-height: 1px; +} +.x-menu-list-item { + white-space: nowrap; + display: block; + padding: 1px; +} +.x-menu-item { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; +} +.x-menu-item-arrow { + background: transparent no-repeat right; +} +.x-menu-sep { + display: block; + font-size: 1px; + line-height: 1px; + margin: 2px 3px; + border-bottom: 1px solid; + overflow: hidden; +} +.x-menu-focus { + position: absolute; + left: -1px; + top: -1px; + width: 1px; + height: 1px; + line-height: 1px; + font-size: 1px; + -moz-outline: 0 none; + outline: 0 none; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; + overflow: hidden; + display: block; +} +a.x-menu-item { + cursor: pointer; + display: block; + line-height: 16px; + outline-color: -moz-use-text-color; + outline-style: none; + outline-width: 0; + padding: 3px 21px 3px 27px; + position: relative; + text-decoration: none; + white-space: nowrap; +} +.x-menu-item-active { + background-repeat: repeat-x; + background-position: left bottom; + border-style: solid; + border-width: 1px 0; + margin: 0 1px; + padding: 0; +} +.x-menu-item-active a.x-menu-item { + border-style: solid; + border-width: 0 1px; + margin: 0 -1px; +} +.x-menu-item-icon { + border: 0 none; + height: 16px; + padding: 0; + vertical-align: top; + width: 16px; + position: absolute; + left: 3px; + top: 3px; + margin: 0; + background-position: center; +} +.ext-ie .x-menu-item-icon { + left: -24px; +} +.ext-strict .x-menu-item-icon { + left: 3px; +} +.ext-ie6 .x-menu-item-icon { + left: -24px; +} +.ext-ie .x-menu-item-icon { + vertical-align: middle; +} +.x-menu-check-item .x-menu-item-icon { + background: transparent no-repeat center; +} +.x-menu-group-item .x-menu-item-icon { + background: transparent; +} +.x-menu-item-checked .x-menu-group-item .x-menu-item-icon { + background: transparent no-repeat center; +} +.x-date-menu .x-menu-list { + padding: 0; +} +.x-menu-date-item { + padding: 0; +} +.x-menu .x-color-palette, .x-menu .x-date-picker { + margin-left: 26px; + margin-right: 4px; +} +.x-menu .x-date-picker { + border: 1px solid; + margin-top: 2px; + margin-bottom: 2px; +} +.x-menu-plain .x-color-palette, .x-menu-plain .x-date-picker { + margin: 0; + border: 0 none; +} +.x-date-menu { + padding: 0 !important; +} +.ext-strict .ext-ie6 .x-menu-sep-li { + padding: 3px 4px; +} +.ext-strict .ext-ie6 .x-menu-sep { + margin: 0; + height: 1px; +} +.ext-ie .x-date-menu { + height: 199px; +} +.ext-strict .ext-ie .x-date-menu, .ext-border-box .ext-ie8 .x-date-menu { + height: 197px; +} +.ext-strict .ext-ie7 .x-date-menu { + height: 195px; +} +.ext-strict .ext-ie8 .x-date-menu { + height: auto; +} +.x-cycle-menu .x-menu-item-checked { + border: 1px dotted !important; + padding: 0; +} +.x-menu .x-menu-scroller { + width: 100%; + background-repeat: no-repeat; + background-position: center; + height: 8px; + line-height: 8px; + cursor: pointer; + margin: 0; + padding: 0; +} +.x-menu .x-menu-scroller-active { + height: 6px; + line-height: 6px; +} +.x-menu-list-item-indent { + padding-left: 27px; +} +.x-box-tl { + background: transparent no-repeat 0 0; + zoom: 1; +} +.x-box-tc { + height: 8px; + background: transparent repeat-x 0 0; + overflow: hidden; +} +.x-box-tr { + background: transparent no-repeat right -8px; +} +.x-box-ml { + background: transparent repeat-y 0; + padding-left: 4px; + overflow: hidden; + zoom: 1; +} +.x-box-mc { + background: repeat-x 0 -16px; + padding: 4px 10px; +} +.x-box-mc h3 { + margin: 0 0 4px 0; + zoom: 1; +} +.x-box-mr { + background: transparent repeat-y right; + padding-right: 4px; + overflow: hidden; +} +.x-box-bl { + background: transparent no-repeat 0 -16px; + zoom: 1; +} +.x-box-bc { + background: transparent repeat-x 0 -8px; + height: 8px; + overflow: hidden; +} +.x-box-br { + background: transparent no-repeat right -24px; +} +.x-box-tl, .x-box-bl { + padding-left: 8px; + overflow: hidden; +} +.x-box-tr, .x-box-br { + padding-right: 8px; + overflow: hidden; +} +.x-combo-list { + border: 1px solid; + zoom: 1; + overflow: hidden; +} +.x-combo-list-inner { + overflow: auto; + position: relative; + + zoom: 1; + overflow-x: hidden; +} +.x-combo-list-hd { + border-bottom: 1px solid; + padding: 3px; +} +.x-resizable-pinned .x-combo-list-inner { + border-bottom: 1px solid; +} +.x-combo-list-item { + padding: 2px; + border: 1px solid; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.x-combo-list .x-combo-selected { + border: 1px dotted !important; + cursor: pointer; +} +.x-combo-list .x-toolbar { + border-top: 1px solid; + border-bottom: 0 none; +} +.x-panel { + border-style: solid; + border-width: 0; +} +.x-panel-header { + overflow: hidden; + zoom: 1; + padding: 5px 3px 4px 5px; + border: 1px solid; + line-height: 15px; + background: transparent repeat-x 0 -1px; +} +.x-panel-body { + border: 1px solid; + border-top: 0 none; + overflow: hidden; + position: relative; + +} +.x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { + border: 1px solid; + border-top: 0 none; + overflow: hidden; + padding: 2px; +} +.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { + border-top: 1px solid; + border-bottom: 0 none; +} +.x-panel-body-noheader, .x-panel-mc .x-panel-body { + border-top: 1px solid; +} +.x-panel-header { + overflow: hidden; + zoom: 1; +} +.x-panel-tl .x-panel-header { + padding: 5px 0 4px 0; + border: 0 none; + background: transparent; +} +.x-panel-tl .x-panel-icon, .x-window-tl .x-panel-icon { + padding-left: 20px !important; + background-repeat: no-repeat; + background-position: 0 4px; + zoom: 1; +} +.x-panel-inline-icon { + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: 0 0; + vertical-align: middle; + margin-right: 4px; + margin-top: -1px; + margin-bottom: -1px; +} +.x-panel-tc { + background: transparent repeat-x 0 0; + overflow: hidden; +} +.ext-strict .ext-ie7 .x-panel-tc { + overflow: visible; +} +.x-panel-tl { + background: transparent no-repeat 0 0; + padding-left: 6px; + zoom: 1; + border-bottom: 1px solid; +} +.x-panel-tr { + background: transparent no-repeat right 0; + zoom: 1; + padding-right: 6px; +} +.x-panel-bc { + background: transparent repeat-x 0 bottom; + zoom: 1; +} +.x-panel-bc .x-panel-footer { + zoom: 1; +} +.x-panel-bl { + background: transparent no-repeat 0 bottom; + padding-left: 6px; + zoom: 1; +} +.x-panel-br { + background: transparent no-repeat right bottom; + padding-right: 6px; + zoom: 1; +} +.x-panel-mc { + border: 0 none; + padding: 0; + margin: 0; + padding-top: 6px; +} +.x-panel-mc .x-panel-body { + background: transparent; + border: 0 none; +} +.x-panel-ml { + background: repeat-y 0 0; + padding-left: 6px; + zoom: 1; +} +.x-panel-mr { + background: transparent repeat-y right 0; + padding-right: 6px; + zoom: 1; +} +.x-panel-bc .x-panel-footer { + padding-bottom: 6px; +} +.x-panel-nofooter .x-panel-bc, .x-panel-nofooter .x-window-bc { + height: 6px; + font-size: 0; + line-height: 0; +} +.x-panel-bwrap { + overflow: hidden; + zoom: 1; + left: 0; + top: 0; +} +.x-panel-body { + overflow: hidden; + zoom: 1; +} +.x-panel-collapsed .x-resizable-handle { + display: none; +} +.ext-gecko .x-panel-animated div { + overflow: hidden !important; +} +.x-plain-body { + overflow: hidden; +} +.x-plain-bbar .x-toolbar { + overflow: hidden; + padding: 2px; +} +.x-plain-tbar .x-toolbar { + overflow: hidden; + padding: 2px; +} +.x-plain-bwrap { + overflow: hidden; + zoom: 1; +} +.x-plain { + overflow: hidden; +} +.x-tool { + overflow: hidden; + width: 15px; + height: 15px; + float: right; + cursor: pointer; + background: transparent no-repeat; + margin-left: 2px; +} +.x-tool-toggle { + background-position: 0 -60px; +} +.x-tool-toggle-over { + background-position: -15px -60px; +} +.x-panel-collapsed .x-tool-toggle { + background-position: 0 -75px; +} +.x-panel-collapsed .x-tool-toggle-over { + background-position: -15px -75px; +} +.x-tool-close { + background-position: 0 0; +} +.x-tool-close-over { + background-position: -15px 0; +} +.x-tool-minimize { + background-position: 0 -15px; +} +.x-tool-minimize-over { + background-position: -15px -15px; +} +.x-tool-maximize { + background-position: 0 -30px; +} +.x-tool-maximize-over { + background-position: -15px -30px; +} +.x-tool-restore { + background-position: 0 -45px; +} +.x-tool-restore-over { + background-position: -15px -45px; +} +.x-tool-gear { + background-position: 0 -90px; +} +.x-tool-gear-over { + background-position: -15px -90px; +} +.x-tool-pin { + background-position: 0 -135px; +} +.x-tool-pin-over { + background-position: -15px -135px; +} +.x-tool-unpin { + background-position: 0 -150px; +} +.x-tool-unpin-over { + background-position: -15px -150px; +} +.x-tool-right { + background-position: 0 -165px; +} +.x-tool-right-over { + background-position: -15px -165px; +} +.x-tool-left { + background-position: 0 -180px; +} +.x-tool-left-over { + background-position: -15px -180px; +} +.x-tool-up { + background-position: 0 -210px; +} +.x-tool-up-over { + background-position: -15px -210px; +} +.x-tool-down { + background-position: 0 -195px; +} +.x-tool-down-over { + background-position: -15px -195px; +} +.x-tool-refresh { + background-position: 0 -225px; +} +.x-tool-refresh-over { + background-position: -15px -225px; +} +.x-tool-minus { + background-position: 0 -255px; +} +.x-tool-minus-over { + background-position: -15px -255px; +} +.x-tool-plus { + background-position: 0 -240px; +} +.x-tool-plus-over { + background-position: -15px -240px; +} +.x-tool-search { + background-position: 0 -270px; +} +.x-tool-search-over { + background-position: -15px -270px; +} +.x-tool-save { + background-position: 0 -285px; +} +.x-tool-save-over { + background-position: -15px -285px; +} +.x-tool-help { + background-position: 0 -300px; +} +.x-tool-help-over { + background-position: -15px -300px; +} +.x-tool-print { + background-position: 0 -315px; +} +.x-tool-print-over { + background-position: -15px -315px; +} +.x-panel-ghost { + z-index: 12000; + overflow: hidden; + position: absolute; + left: 0; + top: 0; + opacity: .65; + -moz-opacity: .65; + filter: alpha(opacity=65); +} +.x-panel-ghost ul { + margin: 0; + padding: 0; + overflow: hidden; + font-size: 0; + line-height: 0; + border: 1px solid; + border-top: 0 none; + display: block; +} +.x-panel-ghost * { + cursor: move !important; +} +.x-panel-dd-spacer { + border: 2px dashed; +} +.x-panel-btns { + padding: 5px; + overflow: hidden; +} +.x-panel-btns td.x-toolbar-cell { + padding: 3px; +} +.x-panel-btns .x-btn-focus .x-btn-left { + background-position: 0 -147px; +} +.x-panel-btns .x-btn-focus .x-btn-right { + background-position: 0 -168px; +} +.x-panel-btns .x-btn-focus .x-btn-center { + background-position: 0 -189px; +} +.x-panel-btns .x-btn-over .x-btn-left { + background-position: 0 -63px; +} +.x-panel-btns .x-btn-over .x-btn-right { + background-position: 0 -84px; +} +.x-panel-btns .x-btn-over .x-btn-center { + background-position: 0 -105px; +} +.x-panel-btns .x-btn-click .x-btn-center { + background-position: 0 -126px; +} +.x-panel-btns .x-btn-click .x-btn-right { + background-position: 0 -84px; +} +.x-panel-btns .x-btn-click .x-btn-left { + background-position: 0 -63px; +} +.x-panel-fbar td, +.x-panel-fbar span, +.x-panel-fbar input, +.x-panel-fbar div, +.x-panel-fbar select, +.x-panel-fbar label { + white-space: nowrap; +} +.x-panel-reset .x-panel-body html, +.x-panel-reset .x-panel-body address, +.x-panel-reset .x-panel-body blockquote, +.x-panel-reset .x-panel-body body, +.x-panel-reset .x-panel-body dd, +.x-panel-reset .x-panel-body div, +.x-panel-reset .x-panel-body dl, +.x-panel-reset .x-panel-body dt, +.x-panel-reset .x-panel-body fieldset, +.x-panel-reset .x-panel-body form, +.x-panel-reset .x-panel-body frame, +frameset, +.x-panel-reset .x-panel-body h1, +.x-panel-reset .x-panel-body h2, +.x-panel-reset .x-panel-body h3, +.x-panel-reset .x-panel-body h4, +.x-panel-reset .x-panel-body h5, +.x-panel-reset .x-panel-body h6, +.x-panel-reset .x-panel-body noframes, +.x-panel-reset .x-panel-body ol, +.x-panel-reset .x-panel-body p, +.x-panel-reset .x-panel-body ul, +.x-panel-reset .x-panel-body center, +.x-panel-reset .x-panel-body dir, +.x-panel-reset .x-panel-body hr, +.x-panel-reset .x-panel-body menu, +.x-panel-reset .x-panel-body pre { + display: block; +} +.x-panel-reset .x-panel-body li { + display: list-item; +} +.x-panel-reset .x-panel-body head { + display: none; +} +.x-panel-reset .x-panel-body table { + display: table; +} +.x-panel-reset .x-panel-body tr { + display: table-row; +} +.x-panel-reset .x-panel-body thead { + display: table-header-group; +} +.x-panel-reset .x-panel-body tbody { + display: table-row-group; +} +.x-panel-reset .x-panel-body tfoot { + display: table-footer-group; +} +.x-panel-reset .x-panel-body col { + display: table-column; +} +.x-panel-reset .x-panel-body colgroup { + display: table-column-group; +} +.x-panel-reset .x-panel-body td, .x-panel-reset .x-panel-body th { + display: table-cell; +} +.x-panel-reset .x-panel-body caption { + display: table-caption; +} +.x-panel-reset .x-panel-body th { + font-weight: bolder; + text-align: center; +} +.x-panel-reset .x-panel-body caption { + text-align: center; +} +.x-panel-reset .x-panel-body body { + margin: 8px; +} +.x-panel-reset .x-panel-body h1 { + font-size: 2em; + margin: 0.67em 0; +} +.x-panel-reset .x-panel-body h2 { + font-size: 1.5em; + margin: 0.75em 0; +} +.x-panel-reset .x-panel-body h3 { + font-size: 1.17em; + margin: 0.83em 0; +} +.x-panel-reset .x-panel-body h4, +.x-panel-reset .x-panel-body p, +.x-panel-reset .x-panel-body blockquote, +.x-panel-reset .x-panel-body ul, +.x-panel-reset .x-panel-body fieldset, +.x-panel-reset .x-panel-body form, +.x-panel-reset .x-panel-body ol, +.x-panel-reset .x-panel-body dl, +.x-panel-reset .x-panel-body dir, +.x-panel-reset .x-panel-body menu { + margin: 1.12em 0; +} +.x-panel-reset .x-panel-body h5 { + font-size: .83em; + margin: 1.5em 0; +} +.x-panel-reset .x-panel-body h6 { + font-size: .75em; + margin: 1.67em 0; +} +.x-panel-reset .x-panel-body h1, +.x-panel-reset .x-panel-body h2, +.x-panel-reset .x-panel-body h3, +.x-panel-reset .x-panel-body h4, +.x-panel-reset .x-panel-body h5, +.x-panel-reset .x-panel-body h6, +.x-panel-reset .x-panel-body b, +.x-panel-reset .x-panel-body strong { + font-weight: bolder; +} +.x-panel-reset .x-panel-body blockquote { + margin-left: 40px; + margin-right: 40px; +} +.x-panel-reset .x-panel-body i, +.x-panel-reset .x-panel-body cite, +.x-panel-reset .x-panel-body em, +.x-panel-reset .x-panel-body var, +.x-panel-reset .x-panel-body address { + font-style: italic; +} +.x-panel-reset .x-panel-body pre, +.x-panel-reset .x-panel-body tt, +.x-panel-reset .x-panel-body code, +.x-panel-reset .x-panel-body kbd, +.x-panel-reset .x-panel-body samp { + font-family: monospace; +} +.x-panel-reset .x-panel-body pre { + white-space: pre; +} +.x-panel-reset .x-panel-body button, +.x-panel-reset .x-panel-body textarea, +.x-panel-reset .x-panel-body input, +.x-panel-reset .x-panel-body select { + display: inline-block; +} +.x-panel-reset .x-panel-body big { + font-size: 1.17em; +} +.x-panel-reset .x-panel-body small, .x-panel-reset .x-panel-body sub, .x-panel-reset .x-panel-body sup { + font-size: 0.83em; +} +.x-panel-reset .x-panel-body sub { + vertical-align: sub; +} +.x-panel-reset .x-panel-body sup { + vertical-align: super; +} +.x-panel-reset .x-panel-body table { + border-spacing: 2px; +} +.x-panel-reset .x-panel-body thead, .x-panel-reset .x-panel-body tbody, .x-panel-reset .x-panel-body tfoot { + vertical-align: middle; +} +.x-panel-reset .x-panel-body td, .x-panel-reset .x-panel-body th { + vertical-align: inherit; +} +.x-panel-reset .x-panel-body s, .x-panel-reset .x-panel-body strike, .x-panel-reset .x-panel-body del { + text-decoration: line-through; +} +.x-panel-reset .x-panel-body hr { + border: 1px inset; +} +.x-panel-reset .x-panel-body ol, +.x-panel-reset .x-panel-body ul, +.x-panel-reset .x-panel-body dir, +.x-panel-reset .x-panel-body menu, +.x-panel-reset .x-panel-body dd { + margin-left: 40px; +} +.x-panel-reset .x-panel-body ul, .x-panel-reset .x-panel-body menu, .x-panel-reset .x-panel-body dir { + list-style-type: disc; +} +.x-panel-reset .x-panel-body ol { + list-style-type: decimal; +} +.x-panel-reset .x-panel-body ol ul, +.x-panel-reset .x-panel-body ul ol, +.x-panel-reset .x-panel-body ul ul, +.x-panel-reset .x-panel-body ol ol { + margin-top: 0; + margin-bottom: 0; +} +.x-panel-reset .x-panel-body u, .x-panel-reset .x-panel-body ins { + text-decoration: underline; +} +.x-panel-reset .x-panel-body br:before { + content: "\A"; +} +.x-panel-reset .x-panel-body :before, .x-panel-reset .x-panel-body :after { + white-space: pre-line; +} +.x-panel-reset .x-panel-body center { + text-align: center; +} +.x-panel-reset .x-panel-body :link, .x-panel-reset .x-panel-body :visited { + text-decoration: underline; +} +.x-panel-reset .x-panel-body :focus { + outline: invert dotted thin; +} +.x-panel-reset .x-panel-body BDO[DIR="ltr"] { + direction: ltr; + unicode-bidi: bidi-override; +} +.x-panel-reset .x-panel-body BDO[DIR="rtl"] { + direction: rtl; + unicode-bidi: bidi-override; +} +.x-window { + zoom: 1; +} +.x-window .x-window-handle { + opacity: 0; + -moz-opacity: 0; + filter: alpha(opacity=0); +} +.x-window-proxy { + border: 1px solid; + z-index: 12000; + overflow: hidden; + position: absolute; + left: 0; + top: 0; + display: none; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); +} +.x-window-header { + overflow: hidden; + zoom: 1; +} +.x-window-bwrap { + z-index: 1; + position: relative; + zoom: 1; + left: 0; + top: 0; +} +.x-window-tl .x-window-header { + padding: 5px 0 4px 0; +} +.x-window-header-text { + cursor: pointer; +} +.x-window-tc { + background: transparent repeat-x 0 0; + overflow: hidden; + zoom: 1; +} +.x-window-tl { + background: transparent no-repeat 0 0; + padding-left: 6px; + zoom: 1; + z-index: 1; + position: relative; +} +.x-window-tr { + background: transparent no-repeat right 0; + padding-right: 6px; +} +.x-window-bc { + background: transparent repeat-x 0 bottom; + zoom: 1; +} +.x-window-bc .x-window-footer { + padding-bottom: 6px; + zoom: 1; + font-size: 0; + line-height: 0; +} +.x-window-bl { + background: transparent no-repeat 0 bottom; + padding-left: 6px; + zoom: 1; +} +.x-window-br { + background: transparent no-repeat right bottom; + padding-right: 6px; + zoom: 1; +} +.x-window-mc { + border: 1px solid; + padding: 0; + margin: 0; +} +.x-window-ml { + background: transparent repeat-y 0 0; + padding-left: 6px; + zoom: 1; +} +.x-window-mr { + background: transparent repeat-y right 0; + padding-right: 6px; + zoom: 1; +} +.x-window-body { + overflow: hidden; +} +.x-window-bwrap { + overflow: hidden; +} +.x-window-maximized .x-window-bl, +.x-window-maximized .x-window-br, +.x-window-maximized .x-window-ml, +.x-window-maximized .x-window-mr, +.x-window-maximized .x-window-tl, +.x-window-maximized .x-window-tr { + padding: 0; +} +.x-window-maximized .x-window-footer { + padding-bottom: 0; +} +.x-window-maximized .x-window-tc { + padding-left: 3px; + padding-right: 3px; +} +.x-window-maximized .x-window-mc { + border-left: 0 none; + border-right: 0 none; +} +.x-window-tbar .x-toolbar, .x-window-bbar .x-toolbar { + border-left: 0 none; + border-right: 0 none; +} +.x-window-bbar .x-toolbar { + border-top: 1px solid; + border-bottom: 0 none; +} +.x-window-draggable, .x-window-draggable .x-window-header-text { + cursor: move; +} +.x-window-maximized .x-window-draggable, .x-window-maximized .x-window-draggable .x-window-header-text { + cursor: default; +} +.x-window-body { + background: transparent; +} +.x-panel-ghost .x-window-tl { + border-bottom: 1px solid; +} +.x-panel-collapsed .x-window-tl { + border-bottom: 1px solid; +} +.x-window-maximized-ct { + overflow: hidden; +} +.x-window-maximized .x-window-handle { + display: none; +} +.x-window-sizing-ghost ul { + border: 0 none !important; +} +.x-dlg-focus { + -moz-outline: 0 none; + outline: 0 none; + width: 0; + height: 0; + overflow: hidden; + position: absolute; + top: 0; + left: 0; +} +.ext-webkit .x-dlg-focus { + width: 1px; + height: 1px; +} +.x-dlg-mask { + z-index: 10000; + display: none; + position: absolute; + top: 0; + left: 0; + -moz-opacity: 0.5; + opacity: .50; + filter: alpha(opacity=50); +} +body.ext-ie6.x-body-masked select { + visibility: hidden; +} +body.ext-ie6.x-body-masked .x-window select { + visibility: visible; +} +.x-window-plain .x-window-mc { + border: 1px solid; +} +.x-window-plain .x-window-body { + border: 1px solid; + background: transparent !important; +} +.x-html-editor-wrap { + border: 1px solid; +} +.x-html-editor-tb .x-btn-text { + background: transparent no-repeat; +} +.x-html-editor-tb .x-edit-bold, .x-menu-item img.x-edit-bold { + background-position: 0 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-italic, .x-menu-item img.x-edit-italic { + background-position: -16px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-underline, .x-menu-item img.x-edit-underline { + background-position: -32px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-forecolor, .x-menu-item img.x-edit-forecolor { + background-position: -160px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-backcolor, .x-menu-item img.x-edit-backcolor { + background-position: -176px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-justifyleft, .x-menu-item img.x-edit-justifyleft { + background-position: -112px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-justifycenter, .x-menu-item img.x-edit-justifycenter { + background-position: -128px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-justifyright, .x-menu-item img.x-edit-justifyright { + background-position: -144px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-insertorderedlist, .x-menu-item img.x-edit-insertorderedlist { + background-position: -80px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-insertunorderedlist, .x-menu-item img.x-edit-insertunorderedlist { + background-position: -96px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-increasefontsize, .x-menu-item img.x-edit-increasefontsize { + background-position: -48px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-decreasefontsize, .x-menu-item img.x-edit-decreasefontsize { + background-position: -64px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-sourceedit, .x-menu-item img.x-edit-sourceedit { + background-position: -192px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tb .x-edit-createlink, .x-menu-item img.x-edit-createlink { + background-position: -208px 0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-html-editor-tip .x-tip-bd .x-tip-bd-inner { + padding: 5px; + padding-bottom: 1px; +} +.x-html-editor-tb .x-toolbar { + position: static !important; +} +.x-panel-noborder .x-panel-body-noborder { + border-width: 0; +} +.x-panel-noborder .x-panel-header-noborder { + border-width: 0 0 1px; + border-style: solid; +} +.x-panel-noborder .x-panel-tbar-noborder .x-toolbar { + border-width: 0 0 1px; + border-style: solid; +} +.x-panel-noborder .x-panel-bbar-noborder .x-toolbar { + border-width: 1px 0 0 0; + border-style: solid; +} +.x-window-noborder .x-window-mc { + border-width: 0; +} +.x-window-plain .x-window-body-noborder { + border-width: 0; +} +.x-tab-panel-noborder .x-tab-panel-body-noborder { + border-width: 0; +} +.x-tab-panel-noborder .x-tab-panel-header-noborder { + border-width: 0 0 1px 0; +} +.x-tab-panel-noborder .x-tab-panel-footer-noborder { + border-width: 1px 0 0 0; +} +.x-tab-panel-bbar-noborder .x-toolbar { + border-width: 1px 0 0 0; + border-style: solid; +} +.x-tab-panel-tbar-noborder .x-toolbar { + border-width: 0 0 1px; + border-style: solid; +} +.x-border-layout-ct { + position: relative; +} +.x-border-panel { + position: absolute; + left: 0; + top: 0; +} +.x-tool-collapse-south { + background-position: 0 -195px; +} +.x-tool-collapse-south-over { + background-position: -15px -195px; +} +.x-tool-collapse-north { + background-position: 0 -210px; +} +.x-tool-collapse-north-over { + background-position: -15px -210px; +} +.x-tool-collapse-west { + background-position: 0 -180px; +} +.x-tool-collapse-west-over { + background-position: -15px -180px; +} +.x-tool-collapse-east { + background-position: 0 -165px; +} +.x-tool-collapse-east-over { + background-position: -15px -165px; +} +.x-tool-expand-south { + background-position: 0 -210px; +} +.x-tool-expand-south-over { + background-position: -15px -210px; +} +.x-tool-expand-north { + background-position: 0 -195px; +} +.x-tool-expand-north-over { + background-position: -15px -195px; +} +.x-tool-expand-west { + background-position: 0 -165px; +} +.x-tool-expand-west-over { + background-position: -15px -165px; +} +.x-tool-expand-east { + background-position: 0 -180px; +} +.x-tool-expand-east-over { + background-position: -15px -180px; +} +.x-tool-expand-north, .x-tool-expand-south { + float: right; + margin: 3px; +} +.x-tool-expand-east, .x-tool-expand-west { + float: none; + margin: 3px auto; +} +.x-accordion-hd .x-tool-toggle { + background-position: 0 -255px; +} +.x-accordion-hd .x-tool-toggle-over { + background-position: -15px -255px; +} +.x-panel-collapsed .x-accordion-hd .x-tool-toggle { + background-position: 0 -240px; +} +.x-panel-collapsed .x-accordion-hd .x-tool-toggle-over { + background-position: -15px -240px; +} +.x-accordion-hd { + padding-top: 4px; + padding-bottom: 3px; + border-top: 0 none; + background: transparent repeat-x 0 -9px; +} +.x-layout-collapsed { + position: absolute; + left: -10000px; + top: -10000px; + visibility: hidden; + width: 20px; + height: 20px; + overflow: hidden; + border: 1px solid; + z-index: 20; +} +.ext-border-box .x-layout-collapsed { + width: 22px; + height: 22px; +} +.x-layout-collapsed-over { + cursor: pointer; +} +.x-layout-collapsed-west .x-layout-collapsed-tools, .x-layout-collapsed-east .x-layout-collapsed-tools { + position: absolute; + top: 0; + left: 0; + width: 20px; + height: 20px; +} +.x-layout-split { + position: absolute; + height: 5px; + width: 5px; + line-height: 1px; + font-size: 1px; + z-index: 3; + background-color: transparent; +} +.ext-strict .ext-ie6 .x-layout-split { + background-color: #fff !important; + filter: alpha(opacity=1); +} +.x-layout-split-h { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/s.gif); + background-position: left; +} +.x-layout-split-v { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/s.gif); + background-position: top; +} +.x-column-layout-ct { + overflow: hidden; + zoom: 1; +} +.x-column { + float: left; + padding: 0; + margin: 0; + overflow: hidden; + zoom: 1; +} +.x-column-inner { + overflow: hidden; + zoom: 1; +} +.x-layout-mini { + position: absolute; + top: 0; + left: 0; + display: block; + width: 5px; + height: 35px; + cursor: pointer; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); +} +.x-layout-mini-over, .x-layout-collapsed-over .x-layout-mini { + opacity: 1; + -moz-opacity: 1; + filter: none; +} +.x-layout-split-west .x-layout-mini { + top: 48%; +} +.x-layout-split-east .x-layout-mini { + top: 48%; +} +.x-layout-split-north .x-layout-mini { + left: 48%; + height: 5px; + width: 35px; +} +.x-layout-split-south .x-layout-mini { + left: 48%; + height: 5px; + width: 35px; +} +.x-layout-cmini-west .x-layout-mini { + top: 48%; +} +.x-layout-cmini-east .x-layout-mini { + top: 48%; +} +.x-layout-cmini-north .x-layout-mini { + left: 48%; + height: 5px; + width: 35px; +} +.x-layout-cmini-south .x-layout-mini { + left: 48%; + height: 5px; + width: 35px; +} +.x-layout-cmini-west, .x-layout-cmini-east { + border: 0 none; + width: 5px !important; + padding: 0; + background: transparent; +} +.x-layout-cmini-north, .x-layout-cmini-south { + border: 0 none; + height: 5px !important; + padding: 0; + background: transparent; +} +.x-viewport, .x-viewport body { + margin: 0; + padding: 0; + border: 0 none; + overflow: hidden; + height: 100%; +} +.x-abs-layout-item { + position: absolute; + left: 0; + top: 0; +} +.ext-ie input.x-abs-layout-item, .ext-ie textarea.x-abs-layout-item { + margin: 0; +} +.x-box-layout-ct { + overflow: hidden; + zoom: 1; +} +.x-box-inner { + overflow: hidden; + zoom: 1; + position: relative; + left: 0; + top: 0; +} +.x-box-item { + position: absolute; + left: 0; + top: 0; +} +.x-progress-wrap { + border: 1px solid; + overflow: hidden; +} +.x-progress-inner { + height: 18px; + background: repeat-x; + position: relative; +} +.x-progress-bar { + height: 18px; + float: left; + width: 0; + background: repeat-x left center; + border-top: 1px solid; + border-bottom: 1px solid; + border-right: 1px solid; +} +.x-progress-text { + padding: 1px 5px; + overflow: hidden; + position: absolute; + left: 0; + text-align: center; +} +.x-progress-text-back { + line-height: 16px; +} +.ext-ie .x-progress-text-back { + line-height: 15px; +} +.ext-strict .ext-ie7 .x-progress-text-back { + width: 100%; +} +.x-list-header { + background: repeat-x 0 bottom; + cursor: default; + zoom: 1; + height: 22px; +} +.x-list-header-inner div { + display: block; + float: left; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} +.x-list-header-inner div em { + display: block; + border-left: 1px solid; + padding: 4px 4px; + overflow: hidden; + -moz-user-select: none; + -khtml-user-select: none; + line-height: 14px; +} +.x-list-body { + overflow: auto; + overflow-x: hidden; + overflow-y: auto; + zoom: 1; + float: left; + width: 100%; +} +.x-list-body dl { + zoom: 1; +} +.x-list-body dt { + display: block; + float: left; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + zoom: 1; +} +.x-list-body dt em { + display: block; + padding: 3px 4px; + overflow: hidden; + -moz-user-select: none; + -khtml-user-select: none; +} +.x-list-resizer { + border-left: 1px solid; + border-right: 1px solid; + position: absolute; + left: 0; + top: 0; +} +.x-list-header-inner em.sort-asc { + background: transparent no-repeat center 0; + border-style: solid; + border-width: 0 1px 1px; + padding-bottom: 3px; +} +.x-list-header-inner em.sort-desc { + background: transparent no-repeat center -23px; + border-style: solid; + border-width: 0 1px 1px; + padding-bottom: 3px; +} +.x-slider { + zoom: 1; +} +.x-slider-inner { + position: relative; + left: 0; + top: 0; + overflow: visible; + zoom: 1; +} +.x-slider-focus { + position: absolute; + left: 0; + top: 0; + width: 1px; + height: 1px; + line-height: 1px; + font-size: 1px; + -moz-outline: 0 none; + outline: 0 none; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: ignore; + display: block; + overflow: hidden; +} +.x-slider-horz { + padding-left: 7px; + background: transparent no-repeat 0 -22px; +} +.x-slider-horz .x-slider-end { + padding-right: 7px; + zoom: 1; + background: transparent no-repeat right -44px; +} +.x-slider-horz .x-slider-inner { + background: transparent repeat-x 0 0; + height: 22px; +} +.x-slider-horz .x-slider-thumb { + width: 14px; + height: 15px; + position: absolute; + left: 0; + top: 3px; + background: transparent no-repeat 0 0; +} +.x-slider-horz .x-slider-thumb-over { + background-position: -14px -15px; +} +.x-slider-horz .x-slider-thumb-drag { + background-position: -28px -30px; +} +.x-slider-vert { + padding-top: 7px; + background: transparent no-repeat -44px 0; + width: 22px; +} +.x-slider-vert .x-slider-end { + padding-bottom: 7px; + zoom: 1; + background: transparent no-repeat -22px bottom; +} +.x-slider-vert .x-slider-inner { + background: transparent repeat-y 0 0; +} +.x-slider-vert .x-slider-thumb { + width: 15px; + height: 14px; + position: absolute; + left: 3px; + bottom: 0; + background: transparent no-repeat 0 0; +} +.x-slider-vert .x-slider-thumb-over { + background-position: -15px -14px; +} +.x-slider-vert .x-slider-thumb-drag { + background-position: -30px -28px; +} +.x-window-dlg .x-window-body { + border: 0 none !important; + padding: 5px 10px; + overflow: hidden !important; +} +.x-window-dlg .x-window-mc { + border: 0 none !important; +} +.x-window-dlg .ext-mb-input { + margin-top: 4px; + width: 95%; +} +.x-window-dlg .ext-mb-textarea { + margin-top: 4px; +} +.x-window-dlg .x-progress-wrap { + margin-top: 4px; +} +.ext-ie .x-window-dlg .x-progress-wrap { + margin-top: 6px; +} +.x-window-dlg .x-msg-box-wait { + background: transparent no-repeat left; + display: block; + width: 300px; + padding-left: 18px; + line-height: 18px; +} +.x-window-dlg .ext-mb-icon { + float: left; + width: 47px; + height: 32px; +} +.ext-ie .x-window-dlg .ext-mb-icon { + width: 44px; + +} +.x-window-dlg .x-dlg-icon .ext-mb-content { + zoom: 1; + margin-left: 47px; +} +.x-window-dlg .ext-mb-info, +.x-window-dlg .ext-mb-warning, +.x-window-dlg .ext-mb-question, +.x-window-dlg .ext-mb-error { + background: transparent no-repeat top left; +} +.ext-gecko2 .ext-mb-fix-cursor { + overflow: auto; +} +.ext-el-mask { + background-color: #ccc; +} +.ext-el-mask-msg { + border-color: #6593cf; + background-color: #c3daf9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb-blue.gif); +} +.ext-el-mask-msg div { + background-color: #eee; + border-color: #a3bad9; + color: #222; + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-mask-loading div { + background-color: #fbfbfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-item-disabled { + color: gray; +} +.x-item-disabled * { + color: gray !important; +} +.x-splitbar-proxy { + background-color: #aaa; +} +.x-color-palette a { + border-color: #fff; +} +.x-color-palette a:hover, .x-color-palette a.x-color-palette-sel { + border-color: #8bb8f3; + background-color: #deecfd; +} +.x-color-palette em:hover, .x-color-palette span:hover { + background-color: #deecfd; +} +.x-color-palette em { + border-color: #aca899; +} +.x-ie-shadow { + background-color: #777; +} +.x-shadow .xsmc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow-c.png); +} +.x-shadow .xsml, .x-shadow .xsmr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow-lr.png); +} +.x-shadow .xstl, +.x-shadow .xstc, +.x-shadow .xstr, +.x-shadow .xsbl, +.x-shadow .xsbc, +.x-shadow .xsbr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow.png); +} +.loading-indicator { + font-size: 11px; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-spotlight { + background-color: #ccc; +} +.x-tab-panel-header, .x-tab-panel-footer { + background-color: #deecfd; + border-color: #8db2e3; + overflow: hidden; + zoom: 1; +} +.x-tab-panel-header, .x-tab-panel-footer { + border-color: #8db2e3; +} +ul.x-tab-strip-top { + background-color: #cedff5; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-strip-bg.gif); + border-bottom-color: #8db2e3; +} +ul.x-tab-strip-bottom { + background-color: #cedff5; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-strip-btm-bg.gif); + border-top-color: #8db2e3; +} +.x-tab-panel-header-plain .x-tab-strip-spacer, .x-tab-panel-footer-plain .x-tab-strip-spacer { + border-color: #8db2e3; + background-color: #deecfd; +} +.x-tab-strip span.x-tab-strip-text { + font: normal 11px tahoma,arial,helvetica; + color: #416aa3; +} +.x-tab-strip-over span.x-tab-strip-text { + color: #15428b; +} +.x-tab-strip-active span.x-tab-strip-text { + color: #15428b; + font-weight: bold; +} +.x-tab-strip-disabled .x-tabs-text { + color: #aaaaaa; +} +.x-tab-strip-top .x-tab-right, .x-tab-strip-top .x-tab-left, .x-tab-strip-top .x-tab-strip-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tabs-sprite.gif); +} +.x-tab-strip-bottom .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-inactive-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-inactive-left-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-over .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-over-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-over .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-over-left-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-btm-left-bg.gif); +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-close.gif); +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close:hover { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/tab-close.gif); +} +.x-tab-panel-body { + border-color: #8db2e3; + background-color: #fff; +} +.x-tab-panel-body-top { + border-top: 0 none; +} +.x-tab-panel-body-bottom { + border-bottom: 0 none; +} +.x-tab-scroller-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/scroll-left.gif); + border-bottom-color: #8db2e3; +} +.x-tab-scroller-left-over { + background-position: 0 0; +} +.x-tab-scroller-left-disabled { + background-position: -18px 0; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); + cursor: default; +} +.x-tab-scroller-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tabs/scroll-right.gif); + border-bottom-color: #8db2e3; +} +.x-tab-panel-bbar .x-toolbar, .x-tab-panel-tbar .x-toolbar { + border-color: #99bbe8; +} +.x-form-field { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-text, textarea.x-form-field { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/text-bg.gif); + border-color: #b5b8c8; +} +.x-form-select-one { + background-color: #fff; + border-color: #b5b8c8; +} +.x-form-check-group-label { + border-bottom: 1px solid #99bbe8; + color: #15428b; +} +.x-editor .x-form-check-wrap { + background-color: #fff; +} +.x-form-field-wrap .x-form-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/trigger.gif); + border-bottom-color: #b5b8c8; +} +.x-form-field-wrap .x-form-date-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/date-trigger.gif); +} +.x-form-field-wrap .x-form-clear-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/clear-trigger.gif); +} +.x-form-field-wrap .x-form-search-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/search-trigger.gif); +} +.x-trigger-wrap-focus .x-form-trigger { + border-bottom-color: #7eadd9; +} +.x-item-disabled .x-form-trigger-over { + border-bottom-color: #b5b8c8; +} +.x-item-disabled .x-form-trigger-click { + border-bottom-color: #b5b8c8; +} +.x-form-focus, textarea.x-form-focus { + border-color: #7eadd9; +} +.x-form-invalid, textarea.x-form-invalid { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif); + border-color: #c30; +} +.x-form-invalid.x-form-composite { + border: none; + background-image: none; +} +.x-form-invalid.x-form-composite .x-form-invalid { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif); + border-color: #c30; +} +.x-form-inner-invalid, textarea.x-form-inner-invalid { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif); +} +.x-form-grow-sizer { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-item { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-invalid-msg { + color: #c0272b; + font: normal 11px tahoma, arial, helvetica, sans-serif; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/warning.gif); +} +.x-form-empty-field { + color: gray; +} +.x-small-editor .x-form-field { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.ext-webkit .x-small-editor .x-form-field { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-form-invalid-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/exclamation.gif); +} +.x-fieldset { + border-color: #b5b8c8; +} +.x-fieldset legend { + font: bold 11px tahoma, arial, helvetica, sans-serif; + color: #15428b; +} +.x-btn { + font: normal 11px tahoma, verdana, helvetica; +} +.x-btn button { + font: normal 11px arial,tahoma,verdana,helvetica; + color: #333; +} +.x-btn em { + font-style: normal; + font-weight: normal; +} +.x-btn-tl, +.x-btn-tr, +.x-btn-tc, +.x-btn-ml, +.x-btn-mr, +.x-btn-mc, +.x-btn-bl, +.x-btn-br, +.x-btn-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/btn.gif); +} +.x-btn-click .x-btn-text, .x-btn-menu-active .x-btn-text, .x-btn-pressed .x-btn-text { + color: #000; +} +.x-btn-disabled * { + color: gray !important; +} +.x-btn-mc em.x-btn-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/arrow.gif); +} +.x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow.gif); +} +.x-btn-over .x-btn-mc em.x-btn-split, +.x-btn-click .x-btn-mc em.x-btn-split, +.x-btn-menu-active .x-btn-mc em.x-btn-split, +.x-btn-pressed .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-o.gif); +} +.x-btn-mc em.x-btn-arrow-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b-noline.gif); +} +.x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b.gif); +} +.x-btn-over .x-btn-mc em.x-btn-split-bottom, +.x-btn-click .x-btn-mc em.x-btn-split-bottom, +.x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, +.x-btn-pressed .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-bo.gif); +} +.x-btn-group-header { + color: #3e6aaa; +} +.x-btn-group-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-tb.gif); +} +.x-btn-group-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-cs.gif); +} +.x-btn-group-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-cs.gif); +} +.x-btn-group-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-tb.gif); +} +.x-btn-group-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-cs.gif); +} +.x-btn-group-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-cs.gif); +} +.x-btn-group-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-lr.gif); +} +.x-btn-group-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-lr.gif); +} +.x-btn-group-notitle .x-btn-group-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/group-tb.gif); +} +.x-toolbar { + border-color: #a9bfd3; + background-color: #d0def0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/toolbar/bg.gif); +} +.x-toolbar td, +.x-toolbar span, +.x-toolbar input, +.x-toolbar div, +.x-toolbar select, +.x-toolbar label { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-toolbar .x-item-disabled { + color: gray; +} +.x-toolbar .x-item-disabled * { + color: gray; +} +.x-toolbar .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-noline.gif); +} +.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split, +.x-toolbar .x-btn-click .x-btn-mc em.x-btn-split, +.x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split, +.x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-o.gif); +} +.x-toolbar .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b-noline.gif); +} +.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split-bottom, +.x-toolbar .x-btn-click .x-btn-mc em.x-btn-split-bottom, +.x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, +.x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-bo.gif); +} +.x-toolbar .xtb-sep { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-blue-split.gif); +} +.x-tbar-page-first { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-first.gif) !important; +} +.x-tbar-loading { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/refresh.gif) !important; +} +.x-tbar-page-last { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-last.gif) !important; +} +.x-tbar-page-next { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-next.gif) !important; +} +.x-tbar-page-prev { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-prev.gif) !important; +} +.x-item-disabled .x-tbar-loading { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif) !important; +} +.x-item-disabled .x-tbar-page-first { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-first-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-last { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-last-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-next { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-next-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-prev { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-prev-disabled.gif) !important; +} +.x-paging-info { + color: #444; +} +.x-toolbar-more-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/toolbar/more.gif) !important; +} +.x-resizable-handle { + background-color: #fff; +} +.x-resizable-over .x-resizable-handle-east, +.x-resizable-pinned .x-resizable-handle-east, +.x-resizable-over .x-resizable-handle-west, +.x-resizable-pinned .x-resizable-handle-west { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/e-handle.gif); +} +.x-resizable-over .x-resizable-handle-south, +.x-resizable-pinned .x-resizable-handle-south, +.x-resizable-over .x-resizable-handle-north, +.x-resizable-pinned .x-resizable-handle-north { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/s-handle.gif); +} +.x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/s-handle.gif); +} +.x-resizable-over .x-resizable-handle-southeast, .x-resizable-pinned .x-resizable-handle-southeast { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/se-handle.gif); +} +.x-resizable-over .x-resizable-handle-northwest, .x-resizable-pinned .x-resizable-handle-northwest { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/nw-handle.gif); +} +.x-resizable-over .x-resizable-handle-northeast, .x-resizable-pinned .x-resizable-handle-northeast { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/ne-handle.gif); +} +.x-resizable-over .x-resizable-handle-southwest, .x-resizable-pinned .x-resizable-handle-southwest { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/sizer/sw-handle.gif); +} +.x-resizable-proxy { + border-color: #3b5a82; +} +.x-resizable-overlay { + background-color: #fff; +} +.x-grid3 { + background-color: #fff; +} +.x-grid-panel .x-panel-mc .x-panel-body { + border-color: #99bbe8; +} +.x-grid3-row td, .x-grid3-summary-row td { + font: normal 11px/13px arial, tahoma, helvetica, sans-serif; +} +.x-grid3-hd-row td { + font: normal 11px/15px arial, tahoma, helvetica, sans-serif; +} +.x-grid3-hd-row td { + border-left-color: #eee; + border-right-color: #d0d0d0; +} +.x-grid-row-loading { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/loading-balls.gif); +} +.x-grid3-row { + border-color: #ededed; + border-top-color: #fff; +} +.x-grid3-row-alt { + background-color: #fafafa; +} +.x-grid3-row-over { + border-color: #ddd; + background-color: #efefef; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/row-over.gif); +} +.x-grid3-resize-proxy { + background-color: #777; +} +.x-grid3-resize-marker { + background-color: #777; +} +.x-grid3-header { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow.gif); +} +.x-grid3-header-pop { + border-left-color: #d0d0d0; +} +.x-grid3-header-pop-inner { + border-left-color: #eee; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hd-pop.gif); +} +td.x-grid3-hd-over, +td.sort-desc, +td.sort-asc, +td.x-grid3-hd-menu-open { + border-left-color: #aaccf6; + border-right-color: #aaccf6; +} +td.x-grid3-hd-over .x-grid3-hd-inner, +td.sort-desc .x-grid3-hd-inner, +td.sort-asc .x-grid3-hd-inner, +td.x-grid3-hd-menu-open .x-grid3-hd-inner { + background-color: #ebf3fd; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow-over.gif); +} +.sort-asc .x-grid3-sort-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/sort_asc.gif); +} +.sort-desc .x-grid3-sort-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/sort_desc.gif); +} +.x-grid3-cell-text, .x-grid3-hd-text { + color: #000; +} +.x-grid3-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-split.gif); +} +.x-grid3-hd-text { + color: #15428b; +} +.x-dd-drag-proxy .x-grid3-hd-inner { + background-color: #ebf3fd; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow-over.gif); + border-color: #aaccf6; +} +.col-move-top { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/col-move-top.gif); +} +.col-move-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/col-move-bottom.gif); +} +.x-grid3-row-selected { + background-color: #dfe8f6 !important; + background-image: none; + border-color: #a3bae9; +} +.x-grid3-cell-selected { + background-color: #b8cfee !important; + color: #000; +} +.x-grid3-cell-selected span { + color: #000 !important; +} +.x-grid3-cell-selected .x-grid3-cell-text { + color: #000; +} +.x-grid3-locked td.x-grid3-row-marker, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker { + background-color: #ebeadb !important; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-hrow.gif) !important; + color: #000; + border-top-color: #fff; + border-right-color: #6fa0df !important; +} +.x-grid3-locked td.x-grid3-row-marker div, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker div { + color: #15428b !important; +} +.x-grid3-dirty-cell { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/dirty.gif); +} +.x-grid3-topbar, .x-grid3-bottombar { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-grid3-bottombar .x-toolbar { + border-top-color: #a9bfd3; +} +.x-props-grid .x-grid3-td-name .x-grid3-cell-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif) !important; + color: #000 !important; +} +.x-props-grid .x-grid3-body .x-grid3-td-name { + background-color: #fff !important; + border-right-color: #eee; +} +.xg-hmenu-sort-asc .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-asc.gif); +} +.xg-hmenu-sort-desc .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-desc.gif); +} +.xg-hmenu-lock .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-lock.gif); +} +.xg-hmenu-unlock .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-unlock.gif); +} +.x-grid3-hd-btn { + background-color: #c3daf9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hd-btn.gif); +} +.x-grid3-body .x-grid3-td-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-row-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/row-expand-sprite.gif); +} +.x-grid3-body .x-grid3-td-checker { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-row-checker, .x-grid3-hd-checker { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/row-check-sprite.gif); +} +.x-grid3-body .x-grid3-td-numberer { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-body .x-grid3-td-numberer .x-grid3-cell-inner { + color: #444; +} +.x-grid3-body .x-grid3-td-row-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, .x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, .x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-sel-bg.gif); +} +.x-grid3-check-col { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/unchecked.gif); +} +.x-grid3-check-col-on { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/checked.gif); +} +.x-grid-group, .x-grid-group-body, .x-grid-group-hd { + zoom: 1; +} +.x-grid-group-hd { + border-bottom-color: #99bbe8; +} +.x-grid-group-hd div.x-grid-group-title { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-collapse.gif); + color: #3764a0; + font: bold 11px tahoma, arial, helvetica, sans-serif; +} +.x-grid-group-collapsed .x-grid-group-hd div.x-grid-group-title { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-expand.gif); +} +.x-group-by-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-by.gif); +} +.x-cols-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/columns.gif); +} +.x-show-groups-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-by.gif); +} +.x-grid-empty { + color: gray; + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-grid-with-col-lines .x-grid3-row td.x-grid3-cell { + border-right-color: #ededed; +} +.x-grid-with-col-lines .x-grid3-row-selected { + border-top-color: #a3bae9; +} +.x-dd-drag-ghost { + color: #000; + font: normal 11px arial, helvetica, sans-serif; + border-color: #ddd #bbb #bbb #ddd; + background-color: #fff; +} +.x-dd-drop-nodrop .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-no.gif); +} +.x-dd-drop-ok .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-yes.gif); +} +.x-dd-drop-ok-add .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-add.gif); +} +.x-view-selector { + background-color: #c3daf9; + border-color: #3399bb; +} +.x-tree-node-expanded .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/folder-open.gif); +} +.x-tree-node-leaf .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/leaf.gif); +} +.x-tree-node-collapsed .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/folder.gif); +} +.x-tree-node-loading .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/loading.gif) !important; +} +.x-tree-node .x-tree-node-inline-icon { + background-image: none; +} +.x-tree-node-loading a span { + font-style: italic; + color: #444444; +} +.x-tree-lines .x-tree-elbow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow.gif); +} +.x-tree-lines .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus.gif); +} +.x-tree-lines .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus.gif); +} +.x-tree-lines .x-tree-elbow-end { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end.gif); +} +.x-tree-lines .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-plus.gif); +} +.x-tree-lines .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-minus.gif); +} +.x-tree-lines .x-tree-elbow-line { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-line.gif); +} +.x-tree-no-lines .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-plus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end-minus-nl.gif); +} +.x-tree-arrows .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/arrows.gif); +} +.x-tree-node { + color: #000; + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-tree-node a, .x-dd-drag-ghost a { + color: #000; +} +.x-tree-node a span, .x-dd-drag-ghost a span { + color: #000; +} +.x-tree-node .x-tree-node-disabled a span { + color: gray !important; +} +.x-tree-node div.x-tree-drag-insert-below { + border-bottom-color: #36c; +} +.x-tree-node div.x-tree-drag-insert-above { + border-top-color: #36c; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below a { + border-bottom-color: #36c; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above a { + border-top-color: #36c; +} +.x-tree-node .x-tree-drag-append a span { + background-color: #ddd; + border-color: gray; +} +.x-tree-node .x-tree-node-over { + background-color: #eee; +} +.x-tree-node .x-tree-selected { + background-color: #d9e8fb; +} +.x-tree-drop-ok-append .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-add.gif); +} +.x-tree-drop-ok-above .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-over.gif); +} +.x-tree-drop-ok-below .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-under.gif); +} +.x-tree-drop-ok-between .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-between.gif); +} +.x-date-picker { + border-color: #1b376c; + background-color: #fff; +} +.x-date-middle, .x-date-left, .x-date-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/hd-sprite.gif); + color: #fff; + font: bold 11px "sans serif", tahoma, verdana, helvetica; +} +.x-date-middle .x-btn .x-btn-text { + color: #fff; +} +.x-date-middle .x-btn-mc em.x-btn-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/toolbar/btn-arrow-light.gif); +} +.x-date-right a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/right-btn.gif); +} +.x-date-left a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/left-btn.gif); +} +.x-date-inner th { + background-color: #dfecfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif); + border-bottom-color: #a3bad9; + font: normal 10px arial, helvetica, tahoma, sans-serif; + color: #233d6d; +} +.x-date-inner td { + border-color: #fff; +} +.x-date-inner a { + font: normal 11px arial, helvetica, tahoma, sans-serif; + color: #000; +} +.x-date-inner .x-date-active { + color: #000; +} +.x-date-inner .x-date-selected a { + background-color: #dfecfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif); + border-color: #8db2e3; +} +.x-date-inner .x-date-today a { + border-color: darkred; +} +.x-date-inner .x-date-selected span { + font-weight: bold; +} +.x-date-inner .x-date-prevday a, .x-date-inner .x-date-nextday a { + color: #aaa; +} +.x-date-bottom { + border-top-color: #a3bad9; + background-color: #dfecfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif); +} +.x-date-inner a:hover, .x-date-inner .x-date-disabled a:hover { + color: #000; + background-color: #ddecfe; +} +.x-date-inner .x-date-disabled a { + background-color: #eee; + color: #bbb; +} +.x-date-mmenu { + background-color: #eee !important; +} +.x-date-mmenu .x-menu-item { + font-size: 10px; + color: #000; +} +.x-date-mp { + background-color: #fff; +} +.x-date-mp td { + font: normal 11px arial, helvetica, tahoma, sans-serif; +} +.x-date-mp-btns button { + background-color: #083772; + color: #fff; + border-color: #3366cc #000055 #000055 #3366cc; + font: normal 11px arial, helvetica, tahoma, sans-serif; +} +.x-date-mp-btns { + background-color: #dfecfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif); +} +.x-date-mp-btns td { + border-top-color: #c5d2df; +} +td.x-date-mp-month a, td.x-date-mp-year a { + color: #15428b; +} +td.x-date-mp-month a:hover, td.x-date-mp-year a:hover { + color: #15428b; + background-color: #ddecfe; +} +td.x-date-mp-sel a { + background-color: #dfecfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/glass-bg.gif); + border-color: #8db2e3; +} +.x-date-mp-ybtn a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/tool-sprites.gif); +} +td.x-date-mp-sep { + border-right-color: #c5d2df; +} +.x-tip .x-tip-close { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/qtip/close.gif); +} +.x-tip .x-tip-tc, +.x-tip .x-tip-tl, +.x-tip .x-tip-tr, +.x-tip .x-tip-bc, +.x-tip .x-tip-bl, +.x-tip .x-tip-br, +.x-tip .x-tip-ml, +.x-tip .x-tip-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/qtip/tip-sprite.gif); +} +.x-tip .x-tip-mc { + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-tip .x-tip-ml { + background-color: #fff; +} +.x-tip .x-tip-header-text { + font: bold 11px tahoma, arial, helvetica, sans-serif; + color: #444; +} +.x-tip .x-tip-body { + font: normal 11px tahoma, arial, helvetica, sans-serif; + color: #444; +} +.x-form-invalid-tip .x-tip-tc, +.x-form-invalid-tip .x-tip-tl, +.x-form-invalid-tip .x-tip-tr, +.x-form-invalid-tip .x-tip-bc, +.x-form-invalid-tip .x-tip-bl, +.x-form-invalid-tip .x-tip-br, +.x-form-invalid-tip .x-tip-ml, +.x-form-invalid-tip .x-tip-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/error-tip-corners.gif); +} +.x-form-invalid-tip .x-tip-body { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/exclamation.gif); +} +.x-tip-anchor { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/qtip/tip-anchor-sprite.gif); +} +.x-menu { + background-color: #f0f0f0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/menu.gif); +} +.x-menu-floating { + border-color: #718bb7; +} +.x-menu-nosep { + background-image: none; +} +.x-menu-list-item { + font: normal 11px arial, tahoma, sans-serif; +} +.x-menu-item-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/menu-parent.gif); +} +.x-menu-sep { + background-color: #e0e0e0; + border-bottom-color: #fff; +} +a.x-menu-item { + color: #222; +} +.x-menu-item-active { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/item-over.gif); + background-color: #dbecf4; + border-color: #aaccf6; +} +.x-menu-item-active a.x-menu-item { + border-color: #aaccf6; +} +.x-menu-check-item .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/unchecked.gif); +} +.x-menu-item-checked .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/checked.gif); +} +.x-menu-item-checked .x-menu-group-item .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/group-checked.gif); +} +.x-menu-group-item .x-menu-item-icon { + background-image: none; +} +.x-menu-plain { + background-color: #f0f0f0 !important; + background-image: none; +} +.x-date-menu, .x-color-menu { + background-color: #fff !important; +} +.x-menu .x-date-picker { + border-color: #a3bad9; +} +.x-cycle-menu .x-menu-item-checked { + border-color: #a3bae9 !important; + background-color: #def8f6; +} +.x-menu-scroller-top { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-menu-scroller-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-box-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); +} +.x-box-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/l.gif); +} +.x-box-mc { + background-color: #eee; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); + font-family: "Myriad Pro", "Myriad Web", "Tahoma", "Helvetica", "Arial", sans-serif; + color: #393939; + font-size: 12px; +} +.x-box-mc h3 { + font-size: 14px; + font-weight: bold; +} +.x-box-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/r.gif); +} +.x-box-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); +} +.x-box-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-blue .x-box-bl, +.x-box-blue .x-box-br, +.x-box-blue .x-box-tl, +.x-box-blue .x-box-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners-blue.gif); +} +.x-box-blue .x-box-bc, .x-box-blue .x-box-mc, .x-box-blue .x-box-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb-blue.gif); +} +.x-box-blue .x-box-mc { + background-color: #c3daf9; +} +.x-box-blue .x-box-mc h3 { + color: #17385b; +} +.x-box-blue .x-box-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/l-blue.gif); +} +.x-box-blue .x-box-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/r-blue.gif); +} +.x-combo-list { + border-color: #98c0f4; + background-color: #ddecfe; + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-combo-list-inner { + background-color: #fff; +} +.x-combo-list-hd { + font: bold 11px tahoma, arial, helvetica, sans-serif; + color: #15428b; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/panel-title-light-bg.gif); + border-bottom-color: #98c0f4; +} +.x-resizable-pinned .x-combo-list-inner { + border-bottom-color: #98c0f4; +} +.x-combo-list-item { + border-color: #fff; +} +.x-combo-list .x-combo-selected { + border-color: #a3bae9 !important; + background-color: #dfe8f6; +} +.x-combo-list .x-toolbar { + border-top-color: #98c0f4; +} +.x-combo-list-small { + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-panel { + border-color: #99bbe8; +} +.x-panel-header { + color: #15428b; + font-weight: bold; + font-size: 11px; + font-family: tahoma, arial, verdana, sans-serif; + border-color: #99bbe8; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/white-top-bottom.gif); +} +.x-panel-body { + border-color: #99bbe8; + background-color: #fff; +} +.x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { + border-color: #99bbe8; +} +.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { + border-top-color: #99bbe8; +} +.x-panel-body-noheader, .x-panel-mc .x-panel-body { + border-top-color: #99bbe8; +} +.x-panel-tl .x-panel-header { + color: #15428b; + font: bold 11px tahoma, arial, verdana, sans-serif; +} +.x-panel-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/top-bottom.gif); +} +.x-panel-tl, +.x-panel-tr, +.x-panel-bl, +.x-panel-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/corners-sprite.gif); + border-bottom-color: #99bbe8; +} +.x-panel-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/top-bottom.gif); +} +.x-panel-mc { + font: normal 11px tahoma, arial, helvetica, sans-serif; + background-color: #dfe8f6; +} +.x-panel-ml { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/left-right.gif); +} +.x-panel-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/left-right.gif); +} +.x-tool { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/tool-sprites.gif); +} +.x-panel-ghost { + background-color: #cbddf3; +} +.x-panel-ghost ul { + border-color: #99bbe8; +} +.x-panel-dd-spacer { + border-color: #99bbe8; +} +.x-panel-fbar td, +.x-panel-fbar span, +.x-panel-fbar input, +.x-panel-fbar div, +.x-panel-fbar select, +.x-panel-fbar label { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-window-proxy { + background-color: #c7dffc; + border-color: #99bbe8; +} +.x-window-tl .x-window-header { + color: #15428b; + font: bold 11px tahoma, arial, verdana, sans-serif; +} +.x-window-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/top-bottom.png); +} +.x-window-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/left-corners.png); +} +.x-window-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/right-corners.png); +} +.x-window-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/top-bottom.png); +} +.x-window-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/left-corners.png); +} +.x-window-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/right-corners.png); +} +.x-window-mc { + border-color: #99bbe8; + font: normal 11px tahoma, arial, helvetica, sans-serif; + background-color: #dfe8f6; +} +.x-window-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/left-right.png); +} +.x-window-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/left-right.png); +} +.x-window-maximized .x-window-tc { + background-color: #fff; +} +.x-window-bbar .x-toolbar { + border-top-color: #99bbe8; +} +.x-panel-ghost .x-window-tl { + border-bottom-color: #99bbe8; +} +.x-panel-collapsed .x-window-tl { + border-bottom-color: #84a0c4; +} +.x-dlg-mask { + background-color: #ccc; +} +.x-window-plain .x-window-mc { + background-color: #ccd9e8; + border-color: #a3bae9 #dfe8f6 #dfe8f6 #a3bae9; +} +.x-window-plain .x-window-body { + border-color: #dfe8f6 #a3bae9 #a3bae9 #dfe8f6; +} +body.x-body-masked .x-window-plain .x-window-mc { + background-color: #ccd9e8; +} +.x-html-editor-wrap { + border-color: #a9bfd3; + background-color: #fff; +} +.x-html-editor-tb .x-btn-text { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-panel-noborder .x-panel-header-noborder { + border-bottom-color: #99bbe8; +} +.x-panel-noborder .x-panel-tbar-noborder .x-toolbar { + border-bottom-color: #99bbe8; +} +.x-panel-noborder .x-panel-bbar-noborder .x-toolbar { + border-top-color: #99bbe8; +} +.x-tab-panel-bbar-noborder .x-toolbar { + border-top-color: #99bbe8; +} +.x-tab-panel-tbar-noborder .x-toolbar { + border-bottom-color: #99bbe8; +} +.x-border-layout-ct { + background-color: #dfe8f6; +} +.x-accordion-hd { + color: #222; + font-weight: normal; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/panel/light-hd.gif); +} +.x-layout-collapsed { + background-color: #d2e0f2; + border-color: #98c0f4; +} +.x-layout-collapsed-over { + background-color: #d9e8fb; +} +.x-layout-split-west .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-left.gif); +} +.x-layout-split-east .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-right.gif); +} +.x-layout-split-north .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-layout-split-south .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-layout-cmini-west .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-right.gif); +} +.x-layout-cmini-east .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-left.gif); +} +.x-layout-cmini-north .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-layout-cmini-south .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-progress-wrap { + border-color: #6593cf; +} +.x-progress-inner { + background-color: #e0e8f3; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/qtip/bg.gif); +} +.x-progress-bar { + background-color: #9cbfee; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/progress/progress-bg.gif); + border-top-color: #d1e4fd; + border-bottom-color: #7fa9e4; + border-right-color: #7fa9e4; +} +.x-progress-text { + font-size: 11px; + font-weight: bold; + color: #fff; +} +.x-progress-text-back { + color: #396095; +} +.x-list-header { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-hrow.gif); +} +.x-list-header-inner div em { + border-left-color: #ddd; + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-list-body dt em { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-list-over { + background-color: #eee; +} +.x-list-selected { + background-color: #dfe8f6; +} +.x-list-resizer { + border-left-color: #555; + border-right-color: #555; +} +.x-list-header-inner em.sort-asc, .x-list-header-inner em.sort-desc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/sort-hd.gif); + border-color: #99bbe8; +} +.x-slider-horz, .x-slider-horz .x-slider-end, .x-slider-horz .x-slider-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-bg.png); +} +.x-slider-horz .x-slider-thumb { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-thumb.png); +} +.x-slider-vert, .x-slider-vert .x-slider-end, .x-slider-vert .x-slider-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-v-bg.png); +} +.x-slider-vert .x-slider-thumb { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-v-thumb.png); +} +.x-window-dlg .ext-mb-text, .x-window-dlg .x-window-header-text { + font-size: 12px; +} +.x-window-dlg .ext-mb-textarea { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-window-dlg .x-msg-box-wait { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-window-dlg .ext-mb-info { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/icon-info.gif); +} +.x-window-dlg .ext-mb-warning { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/icon-warning.gif); +} +.x-window-dlg .ext-mb-question { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/icon-question.gif); +} +.x-window-dlg .ext-mb-error { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/window/icon-error.gif); +} +.ext-el-mask { + background-color: #ccc; +} +.ext-el-mask-msg { + border-color: #999; + background-color: #ddd; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif); + background-position: 0 -1px; +} +.ext-el-mask-msg div { + background-color: #eee; + border-color: #d0d0d0; + color: #222; + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-mask-loading div { + background-color: #fbfbfb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-item-disabled { + color: gray; +} +.x-item-disabled * { + color: gray !important; +} +.x-splitbar-proxy { + background-color: #aaa; +} +.x-color-palette a { + border-color: #fff; +} +.x-color-palette a:hover, .x-color-palette a.x-color-palette-sel { + border-color: #CFCFCF; + background-color: #eaeaea; +} +.x-color-palette em:hover, .x-color-palette span:hover { + background-color: #eaeaea; +} +.x-color-palette em { + border-color: #aca899; +} +.x-ie-shadow { + background-color: #777; +} +.x-shadow .xsmc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow-c.png); +} +.x-shadow .xsml, .x-shadow .xsmr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow-lr.png); +} +.x-shadow .xstl, .x-shadow .xstc, .x-shadow .xstr, .x-shadow .xsbl, .x-shadow .xsbc, .x-shadow .xsbr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shadow.png); +} +.loading-indicator { + font-size: 11px; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-spotlight { + background-color: #ccc; +} +.x-tab-panel-header, .x-tab-panel-footer { + background-color: #eaeaea; + border-color: #d0d0d0; + overflow: hidden; + zoom: 1; +} +.x-tab-panel-header, .x-tab-panel-footer { + border-color: #d0d0d0; +} +ul.x-tab-strip-top { + background-color: #dbdbdb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-strip-bg.gif); + border-bottom-color: #d0d0d0; +} +ul.x-tab-strip-bottom { + background-color: #dbdbdb; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-strip-btm-bg.gif); + border-top-color: #d0d0d0; +} +.x-tab-panel-header-plain .x-tab-strip-spacer, +.x-tab-panel-footer-plain .x-tab-strip-spacer { + border-color: #d0d0d0; + background-color: #eaeaea; +} +.x-tab-strip span.x-tab-strip-text { + font: normal 11px tahoma,arial,helvetica; + color: #333; +} +.x-tab-strip-over span.x-tab-strip-text { + color: #111; +} +.x-tab-strip-active span.x-tab-strip-text { + color: #333; + font-weight: bold; +} +.x-tab-strip-disabled .x-tabs-text { + color: #aaaaaa; +} +.x-tab-strip-top .x-tab-right, .x-tab-strip-top .x-tab-left, .x-tab-strip-top .x-tab-strip-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tabs-sprite.gif); +} +.x-tab-strip-bottom .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-inactive-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-inactive-left-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-over .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-over-left-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-over .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-over-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-right-bg.gif); +} +.x-tab-strip-bottom .x-tab-strip-active .x-tab-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-btm-left-bg.gif); +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-close.gif); +} +.x-tab-strip .x-tab-strip-closable a.x-tab-strip-close:hover { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/tab-close.gif); +} +.x-tab-panel-body { + border-color: #d0d0d0; + background-color: #fff; +} +.x-tab-panel-body-top { + border-top: 0 none; +} +.x-tab-panel-body-bottom { + border-bottom: 0 none; +} +.x-tab-scroller-left { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/scroll-left.gif); + border-bottom-color: #d0d0d0; +} +.x-tab-scroller-left-over { + background-position: 0 0; +} +.x-tab-scroller-left-disabled { + background-position: -18px 0; + opacity: .5; + -moz-opacity: .5; + filter: alpha(opacity=50); + cursor: default; +} +.x-tab-scroller-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tabs/scroll-right.gif); + border-bottom-color: #d0d0d0; +} +.x-tab-panel-bbar .x-toolbar, .x-tab-panel-tbar .x-toolbar { + border-color: #d0d0d0; +} +.x-form-field { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-text, textarea.x-form-field { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/text-bg.gif); + border-color: #C1C1C1; +} +.x-form-select-one { + background-color: #fff; + border-color: #C1C1C1; +} +.x-form-check-group-label { + border-bottom: 1px solid #d0d0d0; + color: #333; +} +.x-editor .x-form-check-wrap { + background-color: #fff; +} +.x-form-field-wrap .x-form-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/form/trigger.gif); + border-bottom-color: #b5b8c8; +} +.x-form-field-wrap .x-form-date-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/form/date-trigger.gif); +} +.x-form-field-wrap .x-form-clear-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/form/clear-trigger.gif); +} +.x-form-field-wrap .x-form-search-trigger { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/form/search-trigger.gif); +} +.x-trigger-wrap-focus .x-form-trigger { + border-bottom-color: #777777; +} +.x-item-disabled .x-form-trigger-over { + border-bottom-color: #b5b8c8; +} +.x-item-disabled .x-form-trigger-click { + border-bottom-color: #b5b8c8; +} +.x-form-focus, textarea.x-form-focus { + border-color: #777777; +} +.x-form-invalid, textarea.x-form-invalid { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif); + border-color: #c30; +} +.ext-webkit .x-form-invalid { + background-color: #fee; + border-color: #ff7870; +} +.x-form-inner-invalid, textarea.x-form-inner-invalid { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/invalid_line.gif); +} +.x-form-grow-sizer { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-item { + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-form-invalid-msg { + color: #c0272b; + font: normal 11px tahoma, arial, helvetica, sans-serif; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/warning.gif); +} +.x-form-empty-field { + color: gray; +} +.x-small-editor .x-form-field { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.ext-webkit .x-small-editor .x-form-field { + font: normal 12px arial, tahoma, helvetica, sans-serif; +} +.x-form-invalid-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/exclamation.gif); +} +.x-fieldset { + border-color: #CCCCCC; +} +.x-fieldset legend { + font: bold 11px tahoma, arial, helvetica, sans-serif; + color: #777777; +} +.x-btn { + font: normal 11px tahoma, verdana, helvetica; +} +.x-btn button { + font: normal 11px arial,tahoma,verdana,helvetica; + color: #333; +} +.x-btn em { + font-style: normal; + font-weight: normal; +} +.x-btn-tl, .x-btn-tr, .x-btn-tc, .x-btn-ml, .x-btn-mr, .x-btn-mc, .x-btn-bl, .x-btn-br, .x-btn-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/btn.gif); +} +.x-btn-click .x-btn-text, .x-btn-menu-active .x-btn-text, .x-btn-pressed .x-btn-text { + color: #000; +} +.x-btn-disabled * { + color: gray !important; +} +.x-btn-mc em.x-btn-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/arrow.gif); +} +.x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow.gif); +} +.x-btn-over .x-btn-mc em.x-btn-split, .x-btn-click .x-btn-mc em.x-btn-split, .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-btn-pressed .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-o.gif); +} +.x-btn-mc em.x-btn-arrow-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b-noline.gif); +} +.x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b.gif); +} +.x-btn-over .x-btn-mc em.x-btn-split-bottom, .x-btn-click .x-btn-mc em.x-btn-split-bottom, .x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, .x-btn-pressed .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-bo.gif); +} +.x-btn-group-header { + color: #666; +} +.x-btn-group-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-tb.gif); +} +.x-btn-group-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-cs.gif); +} +.x-btn-group-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-cs.gif); +} +.x-btn-group-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-tb.gif); +} +.x-btn-group-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-cs.gif); +} +.x-btn-group-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-cs.gif); +} +.x-btn-group-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-lr.gif); +} +.x-btn-group-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-lr.gif); +} +.x-btn-group-notitle .x-btn-group-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/group-tb.gif); +} +.x-toolbar { + border-color: #d0d0d0; + background-color: #f0f0f0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/toolbar/bg.gif); +} +.x-toolbar td, .x-toolbar span, .x-toolbar input, .x-toolbar div, .x-toolbar select, .x-toolbar label { + font: normal 11px arial,tahoma, helvetica, sans-serif; +} +.x-toolbar .x-item-disabled { + color: gray; +} +.x-toolbar .x-item-disabled * { + color: gray; +} +.x-toolbar .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-noline.gif); +} +.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split, +.x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-o.gif); +} +.x-toolbar .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/button/s-arrow-b-noline.gif); +} +.x-toolbar .x-btn-over .x-btn-mc em.x-btn-split-bottom, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split-bottom, +.x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/button/s-arrow-bo.gif); +} +.x-toolbar .xtb-sep { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-split.gif); +} +.x-tbar-page-first { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/page-first.gif) !important; +} +.x-tbar-loading { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/refresh.gif) !important; +} +.x-tbar-page-last { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/page-last.gif) !important; +} +.x-tbar-page-next { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/page-next.gif) !important; +} +.x-tbar-page-prev { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/page-prev.gif) !important; +} +.x-item-disabled .x-tbar-loading { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif) !important; +} +.x-item-disabled .x-tbar-page-first { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-first-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-last { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-last-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-next { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-next-disabled.gif) !important; +} +.x-item-disabled .x-tbar-page-prev { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/page-prev-disabled.gif) !important; +} +.x-paging-info { + color: #444; +} +.x-toolbar-more-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/toolbar/more.gif) !important; +} +.x-resizable-handle { + background-color: #fff; +} +.x-resizable-over .x-resizable-handle-east, .x-resizable-pinned .x-resizable-handle-east, +.x-resizable-over .x-resizable-handle-west, .x-resizable-pinned .x-resizable-handle-west { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/e-handle.gif); +} +.x-resizable-over .x-resizable-handle-south, .x-resizable-pinned .x-resizable-handle-south, +.x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/s-handle.gif); +} +.x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/s-handle.gif); +} +.x-resizable-over .x-resizable-handle-southeast, .x-resizable-pinned .x-resizable-handle-southeast { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/se-handle.gif); +} +.x-resizable-over .x-resizable-handle-northwest, .x-resizable-pinned .x-resizable-handle-northwest { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/nw-handle.gif); +} +.x-resizable-over .x-resizable-handle-northeast, .x-resizable-pinned .x-resizable-handle-northeast { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/ne-handle.gif); +} +.x-resizable-over .x-resizable-handle-southwest, .x-resizable-pinned .x-resizable-handle-southwest { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/sizer/sw-handle.gif); +} +.x-resizable-proxy { + border-color: #565656; +} +.x-resizable-overlay { + background-color: #fff; +} +.x-grid3 { + background-color: #fff; +} +.x-grid-panel .x-panel-mc .x-panel-body { + border-color: #d0d0d0; +} +.x-grid3-hd-row td, .x-grid3-row td, .x-grid3-summary-row td { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-grid3-hd-row td { + border-left-color: #eee; + border-right-color: #d0d0d0; +} +.x-grid-row-loading { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/shared/loading-balls.gif); +} +.x-grid3-row { + border-color: #ededed; + border-top-color: #fff; +} +.x-grid3-row-alt { + background-color: #fafafa; +} +.x-grid3-row-over { + border-color: #ddd; + background-color: #efefef; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/row-over.gif); +} +.x-grid3-resize-proxy { + background-color: #777; +} +.x-grid3-resize-marker { + background-color: #777; +} +.x-grid3-header { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow2.gif); +} +.x-grid3-header-pop { + border-left-color: #d0d0d0; +} +.x-grid3-header-pop-inner { + border-left-color: #eee; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hd-pop.gif); +} +td.x-grid3-hd-over, td.sort-desc, td.sort-asc, td.x-grid3-hd-menu-open { + border-left-color: #ACACAC; + border-right-color: #ACACAC; +} +td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow-over2.gif); +} +.sort-asc .x-grid3-sort-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/sort_asc.gif); +} +.sort-desc .x-grid3-sort-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/sort_desc.gif); +} +.x-grid3-cell-text, .x-grid3-hd-text { + color: #000; +} +.x-grid3-split { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-split.gif); +} +.x-grid3-hd-text { + color: #333; +} +.x-dd-drag-proxy .x-grid3-hd-inner { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow-over2.gif); + border-color: #ACACAC; +} +.col-move-top { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/col-move-top.gif); +} +.col-move-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/col-move-bottom.gif); +} +.x-grid3-row-selected { + background-color: #CCCCCC !important; + background-image: none; + border-color: #ACACAC; +} +.x-grid3-cell-selected { + background-color: #CBCBCB !important; + color: #000; +} +.x-grid3-cell-selected span { + color: #000 !important; +} +.x-grid3-cell-selected .x-grid3-cell-text { + color: #000; +} +.x-grid3-locked td.x-grid3-row-marker, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker { + background-color: #ebeadb !important; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid-hrow.gif) !important; + color: #000; + border-top-color: #fff; + border-right-color: #6fa0df !important; +} +.x-grid3-locked td.x-grid3-row-marker div, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker div { + color: #333 !important; +} +.x-grid3-dirty-cell { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/dirty.gif); +} +.x-grid3-topbar, .x-grid3-bottombar { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-grid3-bottombar .x-toolbar { + border-top-color: #a9bfd3; +} +.x-props-grid .x-grid3-td-name .x-grid3-cell-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif) !important; + color: #000 !important; +} +.x-props-grid .x-grid3-body .x-grid3-td-name { + background-color: #fff !important; + border-right-color: #eee; +} +.xg-hmenu-sort-asc .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-asc.gif); +} +.xg-hmenu-sort-desc .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-desc.gif); +} +.xg-hmenu-lock .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-lock.gif); +} +.xg-hmenu-unlock .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/hmenu-unlock.gif); +} +.x-grid3-hd-btn { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hd-btn.gif); +} +.x-grid3-body .x-grid3-td-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-row-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/row-expand-sprite.gif); +} +.x-grid3-body .x-grid3-td-checker { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-row-checker, .x-grid3-hd-checker { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/row-check-sprite.gif); +} +.x-grid3-body .x-grid3-td-numberer { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-body .x-grid3-td-numberer .x-grid3-cell-inner { + color: #444; +} +.x-grid3-body .x-grid3-td-row-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/grid3-special-col-bg.gif); +} +.x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, +.x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, +.x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-special-col-sel-bg.gif); +} +.x-grid3-check-col { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/unchecked.gif); +} +.x-grid3-check-col-on { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/checked.gif); +} +.x-grid-group, .x-grid-group-body, .x-grid-group-hd { + zoom: 1; +} +.x-grid-group-hd { + border-bottom-color: #d0d0d0; +} +.x-grid-group-hd div.x-grid-group-title { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/group-collapse.gif); + color: #5F5F5F; + font: bold 11px tahoma, arial, helvetica, sans-serif; +} +.x-grid-group-collapsed .x-grid-group-hd div.x-grid-group-title { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/group-expand.gif); +} +.x-group-by-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-by.gif); +} +.x-cols-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/columns.gif); +} +.x-show-groups-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/group-by.gif); +} +.x-grid-empty { + color: gray; + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-grid-with-col-lines .x-grid3-row td.x-grid3-cell { + border-right-color: #ededed; +} +.x-grid-with-col-lines .x-grid3-row { + border-top-color: #ededed; +} +.x-grid-with-col-lines .x-grid3-row-selected { + border-top-color: #B9B9B9; +} +.x-dd-drag-ghost { + color: #000; + font: normal 11px arial, helvetica, sans-serif; + border-color: #ddd #bbb #bbb #ddd; + background-color: #fff; +} +.x-dd-drop-nodrop .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-no.gif); +} +.x-dd-drop-ok .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-yes.gif); +} +.x-dd-drop-ok-add .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/dd/drop-add.gif); +} +.x-view-selector { + background-color: #D6D6D6; + border-color: #888888; +} +.x-tree-node-expanded .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/folder-open.gif); +} +.x-tree-node-leaf .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/leaf.gif); +} +.x-tree-node-collapsed .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/folder.gif); +} +.x-tree-node-loading .x-tree-node-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/loading.gif) !important; +} +.x-tree-node .x-tree-node-inline-icon { + background-image: none; +} +.x-tree-node-loading a span { + font-style: italic; + color: #444444; +} +.ext-ie .x-tree-node-el input { + width: 15px; + height: 15px; +} +.x-tree-lines .x-tree-elbow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow.gif); +} +.x-tree-lines .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus.gif); +} +.x-tree-lines .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus.gif); +} +.x-tree-lines .x-tree-elbow-end { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-end.gif); +} +.x-tree-lines .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-plus.gif); +} +.x-tree-lines .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-minus.gif); +} +.x-tree-lines .x-tree-elbow-line { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-line.gif); +} +.x-tree-no-lines .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-plus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/elbow-minus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-plus-nl.gif); +} +.x-tree-no-lines .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/elbow-end-minus-nl.gif); +} +.x-tree-arrows .x-tree-elbow-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-end-plus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/arrows.gif); +} +.x-tree-arrows .x-tree-elbow-end-minus { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/tree/arrows.gif); +} +.x-tree-node { + color: #000; + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-tree-node a, .x-dd-drag-ghost a { + color: #000; +} +.x-tree-node a span, .x-dd-drag-ghost a span { + color: #000; +} +.x-tree-node .x-tree-node-disabled a span { + color: gray !important; +} +.x-tree-node div.x-tree-drag-insert-below { + border-bottom-color: #36c; +} +.x-tree-node div.x-tree-drag-insert-above { + border-top-color: #36c; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below a { + border-bottom-color: #36c; +} +.x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above a { + border-top-color: #36c; +} +.x-tree-node .x-tree-drag-append a span { + background-color: #ddd; + border-color: gray; +} +.x-tree-node .x-tree-node-over { + background-color: #eee; +} +.x-tree-node .x-tree-selected { + background-color: #ddd; +} +.x-tree-drop-ok-append .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-add.gif); +} +.x-tree-drop-ok-above .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-over.gif); +} +.x-tree-drop-ok-below .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-under.gif); +} +.x-tree-drop-ok-between .x-dd-drop-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/tree/drop-between.gif); +} +.x-date-picker { + border-color: #585858; + background-color: #fff; +} +.x-date-middle, .x-date-left, .x-date-right { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/shared/hd-sprite.gif); + color: #fff; + font: bold 11px "sans serif", tahoma, verdana, helvetica; +} +.x-date-middle .x-btn .x-btn-text { + color: #fff; +} +.x-date-middle .x-btn-mc em.x-btn-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/toolbar/btn-arrow-light.gif); +} +.x-date-right a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/shared/right-btn.gif); +} +.x-date-left a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/shared/left-btn.gif); +} +.x-date-inner th { + background-color: #D8D8D8; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif); + border-bottom-color: #AFAFAF; + font: normal 10px arial, helvetica,tahoma,sans-serif; + color: #595959; +} +.x-date-inner td { + border-color: #fff; +} +.x-date-inner a { + font: normal 11px arial, helvetica,tahoma,sans-serif; + color: #000; +} +.x-date-inner .x-date-active { + color: #000; +} +.x-date-inner .x-date-selected a { + background-image: none; + background-color: #D8D8D8; + border-color: #DCDCDC; +} +.x-date-inner .x-date-today a { + border-color: darkred; +} +.x-date-inner .x-date-selected span { + font-weight: bold; +} +.x-date-inner .x-date-prevday a, .x-date-inner .x-date-nextday a { + color: #aaa; +} +.x-date-bottom { + border-top-color: #AFAFAF; + background-color: #D8D8D8; + background: #d8d8d8 url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif) 0 -2px; +} +.x-date-inner a:hover, .x-date-inner .x-date-disabled a:hover { + color: #000; + background-color: #D8D8D8; +} +.x-date-inner .x-date-disabled a { + background-color: #eee; + color: #bbb; +} +.x-date-mmenu { + background-color: #eee !important; +} +.x-date-mmenu .x-menu-item { + font-size: 10px; + color: #000; +} +.x-date-mp { + background-color: #fff; +} +.x-date-mp td { + font: normal 11px arial, helvetica,tahoma,sans-serif; +} +.x-date-mp-btns button { + background-color: #4E565F; + color: #fff; + border-color: #C0C0C0 #434343 #434343 #C0C0C0; + font: normal 11px arial, helvetica,tahoma,sans-serif; +} +.x-date-mp-btns { + background-color: #D8D8D8; + background: #d8d8d8 url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif) 0 -2px; +} +.x-date-mp-btns td { + border-top-color: #AFAFAF; +} +td.x-date-mp-month a, td.x-date-mp-year a { + color: #333; +} +td.x-date-mp-month a:hover, td.x-date-mp-year a:hover { + color: #333; + background-color: #FDFDFD; +} +td.x-date-mp-sel a { + background-color: #D8D8D8; + background: #d8d8d8 url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif) 0 -2px; + border-color: #DCDCDC; +} +.x-date-mp-ybtn a { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/tool-sprites.gif); +} +td.x-date-mp-sep { + border-right-color: #D7D7D7; +} +.x-tip .x-tip-close { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/qtip/close.gif); +} +.x-tip .x-tip-tc, .x-tip .x-tip-tl, .x-tip .x-tip-tr, .x-tip .x-tip-bc, .x-tip .x-tip-bl, .x-tip .x-tip-br, .x-tip .x-tip-ml, .x-tip .x-tip-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/qtip/tip-sprite.gif); +} +.x-tip .x-tip-mc { + font: normal 11px tahoma,arial,helvetica,sans-serif; +} +.x-tip .x-tip-ml { + background-color: #fff; +} +.x-tip .x-tip-header-text { + font: bold 11px tahoma,arial,helvetica,sans-serif; + color: #444; +} +.x-tip .x-tip-body { + font: normal 11px tahoma,arial,helvetica,sans-serif; + color: #444; +} +.x-form-invalid-tip .x-tip-tc, .x-form-invalid-tip .x-tip-tl, .x-form-invalid-tip .x-tip-tr, .x-form-invalid-tip .x-tip-bc, +.x-form-invalid-tip .x-tip-bl, .x-form-invalid-tip .x-tip-br, .x-form-invalid-tip .x-tip-ml, .x-form-invalid-tip .x-tip-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/error-tip-corners.gif); +} +.x-form-invalid-tip .x-tip-body { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/form/exclamation.gif); +} +.x-tip-anchor { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/qtip/tip-anchor-sprite.gif); +} +.x-menu { + background-color: #f0f0f0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/menu.gif); +} +.x-menu-floating { + border-color: #7D7D7D; +} +.x-menu-nosep { + background-image: none; +} +.x-menu-list-item { + font: normal 11px arial,tahoma,sans-serif; +} +.x-menu-item-arrow { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/menu/menu-parent.gif); +} +.x-menu-sep { + background-color: #e0e0e0; + border-bottom-color: #fff; +} +a.x-menu-item { + color: #222; +} +.x-menu-item-active { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/menu/item-over.gif); + background-color: #f1f1f1; + border-color: #ACACAC; +} +.x-menu-item-active a.x-menu-item { + border-color: #ACACAC; +} +.x-menu-check-item .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/unchecked.gif); +} +.x-menu-item-checked .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/menu/checked.gif); +} +.x-menu-item-checked .x-menu-group-item .x-menu-item-icon { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/menu/group-checked.gif); +} +.x-menu-group-item .x-menu-item-icon { + background-image: none; +} +.x-menu-plain { + background-color: #fff !important; +} +.x-menu .x-date-picker { + border-color: #AFAFAF; +} +.x-cycle-menu .x-menu-item-checked { + border-color: #B9B9B9 !important; + background-color: #F1F1F1; +} +.x-menu-scroller-top { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-menu-scroller-bottom { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-box-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); +} +.x-box-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/l.gif); +} +.x-box-mc { + background-color: #eee; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); + font-family: "Myriad Pro","Myriad Web","Tahoma","Helvetica","Arial",sans-serif; + color: #393939; + font-size: 12px; +} +.x-box-mc h3 { + font-size: 14px; + font-weight: bold; +} +.x-box-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/r.gif); +} +.x-box-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb.gif); +} +.x-box-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners.gif); +} +.x-box-blue .x-box-bl, .x-box-blue .x-box-br, .x-box-blue .x-box-tl, .x-box-blue .x-box-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/corners-blue.gif); +} +.x-box-blue .x-box-bc, .x-box-blue .x-box-mc, .x-box-blue .x-box-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/tb-blue.gif); +} +.x-box-blue .x-box-mc { + background-color: #c3daf9; +} +.x-box-blue .x-box-mc h3 { + color: #17385b; +} +.x-box-blue .x-box-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/l-blue.gif); +} +.x-box-blue .x-box-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/box/r-blue.gif); +} +.x-combo-list { + border-color: #ccc; + background-color: #ddd; + font: normal 12px tahoma, arial, helvetica, sans-serif; +} +.x-combo-list-inner { + background-color: #fff; +} +.x-combo-list-hd { + font: bold 11px tahoma, arial, helvetica, sans-serif; + color: #333; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/panel-title-light-bg.gif); + border-bottom-color: #BCBCBC; +} +.x-resizable-pinned .x-combo-list-inner { + border-bottom-color: #BEBEBE; +} +.x-combo-list-item { + border-color: #fff; +} +.x-combo-list .x-combo-selected { + border-color: #777 !important; + background-color: #f0f0f0; +} +.x-combo-list .x-toolbar { + border-top-color: #BCBCBC; +} +.x-combo-list-small { + font: normal 11px tahoma, arial, helvetica, sans-serif; +} +.x-panel { + border-color: #d0d0d0; +} +.x-panel-header { + color: #333; + font-weight: bold; + font-size: 11px; + font-family: tahoma,arial,verdana,sans-serif; + border-color: #d0d0d0; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/white-top-bottom.gif); +} +.x-panel-body { + border-color: #d0d0d0; + background-color: #fff; +} +.x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { + border-color: #d0d0d0; +} +.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { + border-top-color: #d0d0d0; +} +.x-panel-body-noheader, .x-panel-mc .x-panel-body { + border-top-color: #d0d0d0; +} +.x-panel-tl .x-panel-header { + color: #333; + font: bold 11px tahoma,arial,verdana,sans-serif; +} +.x-panel-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/top-bottom.gif); +} +.x-panel-tl, .x-panel-tr, .x-panel-bl, .x-panel-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/corners-sprite.gif); + border-bottom-color: #d0d0d0; +} +.x-panel-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/top-bottom.gif); +} +.x-panel-mc { + font: normal 11px tahoma,arial,helvetica,sans-serif; + background-color: #f1f1f1; +} +.x-panel-ml { + background-color: #fff; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/left-right.gif); +} +.x-panel-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/left-right.gif); +} +.x-tool { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/tool-sprites.gif); +} +.x-panel-ghost { + background-color: #f2f2f2; +} +.x-panel-ghost ul { + border-color: #d0d0d0; +} +.x-panel-dd-spacer { + border-color: #d0d0d0; +} +.x-panel-fbar td, .x-panel-fbar span, .x-panel-fbar input, .x-panel-fbar div, .x-panel-fbar select, .x-panel-fbar label { + font: normal 11px arial,tahoma, helvetica, sans-serif; +} +.x-window-proxy { + background-color: #fcfcfc; + border-color: #d0d0d0; +} +.x-window-tl .x-window-header { + color: #555; + font: bold 11px tahoma,arial,verdana,sans-serif; +} +.x-window-tc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/top-bottom.png); +} +.x-window-tl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/left-corners.png); +} +.x-window-tr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/right-corners.png); +} +.x-window-bc { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/top-bottom.png); +} +.x-window-bl { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/left-corners.png); +} +.x-window-br { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/right-corners.png); +} +.x-window-mc { + border-color: #d0d0d0; + font: normal 11px tahoma,arial,helvetica,sans-serif; + background-color: #e8e8e8; +} +.x-window-ml { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/left-right.png); +} +.x-window-mr { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/left-right.png); +} +.x-window-maximized .x-window-tc { + background-color: #fff; +} +.x-window-bbar .x-toolbar { + border-top-color: #d0d0d0; +} +.x-panel-ghost .x-window-tl { + border-bottom-color: #d0d0d0; +} +.x-panel-collapsed .x-window-tl { + border-bottom-color: #d0d0d0; +} +.x-dlg-mask { + background-color: #ccc; +} +.x-window-plain .x-window-mc { + background-color: #E8E8E8; + border-color: #D0D0D0 #EEEEEE #EEEEEE #D0D0D0; +} +.x-window-plain .x-window-body { + border-color: #EEEEEE #D0D0D0 #D0D0D0 #EEEEEE; +} +body.x-body-masked .x-window-plain .x-window-mc { + background-color: #E4E4E4; +} +.x-html-editor-wrap { + border-color: #BCBCBC; + background-color: #fff; +} +.x-html-editor-tb .x-btn-text { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/editor/tb-sprite.gif); +} +.x-panel-noborder .x-panel-header-noborder { + border-bottom-color: #d0d0d0; +} +.x-panel-noborder .x-panel-tbar-noborder .x-toolbar { + border-bottom-color: #d0d0d0; +} +.x-panel-noborder .x-panel-bbar-noborder .x-toolbar { + border-top-color: #d0d0d0; +} +.x-tab-panel-bbar-noborder .x-toolbar { + border-top-color: #d0d0d0; +} +.x-tab-panel-tbar-noborder .x-toolbar { + border-bottom-color: #d0d0d0; +} +.x-border-layout-ct { + background-color: #f0f0f0; +} +.x-border-layout-ct { + background-color: #f0f0f0; +} +.x-accordion-hd { + color: #222; + font-weight: normal; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/panel/light-hd.gif); +} +.x-layout-collapsed { + background-color: #dfdfdf; + border-color: #d0d0d0; +} +.x-layout-collapsed-over { + background-color: #e7e7e7; +} +.x-layout-split-west .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-left.gif); +} +.x-layout-split-east .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-right.gif); +} +.x-layout-split-north .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-layout-split-south .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-layout-cmini-west .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-right.gif); +} +.x-layout-cmini-east .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-left.gif); +} +.x-layout-cmini-north .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-bottom.gif); +} +.x-layout-cmini-south .x-layout-mini { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/layout/mini-top.gif); +} +.x-progress-wrap { + border-color: #8E8E8E; +} +.x-progress-inner { + background-color: #E7E7E7; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/qtip/bg.gif); +} +.x-progress-bar { + background-color: #BCBCBC; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/progress/progress-bg.gif); + border-top-color: #E2E2E2; + border-bottom-color: #A4A4A4; + border-right-color: #A4A4A4; +} +.x-progress-text { + font-size: 11px; + font-weight: bold; + color: #fff; +} +.x-progress-text-back { + color: #5F5F5F; +} +.x-list-header { + background-color: #f9f9f9; + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/grid/grid3-hrow2.gif); +} +.x-list-header-inner div em { + border-left-color: #ddd; + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-list-body dt em { + font: normal 11px arial, tahoma, helvetica, sans-serif; +} +.x-list-over { + background-color: #eee; +} +.x-list-selected { + background-color: #f0f0f0; +} +.x-list-resizer { + border-left-color: #555; + border-right-color: #555; +} +.x-list-header-inner em.sort-asc, .x-list-header-inner em.sort-desc { + background-image: none; + border-color: #d0d0d0; +} +.x-slider-horz, .x-slider-horz .x-slider-end, .x-slider-horz .x-slider-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-bg.png); +} +.x-slider-horz .x-slider-thumb { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/slider/slider-thumb.png); +} +.x-slider-vert, .x-slider-vert .x-slider-end, .x-slider-vert .x-slider-inner { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/slider/slider-v-bg.png); +} +.x-slider-vert .x-slider-thumb { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/slider/slider-v-thumb.png); +} +.x-window-dlg .ext-mb-text, +.x-window-dlg .x-window-header-text { + font-size: 12px; +} +.x-window-dlg .ext-mb-textarea { + font: normal 12px tahoma,arial,helvetica,sans-serif; +} +.x-window-dlg .x-msg-box-wait { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/default/grid/loading.gif); +} +.x-window-dlg .ext-mb-info { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/icon-info.gif); +} +.x-window-dlg .ext-mb-warning { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/icon-warning.gif); +} +.x-window-dlg .ext-mb-question { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/icon-question.gif); +} +.x-window-dlg .ext-mb-error { + background-image: url(../lib/vendor/ext-3.2.1/resources/images/gray/window/icon-error.gif); +} +.aloha-floatingmenu { + position: absolute; +} +.aloha-floatingmenu.fixed { + position: fixed !important; +} +.aloha-floatingmenu .x-tab-panel-header { + border-width: 0px 0px 1px 0px !important; + background: none !important; +} +.aloha-floatingmenu .x-tab-panel-header .x-tab-strip-wrap, .aloha-floatingmenu ul.x-tab-strip-top { + background: none !important; +} +.x-tab-strip-wrap ul li a:hover { + border: none; + text-decoration:none; +} +.aloha-floatingmenu .x-tab-panel-header { + padding-bottom: 0px !important; +} +.aloha-floatingmenu:hover { + background-color: #E0E0E0; + -moz-border-radius-topleft: 3px; + -moz-border-radius-topright: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-top-right-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + background: url(../img/grabhandle.png) no-repeat scroll center 5px rgba(0, 0, 0, 0.4); +} +.aloha-floatingmenu:hover .aloha-floatingmenu-pin { + display: block; +} +.aloha-floatingmenu-pin { + background: url(../img/pin.png) no-repeat scroll 0 6px transparent; + cursor: pointer; + margin-left: 5px !important; + width: 16px; + position: absolute !important; + right: 10px; + display: none; +} +.aloha-floatingmenu-pinned { + background-position: -16px 6px; +} +#aloha-floatingmenu-shadow { + position: absolute; + top: -1000; + left: -1000; + display: none; + z-index: 8800; +} +#aloha-floatingmenu-shadow.fixed { + position: fixed !important; +} +.x-tree-root-ct { + padding: 0px; +} +.x-tree-node { + list-style: none; +} +.x-tree-node-ct { + padding: 0px; +} +.aloha-button a:focus { + outline: none; +} +button.aloha-button { + background: url(../img/base.png) no-repeat !important; +} +button.aloha-button-big { + background: url(../img/base-big.png) no-repeat !important; +} +button.aloha-button-b { + background-position: 0px 0px; +} +button.aloha-button-i { + background-position: -16px 0px !important; +} +button.aloha-button-u { + background-position: -32px 0px !important; +} +button.aloha-button-del { + background-position: -48px 0px !important; +} +button.aloha-button-sub { + background-position: -64px 0px !important; +} +button.aloha-button-sup { + background-position: -80px 0px !important; +} +button.aloha-button-ul { + background-position: -256px 0px !important; +} +button.aloha-button-ol { + background-position: -272px 0px !important; +} +button.aloha-button-indent-list { + background-image: url(../img/text_indent.png) !important; +} +button.aloha-button-outdent-list { + background-image: url(../img/text_indent_remove.png) !important; +} +button.aloha-button-a { + background-position: -288px 0px !important; +} +button.aloha-button-a-remove { + background-position: -304px 0px !important; +} +button.aloha-button-p { + background-position: 0px 0 !important; +} +button.aloha-button-p-de { + background-position: 0px -42px !important; +} +button.aloha-button-h1 { + background-position: -52px 0 !important; +} +button.aloha-button-h1-de { + background-position: -52px -42px !important; +} +button.aloha-button-h2 { + background-position: -104px 0 !important; +} +button.aloha-button-h2-de { + background-position: -104px -42px !important; +} +button.aloha-button-h3 { + background-position: -156px 0 !important; +} +button.aloha-button-h3-de { + background-position: -156px -42px !important; +} +button.aloha-button-h4 { + background-position: -208px 0 !important; +} +button.aloha-button-h4-de { + background-position: -208px -42px !important; +} +button.aloha-button-h5 { + background-position: -260px 0 !important; +} +button.aloha-button-h5-de { + background-position: -260px -42px !important; +} +button.aloha-button-h6 { + background-position: -312px 0 !important; +} +button.aloha-button-h6-de { + background-position: -312px -42px !important; +} +button.aloha-button-pre { + background-position: -364px 0 !important; +} +button.aloha-button-pre-de { + background-position: -364px -42px !important; +} +button.aloha-button-title { + background-position: -416px 0 !important; +} +button.aloha-button-title-de { + background-position: -416px -42px !important; +} +button.aloha-button-table { + background-position: -96px 0 !important; +} +button.aloha-button-addColumnLeft { + background-position: -112px 0 !important; +} +button.aloha-button-addColumnRight { + background-position: -128px 0 !important; +} +button.aloha-button-addRowBefore { + background-position: -144px 0 !important; +} +button.aloha-button-addRowAfter { + background-position: -160px 0 !important; +} +button.aloha-button-deleteRows { + background-position: -176px 0 !important; +} +button.aloha-button-deleteColumns { + background-position: -192px 0 !important; +} +button.aloha-button-addPerson { + background-position: -224px 0 !important; +} +button.aloha-button-addEvent { + background-position: -208px 0 !important; +} +button.aloha-button-abbr { + background-position: -336px 0px !important; +} +button.aloha-button-row-header { + background-position: -352px 0px !important; +} +button.aloha-button-col-header { + background-position: -368px 0px !important; +} +button.aloha-button-tree { + background-position: -0 0 !important; +} +div.aloha-button a:hover { + border: 1px solid #b2cbff; +} +.aloha-floatingmenu { + display: none; +} +.aloha-floatingmenu .pressed a { + border:1px solid #ccc; +} +html body #aloha-ribbon { + z-index:90000; + position:fixed; + top:0; + left:0; + width:100%; + padding-left:0; + padding-right:0; + display: none; +} +.x-menu-list-item { + text-align:left; +} +.aloha-shadow { + -moz-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); +} +ul.aloha-multisplit button.aloha-button { + background-image: url(../img/base-multi.png) !important; + background-repeat: no-repeat; + background-position: 0 0; + + width: 54px !important; + height: 44px !important; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +} +.aloha-multisplit { + float: left; + list-style: none; +} +ul.aloha-multisplit, div.aloha-multisplit-wrapper { + width: 232px; + height: 46px; + overflow: hidden; + margin: 0px; + padding: 0px; +} +div.aloha-multisplit-wrapper { + width: 248px; +} +ul.aloha-multisplit li { + float: left; + padding: 0px 1px; + margin: 0px; +} +ul.aloha-multisplit button.aloha-multisplit-wide { + font: 11px tahoma,arial,helvetica; + height: 18px !important; + width: 234px !important; + border: 0; + border-top: 1px solid #cccccc; + cursor: pointer; + background-color: white; + background-repeat: no-repeat; + background-position: 6px 1px !important; + text-align: left; + margin-left: -2px; + padding-left: 26px; +} +button.aloha-multisplit-toggle { + float: right; + margin: 0; + padding: 0; + width: 15px; + height: 12px; + margin-top: 32px; + cursor: pointer; + border: 0; +} +button.aloha-multisplit-toggle-open { + background-image: url(../img/multisplit-open.gif); +} +button.aloha-multisplit-toggle-close { + background-image: url(../img/multisplit-close.gif); +} +ul.aloha-multisplit button { + border: 1px solid #cccccc; + margin: 1px; + cursor: pointer; +} +ul.aloha-multisplit button:hover { + border: 1px solid #666666; +} +ul.aloha-multisplit button.aloha-multisplit-wide:hover { + border: 0; + border-top: 1px solid #cccccc; +} +ul.aloha-multisplit .aloha-multisplit-activeitem button { + border: 2px solid #3B73D7; +} +ul.aloha-multisplit-expanded { + position: absolute; + top: 0px; + left: 0px; + z-index: 20000; + background-color: white; + border: 1px solid #afafaf; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +} +ul.aloha-multisplit button.aloha-button-removeFormat { + background-image: url(../img/removeformat.png) !important; +} +.x-combo-list { + text-align: left; +} +.x-combo-list-inner { + padding: 3px; +} +.x-combo-list-inner .loading-indicator { + margin: 0; +} +.x-combo-selected { + color: #fff !important; + background-color: #3B73D7 !important; +} +.x-form-field.x-form-text { + color: #333 !important; + padding: 3px; +} +.x-form-field.x-form-text::selection { + color: #fff; + background: #3B73D7; +} +.x-form-field.x-form-text::-moz-selection { + color: #fff; + background: #3B73D7; +} +.x-form-field.x-form-text::-webkit-selection { + color: #fff; + background: #3B73D7; +} +.aloha-editable { + min-height: 1.2em; + outline: none; +} +.aloha-editable ::selection, +.aloha-editable ::-moz-selection { + background: #80B5F2; + color: white; +} +.aloha-editable-zerowidthfix { + padding: 0px 5px 0px 5px !important; +} +.aloha-logo { + width:37px !important; + height:25px !important; + background-image: url(../img/gentics-logo.png) !important; +} +.aloha-maximize { + background-image: url(../img/gentics-logo.png) !important; +} +.aloha-fade-out { + background-image: url(../img/fade-out.png) !important; + width:20px !important; + height:20px !important; +} +.aloha-fade-in { + background-image: url(../img/fade-in.png) !important; + width:20px !important; + height:20px !important; +} +.aloha-maximize { + width:20px !important; + height:20px !important; + background-image: url(../img/maximize.png) !important; +} +.aloha-textarea { + overflow: hidden; + border:1px solid #ccc; + padding:6px; + overflow:auto; +} +.aloha-sidebar-bar { + z-index: 999999999; + position: fixed; + top: 0; + left: 0; + text-align: left; + font-family: Arial, sans-serif; + font-size: 12px; + border-right: 1px solid #888; + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + +} +.aloha-sidebar-bar.aloha-sidebar-right { + left: auto; + right: 0; + border-right-width: 0; + border-left: 1px solid #888; +} +.aloha-sidebar-inner { + position: relative; + background-color: #ccc; + background-image: -webkit-radial-gradient( + rgba(0, 0, 0, 0.0) 20%, + rgba(0, 0, 0, 0.2) 80%, + rgba(0, 0, 0, 0.3) 100% + ); + background-image: -moz-radial-gradient( + rgba(0, 0, 0, 0.0) 20%, + rgba(0, 0, 0, 0.2) 80%, + rgba(0, 0, 0, 0.3) 100% + ); +} +.aloha-sidebar-panels { + margin: 0; + padding: 15px 0; +} +.aloha-sidebar-panels li { + overflow: hidden; + margin: 0; + padding: 0 15px; +} +.aloha-sidebar-panel-top { + -webkit-border-top-left-radius: 5px; + -webkit-border-top-right-radius: 5px; + -moz-border-radius-topleft: 5px; + -moz-border-radius-topright: 5px; +} +.aloha-sidebar-panel-content.aloha-sidebar-panel-bottom { + padding-bottom: 0; + -webkit-border-bottom-left-radius: 5px; + -webkit-border-bottom-right-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -moz-border-radius-bottomright: 5px; + border-bottom-width: 1px; +} +.aloha-sidebar-panel-title { + position: relative; + overflow: hidden; + padding: 8px 0 0 8px; + border: 1px solid rgba(0, 0, 0, 0.3); + border-bottom-width: 0; + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + color: #ccc; + cursor: pointer; + font-size: 13px; + font-weight: bold; + line-height: 1.5em; + text-shadow: 0 0 6px #23262b; +} +.aloha-sidebar-panel-title:hover { + color: #fff; +} +.aloha-sidebar-panel-title-arrow { + position: absolute; + top: 8px; + left: 8px; + width: 16px; + height: 16px; + background: url(../img/arrow.png) no-repeat center center; + opacity: 0.3; + +} +.aloha-sidebar-panel-title:hover .aloha-sidebar-panel-title-arrow { + opacity: 0.9; + +} +.aloha-sidebar-panel-title .aloha-sidebar-panel-title-arrow.aloha-sidebar-panel-title-arrow-down { + background-image: url(../img/arrow-down.png); +} +.aloha-sidebar-panel-title-text { + margin-left: 24px; + white-space: nowrap; +} +.aloha-sidebar-panel-content { + overflow: hidden; + height: 5px; + background: #303539; +} +.aloha-sidebar-panel-content-inner { + margin: 5px 0 0; + padding: 0; + color: #888; + background: #fff; + background-image: -webkit-radial-gradient( + rgba(0, 0, 0, 0.0) 50%, + rgba(0, 0, 0, 0.1) 90%, + rgba(0, 0, 0, 0.2) 100% + ); + background-image: -moz-radial-gradient( + rgba(0, 0, 0, 0.0) 50%, + rgba(0, 0, 0, 0.1) 90%, + rgba(0, 0, 0, 0.2) 100% + ); +} +.aloha-sidebar-panel-content input { + margin: 5px; + padding: 5px; +} +.aloha-sidebar-handle { + position: absolute; + top: 30px; + right: -30px; + width: 40px; + height: 30px; + overflow: hidden; + + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + + cursor: pointer; + + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + box-shadow: 0px 0px 10px rgba(0, 0, 0, .5); + + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + -moz-border-radius-topright: 5px; + -moz-border-radius-bottomright: 5px; + -webkit-border-top-right-radius: 5px; + -webkit-border-bottom-right-radius: 5px; +} +.aloha-sidebar-right .aloha-sidebar-handle { + left: -30px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + -moz-border-radius-topright: 0px; + -moz-border-radius-bottomright: 0px; + -webkit-border-top-right-radius: 0px; + -webkit-border-bottom-right-radius: 0px; + + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + -moz-border-radius-topleft: 5px; + -moz-border-radius-bottomleft: 5px; + -webkit-border-top-left-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} +.aloha-sidebar-handle-icon { + display: block; + position: absolute; + top: 5px; + right: 5px; + background: url(../img/arrow.png) no-repeat center center; + width: 20px; + height: 20px; + opacity: 0.5; + +} +.aloha-sidebar-right .aloha-sidebar-handle-icon { + left: 5px; + right: auto; +} +.aloha-sidebar-handle-icon.aloha-sidebar-handle-icon-left { + background-image: url(../img/arrow-left.png); +} +.aloha-sidebar-panel-parent-path { + background-color: #303539; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.00, #6c6f74), + color-stop(0.05, #4c4f54), + color-stop(0.10, #3f4448), + color-stop(0.45, #383d41), + color-stop(0.50, #303539), + color-stop(0.95, #33363b) + ); + background-image: -moz-linear-gradient( + center top, + #6c6f74 0%, + #4c4f54 5%, + #3f4448 10%, + #383d41 45%, + #303539 50%, + #33363b 95% + ); + + color: #fff; + cursor: pointer; + font-size: 12px; + text-shadow: 0 0 6px #23262b; + white-space: nowrap; + line-height: 1em; +} +.aloha-sidebar-panel-parent-path:hover { + opacity: 0.9; + +} +.aloha-sidebar-panel-parent-path span { + display: inline-block; + padding: 0 10px 0 5px; + background: url(../img/breadcrumb-divider.png) no-repeat right center; + opacity: 0.25; + + line-height: 1.6em; +} +.aloha-sidebar-panel-parent-path span:first-child { + font-weight: bold; + opacity: 0.8; + +} +.aloha-sidebar-panel-parent-path span:last-child { + background: none; +} +.aloha-sidebar-panel-parent-content { + padding: 4px; + background-image: -webkit-gradient( + linear, + center top, + center bottom, + color-stop(0.0, rgba(0, 0, 0, 0.25)), + color-stop(0.05, rgba(0, 0, 0, 0.0)) + ); + background-image: -moz-linear-gradient( + center top, + rgba(0, 0, 0, 0.25) 0%, + rgba(0, 0, 0, 0.0) 5% + ); +} diff --git a/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha-reset.css b/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha-reset.css new file mode 100644 index 00000000..372c4208 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha-reset.css @@ -0,0 +1,33 @@ +.aloha-floatingmenu table, .aloha-floatingmenu tr, .aloha-floatingmenu td, +.ext-root table, .ext-root tr, .ext-root td, +table.x-layer, .x-layer tr, .x-layer td, +table.x-window, .x-window tr, .x-window td, +table.x-toolbar-ct, .x-toolbar-ct tr, .x-toolbar-ct td, +table.x-toolbar-left, .x-toolbar-left tr, .x-toolbar-left td, +table.x-table-layout, .x-table-layout tr, .x-table-layout td, +table.x-toolbar-ct table, .x-toolbar-cell td, .x-table-layout-cell td { + width: 0 !important; + height: 0 !important; + border: 0 !important; + padding: 0 !important; + margin: 0 !important; + background-color: transparent !important; +} +/* reset for floatingmenu */ +div.aloha-floatingmenu, div.aloha-shadow { + min-width: 0px; +} +/* more specific for browsers that support nth-child. */ +.ext-root tr:nth-child(2n), .ext-root tr:nth-child(3n), .ext-root tr:nth-child(4n), .ext-root tr:nth-child(5n) { + width: 0 !important; + height: 0 !important; + border: 0 !important; + padding: 0 !important; + margin: 0 !important; + background-color: transparent !important; +} +.ext-root ol, .ext-root ul, .x-menu ul, .x-menu ol { + list-style:none; + margin:0; + padding:0; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha.css b/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha.css new file mode 100644 index 00000000..83a6d5e6 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/css/ext-aloha.css @@ -0,0 +1,357 @@ +.aloha-floatingmenu { + position: absolute; +} +.aloha-floatingmenu.fixed { + position: fixed !important; +} +.aloha-floatingmenu .x-tab-panel-header { + border-width: 0px 0px 1px 0px !important; + background: none !important; +} +.aloha-floatingmenu .x-tab-panel-header .x-tab-strip-wrap, .aloha-floatingmenu ul.x-tab-strip-top { + background: none !important; +} +.x-tab-strip-wrap ul li a:hover { + border: none; + text-decoration:none; +} +.aloha-floatingmenu .x-tab-panel-header { + padding-bottom: 0px !important; +} +.aloha-floatingmenu:hover { + background-color: #E0E0E0; + -moz-border-radius-topleft: 3px; + -moz-border-radius-topright: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-top-right-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + background: url(../img/grabhandle.png) no-repeat scroll center 5px rgba(0, 0, 0, 0.4); +} +.aloha-floatingmenu:hover .aloha-floatingmenu-pin { + display: block; +} +.aloha-floatingmenu-pin { + background: url("../img/pin.png") no-repeat scroll 0 6px transparent; + cursor: pointer; + margin-left: 5px !important; + width: 16px; + position: absolute !important; + right: 10px; + display: none; +} +.aloha-floatingmenu-pinned { + background-position: -16px 6px; +} +#aloha-floatingmenu-shadow { + position: absolute; + top: -1000; + left: -1000; + display: none; + z-index: 8800; +} +#aloha-floatingmenu-shadow.fixed { + position: fixed !important; +} + +.x-tree-root-ct { + padding: 0px; +} +.x-tree-node { + list-style: none; +} +.x-tree-node-ct { + padding: 0px; +} +.aloha-button a:focus { + outline: none; +} +button.aloha-button { + background: url('../img/base.png') no-repeat !important; +} +button.aloha-button-big { + background: url('../img/base-big.png') no-repeat !important; +} +button.aloha-button-b { + background-position: 0px 0px; +} +button.aloha-button-i { + background-position: -16px 0px !important; +} +button.aloha-button-u { + background-position: -32px 0px !important; +} +button.aloha-button-del { + background-position: -48px 0px !important; +} +button.aloha-button-sub { + background-position: -64px 0px !important; +} +button.aloha-button-sup { + background-position: -80px 0px !important; +} +button.aloha-button-ul { + background-position: -256px 0px !important; +} +button.aloha-button-ol { + background-position: -272px 0px !important; +} +button.aloha-button-indent-list { + background-image: url(../img/text_indent.png) !important; +} +button.aloha-button-outdent-list { + background-image: url(../img/text_indent_remove.png) !important; +} +button.aloha-button-a { + background-position: -288px 0px !important; +} +button.aloha-button-a-remove { + background-position: -304px 0px !important; +} +button.aloha-button-p { + background-position: 0px 0 !important; +} +button.aloha-button-p-de { + background-position: 0px -42px !important; +} +button.aloha-button-h1 { + background-position: -52px 0 !important; +} +button.aloha-button-h1-de { + background-position: -52px -42px !important; +} +button.aloha-button-h2 { + background-position: -104px 0 !important; +} +button.aloha-button-h2-de { + background-position: -104px -42px !important; +} +button.aloha-button-h3 { + background-position: -156px 0 !important; +} +button.aloha-button-h3-de { + background-position: -156px -42px !important; +} +button.aloha-button-h4 { + background-position: -208px 0 !important; +} +button.aloha-button-h4-de { + background-position: -208px -42px !important; +} +button.aloha-button-h5 { + background-position: -260px 0 !important; +} +button.aloha-button-h5-de { + background-position: -260px -42px !important; +} +button.aloha-button-h6 { + background-position: -312px 0 !important; +} +button.aloha-button-h6-de { + background-position: -312px -42px !important; +} +button.aloha-button-pre { + background-position: -364px 0 !important; +} +button.aloha-button-pre-de { + background-position: -364px -42px !important; +} +button.aloha-button-title { + background-position: -416px 0 !important; +} +button.aloha-button-title-de { + background-position: -416px -42px !important; +} +button.aloha-button-table { + background-position: -96px 0 !important; +} +button.aloha-button-addColumnLeft { + background-position: -112px 0 !important; +} +button.aloha-button-addColumnRight { + background-position: -128px 0 !important; +} +button.aloha-button-addRowBefore { + background-position: -144px 0 !important; +} +button.aloha-button-addRowAfter { + background-position: -160px 0 !important; +} +button.aloha-button-deleteRows { + background-position: -176px 0 !important; +} +button.aloha-button-deleteColumns { + background-position: -192px 0 !important; +} +button.aloha-button-addPerson { + background-position: -224px 0 !important; +} +button.aloha-button-addEvent { + background-position: -208px 0 !important; +} +button.aloha-button-abbr { + background-position: -336px 0px !important; +} +button.aloha-button-row-header { + background-position: -352px 0px !important; +} +button.aloha-button-col-header { + background-position: -368px 0px !important; +} +button.aloha-button-tree { + background-position: -0 0 !important; +} +div.aloha-button a:hover { + border: 1px solid #b2cbff; +} +.aloha-floatingmenu { + display: none; +} +.aloha-floatingmenu .pressed a { + border:1px solid #ccc; +} + +html body #aloha-ribbon { + z-index:90000; + position:fixed; + top:0; + left:0; + width:100%; + padding-left:0; + padding-right:0; + display: none; +} +.x-menu-list-item { + text-align:left; +} +.aloha-shadow { + -moz-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); +} +ul.aloha-multisplit button.aloha-button { + background-image: url(../img/base-multi.png) !important; + background-repeat: no-repeat; + background-position: 0 0; + + width: 54px !important; + height: 44px !important; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +} +.aloha-multisplit { + float: left; + list-style: none; +} +ul.aloha-multisplit, div.aloha-multisplit-wrapper { + width: 232px; + height: 46px; + overflow: hidden; + margin: 0px; + padding: 0px; +} +div.aloha-multisplit-wrapper { + width: 248px; +} +ul.aloha-multisplit li { + float: left; + padding: 0px 1px; + margin: 0px; +} +ul.aloha-multisplit button.aloha-multisplit-wide { + font: 11px tahoma,arial,helvetica; + height: 18px !important; + width: 234px !important; + border: 0; + border-top: 1px solid #cccccc; + cursor: pointer; + background-color: white; + background-repeat: no-repeat; + background-position: 6px 1px !important; + text-align: left; + margin-left: -2px; + padding-left: 26px; +} +button.aloha-multisplit-toggle { + float: right; + margin: 0; + padding: 0; + width: 15px; + height: 12px; + margin-top: 32px; + cursor: pointer; + border: 0; +} +button.aloha-multisplit-toggle-open { + background-image: url(../img/multisplit-open.gif); +} +button.aloha-multisplit-toggle-close { + background-image: url(../img/multisplit-close.gif); +} +ul.aloha-multisplit button { + border: 1px solid #cccccc; + margin: 1px; + cursor: pointer; +} +ul.aloha-multisplit button:hover { + border: 1px solid #666666; +} +ul.aloha-multisplit button.aloha-multisplit-wide:hover { + border: 0; + border-top: 1px solid #cccccc; +} +ul.aloha-multisplit .aloha-multisplit-activeitem button { + border: 2px solid #3B73D7; +} +ul.aloha-multisplit-expanded { + position: absolute; + top: 0px; + left: 0px; + z-index: 20000; + background-color: white; + border: 1px solid #afafaf; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +} +ul.aloha-multisplit button.aloha-button-removeFormat { + background-image: url(../img/removeformat.png) !important; +} + +/** + * combo-list box + */ +.x-combo-list { + text-align: left; +} +.x-combo-list-inner { + padding: 3px; +} +.x-combo-list-inner .loading-indicator { + margin: 0; +} +.x-combo-selected { + color: #fff !important; + background-color: #3B73D7 !important; +} + +/** + * ui-attribute field + */ +.x-form-field.x-form-text { + color: #333 !important; + padding: 3px; +} +.x-form-field.x-form-text::selection { + color: #fff; + background: #3B73D7; +} +.x-form-field.x-form-text::-moz-selection { + color: #fff; + background: #3B73D7; +} +.x-form-field.x-form-text::-webkit-selection { + color: #fff; + background: #3B73D7; +} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/img/arrow-down.png b/vendor/assets/javascripts/locomotive/aloha/img/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..7405ed8acea7ec7d4970c14c345da4e389bcf2f1 GIT binary patch literal 770 zcmV+d1O5DoP)004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000XT000XT0n*)m z`~Uy~h)G02R5(v%Q_oAKXcfOXP8TiMu1#kfO0lUp+v)5|1I?l(yZ{P?x1uky(W!JmFlg-V|FZFu8 zb~#|Duv99Q#`kByz20Q12D=hgz*{U9KaY)#JzQH`lR}{&olZxLMx(e~E}5R5mXni{ ziqGeJTPl^lA-+sXOf~`Ty}iAyp`js9G#VAXUazWawOY|={;`~&pBIC{P#zr}4dC++ z;EbaWPfSd_a=YE0<>lpmG7Er3pDGKjuC9vRZg*^KY`o)+IKASYNF?4QlSw&0KNqjp zE12Zkj;vOzjE|2?tJRWpIxV44=p_Q2+yx8VMuH6##NlvABodL{sHzBeu&}ToQ&Usy zE(Zq(Vm6!a;1j#(SwM>*W4GItYPBk)!K8RRuIMZ+Es?jxVlk;yDr!pjna4$8OAtu2 z**qH=8Bv_e<+3a;E~+FZ>vTFb!O;;VfVrJcK|F=^2e@E?S}vFS9u9}4-KHO^IX+e$ zO(v7@R#=ob!UlmrfW?Xks{(D_5&8I_m9INHJI3AJT@_5TSS)IBSLXNoB^V3}wD3Bg z&nMxpQ0tUs2izL7v$M}R`u_gD>c+j$c!iUblfnWJ*+*atZc1APT#4!N%*@PtEUHQs zXS3PM?d|Q$OeUj5-DotLD=RAr#Cw2S{jmlPROAET>D=7h2T1wn;o)Hk^8U5HzWxdR z7r>*N$%C(vwMgFF+siP1`K&ttUm#zl+WcVmzsLR#$gyst^#A|>07*qoM6N<$f|)&I Aw*UYD literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/arrow-left.png b/vendor/assets/javascripts/locomotive/aloha/img/arrow-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fab0c3533e63c165f23f44628e5726bdb9b25b GIT binary patch literal 790 zcmV+x1L^#UP)004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000XT000XT0n*)m z`~Uy~oJmAMR5(vdsX2tpukx^1&C2n7+Pn_wVa2bC&_ z5ekCqY=msPQV~R`2*FLDM7Or21|@|OYRs>RCN`g*bDN}vcHq2s?|U<6&di;wkw2!v zQVW;?TNg&W+dvH{02SZ?==>GeU()$0@cj7r_(MLQ|5mM5ONBz=dp4U*2Lgcz{<*uv zOr(riX$*c6i9{AQHa6bYYBj^|?yeMzMbT=tGBGhBe!pMR>GUV8L-4%-id52*Jsb{) zU&msxcYAw#a&&Ygdc9sW8jaZPc7Yl(7!0zsv?QHQ=j-U`=nR5CvoswZj{p~B$4*aA zO^1hvGB7ZpWDN}s$@22D-d*VJIf9n1lO1o8^4vHGHvk(~2Y5sOOVInS=A)a5&Lm;4{<+4#0E5&E UTf004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000XT000XT0n*)m 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 KMNUMnLSTXelpPEJ literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/bg.png b/vendor/assets/javascripts/locomotive/aloha/img/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..6c17b3182549dab9ab7fc256be514d626db7487b GIT binary patch literal 520969 zcmc$lV~{05+orpxr)^BzJ*{cmwr$(CIgM%Cwr!lov~AnAakl5({USELKN}nSV=E%7 z?#h!--Y2Un@?^#JoN#$rF?bkk7!VK;cnNV~MG%m0sb9q!3gW9qgK=)~>+s!4P(m5% zYx9OO4*NQXwinlM0s%qj|5reV>`INlDlwf!)SZPKO$?kZ>}&~@Eo@9c=-FxM*=QN* z8R#LWl|{bV;Qni)WM}H^X5eT7B4BK1XhJAz;b`J!=V;|bD5S&;Q9qXp0s<3a@2INg zo_V3!WlJ)Gd}+$&){?Q&na94~#kFSj0@Ckqpbvfk(dZup`vBG0F!mkOsy_e}+_hRc z4ZkNKy9a4|e3?H_=molxoc*QZ^ztRIm|78~h$;8*53Vm4m)?RJpAOTipD*wUSW5D+ z0be!6##VCw_;NRKq=dVf>D$f0L+YQa6ljrk2-r`MeW3%%y2W^?*IgX*)Bv`OoqoC* z^=$x$&5bHOzPkc?ZVxh??mRwzLwlQG==hFNp$p2-oh5_I+O(I0*ZlI!P`Puvd%+k- zG%Y!yF`YHfmkE7T5sb8{DZE)-_P2z%J#l6*0xK_valk)xa-H8XUm{{>hVns7hPMRZ7#4oo@r zNwQ_6Lw4t0flsWT_LG7!=DI=inq$pKK2Vh~aS0~QBQpCf;e2U~>4O&K-}ZE0II2+z zef;n2`GhB%#K#lw<4)kIw-xnISQhGJJ?M{Zp47M2Yk_kE$_n`_b$B$znni_s!tyL> z+lIfn3Gtt0zrZzn>WQ|8xn$HNO~uIy!;u>kR{o~aDZ%59bj98I1-G)kU%mbq^#9V81G$0 z^A7Xx={M`Ale)LxtUU6uLO2$4*eP*Pl(YKfisZTb8-$@XOi=ohYB5tW$BUK?}dd0(hi<{-TQk%Jkag# z^G2v)?eD;FbX-U*U;Z)wRclK;`0(qrt#80}=h4bJQ$ziywr2*#)P42sv5&DTp4sLb zo^$(Ou_lafih3LwA)qL{Kf(3E>gqwlxozOxmi*)(hjhq1B82$vCa->ig`s4TJDwIL zSZ{ibfQ<4X_>F>O9ABvd=oIoG+aSB#jC;mCn7Mbw?nI!Mjp3K2(^%O-npJdvTxGPd zob%(E`nq$^toHlx-7r<1up@ERZ{Zw8?rF-QjRce3pZk^vK7>haoxIkFJ`;UHf5*Jh z&GsIAA%EmdPvw53n$^}32)~N-(Git|qa;q5)c|WxIM+RRO;_Ug8gYWhBU2NvMDDbo) zr6~={=fm$|NjOFeZ+*aU6Bgefx{hPu08Q?`y6QD5+^f?s;Ijt%m)CWG*-{xd zPINcn_0KT?A?WIm-qWg!SLZa)rNA$Y@b~GW!>{Sbe4X~Rx(WEK4#0j_lXq7+pCpcN zD9UXvcMQwEZF`!gU9FxS{G%TtIQwHGaXGTVaOG3^O^5aL7C(?p#81pa?4Hv>^yjyB z|Ar{p7>mER6Eq)l@+L;BcGD1CFH>&!#bqIoHF=*?a*1^dgez4E|gh5FYB|_Or!;i@XZHd@gS34rgZcL`N&;`+XtTSi{`5(_h>xXCpykAAM)bR8 zQ-J&R=^60q(Ct@x0tl(TQ^-@_N9!i}2l>WJ=&sy?oL!~&-c5mLOj9P@2GB8*<3z~U z-L_?~i`lPOPx}V!p81AVm#_TkH^!ac^3_ZRqup%4M8@XFCEcZg!pPI#v=aiKD-9Ex zrDoFotniA=xfc)R&0nmqRPxb5&-t&H3+###vjr z+>w>Ii0&OKx3qRDF0V1C_%=&{CM>nUQ?08t&G^raF5fkY)cc%=$1U=)_XBJDPm3sb z$&ZY!ejbYrCcCD&(=FMRH8$h6JHGp^&#w#P0JYf-p9#GCFq_fm02Be0RvpxUekeHZ zpEWrWz*opbU=|SaI+4{LsKK4^8G-TfwR)H;1g>FxJZ$-vl)HWD4vY^DAi$gK1Mm)d z0+eRGe!p8_Isq<3d{zRNzCK@SIg%?MA_3(?zeWY+L%nta1t48ZfdWvjtw7cIum`C? zw|-pnfbt<-3xVpvJjeMHz&?lj=RiNV`RhSF7y0W!KR5YT5Wv2|K3Dr+K|crh6Tmzx z_QZUDSMQPg{x01!1^zDBLkIpY*;50q{UJQ9*W(86E!Tti{awB%<(u!%?V)eJ#M@@y zd}+5azWGvat9|pO**@*c1tR&rD_kJ#xUYEu_^|sz(RV^mI13i;)PO*@-v8>}8VdNx zcB;(|{4a~pYrl8FvK)jQJ@}n165!YAhxP^Z632hOKEh5Y!9tw4^;$oZ{Pkd4UsvdLp`S025WF6P@BZhYgxF8${`XM{J=5g@^nnXVpITq>exXlx z5Z7|kd^*na^m;U}${+~9=LZ&_Spn0vb-V0pgDiwXjZ`wI#x z&Nh)g&o8BUb*Z!@bAv~vOiKTbaWzJaqWr=J}vx3 zE;Hpvxa3VpTuZt>iBuch;9TUk`Dsp~o+#$r`7QRqIPas64X?~N&$F+;Jwn|3Fy~1J z;rrl39^3cPMu#3Pmv07>%Br6vFnA3!P{rUOxYZ_;t5dnG@-0l(=&&EFO9SU~`$1?= z?Wb3Id-@xZ8G&R%qARMd+oz=7K%C63fPxzD;6(GRR13Dh(po=EpEyk4M!~ml1w7y_ zQY5t_qDE@Nt!fpDmV*sIahf19rcIVHJ*}LX6MFZU+`S=U#xG$Z#-+yGINDmqL z;%0xdOh&|bmS6(OaRhNoddk(l0u_~~k#F~&4EDuQkfQI;-GGEK(-tL*t)UtD9jjDH~JB?tpF=Gc!2U)Q)e)5KJ8s>q4T->0eNzO_>9XO^#D-T%mzT7|_4P zlI9JPu#KDQYb4e8L=0Lxz>XT!MCE42z+F*>h#JjRz+(OtBx*8U3T}>XZ|>@EK&$V3 z)w?AJg#vl(g&^O63~!R&Kg5c~pU8_rxKs%m=G}oSJOfWdl0{U=6f7MQJA%ZR)*os} zH-1wgrYNcWz;B5ks)%@+dBm7lwSM%wcfQM1pLbXP zGO({J4{4kV+4gx|oH8rS;3NcY)LkO6W>KNLTR(JRgAAz|oT8`+xe(&oqo%XsxACL~1N`bZ!(n%auh8?FeQ+1GA*m}2SFPU{@MAXVR6xaY-8^yo zCG3*#(_PkyRxDEP$O)wI*cfoGbqr}iv^b5geWl7<-fbhgTr#l%?56Zo>^zhdBw3L^ zc|4`~BMU~%>JQLwCjL}owL!s(R%Q@Zba*q9l@t;+htT#fnl7)xX=NCUK_STn76#L- zvKIuUUGfkNK~I>6jM~{GHX_GPz~OMj7iO?Gf0w#iEi5ebr;IJ=Y-aq>`99Op2fR+& zIuxeSfhZZ;{<%jBS>mbG#f+66Nm%qJyrB}RR2Qst0E}vzqHZ~J$R)wZ(n;Q?L6T=c z+YH8ZS1Qe!9~Rj@-y~3AOR?w9e|&Ulz0+GJ(~~HRshBABUWEo^9O4qozi1QB!Ac2r zRm{^icnYwU!TCvQ zgWf~EoJrIQXEQ%BG{f(T+ulXUHyuE-AQKd@X=i8HnvlZbOd(*a0_XzOEXpH-iaM-Y zi*EEo2f3V!yWI)M~-3evYw<{XcNKDTlsp=@$(GL{Mu2UXPfV1 zpoy!*ceLT15SrtG;3AF|9kwql5D@E&v&TW!EvplJKDoQ;pu6suP|cb8zL1bX=W>%? zYJj!`-Xf@XiUtc=!^)^+(8w$tE8V-|qEVnE>({Rk!f1JB&V7b7y8WSm@3PHAI>Fi1 zpkHG5H)>r}`dtw%(y9Ur?X{Eg?5?aCMFzVw#R+Tro+ig9$jE^=SYwT(xMmOe2<#K@ zL0t;_u4fK6C7&P~sYaxPfp?m}#6=b+Pgn6Y4AL`oh)=94fV)sW)O*Er7@F02teM@y z$&*;k*){%kj{*Y)2`1R%7$wVZSmXw_7x#`Hiso8-xPM;9;&0S>iN}6mT|+WLaa_pS z^kaKmki{^rwC1cv)3Fl+W(JKBg-jmIP|1q34=kZlhGZ#|!h6)Wl-VD{#My}h+{3?Q zdQx&>SqEGSZl^T4m!1-xqLe#D(yP zuFrbbbkfLBBG`u|5MiW(=gS0G8S%_lN08&Ci16$mVh~KjrRj!LXPWTX-g$ zkW=cQw_qJ-(w&%3$35s|xNRP$r+9z>VcU-q0#vR*)gvaKTL?u>#Sc15(Hl_poh3+Y z-FT(`gv`xcA-;(*I=7^rC6T4W9fi`$ zcpPzR{Em3*?}l|Y#96PjQ_$2mV=tg?P4H~52{Z+IIDH}lEoF#^l7dzRdU0%4--A^8 zYkCXN94l610!);2xbwwGjB`$h5h~^TGMIrNp!h(ModtP{`WsD^53*szcf3J0H9_8Lne3H{DY`5cJh6b*_IOUX6gg~P(r{(Ywx#SqNpod>l zo9jW=l*V)9+Tu$rDT$bQu2G%CitSL8-@!ItL9V^{T0ie>vG@6XtC%Mjs~M^r(4`H=F5f=HLH>v>L+bkMtaoAq zGf*UM%mxOpshP#XK{WyoP7vnMyTyBFNg{V^!(Wc#7aC{0iYPOKG{$TK+8I&HWnDP6 zZ6?zbr7t%g?n6yAiWHO{Q4y4!j zRsH!A>H=gbF8$CW_f&*iUEB(!t?LMUtuo1%#D>wtf%3wJU%du;^T(9)A(`=<15SXt|ILZ(J0*P-vX3eSvT^Dvid~3pNM^^IZ%;0CS4OXbFcH5rHsV?@kH-{?UpoCO-4i|&?{skRO^w(W>lvq=My2Nd5 z?$iy5fQh$jxil?nKjIoto*PvJ>+r78ajQ^rs!**~(6ILFJhhV~YHk&bJlPOc6RvZb z?_uIT2328C=kzVNhpX&?YJ|bHc~$#ugtjLJ6IiiZl83#1dTOT$PY*tEnU9^Sh>JJ3 z_-^O~FW@4uAEL@I^P|kQbSRz1Mm$qk0CVDxBa_N0HmR0nr~+ zOzOqU%@c#ZWrllEvWi8^=e<9`vcZ5X=P51iuNjKLZ-Lo-*J(1|1BYub0`E%)aPnHZ{ICL2E3m8A|XS#KxME0e6| z!)onZ9@vV|q?zU)7u6TpAw;Y4e-dESVo?xHw z=cqUkl6V0}fJCc-JY}t!?SfzJw`}Z)J22ThO<}${lfSJH3QOXWHZ516pW-^2YB=LILd+A;ytm$W^>M;{PY%EKS@DO@_U&b{x94lxDlMP84&%9una zF5em{v7(u;^b|@$?_s@b%p+y|oR0A}o)p#%&@SEiuSniX-&NB9@4@F2_CBAFSUHPP zh3p?`g$jeeI;7_5Q?@9YykRZxLIR;~BGK*zCx_ZHhZ>dd;(@DU9KQ)>I~r$otl5+W z=9m<>-8NJ{!LH?657D&l!&q5?lTpIwI5XoPTK0hSH%v*zzFYs&;_l#|Pn0S4Ig;-E z&{C?v^^GE~p~f!CeAVI0@rBOd4Sc^hR`YO1!atclu5A|$*bHPkpLjo!DS-W+9DpZ; zdGv{#7^cW+k}@4dAXdVmj_Tu7$;l&s_FcZB(U_ZUIM>)md*&SgG<+-f6D(d(x_<~f zWss745B`|e%V|z)dgN(-k8WEtdu5Uk2)$-LnB&Md)W60-Mz(9)yQ0;QxxwH(G)-l8 z%(&zV_aDs|(mjOrs&?uH=ws3i@R@UP9-65*G;i2DjxOMew(Xg5;}Aonz;#}!a~hhY zGCN{ab3R}Hr(GDLk#j?)`gxcBby;C*-eGhcoyQeo+dJKcDK<2XCsdP}7xk~^60=<- z7|d;~`)s+*=!m7ZVc}mq9v7@@vbkf+ZFT;ZTjoYp=NWs)-nojsYjGCa&Uua9fzHr$ zOF&*nk{h0o8{9^49$@fGifuteU#f1p;BGiLqeg$Wf5~%ioaHtxkEMT|+8E;MO^tR$ z=h=Y?xlvtl{_}f5+mR5`kL%u%a0VkbUk zu}L!#0lTbS%(p3nu)%OHt!m~uTuuI{92*m?u910rkMB$=@iDc!cuUxQ4{*6cUg~;p zRcaOn9Ib|){V`a7-Zfi`jPF)n%Rg|b@za)ST#uH~%HPmlBbY&1ko4(j5UzN65g07# zndWG;>zO8T@8ckPHDPl0xWD>0p6I*|^HuXs?cJx~PTu|Vj2F9PVOTDp%_48C#Taq> zQ|e$6+k6a65hdS_nJCzil|rsN;Rw>_?lRt7svU}4iDqyd=zQLHXX+%bL)RUyQ{C?` zC06{7x@&hV&u->ch}m)S@XN#ZDA_Io1*p*`fc_^b1-|nHAbGZP=xTSAA8gU4!h1Zv z510*|<;;`hJbk+hq~h5Sx#0_VK$56{8nuj^SywQ(!2i_LsM+7D&bYAm|REJ(UDVc^mCB`VC4! z(hmBdY-;B2-=%symx?by`74V2R|?7KG;vy$5bH%O#p5Qwug10*HXrtky%+qpF5i1nZ$#{5<%J9vufFAo!{# zF;{VSz)RPui*ob9%&_sc6fMqFht+$wU;Fb=ZY9w9?>5alO-c=mwU0IyUYV7TtJ>Y7 z8eduY!-E`U3$LDU-GkgOO`xQNUuxYbd9`4!cS)sh%ukAOuU#Wb6q#&SfdAmR(63h*=*JwsL|rPd&E%xdjft2hWb8=K5LElQ?GD zW|DQ8)VaDeYHX%i-8{qLtWjohGv9S)Sz;NWHaRl*#=b%DE%&W|WZ~hiK<7PR662hH zqWUCxpn7-2xmY?)0JR=HKq z>V|G_2Kt}f7BB3xt}D1A7EZT@6C4*Y)!#xW7x6f&oJCIeB1~3I7GDFN?-Mk0?W68A z@3dl6z;&*qyOny(N1f6!$n=Q8bRYC~<_>fNDz>d?S9|68#lZ0^{<3G=Id<{`Pz_XT z-Q=oCb>pA1<}!a^;`!Gd=4H&Ie`Ua`So{?Auy*~K+~SVMV~hSl&W)emZQ`1t1;r(Q z3z=!A$&bQ0!e5fTmtcm~H&dwbw^PP=Mp~|cMYtmF@B3nn(66mOZFXb{=WoPa{6USu zgZN6z1!Y$*8Rs*VNf|xQ$W>6i9-8;%(BGRS>M`P3Qf%I`d?VhnD!Vd{1LP8YN|(t0X0u)Aq#U>N z=|=D)vf|0%s(G=9dH$)&{0>6%8g89;8q-CzDbiMiyp$oe{w=)Cm}S{NOh#3&ZwV%K z9t?F?C+c}2KS{Q=8|#BN#qrsye(FrC+jG-L@;rT@{jO6>cV<6H{fRE=Nwvl~eW(L5 zQSXPh)#DnedBBicZQi;KveII>kAs^Qzox&ZVFDdSEX2?Kjg$TUyo)vjno`?`Q6%<$+dWXo@vCY9o?;R`UKWe_G-Um95P*ImE~y6GRmYhNi|W4ieDzbQh}bKT zYt!v>n$?~td?>h|lzUg#-Rrt+`|N;Ob5qwQ%I<#J^*_D+gxxYz*XHVaZ$VjMdK%xd zC{4OdZJ9%|sc5EJ8@rR*&=q2}TD)L+cYMTdC%srZNBCn$?0RSkd~2fD?ZorIRgZdbHcm?86OR)2k9>xYY5#Zj-;1z9#W)?9r_I$(vfX z-2Uh1cg;|{ggYx6PRs|&G4sE(2+KPh_{9lFT@_Z3+g#hPwV>~K%%?{cXL=#ALng^+$Dn zCoP13;`s}~(S2v_qOZQo#`-e(C^3noSGVQanM^hGRW=pp*m+fw2|RKyFmbERGu@D^ zp%kejGfNQeXg!a}Gd8WGe%o3SPV+qX%rm!7q}--w}^50cA=YX zj4cKx4TIayj5$>LnS`rQX=KmU=T~9#*@cJ|QB~&0pLB*Egn3BTYK1ke2MmZMXAC!{ znG&7n7<}@G?&S*Gl5N5nW%}o3h_vRIsdd(mK$`=41`7Q0o082$9mqoI{|xxJ8hRv8 z3-mAG=``|$U6aIu6omyVkGEIxb1y6rX%S0tukMTsjOQa%2|xPi%+ zPuq^A?y%@O*7z4y`G@n*4mqbietmR^?h|7g7+k8kZ~enhxI+y>d?g3Z$XkZfU^m(pq>6Qhm~VAL36UF;ckiVRp$o#-8Y@2ALxp3p_MuRJpq$2@X*H z$zhBtW6llfzme}j6|9zqpR|}5tT%=il*Wv4IDOAe*Nr$`V}}NY3!$r2zyfTIU%KNg zvMj_xN;OJ<%P!_q492*(;|Y5f)5V>najXyn!dZo7w@tK>#AFwF)yO=n8wD~)(tgO8~E`INFjf`7}*g1W1|0FHf{Rw?Y08>b& z53cBw1Exv|5cBiyeYI~d)rZFToflg=-s*weijxDc zK4FFkFw1p7KDTl7edqr9JHDUyYzbpY{|72e6@1=7%`nle zZ);;IBE;ENPn?rE4m2!Qy$uNued*i#5tg%k`warl=MWRvryDp9Zud!$LatXX!+?a{_Wwh;e*PEoy?#lsXQ_a+8Lb`HWZ4cNK7_YnwIF((qH zMsYhH_Xs&FwWJl!HVBL7}jS>5CB`iG%V=(;EzvG1kMk$=h8Wb zwyqK*;+>OP0Bj6iZ|sg-PE>T-T}K92&(iAg{iE*6ud%d%Xx%~~ctp~YG|C*DO= zg4Okl=pGYwcT0}NIg&+53dfyRW9AL%HCqM*7e+vaS8Sjx7er@>{f8cAh|I?0<|K4d zCzuMWq1);ifgy|6&=9-#Lv$Hw*A2c2_8jJd5D*W6XZNq}{{r&rAh~SBer;@o?w(-S zb)MwsyO&)TF1TQFKB7V?d^FLps!*9OLQ*X%`p$WWBEi*pr(tpJvAYp)5)4q6 z^a~{GK+T9^qBMhKjv1}tx>z{VN49UUxOszyOs-qu@ZC7^zx9UpI&&Y2F>AWe%YRY% zS-74O+@A9Z$n%fOmrM`(Jbgi>mec8boLr6BMowm_^h3H9HtkT9IHhwF+uM6MI^oh(?MzY&9#q-Z>l&SEB0HGlwESion#vnmh!Yk z{)TvxuQVovHYXH3aryHl-GgMHz%cd`t3C_CgcyR)T6Qd{p_4c?^2yx`hSld*)up{J z_CA1AZ~IpYlDqxo1CB_PT+_Vh>RJ7r4O(3)M4=nScBGov`$0x&)W@xlK>T$tul`&(}_sSJqcN2 zgvuaYCY`WGRWI-Q^iOq}=m{L?-7N4>yu4hn|4-nZroN8`=gN|3w)4QSQQOIf1=DAU zq3@(fijq?ndn=*AH;XN(1^s%4EgEq^jUsHJL!so2{2D_GH+AU$io1I;FGYUb`uG^9 z1(jk&6~LuiHeaPDj}rcrf?$w7?eiT2Wr*4E3BdCT5Eh5!*-DgO`_XX!@Mu*Au=J$3 zs3Tp^tmUyKi%ELzoWhPuVwc6=;|b!JJ;+r*bP2vz44O8CBn zBtv669x#5(kCcEuy+H%fx5_V?$+jeyyNF_H9?J4}JlbQ3wDi&a-nR^f{ae@E9;U2k zL*Y{89>PlY(aTrrWOPO<{4*^BhCdA+qdS0fLCd#gV3SieN)MMQ^+#qlT4J26Xgq!w zDPec+Z_29ys2NZlv5EtKHB_6;^04J2AXR%54C^>z&d7%54|7*dlRW>l zO`?teO<_FoM<>>vjUIG55Te}n=-Dcc{U}GR4o#TAnnRL)Ek_421$%<)QM`(7Z7PF4 zph>HJ%9+6!zObI;P@{WLhhYDqh!Ab=W8)Kaa`}XejdxU$n`H77l&Hs6!;cq z{PSsdemsnnp6zG--MGr_LColvx8IvHYslEn6U^1I5T`7B-4?mod*(^@)TcO>JE_Uy zs)%i@Ifr>C_(6EcVkE}wvopCQU+ggos%BoD=>7iXc?09Q=q<)PZsX7rbHJsy zYC45;ps%+gYFrtU1|IpRlD(_W;&I~KmVIJgssUHUzWJnAz60dM2X5;$zs!nfu=te?Kvv#rQ$) zYv!S%D+{^%M^9($JurA@&7(r3Q_`Yn_uNpAcc*#mVIdfo;S`&YOnspi>xcx_5^_fo zGx9RNXh$N@JpR;B+L@P7Z8SjblHv`$_-9G)sz+)&Ra9%-2Xl-zz3bv^FY~ND&Z;h( zBRzatkc1Rx1-cI{gi(VDToI-6&NFjHwH>Ijr4qCY*&l$ywqpA?jlT)?sgN2)CnLwq zY%t}KJd&^$M@H*|#xkux;?SzX{@VH5p&FeRR~O-G=@b`@n@%_dh506uQ_a>6g=uMC zCAAb$4uF2x27hnsp+>TS(Z)H;bJgKKX{A0TVgo$;n-1SIIv-Gqh}RDU&=4&eFQi)`P$K{azzsaqQvW=ED3ci z)fiuj3Z#;PG=HGdPVPF&{tT)&Kgw) zG53=Ms9zCVs)7bpZ#m(BK zAa>$Gya=U_m(Jmx@6kJMiKiLOAM+hts$P_%?33U-K5qTzvocyVo(SO?amOLB(it~n zy9A?6omI!(nIgd8C=Wbr8N!mq#o%Awg)P!VD6VQ4m#RDOIAC)e);J03jrXD8ovB%A z*DhLbYH+jwtk%=AFgn|0+8Y{QHbV5*(y`?-DKn@OW9Zjk zw)gxY)pAANgGxq|x?d-ilJ?6OES@kA&;zg(#FNk|ZBLZmXtavMW`eP;LI-T}Yxgcc zf~y1>^^q-5K5_O_NPc=t zEOHFE@+rKHIgWkgdrH{;cX%EK0H%BlIw*L?1VduF`y^^4F( z?Zuq-svuoQW~jFO``G26B4UKn*b#<{qbY7K+5WP&ruKr zVAM6=w z5u&##s$SiTYxl22tMBTEsAjq2Q6|0<{Gq^R5$dWWu$a-EESqYFbl~mS^ts^b_RZjUs*6*6giIS zHC==Sg0fs>uZ-DZ-_ebwY3etJ~E_U)RvRWVBGx)YS{!fu;k+f-3WK=^t4@Dt6xw?tUxe58f=; zC0ucZ6C(v#$WP1Iz^&rnCAKCsYGk8k%&9M^z{1ksnNN-!et8=@{?Joz@QbCfZw9n( z?S&_SFDASAVs(;F=K^KV8THScpsR^+V(CvcrE@~B;N5D>gT(-j`{>Izic5MJH}2f0 zI3H!-ig7((!AH|pUca|UxieA4%unfA3ZtYAQp?mayF|@y@Fou-fnax07*C?3J?%*& z&2oLOfI=(4Z@G%L~#n;&5sROY}Hyp0*4aDRD#Gp>_s@`p-@(Lz}50M z>%doM@@32aubn&)RD!5@XD?7{4=wu!!a1d@?S$rd-|O@S!=7f!+AJ0rY{R@K*Os%l zbAgMB>d>-%UZpYl1(c1BlbD>-to{SGjm)uxw)WsYs2;lXcCc!Cx=+~K_l{MZ8dv^- zbUZP(?cCZ|RJf%Gr@P23mIVY21&h2HP5msd{z#Ybm>b4f9Ok#Dt`E3V0ZP&{+P;qezc z*W6@={o~RXST{Oe>zUs8hr_?HeBZR*-j^(}0~7m4#-lIU+o8q$biSl(H~jhf7a9N8 zDJw&CjoE)g?;&}B?0*z~3nJv7%fGyV45*={x-WyHwVug;23cILlgn+0ZSp{;Tk1Nd zs}(C#GlJ)FCFy5j`Roof*XpI!`pFeiy*J&ROOLbiJCBu)UrekHQrfXoR7(uF$oJ{Z zRw$&Fg=HZq_-5VPD3-9lQdrJDp zxT|dX$H?3}nMfb?Snb@eUl;dZ0)tMaejD5e{hktO`N8oJIHj#p$1`B2338 z>k&XBGYHjCZ{Hk}muz2dW!0bQ{YJD>ubhqc#!FC_!0~b7olPqLcNUPis@Fz298~nmfK+4vryELa`V|2xQxOsz#rM3MBHH2N26O~J|;VLeISX* z8~&cZ8ko3ybgAwwq+@c?k_J(e#*j_SGF-*cyzB_u?nsk9@nikSTTK_;V5ExJ z+N_k?>%n=AM{Nl(7NLwSP-jtRAx(oU{c}lAs$NCCDk{4~aPCMXP6OX-QZhsJ`kvGz zcip_>CSp4#J{w zF;UK9dff0BtQR3G=7?fQmtU}oMDn3eMj^4==e4-yBZfH5cR z;F^QIkJ{`#`tNhqR{Kqd#9IWTkIYL(Wb3k(*_gHC5$Y}Pnid4&b~Ia}n!7hCPn_5> zs~OHY3a8rq;DNaob>l><%PN_bokEBC`Oot$sw3k)pUg`{(CLqz{nOW%8QM?&BUsl| z(I`LLcjddC)Z7~&bo&R=(D9xmqk03 z3@+H#2LJ!;>~g@p={mlZMZ#}Ya)jW;{V-Gv<}4g;lC#3=RD{E+!Uojh2OcI{=$Le( z`=%5m`CVp>zF2F(z0uAefK7-PP4L3%r0Yb~CS}-(aj}2B6$l)<Qw`qcrt#cZvp9v%-wx{#u!51E^~f3(%VM+e{hMD0HY0MP z9(x$)7a1=O^@@{DypInhs`z%?eHs6 zBNPzZls%QT^xi1ujY5U(>yQ2++${evw25?;zdjpwHbH6|@K?JY+nWC`Sq0sW6}a?i z0Q60@=)2{NB)Rrhq;HNC$2-f)(F2Vh&lNAJ>xAKk$0kjU`K@H-Tgs?cg&OC?-Uj4o z4NN!7+XYHv&mPyZ{AF_(<=Nlv)(#p%8vg&m+j|E!;dJ}MDk>_{L;)!QMFkZ^Ksrfm zfQ2GoL_~TsB0}f^LJ|}arK+e%OGFfu7J7$(^coN$K!51y&hDN)=j>;JC0!{(w*-!DtOjk&3@{vGB=1*+Z^^9f-zbJu$p>TZ z(4HC0PR(B&x%9+*$FPJ}8Cucs=fTKwRId!p>@33QhD%?po@KCQ)|dWWRZ$VLyj< zSm@i*JBvfc&t_)VrBaNjpU?ED2Ba9#>y3S_=SYe)SzakE)FaSmrR3^gVxx$YuTnm{ zQEF3e%xTcPtIJ;2l2E~_?0OPcFe=2iXf%U7`YCCTY|eyLHmtnuO1c7u^#f}($|)I` znM=W#g>_B7JG-x>=;1k$Tfee)6k-;huVKwA-x@2;8hB_D$AfRpfm{`a9_=lEHZ&}_ zjQ(~i>_W;P_&P=4_EN^~R!G*ro!JD~7noe~7J8sStNpTDtJP^cWhB0Povx#L8SMEvJ32#u_cOQbVK^L>bNTi-Ko8|w>VPVOYdj7-SfDbKj<0= zmw2oEw>*8yC@zXBI7t?&aE9`x`77g~7yzy<%N zVC)O_#^-7dJnI3zwTu?CR9#J;RZogb$E~}`Ll@8ctp`J*C^z-C)2*CO$g*by(Uu8Bk#g(u*>~tAyEIo1ygTnV^xE;W&u-pB47@?=Mnj_Qyv@NR#zXTLl(0NVXweVItZC)hJ0+)|yubRZ zYArd-<7tiZ{zmK@&8^X`>x1K;L0^TlsKj@-0@sut<%gvyHyZ08TP2o=A#w*u9O$2`+s{Y<}Jnd9}awi+++OyGH(DetDY8a{s3OvLqg9E;Mrp_&!-D&Mg7 z30!Q(RB`Ve@xwp$UY*>ZI@0#;M2%gcIblm{4$*h)JKsBh=CpZI;lK&cS`Fk)#~`iZ z*#hb(uQ$p+E-c*&!7Q{tZ&E!PG1T?wxZZ=D1FzoE^b;X5NQ<6zrN*`|g0o?@knz+j zO4<*!5?;33r&b!|rMyf# zeOi93Eu^$0@O7l<9j)rI+i2~({M=7nIzjBwzUq!3ieggSyW0|v@(=Et?A$;o4H*n2 z9)6DtwkXB%+F;c?kbw*Q9wPIpM0piP}Jhi`GH?P)RUvwN| zk_#*a6UCqID0?(Gi>iK^GP5@)^pq=J;g~5o3Wq=a{L$-W(GTTKV;hO@dqllbTfgM) z+F8ifepbIz;;6e8Z4uf?_BdMDVIkrTK2&a2woj{6(_}rUBak0ipqLO3dyW>kt9WR3 zpJ%^@)#pU#)5V`B&FuW3C-Yv|e_zXb z5Gvv&A+a42x>VLO`1x7lwYqa#^!dRbmuhVow4 zeVaRx8z6AbuBFL+xrsM1iyZk25o>Zs?&TLNCLAOS)xeHbVMUwZ>qnbU; zm-qN~Om$rXC>xq?R?n!1h9;gE&Z%qA3h(z#GJ8KcCE`e>4ODU0hqne@-aF)j?S{IR z-)6>(?0lR$4^CYLDId!1P+r?6Cxbrf%dcW0S`ROrDrcWK;8C$WqjA_HG_+OZ^A@=I zEHQiexqQjP;e(WCrG3D_vvPA5 zUp+Qit~qc}8Jslu_AZtfz7!WY+_TZ)60t_V9D5T$sxSszE^66yAT%Gcq_5cN`#yu8 zM#-%k6=f08?_v%Qm&(u>pztMd9JPC+ZEq)}&4Z3{tm|=sjiK`K9Vqcw? z0Z@LQ)bgVbcf`3s!~LJa+QXNE42A}^rv|H7VaO=f70N0pbWHAH?9jPhF&&It~yTK~S+)b9h-L-yb^7X^lgdZj0*E98j& z=rO!wGNHfon#}Q1_Q}bgpLO~+tJWsQ#?Yo8C0e5H!(}xXw+^$c-aKo)rEC!EH5iqM z&Yx;a@*8%QR=$~PApPxtb1lF*=SIl{9|UXPPyR^m@AmVd1Q3NH|DSLK{!^I`Au#T3 zoqc)Ft3e(wror#9>;;!kua3x^=+)Pvjj9tf*Z1C}Tn@5q8PIk;G!rKMD%T62+TbzL z)`lV`(Zrc)c7eD?gndc@ZA$X@7Bh}F$f7SUC=?LU)&yG%N@IdU7Z_%x8n0bDyWnWdDRQll>oU9PjQNTq$`JRM4snqi zl2SuMZL6BHhAs{wSJ(tD`%XC~m$UWZDT%gR#996Tq9GnHK8meG{lQpY7@vZKT*?iC z;{&nAtXeN;UFu3@ZUf$j?Kn=L`oS^8ZR^Gf^xdIG-*JNZe+uLvCd;wuknrIDo2yS< z`B$#s|4!tlH@JI^R2T$j&yvPHdyYTFrVNL%sQZrI;I${F-S?Cy_$suoClrb!a( z3RY~$Y3{{X@Xhs(n{3!|Uh-@3*;%|5`>Z%BVYW(zoAVl{Jd2W8Pg3Eki}T`Vo!@Lr zwlP(ZmaR!DiO1Hp#5=4qRA#TlmfigGRnM~3`1D^ZhjU-WjkRL)Z#tOzC%-1DtUhQ( z92d1JKQ@>+t08V_^{ktV|3cs@6r&iyKPov|^)Qk$3-!W@j?7 zm-x1WIbL#`6-;KEGR=utd*WgR?o|Lop&|L*F!w+u6nha%%t1VIvNdKY->S-e2*F** z#g=kJ`OVvpCLn%0n>wWsoM09>VODv)Z#pB--^r7-w}Nx=eov#BQ*Np4aBvVYf1+nJ zKVa8<%zEh|krvmm8s4u%vFDFVTikIVgUQ-w}crMj6}VMvCDSt0xoWDYiuGrJ}`e^P4v1 z&NhUfrJTI_OGyalnT88hJYk)5f@k5pXWz2T!eZ=z4=xW~Cd{%mE+|uI;u7;mV4f7) z;mx4&+~Gj_c>YA$sHjUFBmXJWrV{##I|e(I&bb^_Rn%Y?h9*8M`&4zF1vh^7yD|Uu z6?m-Um~B=fYnYnM#Wiz@i(M;uZn(Tp&VL#O$Ec?Fo}m&&{zaQ)h8=n=kJ2+2+%@1s zvTikneFU~a-}+($u(b$uebEJm=ih2$3TX+Fu7xSG2e35Zd_cq<^D)R|{<~oi9>mrQ z@d3YJGLGM?5`I!Q;vv)9S@gsL+X7O<4*8Jozf45bT%ezZYtctGHpcJrpgDU<@rNh$ zUU_dPE1esKRN2p}_%c19Jx;p{#$3}+dr5t7 zLf7T5NZ9J`{+M13oU9+@_8hxFM^JI-`m6pP42pqUrtC@^>ECC(sVk$aaYZ6Uy839=d`%x1a* zr$;oV+mXo%>w!ZeZ1}00lB`m=W?Z9lRy-nA207A@T34RLHb1E+y59%?LkncN5RAC! zH`ARuO-uK4v-5jOl$PXw6|A^+Hv9;xxmvf8s>fN)Qot{2fD18LDP!L+Enj z_49gl%-vV(%V7JG{$3xX+23o?v)n%^SXCJ;QLLEMz@H4Y2q6X@xo?G9_zl&f5pLb? z#?q0JGblR6iZFLY0T99+k=`)}Y)VO6hQYC;Qa@)>DpI)0gA=56vkYci)j(Vw0uwRJ z0VN7$2+1UdxtHzKZaI!H^Oi!9)(ev|wN(0Q&tzqTJPTw03XEozC-UBKrqX-ms)Nkr zNPWW$i%{nYeMX-Vg(nCH!b^ikW#9U$bCT3#3G|RCe-m#QUO1u}=2NdOw;4Pz{$MX!8T}2+VENQr_BQt9D)i7Q859pdiQWr&v-7;H9(*Y_FqcwUp(Pb^1_ zG|1SLss~EC4+9F#$L{h19T>X3KS=HqSui4J?+xA|BeRu7=@+iycn#@eWdLplZWPkD z(mf6d0uCyZ?W=W(F1-h>`(Is3C!clgY<}nGnshgUYaPN; z4E=jV{Mit4cx*Qc;SXO%JxcbHX<^K5TQM%VRZ4gV~hHY{C$(-sCow5b4%)3K^co zxO*>)9-&v6c@bw>og{y1%}NkL>ThBk##&Dk@2%(BZ|aOIuN^4G`%R+uDe?C2qwKzL z)O%sL6~(cj*aT-9F#tQ5wCrUUosGyO*Ex_|BQKVF;|Cdd5B5XkNzWH&=g(L_*Nhoj z=4^z2Y*@>AKgLUfnH(h!h@1S5SOSA$3}Z%ul>-u(v+^x9{zrr92mg-jp|-%kTvKqA zk{OY>QfMtFYB6)9BdTljg}-kGme0N+sS13pZT2lSXv(7B$naX($Oe7fvJ3YZ&|JZh z=m>Nmy>X}DJJ#j^Ez!aIQaT^$8g2l-)O@+ktvoE8eV!^ia*{hH<6gi^rP7UX=fg!H zQjFg?UrsB0TKQ;hN8DC}A^165kh2W9yyC~VY6FKkG66?Jg*j9iqiSss#yR^y{tLvr z@ctsI4LRZ@{9|4BR1!zM*Zm3H)k&&|YT1My+y*4lg;)4nW;9pC;T=xv<;9hKU~F@O zO_be0D=H34uJ=Uq14ZHTEc*RLjXW3H`O{wN9Q8u?lfg$J$YYBknkGX-PcpDsJ2%I5 z9qR@C80u!I&KS6j@ANp(~kqonR7rz znm}DNnWt|QzPJsOk!Wu>=(nRKHxy|-tSiN|afQp3Q8F~hH45sSd;8PN8^suVydOEt zk2)@WX+qCu$sF(6T}&){^==K%V&|BtVdFWqz(+(-jJt~45aTz7az5<}AwBo<+9yVn zw`Rp+!DEYDb$PAN!R^m^nyL6E`ucmi(8(9t!jkm}ZFuIQU!^DbZmSVP86Im;v}NG* z3v{Ge#<9Ow4_DWw9(m}k*;^EF6Ov=WQiYe$M7OY0J3w8{E5y|KdY9#$Eg{qSaoT z@(y^?;$%xtlRNKj^Fvu$l8ZGXf1~yS5dw^}V(43(WJQC=tR39Y%-ORP{X#0O_IfY5 zF$uS@T@f>iZr^)pRK@#Wy2)vXMu-nK0Pn5Naff%$LoXNX{04L&E>+(x+UkrtJQcT# zl+LJd_V?{f9$GumXBAa2HDzP_~SCcDj{(%HL4v=N_SDi}j|LYpcnO&*Usv z;4(f9v^dgtgk=L+$$y4f+%dPIjds=uq!4|6f2Cn zQ$p}>cOn=D=lLDXkLMi!vl>SIj#@&t>93?$zsl7H6mGG$y)k8n`)IU@mM5J}^$G$z z+e!<2fR=vP3S;;rM58gSVH46!zO{Bf%nH>}Avbm8*~`GIhTZGKjHdKA)$dP@stq7o zYe-|y5vgU;7g#p>e8p<gkQn*HZp1XT?>=-&I20hZx62`bkfW>8!2pMhkCb^SUOz|D_<}?&W%q*%P>ttlg$x zpm^DnSJeG#BiUjv zjAnxyuZZn43FS>=!dk$r>S95p?5ldg-OvW(cbsjTO6M(hWj8}^ig=gjDU2#9GG#$B zgyK(~-CpwsE|Lu}?V*nh-O!g?ad3ql(rt#H+-0vO6*rtO=0R#hsvVV(*+BfpF=h6R zTDLT+`*9a204ZdYZhxj;N{<_+cX^pM!z>k0Ca$C(C9wV&u6-w6Gxqnf*U+9olqHS}Ztpgd?gw>x4j1cwH7g3EW12{oSyjhxy zzTiwmkRy4q(p^j|JkeW2M?|ls=i(Ct;a4@Hs$HV`!MEDTX~*S*&Lt@|rD&oOralPO+k)Ft3L+kQm8}f>>Tby)umVAwY%6%ZGMRHow>T?lQ0?b2yUQS&c z8qL+)3}kGm?#I4IjKH2n+<}j2j*(Pm85{#lRgIXFCZ4>48fo)hnUEei`8j@GnGWF(1&l{CV?e^+GebT%3*tV2>C z3_Hy`1;anWL*P$o6GB95bj%1|?bQD3>Ix(wtqq`B*NnYO)ci{k@@^ z6;gqy?q5_Kr;3G_G?K3u?H#wOr{f>BkfIUq%B1TmrQQm!S+N5;W!q^d4e1}YnM8Ymi1^@{rKzfyUJ9?ZjtYi)SsqrH5>2dE z{{}qRFVGl~_yLvl01fk+2gbc4OxcMWP`CaBmuja3u9&|LbEty48j-(Fiv3ED^4r%< znt!Wi;HvN`M}89_tf%|4-Sk0M#+2Z5um~Sx8Yg(olQg5kK8NWB`H)OLQd`<-Um;;i z8Q9F`7=#RSMmza-{i*HVxrkVTsbnx{#J{U8D@~m$m9m-zoCKFkj#e~ubG(VxcYB%F z6Bn;o$To_VC3aSVlLGW>8QUQ0njGqXm+FXV`$DL{ydC_gI{DIJpi)X_!L z088dZn9rxWX}A6eZq zk8BU$Z5VKjD0ZIP!Utfa61TK^g;gwH2l9_t=a@cAPY0(|GkE^e(pJ1A=F*^yC^%Q9 z@j3IFa^8&c#DRqM)z^V0l6m76kDOq|r0>9rn`-KELIz7dkG3(PnU*2(9q!la+sSyn ze&XDN&4vp^y%=j_IFP>?SG?quqDdwzXyw*tV#C2*TGN_%xcS`HCS-xA7neoOd}K_a z*L%D2C_mLk7;hf-ZejJ>ExSHGHS)NFBhvf zLT}izo?slvLV1US{4X7vg;cul=Kj;KKoYnw)#N|xf=gojc`&9PXw)s3ea)FcPc5Lw zri31Cf;V+H~fELM%hj;YAiK z{JLE36MJZqGdyb?8h`*xO$gQ8K;`XSo=CzlRoj~z&Fmpbr?x#ZmRNJA=jwph;d#9M z*Fyzai1J)X>e#(acqztp%542@6+PYW3cUR{ZVF%)<8 z#H&3iaT#r$ET``Uj6mav1MsJ%zA+rxC@wDZN2StQ_<^O>yRe-C*vuuWmui!DKkhwZ zi@_IUO_ahwUHav7FUn4J&KnuTXrrAeUZ4RlEK5F(Sd48igUkC^wb0IeW!~+~xLVz~ zfW&O6nw(^nmq|Ml(2rsf)m6mlY7xaAek5^e2SzC(krYSY@tcr}T5?EvjzGo|9G9F{ ze1?!VPE36?>615beELmFbMAD+9f;nVL7)F1SlP1FJb!+<+_px6qD$y*)MC2eNQK=D zyQvDlVs%1n;|=VReun11^vSObOifX8g-^HBJhB+;WH^d)gg>>T#!>J+;oMahT%8Vi zsHs)%9@8#9ii0fY3C13MBtO~vlC@{g-n;*8j6|I-`=8B>|GQuL#>l}E;ik)bT8g>6 zAcMJs%_pBk3Q8N~PIe6aE#zf^ceDSKI3v6P1Q78{U_y; zb`}1+*6t9LBl=&p6gbOO+?fBWmBih&=iT_PTBfMo|38~s+}$e^0bbbu(Bw29;<)es zl2ya}e@D3gxfGwQ4T~r_$B;#)X%Tg6H5|Co=VYHh_~hG1)w^k}8P_gH-RxJqx=-=i z+^yDr{YBroKP7Gon85tJx>~D*tFvLRlvdhkLyB)&xl@6wx0xfjJ&~yAyO^L|j15QK zfOFS|mv6zlGmINqCjHnY1?^VlabW_S>$#}hzr2BEQvR-}0msyacRQC?@E5nV>1@Nn z7;toLcqtaVs^?s@VH9B*Z^QW~7k6*#VkY;WVQld3MH^J%5bxfWt^ubokJoV(l{>`C z|4R$r6|~{~_{-0IkW2cx3uH@Ec=GJ!5}r`C69Xj#2C_)k)Zo8u#&{REhunFjY0Q{x z2@jaz$yLwNprd@gpafDNJfUqJFc!ka%&5|NPrvk(^0f4N*m!<{o{f=}JW4|7N-9s_ z%46TT#e`Abwc(`xsm>8xOvAfE-V!C@8OLBWxhR=~iv|N3CP*$%odUh8#*79 z)%)+p6oiAufK#t`nA}3dcnV6DQ8gV-uXS$1 zcW_I?Cc$OUUaq9{VqnT75w*9y7u(G(g|j`GjFouWW^V$6!Q*G*K61j~^;RHAYaKEP z+UkVoStf8i>Dvl#ILx_V@BtRzLNnEgM~Sj%eak#)ifkK$_hB@-zig|g6s(S^Q>B@} zSyij+DTM^tvE8cTf9F9Pin^y>SD|-&GFN}p3Q3jm&`x~{afs~gRr@j7HW=6du4Ipe zSnj%)>2A>f^$pC+?Q|mZfJpu@QJMobqbTpm)q023(+m=MafQiT87JfOiNh;K4A`_P z3!aBO!ys9gaokI=i`?9Q^}2RZgPY3P>R=H1xS$C8$<@Wr9ot$09Jw+*f;h?XyD!X! zVf%)f@Y#Dpo3pPmfrGaxYp`HQZ7m>gGDv9z$5$MIY7oP=YlZu>6ndP<`$17?8uqRv z4W-vnRQo-{bjOLf+z@zbI42B|23;O@7{NQA#pXk}S94?X0L_*ye6FH`7*g}Www|ce zF(O!!Wh^#-)^{=Jd{rv@Q~hdEU!xUv!Spd|tbVnWlHdkcVyIiGXobbGC-*}0}-A;d1$+p6-t+^22X#Hvem0TPDJI6a*>&UY{_r?@c#D1Ci6B$ zUiaY%_diPS<+n{mrWNWME1Y=Q#XNUR$@aU^AtXpK<$L^xUcdr4`Z?|J)tTqQ)iFBL z3Qs9Ez>s%H3kLYFYCre@Lqf5~>r(jswx24;(Wgj)A|D)Qe0u@a%0*z4$yH6@PR|IH zTl>7oU1X)SAuWF)FoCg6JXrghqxB~*=w9UPv!k)tx63zH>=u%O!)Jfi)hLzG7^zyecAK5AB?K&BJ$b;eWTn4V3}O zJDhrGN7V{FzOGr961}Ir=DC&m-gCTSJdFa|R&rM2vO~CMoo9J#rjMbmoYM^Tdvy-8 z(y`gDD&nwBdPWuooC5SSU*)+qu}kZ5%8hm1Cu>b8b@$d=ma>kgibhqm9UZZKa2c%C zypSzC8c{7`zx`;?{ZF#_Ww7q^t%L&hJN|e2ANFuwe|x7@~S_)STa)vz+gUZPxP;(Chi5gv`2nm8~JoAVb&$g=fxIl#Rd6v zUtrmrb!^IfO--Iucm4_IWx6f^%YW{t>#UB1NR}d-afG5y%wEaPNEO`K-eFi!LU;@0g|pTwXm_x(rEi;eEZ3Z&8^dSsAhv z_(Foa~KK#wN0kZVmzPbpzWFD6ET2a0;zd7i z{I1NCBpdjHi-j0EhPzDj=&(R})}oEgXIw#d9^qo#S3<0rWmVIZtEF6YBGS2oQ@c>S zD!p`?k^b9Ce4}Nr3a~t11D)Lrz~*%YKWJtD6uM(6--KgaZ|qZ=@3_7unze^rND8d4 ztz#KFy+__>9M4S=O*ZYEI+)JX&C}tjQM6YL7?p$v=XOE;BBq;q5kV`0F3?YjckfA` zX7E+?V1`kt@@lk>=m(RQlJ`)sqJku;Q?UiwvUl6iK>+LS+T)b9tyHSqcY-0*y9fo1 zv%5yM8cIqVng*9|0nUm*o!@he!zQbWNp2zFs}vuS3-bxhd>dw&dGCqw>fJ8s6oZ}k z$2UtZE$a`=ns9Mh+G3lBlb8QU2rNhqQ;~n|G621kr)rNGV{loQbzGcUoF@6!12fCY zrf)?OD{+rj<2kb4HfpgHsL%G+xi!>A%|=X3&mU?dOeDY267t?6wwe@kpV3KwXOR@F z8Be_}qEZo-Rs8wZ8{*jWfR8m!@!)0X3(!*6H$d0>O&|rk;(OfuL-N@WKfG?k%}?g` zi>0}o^m!QcoqN>*2U@0>bL{mentO`GrA7@@V#`#zZj=wN@ zI?tT~%jWO0FP6cs%~abqz`r-r=1)_7c9A7U_-GSU%3uS4B^0VbQ@A_ni9Su*~h#3@EtA~|gtnlc=;E-T_qqc@$!Nt01%|i%*+UZ?X@zNKzMrZ7BdS?{h-pAa8Qr>6VZWVZ zb=S6T30__KvFEklfw-gacAhOgc`d)@{5HJj96Ot2KWd=A^KmcDq!(MJ>ZlT^gpI^fy(zaD5A55SV=QUZgKSWr z4I`ApKD(@aXEuU$FT%|>u$Des_mopK8n4g!$E{KI)*^L1VN{FDLxejF{*h+4{R%>Q zLRh8#la^iRD;2U62jI%9&3H3y%6Z8(5jgPs&~IibVRlzMTzxj*pTXIp-2R|^^W3kp z_bQIM@MAsnxJl5of?-iRQeQ&}Wym7L^Lmy4=&=Jr_HiQu?mu1EJ7;0MoYaT@i?AN7 zP1JN(V){BAWb(Kt;~}1_S-%y2gH3Bay=Gr`5~)u=$>E)0|86{t z{o2gpVr$Yx?P5+j7QSdb9x1}VI@t>baF&tkD|=~mn*>3*swlU?WH^Bs8A6~A3| zf7@A^Ri$|~>q>g$Kglh{udMOt8;ofFRyEP(D9D$M$5-}O`3tj$yN%dw-E!>TkSNrq z%klC$dINJdLX?HWu0aRaa~oeGT*ZxqYI+-QI3DRX?aG>>xI z-tC-F8w~K>0`;n)u77oq28K!L(XQdOi!nE&tG6{KVh_%k7#*$3(Alo=kwDJFemU3r z&~liXi(|Vs_y-PGV2~@&IQ9)2?&tJD(DZUJJT9g!uHW3bwbAMl`1N}?y2b;cfDpY@ z73J4vn%tC0vaAN-X8pHWvx(1$vbsFT8PN}D{j4h(%8T&^jwauMf8~CTjP=~1YP^QZ zmfKVk1Enk%xijgrebIw=5i8IA4MFMF-~z>2CKW`!X!vu2CgdQE56MZOt3eDs(1t$O z08+RT80PHKF4}(yBFtO5?;+0N1sCT6(rpYb>?Qm)UF{bd&8C83*M2IC9b?c*-CUs$ zJ>nC(U-V+Ui-b|D_Uda;#9Df!=)&*w5Bt8&*!o^9iNX2Xk<@&1`Rca)<3fCT8D>m~ zYQ@RiqCPvq%YgI-+A%^J6<@lizq$46J@-u4{1Ju2bEW}mN(dubBDAe}nEcN+%)m=@ zR4DO)vsKuP(cDnK)g{Kt7u4H#0u!GAC}Zzt3Lvv$}LRd@6ilu?==t zvoYo@QRKroqLXOv$+NJ!_SR+HMT*<*eS@KrVkcwKK7|xu;jC*oIY;M7hcdn_SDmps zj*3C?>h6{*o8QSe!!oTu!qY9Vw0>Q969sKT&z9=^>=bO>_FCAKD55uu>7jd@+xx6W z>$Uea+b1_oYF=CZbildrUaim1zljH8e?*kY$ND(weQ_EfdtCb(^LLzQp!0mQ5#1Q=(^ITHPqa2v)S!G{;(G(Tk2 z-FxOw7_DzdcW@Tn&t>^RN`FOt>5%Gq%-cOeSzZkOxbc0`XQlG<)SbAcY~!IiwZVzU z$NH#09wa|msfa~eI{6bn*mdb?Hbf6a(DW&&Y|Z|c3+y}4#DxH-M@Q=V<$>^BUXkCj zL`nGvRfzLg*5;v;$4Kdq{U+oD>4h4XCuIbgh3faNGT3VD45E%PjB>&sMs3R8|7Wlv zxOj@S{}T(-9FE#&CYm!pH1=9WkC}Tm5j7Uck$!4``Ygqafd6iUTgIxHo}pEn2B7@z zt|s|*X~kl*eb+Ya6vyh168l!(wrDFW!b(p1NRW+y@D0urmiw&Na$cBxLzUuw(ZSUQ z#rmz2rOKRfuUF1WEaz+*N_umxpTl`<^$AZTY7fGv^(+9_o@nkzyNae`A#}R}XKU(M zNsa8^nUXL$Hq-XpT4Jc8k<^C5IgvUKJFf5tVYs$n%*>7NQkLO9J+Bt7&yg3qGnQt^ zrbau1vv-w`L!a%138YRbGIXZzS$J4b`czh^mTwz;4$dSBgpn6dLChx_@>=1SZcW-> zV@SBv@r(zf4tIh^U(DWMH{Qr1&zk*Fr!JU2PwBeEaY#(^se>t&e2ARBxyRkqu=;Yy z+NPLy(pRKts9^o{a(l&ukq~3Ss~DJm5MQSM`U^(?7c9l@ZHo(itmG?=7Om{ z$C!m3>5zqjk9OX7ZPfEMb<=+)3RQ;4zI+^&8ntw-%Hh)r-5~H%vH)DL6q;2dPkaOa zRn^^*n58HFeAc~u3;g+Aov|m>opRe_Q3fScN~#AQ?11T<;0li>e}nrTB02BZ8V8l= zDzUbs&WZtQ|LojlbFZM7?EfyhoO}3h#f7HgMdAU|T*uT7cP&Pa)`a)yO7+U3`p^D5*g2^JnyQ%d-Di?XvAf%= zfcB$e_Oa(l^sR%VX!UDcjqy_f>YV1h%UE~(WN8*wH;OZ||MNTGy6)u3m`TI@C6c`G zSRhlbi3Gd4#+4)c!oRGMkktogZ|J61NGW7lwgb=YhKf5RtK3nzq|z+G`HOar(u$&j;{vVR}ecV}Hrl zsY(LsEDYaU(^I(jE%8O#x0Ii){bl!DU@9_~3IG5(cw&;h$L(Evy>z@V{Q%&f&$5F? z{Uh0G!6T)E^;Ekl;l)e0|Bk8QzvNacjMF-TO<0C)6UF3-sDv1y;zT(gU6WHNck2?^ zN7(Wwi)w6O6?JK)stIX718tzEu9Iq56~A!5*hm|;z=SDaw29?+P*oInISgQtP3i#3 z?9iVuSxGvIo1uGa$c<~E$J~3p{+t<2&l$ifwZQVHDJ7?&x@EAOYwC1S0Nb!5|3EqG zqzB0Mgr;(hRewt0G*Vxbh}9{LPWbQ+18qf@U-)>r>T_&174A)uADBA(N4#Bt^+Ui0 z=H^;06;}*uDtsahFnzHG%8V_bQjSW6UW=m&8aut*4nK-u99(I>yqe--34ig^ZkaSx zW0+87oJl^jx(TVfupl)x*8QgMrY@E4*V;UDd0`JqI;v1s!7BT0ZOQ&w^SV>4aIU0> zCA$v>eok9e-GIrI=F+ds3P{O;CiYznr~+nqu(L%|F6dy8ngIeo(Pkb>5J9jh0}n5Q!sU+gadWkP$M1OgI-7d?A$uy?A&))kn!i6L*o_rF?AD* zFQc)P!TvXOFR{mVU)-t_dO!pYB>inpg4>7(=JCMyg4F@fW#5Sz#lOtbO&;IMkh6R% zygD}I5?&ds&%k~F0NV~E0t_=7K1L`_Rm1-n->Ejq6q6RZDmK4V*)me5CaL~UW@evr zeMxrG*av}@2YT0>t=KK+LZN1-SsJ5PxsB<`ii)U2w;cnNNvzsy#SXTZ>aD(Hep^ijWQ5z&W#g8 z?Vezy=}zw_r)Q>|dwtaKlo23u>Dm5?N!eEZ)LG9=Wj>tk8-6v$}<|_3GjYpyTfEdqlRXmbYOy-LMh$lOMpO z&$@oz%5@=U%A1+D_ij<%)SU!}BvpU^6TU%51~Ii3>Z!pcoX@J=&I29L)mIEfpF7w5 zF6^n)$v?J;(`q@`Nb>F+_ji{QffhBd_F;>oYwAx18W8&|{X)GRyXH43!wwep6m z-Y(Y`KEXSAfQ=5@Mb7O`k}esL1lq$4%Mr9VmsX-~RQ^JU(?At3MQuh?*Oim{rX!4m zB{$Z4M{-ZtcMxt39s8CxqR9Ny{uuf_*XdJ-m4&*?C1uT;$QAmHb?;-E$xgQ#x4Rkq zZeMDT$jY;gHNyHke&K!L>?0)LLLHuIxNwUsvI3m;_@4PX4&?UgfO~C5StsFc7Jn)C z%d3+?`YNC1-UJ<49XhI~iF!#<_zF0i?FSZn#Rr;sF=86G_Az2ppK_iSSWXnN&S`a< zDfd%&O5ZU-806 j+GxnnQLvgZ7MQa37g69)DO~kakB`zhRvl2O{d9>mz1I_Pwr> zdsS2a5(GlR4x4>$k$@kY->`^ZEMr!^1-B>my{~%G zOzL1tC@AZ~HrT~igO6oU8N@q4x!wQIQF3FWSRDO~2h@}|)%9%ZGjQ3zQ`hmsH`sfX z=kqQKX%be|QH_x!P0680ebq*17#vGKGC#V($lj#?L5MHoD11|xYi0RYFF2?rlI0m* zzR9~F*`f5drsQb9?B}w{``gI{Pw0*5)~YGGq}|qlx_t}ua>B}(^)pkpJ5$niWlDM+ z+#bKpN*`npXqGLjkwSCxj$%^3L;TNGoU!;``a9y_x0>VI#1R*Xu=KQrCT6H)ef7Zt z%f`!KsMqd3ZcdngY2Lbc!U+G;t@n{Sgw*rq6~zC?HrI(%}g7k!}` zwKBJ#aP=tQjQiRlL^HKAtQroJTXjPRvSy?sB1(=V5_F3Bj@Q097dfeI%H0Lg0MzAa z#Gq=wgxUK0-?wisfL>;W68HTQzIYt^NHIL{K?$njm3wXB+=eQqBNP+_`82$urN0QdMh2xc1aS65I|kk<4g zEuY*9P~Y3vI}Mz*J?L+4ey~Xq*xMaMe9Wpi&lEG$H+1r0uKu#^upWMx)}(h9PL~}` z?hQZ-_^KXhll?qIDpuK&jivcMIu$5{5E-vS1KWZY44)8SxTf_<;mU(|U~2b5SB|xf zy}TPQckQXRN!b3^Dct91&s zst9RqG~WUH-D@S8UxlZ<<*APIPhJUzKkE#yGH{6uENuueXZ%jK>&(nZF5iw$Gb~Y_ z?8soQX8Uim9}8v3@Cctq8&NcS3i^-jr=GTByX;xv)vb{%bf-CbqI zK&AdBYVB7cxp3$r?W7mwJmAb5HRP!8*glw0I~O|0zbC>A6+`Tq@7mryb?;8vF%!!9 zsx&coJC#$mSxSfgfrv>OOnwA94cak)z`g#yhJm&pdbWUJc%+Uf)XBVgGRB4>dRe44 zhV2Z@e5E#*1pm9>GI~Ww3G|k1kh#dR< zLug~ITgfuhv`42HPft{;t76bP~-fn;lg7Y!iI6iwn{>iv1!D`^}Ay+4d1vK z&N*-cP;}PK#_1!J6X)pvG$PFvvq3g zwI}!o5ShN&P$8DFw6E?d9)3-%#=DkuWiK9sZ(gt`K1coG9AeV)rxK1O|F)Z6L;UcB zV(+B%ocC{#Kf+X<|NZc$3Ym6-C*#R~4OIIJoeueY(G4*Q2!`6uw@D}c#9i3UnD!XB z-<|R|)p;R4`tW7ctQk>pAVXLKRrnf}Z5>A|nA*J-AsZ>M>Do$)+t{){wRyhPE%I$U z>YR)Tmv3@Bd*1J#dD4j&4Zh&b5O~68+do9vXIJ9LeKe^r`3PZh;{~3n`4OH}Cn|p! z9jp4Xs2gcL-gl#s7zO8^%O~Bg8i1S*G|%9_VyoV|yUy8?yli{OGG^3)5nKx4=#O9n z>BRnCQ@ao9J;;)y#cwBj!u{1>B3L>eCX;UwK7upv`9??BUcGRL?RM3r>t94UD~o;~ z!FM`vH*))BxSdWn{W~KXi3kAvpKN_q+Omb@xcx#Zjxc(WjeEkbf@P-WPsEjVdWId^ za%&8wYo&LrPo=$@rs|KjjIJ&*3_NI`rQv@E-+ikKy7bFV)%RQY)ekHWm6X{YjW$Ld zHnm|K!(>=v`_&XoL_sM%+PxJM-qAh&UB8f^8mVz&!X?vFH5riu_g`;qFRe^Qg&Yzd zJJFa>UG=AbPK9A&w3Y{PjUiY7UZdQ06q4iZaG5a)$6Y`Bg`P>qKBHUCPFS#E~j zUuX_z3=pKA1>t{ciGw3kpbN(tmM4I|=of<9yBh~~c{&{-?HL1$0gENd&f%fY5~EI% zs|tzkswrBNC*8j~Oa-Kb2Vt5~Fv<6@6vgQA2Aqg;`kUg~j$f5p!WQuanRZ44-$li= zv1zGKY!DsO5)L0D9Ow}6tIc$5RWR(4y8GBcbY1|D)UWvH(QqULOECqv$ATD$h#R0< zXGyjaXmir(wa>XorkqOP$cd@EzYxtU-0C7=Vb8R;{XrX{%+?ADeZ*t4I`<%1)KD&H2Ua6?{0v&5^ zXlW+E`GFVLZEGCuk*RsYI z%%4qq*Stfi(W>=tU!w(H0NX7Hl8iuU;3w~x|KjV;%!74-mM+q?ML9a8Vx&tT^BVD9 zF_-rwZu~IX?F@>G!1~7k27~C%2H$FFyVl5h?Kx$e|HW@>FS8h=&iQ`mjr)OhV$nl7 z@X_@HLkwjP#O)`V>>Y@2G2wKijMsKDJK!vfW&t%#OppH zHB*FZ9(3M|h^bI3Sic6JaLQT|9CNqXP|I=wl?3v1rqM5u=5xev2PEDYJhdbE{swKC z_rhIW;8fx3V?bi(SrMQpDpNA+H$Tf4<=1%{gQiqH0V56qE1IJANJfft(9-w?H&=gA zx4mzS>RGe=@-N$YC5hjUZRKyf*#7|3IgIhawXF;`uTM=yrq4e3o^B8=JhY))T?>rj zyB4)+pOO8O9C0&@;wiZMyKDy2Ua86mRq%oyM;&fs_0sq|{09HXqg!sfD8wJ3bdV3= z{BogP_U;k4i3@yAKt~cNfTSCc@(yfHR-w7g^Ud)wB+7YRhI{~QCzHM3FTV1T?8IK*`3vc$h zH{|LCC)%8)Ufd&6+~RL?U)x4Oy+2UPJug9iO6w>^Uj#xcmSl9z@ox3f6yd?KwJJ;`q?^ zK(Faj$~xD=!*i=^T^b$A8f#~IOA36UpD!;3@6QZ4f$e*tDPQt%EP zzDpstb0CSe0_&#&F&{U6H zlVG!FGazPnt)_3{spHDtPtOM~A5FZ({dl+7B1&4*;4{1MZer?N>##U)J|<-xeV`>B zv0>SYbC+9e>Fa%bC*1?HcIB}4Bz^WUjiliYC-}@)7Ckj^Y$+|$e&3Pm9aP|x=d^+ zY8MDI_yEoHKJ~oXlXm;!n@ti~=Ssrn^%#?$)n2|A2WxC(s`5V>&A1*a67`Vi@p&He6zIRM+Wa_^ zi9%DAxx4>}cXzSxfYg9*ChQ1LfSkno#g*4yj5ImDNr=_+GQRslE{zi3P!_a_wfefe z`Xkbaa&vrMOWS1F-y*LesAgjRnHu52!frYI;$`8}j@nNebi<2@L=S#mbv-GasAdGzMJtT!JRerI4;rtf~>J^6= zc(zn5{I9&qEyv~DE-nAX#5Omy9P%a>(X(_MBl;1Fc(Q04BXVlxT`@ze5z^q*Gwhsl zTT#Ur-|P>Q{A#LVYDEtBq;!bb?p+1CiU3WzmrTyZaSCHux!wxZ%2>p8j#dXVC+fNU zQ|EKSdhNXsd*9E`Vr_}?7-KlPRgGZmp5cEQ)T8FaY7iFm#BjrO&?!p8wBVXn!HVc} zQPJ1L;tI^r7k0~#j{(auOh7`RT+N=Qs?*#0Nqa416Ry4(k)&I>u(E{tnLEB8zQYbg zXw=JSy1?tMaO^h~&tf!fs=PCzo%aoDuYRj%^Rm#(=$eC~PU~kMH?gB9ZBbx#hHWVd z^r<9_X7iF?s19efuKXhMrBM0}njmA4jehSZt_XG@4)3lzUsRO=|MMDn*HKle8n=5p zwES$+*clWRB^YMZajiVkh-JffLUd@dI|^LGe&afX7s;-bxWAZ}=NPeM8~yer^M&zr zb}`*sS_Y4BGMFb(NVs_}aA(5$3#`0Vl&ZFipBKf&-Wsy*7?Q783G7+Ix65r7L=ShO zJax4yR-Ti!I7hctphE0n2d3Q+5GcdcDtUD6>S9K;;ZUduMcr`G<~XMNLZ0FBwVDDv zGBY@Nq+Ix1@ugv%u~xQ(l(k;j!cMMUS#tcBFE>_cq6p?6=j{PDN9TyI5OuPLUo&sC z6-`Kn9TQ6=tpZ>V;f`ON61_>EfFTu_Jgph^c+HrpECtA4$bg&9kVkBkC@{ZcP1-}( zt1TcruDvN6tO)d~5k;&lc-5+Pz+4D7Q+r7*0rjG~;J3Q#drTwfwJBeujM%5c-)K}u zsq^cwj^og&!ama6YmD857jD=7O?bu?(*Bcsdh2ixvpy5+k8R2!Z|F}y!Cs#*Y`Q!K zdV{VWW`g?Ie%X9xS3RxzK+Nt0*0Uk=l~WBIt&v*Z%Hn-`3#V8mUFrj$`O)dHl;1=1 zWpXEOh)2Q4T2lp<@mz%w7!mV;dREP8f)z6%%dXj%273#OsY#izYP-?G$eE$ov2idI z1Vy$qz;VpZVwMv_av)U3GVuXAXWy{a|UbCoaSEs&efwvZSR~zhSmW)?dqLBwLp_x4lwEcldQ(iBU_i zNSH40qhzA#d(C;kLCqG3_Ya8uV_4BTP4dE2lfW42L^yN2`2R%OK7R7b;g?e1D7Y9k^Y*QnURiw<`wNA`s=ke8p*c zKvb*}!2@=O6R%&o0bNz>DD?%tLuN{!O;4P1>U^u4Z1igwkcja~WFFSLcLE0vo_Ik_ zjPm);`mNrG?kT@z`DX|;ev*Wtsc9SiI`plVJ35gp`lbeeu<&o(QHta?Q{>qBt&P-nvPCEboa@ zc?B1qU=}yP`dv46ZYb}Zd`U)#*@K$Fr$S+f*bIIm`9?$Zm+rXHgSH#bi{1A_Aqf0j z>IADomLCst-eAM+4fVOr$piLNpM;YCklB0I9{d5K(766*hHdrD?3kNhT*0j@`-xjJ zV&kt84_oDMtC}X^t zT?u-WROGbt4UF)+#w;f6hj)uP;yQh~#fPM-)}ct*;N9^Rgk<`Z5w~+%E!E}6`u8yH z1f?WJBd#c__ASoUiJ!I~kHRp@muDg4_E^LKB-iM9#xGcye%Wjq@T7eQog)DJX4i09 z--$VoQ*BNA24L%)3ZGV|`PSi`I7wN2;@OPhM|yRVHO8;3U0Y;AW`yK8&T#B@moQz5 zo7f?^GZSz&XHz~H{2BD{K_a%8YZAEj@d4D5jvzFyr({#@)s14?P%@d3rH*a7oS#J* zHQUvG9}?KG8Eg(sjO}u4B9b27%($g0m2z!8KC7VWK$gYRR6R4Q zlg%I|hwn!m#QS;Dk;llS zXZT+ImKe^R2CmL_it0q=VjLULd-eOSZRUKb2XU=d{pw$b&k&9ywB_zY>R{#E^Vp(R zX)U{}D6dxmIR({BFXwvhY&}3u#Knj9&nq6|dGx}+k}zS&Oj7TAg;p-Xx^i3-(<_Bg zyz!c-Zieo51x9EwYJ`M8zC?iuHOOFthSlxG=Nivk{ta8yjr6+39CkknR#~X}t?XVp zs$&wfdtun?&){DSd)Mj!#;nf;wVLw2xt30EbY{*;U3uTk0`lE2hm5`m1C)@i)URtC=r;vx7QA%A)&@M-OWm(6Pza7 zokwY_R|taiQSxyrwjCrR%6FAGf4&oY?5UH<@SH9A&z}mO7VeN3NNz@peAa<8zub?H z<<%BewktOA3x^%M+rR&^r*e*IE;HD?p}KO}f?8J6@`%qSS7<$=6(-h*x)T6Zm060J zv=^%5+3lF-Vl9dsEIRUM2o3))KJR9O+C&ez%AW%0piyK z2_M@=uVxXK0hc+(rc7#;lVbviSlq z(AKuWW}^mX>%E5*>}jQa?&l2kA+d*bcespnQuQ-<5Iu4pVv;9C2Ul^=O{k`D$iCR1uta#({@kI(?4?R(6z6-;ngV72bs5?ndZ28L zobI{}G}D0B%Ag=7e1CZe`z&$Y5Z&t^0K*BC($vM`O$(oT9X^8p)!L;_{(41IWRQyf z_jNRCUa_95vF2_?1Y3RX=%@Kug+Xn8B?-!4}wi^G1Z`aw{KHDK0~gE~voC$}oQNg3jbD zJ(drn@OD(zb$JtGQ**{w-@nd|S7i)#w%!)kye|I}XJ6uvIg?1@x6eGIyCKl>7)T4q zKCj>+DmIZAcG%?lJg*pj722PKKEr&Tl6vPaJ3>4gH_MI2ZtkLhhP8vB&TvC;1eXe>vi`HUUDoqT0@-3 zaZa4_Py97{PkSdosK?bZjuE^@3(DT{?Tlsx#cus3i_pd8@XgMdBS34J_Ea6q4XH?( z_ct!9xpVbx-jl%Ed715eCY!lQp3@#jr*&1fMH14nnw)OGhX6yZWGnac$F4t@q;5=uGZ&wF%;cJ* zRWRK(5!z7{Bp=EJ8Fi^#NTpsJCQ`&zqpMpv z_N#y2d|rA{KMi6!Q-{b>j3x@!A@G2VmPxh8Y1n};Vac^H?lY8zUpv18zsW!g%YSv( zChYYY;Mu2tPv&)uA4NG89Dlq6ckzLr;`|=961}V~PMmW)(P3MRZogY8bXovz2ULG( zTE53s=ms4ijEH9Ve_lAdg5?-2B3ZeJVNmhYqAglE7Qn%hGP}}=WlOlU-qZU_1>EH1CA5-O}upr?7+tp_q; z%`x)vjNd$wH7hLp!|`6w%GX+^vvp2e1csqv!rJX|alpc9je!HXuw5sS@rB~>)+f7j zNnO%j9B1;n60ZQ$&fX|zJNmn{mSA>B;Vww79&YO3kfW{YDRi-ARxa$ibp=Tc8&4SNofom?!b_y%>$& z=~N)oMtC{Mhf5ab>u+Fb6S zN7;>CLs0$uij?)rQf;?~@@PFo7X|3qMD0+HUSo z_(1nJ6R%yMYZ21u!y3~W=rpt=!} z!w8t?GJGj?mjVv1Ij}<+-5=u?ROuBx;0N5h-3w~9&K^B#(m7x{uQ|%3k$I|)2`JS( zbo-x(+LUDj55Sj^QL(j`u06W(7RKRIZX%S zx>Yk)KwW1B5Re^eVt6_Mgj5pcUvhp45(0wvOjb0uyZv3?bj@6RC2@E(pQlw%+%;u; z;Ov$^zz9o+R`>+WiKp)C9_@DLQJ;DcI<z0>vMg!w@Fi4TX0j0+z+^8=^i-T)Re4wg73 zqU4(z2;YATmB+kwXyd882QO>HguA@#ifop<4$1z!cV!vPDK@$pDkADlaoA1YX-#xC z9dx}nkr(7IRa}k;Z!xUid<`w?vTZTzZn^7=41WuHLpN#}0o(^3cDEK#*nRvpZ{qEH zj$T%+zQypZzyfz;!ZGSap}YoG)sch7hAEAf_nKyv^4}f`C_K-&! z95h~)ZD`DpXxm)hm=BqLW~i7!E)GPUILS$3He_tDnH4DqK^7|j8#gnx62_w0a~!wc zOVqEPP5)={MNni$ULv-c5$^$t7VEamunjoB<=*j;xr|+}kK?Mubip;AlNH7yd|KfzdDPRfcD#BqG!H(@;i$64yI4N@?z+ zbm{OqP}Wc(_)1m`q#LsOjbi-*Uz0zI*thclUfu+9qOQb#qVm=@tVqd@BWh(B_pvPK zVdI8y$w!G_qyHI-|I3Vwmh%!#*iiK~EhX6!AODTgYlk+<%0@5QAg2}HJwd|tw^CD8 z5EE80`$yjwzF~0BVvT$hB4Yvrq!USrat&7;TUkzz2)42iW*WY9rvIhf#~80zs0nAV z+!38U@>PMa@>?2f4uMYJwt}x1j@2EX_YCNP5TY*Hkn@d4qxC(^@^eO2pEpJh)5>jV zYTJ0MW(|1m#1LLkp09|}BqDV*X3^Uysh1g|&!=NKLJ=E*+W`X;+C03=ZT7{c<`nf4 zPxrGAKTe{KIhif!C!fPDU#~gb)$~d1o-vAi2h>JIe;FFW_D|i50PdJsaVUSD@G=j! z%^UAgzY*{M^lHWLqR&6HqJSHZy#m2{gOcxl+H>8!PZQyD>pZeV8r`pcFC1~BSh?Ow zsfMuqfJAko;MeCJIDc7WdvPlWu>KMJKE7^cV^UV{u2o(q1CqKGy2pEFM8Zb^_>Pgk z0xq2o+`9=Ho6sUJ%bz5)a&|ID-tsRWcL2_)*=SdL%Qm;87IW@a#=MP_=(4nh@H6b( zJ9#2LEoLvV%w-)a+X`N5kItM94{9x*_{aS>)I<63t(?y@wVePK^k`+*aZeA+PnO4+ z69#0ndlRLymOt^6OW>!c`%a*4BH2*0-5`mv zput@4=FwcJIg3B#ZU$#533IzHp6;sQ>Sori#IS3=EqGKV{e<)L@u_y$NFrg&Evmo{ zj(qQ4?T=B=JwBB`Am>JN3B`d2B7%NG2&~0D=MUnZ7DJM)+{9=lg+IP&XReNJ6;oNw z$#*c!e1tTx>zM17OP{A#x$k18_tr z0-4!23`m7_{CsvhhA{Gcc)R>ou1jbMT0}$F2gkKJPrD z!+C@_F`9v2-MFbn6-C&*g70saZe5hL<4IHN;Ln_xinHMTg821(MKZenwQDAS6uu|W z^9hIPmQ_rolH-?t04S$iY2&3b5;T&8llL9AwP<#yXPo8Cp|PKc(<0x^-mX zK}bHAvn?vK@9HOg)!l>}1=k2MGzO0eeUY|0`d;;0RyXy#J6+NYX4tjt6cyKA9TS)T zjId8IK@K(D32PjhXjBsdTuk?nIcV19n0#~YURhtoxLunXA=B+#I;*$`{KY-fuj>8Y zJChlh^L18#%6SA9SmmQULYVdE3b?kAXg=Y2cU_?=0+3a>JF0)bmftjy`LU6N=)jVZ zg2E6R_=al=h?h^SK|fC6YrUC3gHN3Z`4jX?vC}06|2F+0YYtBw2)loRI);slw2URI zRnS}9Ouvj}KRel+%1PdZ_CfB|IeveAd_P>Nd2UdcEb4yS~NwP0wk z)A?*+<>Vrte^TPkP>;%=&n|Hwr}H1gnY?Y&u>%`%UKd|)Q^g?@rpmv^0Bi-)S#`Jt zti8jYk^C|8UGs`_m6g7psRM*hzZp0v7byavG7A7vyd6qtE@UPaGC*K3uSC;E=XbgT zN8!t>b$>LiV?iQOCVh`9WO4jHHnguEdLgI(#=b>nrUi6e1WIhY+ad5aWSdRPU_^OG zn19_$SQU?@3uA)(sf8e~CEF<066toafy78b8pdbe`Q8zp&*VOmmf>$QA+}cDON#r- zbkwzQne(7k!+VRJqk}(rL+zD8E6dyFXJq_L!;kMZk&gW*9yT_F=9DDO>D#m`O={TF zoU6dPixB2J?bx++^2OpXGhG@!axC%fB7hd={IMjRpz}CsHkS95++| zJe$+`O8raUHKHc*Nsjt$G7p{-&$tC#_Kf-?yPsDMcgkx5WPsLP6tt`~@4)-_uHm^o zT--9E#dIAhk`bNp0O%x2uIm<3^9ZSeJ@4x%ASBGL$p@zM)MtFhJhFT0%7^7j2dNF- zAr~%LUsmBi6unCMdJ(v>dY0D+&m7jO_rQj*#u_I_$nTWBoq{pgOW;{$Qkz#DJayCY zhtG1fC~!BZ$|ie(RqytDpt+ZrcO>|up3B{`95?9rZ!3_l!g}lJZm4-*7wHu7#Q}cB z-&?HOP3)M3P{Eb^kays*i78+_w#PVmgOwd+ceA`ATX$Or07gM#btyHf8@}tp{0eWM z2mZwkg46rla`;|}+ypm${SEZ}DQZtaV|%9=VKG+=`upKm>f?jQIQHMYe!l=8&wfXx zM*Aq-v~c;v6LrJv$)o<>TA{oB1y!!4nBB{lmu<%QiyRr|}$gx_BJ(hS>BPNw+g-?!S4 zRz;zHZb*KJxc3exSdSQpI>KzLs|LLpYvrjI zAST^!Xvy(ZHZ7^X2Ij1@AHN z2ZY*p#rYFRmuNh8{q9|9wmyfqSZRg;V4Dw9+<`y&UZNM+&JzYTUGF|)Sc$1PQ&R8tysh4u;m;u>g^?Z_x+0_xK72W>HgLzj0C>l@|YW_ZPH+yrpHy40cE58kLr z8!7AxT5_<4Pp!A>v?||57G1yTBceY^O%!ho%WwM@Hl1>V71zWtN0rY6lb?f#KZuS* zR(l0_wa*3jgBh2N0fw-AhaI_*-%%E;DdQCyFmaPI$(1M;(iIne_dtSHQyMA#*DN|V zl${>rG^s~E*4emy@`C+qh$ksIrfCq=PS))nfsn%lpp#*5lC@WNUti)mD2i0U8vfNQ zUDezC!4o&3gVo0SCbI3z;SFsbEqtx4FD{wq9CrQg>TaC^O$mJ+ttdZcri$09gh#AlgZ?;xY3AmQJXnMn{IG) zv?kI6eF&{Sq*Evq<%bbfF@RFK9|iu0o~Or1{Fpx##uQjuBcB%88}VlL1Bq{<%RWD1 z>~=#Vxgo;z$`s(Mow?qK%EPd)DRzFg^v#nGRM&_{dxm24WO!?ma%kb$acN(Y>)(8z zN1yDR5p|HfaYK921CM|aynLiv_X)^4@tF{C%e)^)+6Rb zHLCTJ1oUwEyND0HX78bx*xYdd=T%X!HL46wH)W0lcr%_GyuEoG6u(>NMnGc<4!dGC z1m5u->*Z4cL+=l5vZY3~D{+@HN~%vXl=lM(O%PMC^46+xdJ~H1jklOfIEeuc@9Ru^ zj&0xC_RI@9*4~27kI=u>TXZvL2U37QqWZ2RwTE)XZ?f#g1~1)5XHfFs+PF)%lAoyti{H6)pc6 zBSkdM>B4?fEiT381O%7T;0{8~-hgiZn*_Vg-$RO95>@!>^8j0AOpb>Oy+xcT&JDa0 zG1fHFXj6v53!+-+Jo<%`)DLtcFFhj=4KP5z0w&PjNB%ABx{^*(qyKus6Zfo(T$lqq zO^UHDKh$qAbAca>)K2R05E}qtMbQ}}u{F(m;ANxh#pY!?$|`dzajMyq5X9SJOXWTR z4N}G_q3Le!us|YMEG#tRAeVj&zJ`}QqAb!IREsM;Xz(@>?Zdc_5sF9q*Fg!eq*0w_ z8|Hp*(S^Za&ZIb^t zZv5X}!f5i`ieJK0-nSO4As1OgxcNi4|J|wUe96{QCQeT|zxmRjz>I=637D|@C~5qE z`G`%12yb@d%r-Sgo1%!Yb~9qIGa^iQC@jBh2#yh;DiCM7A}){C>$nWvUROwWclyj^MCXM=?>t+aaF6X z^^YV5c~$?5ytX6%qf7pu{LUcnkFMLoxg|2*ga#SVjdU5QabL(LnMA^2E<#`bt#TNqY% z1+p3*@Tgu9^^xz&&q6i*HFoY(OxMb>H5E(v-JPJ%OxG+*gqO7Zj~zc7-dM5Io~!8t zUoD}Zq8i!Jf0fgRX2FDQdeLY4-yInFaM_6(RZL5)q{GYU+dEt}v>Y?~LOD3(2pmf; ztppc+28SKV6w@%%u1?h1a&XjS%pMNea(yN+J(99pFqtVhLdq;5oUjnlg0 z7`HX3r@#MA6Gu^w%~ok<1g;^P2fE#lMl(RcO2GBRo1<{L3o>JqfJZi5PTr5(Adc?> zUQTKZfOF9CxXJb) z3j)mBg#HC1R#DTTOhMcnp&Fpu4R_iMJx&s9VamZUJsT6i^+CF&I#ppQuItP4Ws33f zVsH_)Bw|t7ewtA;aj-mbY?uCvMjW6iE-JUs`_F)Oe$&1X15U>NZN@!-kEJg09}Klq zw=3+(i~tKHh*?g<-RVJ(>7MlG7(iJKMI8w%9YE3N+o;!o>X6HB^hcQ4r9`R$BBBAQ z+~!cW%=#Y$^nv+06a5*9Kui8HFug1)w8@OFf^nT3YH*EojiNf7^8+mghj(Lh9G9Q8 zZD`1$$aCdJ%-`lS#tH}?rIVn5BT7c#W<&=Uj#1s3K~KtrCumrYdhK|T@iICDF-L@A zU)XifioFyK|v_nHn<7AAOIy^LnYo9!BqAiNkT9j)lN`b#t9iVd|*) zm=ijqw}Wg~OjCR?2wRB;_pQ3VnmHDKxS@aD`*MD;^o`=21wgp7hWsFSB%daeKSs4W z48!&>t!HE?kC55@m|%Fc9r^v}s< z+z46W?x4>wn~ThJ{Xh17&{kh(jX>yzxIfuXjmVfVEwVsx8W{JCBjwyrig^bUjgw-K z1M|S;v}gO!Kx@IEHGe9YOOsqcIj4P#_PXgnW`?%<8xY@hoM%?N+Ggf1IW_M5amT8j zp4*Pi@do^=u^Vbt?t}0JIj|J9?9AiDI7zPNn`SvPbaB(aHXCy>*$*2LmdSH5a+8|f zrje#!8t&G2<(M=tm1_---b_Z=@93qN6P1~s!$PSi0z_b)kKr%!>Fz%TvR76{Ac|{@ z=}ZUIEhm_M`pDnc&c`TQ^If&7tU7eF?-^vZO^B@)K>&LYw!YhoA@w8&jHNOVlp+)s zsE(>qyL{5FB#~Zq_-OoXM1=f!|D_06>c?X#M!i?xTNHRnx*l*b!vW~mBmPf;uxFd-`v;d1O66Oe*3bfigM3;-DJ?*xh4DI z5zl^RdA+L-O&v+MAKj-KDOSVUt8ii6gFFa-*ZJ=<*3-lGS4bZka`nwz6K}0mmQ~g+^CcF3N^~71AeD~zY{)w7y0qv?)4D& zjCvnK2HgIg4(uj)xxpqghUg-eL2pj753m4BY(A%IZ<2@}&|@%PLJ!?BRu~$%U?^Z^pi_onpG^Jz!|gM! z4pmN?KqI`2`#s<)*GdA6^Gpjk1tZ4k$Q76@#U7|m6P@6x>SCcJ&_XY_fy_5anW&++ z2lomL)M;t4}pz5PrJc}X_wxpdqWp-h1MVU2sZz8*;Qct%eAT@F4+FbW{v zU6ZNL`P-^wcD3Q#V1x?lNw5^jMB}%XpsNf$}u>tM5 z==E6vT=b@rXec30lw#l3<=Sy8fIAK(2~U9WPo;=XxvT5S7h@yL`_=u#=KBS2SJiNl z#AY?NYMYIKPsI3l@Bi?NXm+CQ$zL|qHlfW^)}q8lmZtfJm{$+qJ|>0ZE4TVEO`-!o z=msS|>q0P=f4SixFgn8VQv~(aUwrkbngSaDn2xacHU_B(*Z=bruP*5gp(N}H(F;%+B@{k) z$ArREw5t45?}wK=$CD2`7fhOu7|h#e{EzA~2Xg0amI!Z~~>J~?)_`X${R36=&bHhrP6NGbF`FE>ndLiA2>J=@%4a!h}AB2bbU z$$IRRng#JIB0eJG(MC(%S(LUa%s}|IJWR@qehGtGBED}> z|Mux@hvGTu>NeOxNEA{#27M0Ra28_?nfcV&^%`Cqa3vhrYN~9OTp9R{1%tYEQS3Ax zHOgUjq3){ur`bves>_#U-VffdPQMe;3J#i#_9!qd$Z2#{mH?#n@M9#DFqU6fBcgoj z=>G`7wxZc;RhAcdpP`LQoTv<9SQXzT+cTYJziEoZKs&+aw7@n@n^Bm&S5bJ9OPX%uul=uvk^Q5% z>8~;5%_k&1UH^jlx$|DyL%hMbe+ zWPS~Qq9?exJw2>l(7kh_m*ux}2$!vcqpqLShfIFuPgR)f_FeiXM%^x3Y-)dg9>1(s z-Y#6;Cf@FHl$!I%{;>Z{XNmQy>x%5sL*Kx02a=*|{x2YwaZDzfAc`;{wshV_6i}%^B)yi{6wyI^(_DlTLG=y01 z5_;ve&9o%i<~|}isx_morQ1w@k11Gfm^lUzcbag@8xer~@Ot-lGd2W#*7dph$CBsn z3(w{-p!sH#{_OKpyDh!l<0%<*+o}2ymq1u5DgMdDHf7-WvTDs+g4xsxV9+JWc_$Z` zwT+pK)=m4p_cjgY{NbpjgVHqTV^J@D6rC0Ggw^?bqWaXEwH%9oHbgnQv76ytU|TI4 z5qyUVHnkp%Ij9?dTtqfo)fy670VV1l8l*gi*q=khl~4vqhCA&Z&Eir9HC-^#2M#M$ zmV+gmO0ApT4}NuZ8;DVC6iLTfwLwgd#IVQ}t6$r@aCeyIgy{UXtbAxZF612RN29y( zVln!PVTsQMIc>PnrMu1-nh9Gak&hFPPM`gt>`g8bj}im^!t{0>4)7I$FMi!DX5BjG z&q?p@{92?ekwucbCo;2lix^@)B&7UdUV0~ZtDpEx<30SkggMJ5DIBW=%zlwyLVLJz z=cqbysT{{9&pHPMVV0ljN~$)S?qMS~yb}@emVr?mRh-9;LLsBW8T$a37_jNx>yUz- zu16z6x+CF^ynahl_N%98AfusU9z_zc7Vs=t!qAo&%xz!qki6hJg-$ zM}_rW?39W<4l#^$`GQ?i-O1%sJzYu4CrYZJXP{?7`>I?~UpsY4*_Kyw(7?dWX7eE;bO%7ZRik#GzbTKoHUefa#&9mSs!q(BDd(@zW>jbW<~pTr^~8ge!etukkw z|1Lj{3WgB9QJZ4%RDRdjH^a=Pk=iL!rBH(`s`TULh5kuO1iGyv;4rS06==r#)K7@j zaEVgPSluYkU67fo)qAT;*{xmVH?ddi-Fy9$;J*U{8c;Q=)Uv`5-0pn~I`+7O8P|D< zFu(JD)ZFYG<2!Q~=KAD*|Lm2{<44t8gf3ql+LfI?rLmT!lkWlj67*Z{I?9t)*uj@I z_SEF@IG(}637Xx-@w$}b%sKU<<_=QpJ)b5CWcMh98mD`j5Yh20vO%Yy_sFeO>@2;% z_wie5bXw3wG>m%fM(y!2h7t6Iu&B=Yvz*BFo>BSzZc(lCgCCISU;r%jMX|_y7lD%aM5x7jC+gs?eMEgU)o`yVF?>=-7}B{EkGCS$|TVwmQEf{V8(F< z&!N>v&)V+BQ$Y9pcY*TbBu2Gu-Vm}l3-`xhXS4fLs8nD|NsF>+xATi>#@LbP|t z8$LQ2)l;lPKJ9B)Ma=#)y;DouDdu0vvL+DkD@w@#*4Wh`GZa~n_-FwiB>R*%4q>}d!>vt00p3|?l&-)CykkKUa=S03~gwsm~_qR8lodN zVtgCEdz{=PaMIc1?n{>m4mN^>W(FfI<|v%Rs4?wTRpK@WhGO!x2jbP)A$Z{W3gg_^<(<)w(~%_2ER7fp??a3l2?- zx;e4{&7C{jI$bK+se357vZYPCT{iP;e1m-{lMopBfi<7XwnzRoM3=FHs~L2i8ZG{B zq@DXelYjjG>#gX7jzkVgQ3*xPW|bo6oJmeORSt8AVP;844oglsZKQ~tm$Mm>Gn3Qi zv^fu(4P(RDzCOQvKYzgI54di(*L7XD>w2CZ&&M6*ZM&L?B26?&cmgKRv|!7xfg!14 zE>wM1@H*_uAp+Jii&gwQ{0O>V3DDT$> zM+H_t3rkT5ZrIQ*x6fl|>Aiyk*0cQXoMqGas)}t!@=bdH-!LKh@>+hhhiI5!{viET z{pTV;R%^H!KgUWy<9Z8N08)xXjS?0UkkH3M-)_wDwlg)6-tVgv@f!P4o#GVRY4A+7 z#oHZu!I=HScEZShUc&b!kas~V)Q(44r?rbOs51_*O%C_ievGmJ97 zHD~&jA&J}k@>rnai^KmmLLWt*{ zOm=dyTgSRTqJew5Ul9*p9Ciw^HPn?27hS9qlL!#<7k3jcq+v`3`GJp@Z7WU4rAw9t zI0skkQdCvy^mLc{zVrmT@S+##kkyt}F(C638#X2A4BwF>+9y}0yeII#(Fk}QS>m=3 z_56u~l^l2A^aBy%^krH%b_z>~Wmaq(jl9UJ{h5>`?cK^#fu_CNHjXV3EkR8KatWgf zyZ68kYW{{X!}j?>vFagqC(XVvS$w~{WrX_hJu}xIZH8adBMhh(GzS_w`|{UOY?C(| zrB7Ed>re>I*aTl>JDWwDpWz4ky(mcM)noOKh3j6XGgcgBs=8GpN;OUTo%o4tg}5fU z7~F+y2X`qHOfd(YOjNr^crh_d3E{Qrm2tfzDTbmsw(i-On1TX%>-TSm?Pi)}Pd@Za zgp1!5ccJ}-xCDq#l{+)LxN6|{VU;ND4nF@S(fvv4?mM7?6ToJc>kGi=!lO6Dv?U?X zrselLlC>H^Q)tZ(@?Cxd(jmm|pz&m=p(xi>mUIO)2Ko~k8go!P!={kek1@dB;a%Zx zd8gd4HP}x>{J{y1_q{?Po>t%1k8eg#BVDugo7CCM-6c6yAP*{ zv#LZ#QZrQyTb$}vlBy8ky_)*P)#BOkXzuOJy@`hWQ~31tueQ>cqH=hGe%8ixMofeF zc2F3Vn)m92tjR7+E5dCpJ2LQ6pQPmeA_0+h4lg}EPP!XYf&6rvplEgSa1`$ql3_aZ zbiC#yM*NV2?AcOb?8K3-fW-iMe=T;9)nN7{JoIs#3(I98B%G1obg+psdBuV;0=_tq z?6wMgh8@souiF7uLSo-Ub2g`R9mt6itt zKP_QgT&xGSv9^LMkH^dCAmumHhuXTiW8hwKl%FQ_zl*NK_>wKlPH*v#MCw$9$H)u&gnAUdIX!Rr0e09{9V zFNrm<%SQ*}V~HbPt$>4A{Cu^;qba;LRj~9&>2sCXbZlDjyQXo`-Zn{_%`?R4 z(|`^S=J(XG_(Ce~Ru?1DLG3_u{Ba3lDNEni8%03sSrbW0qZL-Cqh*sPACp`1dow*v3xw!sOZQ7KE5{ zH_*6V-%N0-9PxOWMf*&LreAhJ9&RAeVbL!(zUhJNJ`tur{V4cNS{oHBHl!z4cuV*8qZav4|U;7YoJt zd$!8tR_rbB)QYfCdko#%)0rY?--Y07?cj660f)*WWCvoTp5SrW1KXpS_zDOzcBXZ+wVu>Eapw6e|Bj=^ z6uUUG6J@p5XI>9XplpZ2Rk=AFg@b>T5R7j7>XXshrty-ySKofW=_yXV%UnW9p~R7G zX>%fEDITOma1b)bFO@8Jt859y3=QciTDkb>bJsgE`xw<6-#hOjdydNkAzOHSTqe;r z-Q_U!ao3B|#+QW*O(NCqV9c&x-M;@s#-tF%{L0x%Hn}1c8tC~k&I)8Z?mrejeIEPR zHe%A5!)T@i+Vf<=khHiLaiTvuwF)o3{PA>MgmIDTS%zlO8yoAzI*;AJre56rutZMhapLgg0|KCk5gS3S7o9Gui&idXjmw*4ueK| zidhg$8kljAwM(flQ&etg9%0OB{%UD{j%;Ntg2fKurQp5SK|f1ee_oYcFh9j8`LlQD z9m+up>#FbPDhcemIhvs6*>{x?S{n#GY$i>S5PWYRC`UaV(RaOyNsbx(S88HO+Nd*} ztNWO#@E-~|>e-^MG3w_k0J#xaP^y1p(n^g{ikQ|=0;~p%&~Gd-{aqPB3J_MzeM{3} zAWYctGdf=ok}+XfSm`>+Xkw~{U<0nAtB;SvM*}CQD&-I-%&ZH)l<1cN6*#~Z)ayNh zJ!jDEe}qiUjy?|1uwrv6zHq}F^t*Qnv5DI?>649$8JZezdN17S_q8q3x!jyWeKgTc%}WG{=2%p>pY$IezS?cR&YzRy9nlEr zA*7Mc6C2@EHC-4uLN`sVfB)8-rov`GRttD%ql-qZ5YPIXU-qfZeQn^|!vW2}% zA9(=8eEhd!>8F?UeBr>`XRTqjVnHZDuSP2sKneGDViJV1JZp5FuVJ?PodXi(pH%#? z2pG=!+ceoHbaCUkNJY}CE4A4gH)p;~MGD1j)QlY+vv_)o`nQ33fS;#~HdBYMaSU6e zf{D>lpr@jv%3TevgiF?95EC1&LZ$PC>pUKZz;wkbe`6m~U($;ii0(=9Ss0RnFOEn_ zWeH4OY5Fd%#JUU!JWR}bF}rgAHR?=r4z`3|xDz31xo+tI@(ngeTAU>~D03Hf6djKE zZhuHd{ir82hI$^?RBQTV>a9ot(^Wo=Zl3`H4OJ8n|J8r*`vT)83V52u+8kkjMrshc z<{u?sJ*X|>uf_+Md zjTaqW3n*8|KZ`1<9fwqPVx(8u;e5YNu^9bC)YzFD^VGZ46A-Omc9vD&yizS69ZN~k z)i2f#3;W@v;feotky`u9`PXE93b(`4Yl%#o7sap43+3HJ%IkZd*JsYq)d&U|#(!)& z$HnWlW>Rpn*tVYJo->R)I}vmRTaxwlxh}`x!yw{o1NQ~vWrW05h>5iErYQasoU?gZ z;=$bfYRkjdt6Nky@95B4!=GUfRHsShnsD=#Xh@`8pRx}6FC-awNu8Qr9)1hIP5)*0?a4|0R_{YnH z>%Z#s+(mZnk2FkmkeiJT=ArHO)VAYYC)$|N27!uJw=zz{AC8wK|1uIx~4r$tioy9zvkz1y{ zR;g*Fd* z-DgFNLf4cJ=7p(+gUv+PIRRBiA$BFW)H^;2m4arLtp{H%_^YAL$?>NNg&Ru&HQWJ0 zL*+T5Xz;IU$b*B((+Yf#(#{#`p)6$ehTqA|D=rkBV}HB=y-{vLssQ>yAG9i)%IdCa zv%z?6!Niids}dy=g2w_%+&T%0q9tp}bB27Uld<;(oN2U4ljZq7H`+1@X?}4>NNKRw z@E7d)ONnI}?@V$y+!e5o3Xfn##I9UMkx z_cqk+=SWt&9txZjtpvL+YayW4z_P=ST96_E6L3Eks(+ZTN^LO69(Ya9OP;xObvx6j z!~duHIu#%-6eSPI%BV8|R)A#@{oSX@zx|H`>(x6Dbfv$Lg}tVzp#zcjgRWRO^gYtW z!o^iYov!v$00ImEGVd{_+AMv4WG}!>9AitiH~(zftPz+pcInazD#6kgb$E zU~fMX-B2QNXsCMP*bGTX;pJbF+%O}4@r4*Y@f9*u1KC|!5 zSjt`D*otew_lF0Mc>bs4MHl<#PzmA-#{W?-t_%Plzr)Pfa%v-D?_2Zj9Y zNMeBg3cZY@{u2p`N_F^fF#ff;*z;OEuAs^z_CadjgUdh5pN>6}qv0q9k;F7j|4vuA7EXl+w(it)S^=A9Ft za9yaZA9kA&32hvfJfAu*w_3%j^00qRw4t<+h{mqv|5d=c8a}D*4_ouWASr;NK~YAs z%l;k4>ry|$d?@|)!`jx(p~LdI^TXV@a{SfR<{z_RiDOkJGTOF{KdM&GP%%uD68NSv?3C)>>Et~aQ(2eEbDTGt);+kc6uXeqzaFyx1|BT`OG(@ zO2J>ap-(t$L50T}e3N*DV3pvGWRX zVcS)qG3YtW>5W!b7C*P>Ar4Nv?9b^+&WiK`2>ACEDdgDHFw>Q`?g&Gwd0RZE;}vT& zExpJnb;a@WYgFx}pvtm|rTYvr7dyxdB@Ky8sn=U`vYAAWG#vVi6Ftc@$raWvQ#||d z4UP6pm7Wx)GiNkee7>mya0-^wO5@F zE;mn6z4_u>1%ipN@@yi?JnC|+qh=kJe5HSY*RRBM5%+0<3WQ!44rm#nLbv`oKO9C_ zwLw;&x0}KA&R&fdVnvMl9vl1KTA##%g492vQr0m7sO>dk$>cCJ_6z2Z=lHB@+| zS^8l+S&r4PMAhTosJ+K}_Uh{7jOOP{&22CNRyE0QRiY4u^jJO?*py6k6L`tl3rtgX z>@0%#U-;UFxMV4t9A7;i1f0RxHKg{l?=T2#Bf}o4@t^25yQN-qwkRH=6Cl2cZ9!_D zft*%=x9s0MrD2j37#|#|3rD{XCXT6hx5eNZyBy1?t%T%-<_Z#>=ah1*7VwWl^o-}~ z@h0vYW=-OyySf4|9Yd%U*76D?5qy=0^>mx3lQQd!EZW#?*SC4@9x^#qk9xxbA#cztpE$eUfw&3~*)56Eg!+R-sNPOfAuM=)<$lwD;bFJo4# ze=_ptuyrvvH8z$43rFPU3+k=DL#<_@ErA~0|Ix0l)?e!Cr5(ycLy`-IRrHEyldMi% zvRvzLkcqn#0~{{Tu<2&`H@(ldL=ps@8lxIYn1vgRIOa+)D7x?I^8i7gcn?P`seHls zc*DOTQh88YC?CwqzO#=P5E+XPy(~dLyW1tvjLlO-I={!LCPuLSe#BZg>C!#{YmCnY z46IK*IM4|!wWV-fNO@+KWT?zTsa}g&Zw#ii%|^Ip(!~2)F5c$-VF=(PakID)Ps^Mi|uz7|GZ#q0{p9gO}exnJi(J$xW_*XmW+?8v1gx#dr&Bk^uWA_W89a# zlt1oZlq={I6M3-eg&~a^tOYyH0>jtd7BW2ldeXf^>IOW*xeyS&SXapHA%Su(it?c+4w ze7?_lw{7$AKl>G#cjruxX-duz=7#QldNTiN!LU@zF+Fe#Wg>5n&isZ;Jgicjjjm_X zJSsd=P1{-tpRNaHi!TDM4e(-RtZhtCO99+8@b|+J{Cce26P1qqvB|_`v^p$XaBu3# zyAr^@EF_pfke$;w-6RqC4$fa(mZKQ3Q!Tk*p}S6WDtp1}MQ{TlW+3nD13#6kX?v-~ zo%sqeqvi|gk6B>EGykyP82UUkvFrwubU>|IYH#Q>{pT~Gyq-s3y44@jk13b!b{=Xs z$sv>^<{b|i1)M`hD*}j1j!Mj$?0@Naz0%=sdmt{1;1!@jMb@{QLXkACAX^^R~2@ z+tP0GTOpJ`v5QT$l>3aEX5Oz~SVZp^R-}7&v5b43On#>0K`Xdu+Sy2xi((L!&fyS( z94TZ#$lzWcvdyEs?|@4|tsJPTT>^~m*i$RhY^+T*NuoW;&ZK@XAZ?bIH}QE`4~~mA zGEpAgy#{9E26)mXyesbyVYjOO3hzlx?Vd!9Kk%B;=TBd&>yPHJ{>UzbRIX5}znP|a zFQH`JnEHF$m8oEGk3BD*6dk&@+W!niDi6>s4|0}KVuz2inYH?{?k2>LnUO#-5a!eK zFpn=?)is3`Og`KO$z*qJdu#gM1$;na;c;=$A7U0{efIRo);vj069^J@e6QjEC;1zq z(?XipHwHdCF|erh2VvW|iI*W9a;1fEYxJf>Liu7wz`*F{PTh&#{*7Hl985Rc0l~Wz zdym0KGyOY53+UpvI6sRTLV1%fRN+W6sez{TUt1CN+sBZ!IS0ZShQDYH?8QJaqFyZq z@T-f}DL@MAgI$A|{8V8k(P+|601}=S*MPR z`8dk8XAw(3d;8wP!KN5RIwv3b+XQ1;Qe054&@m-%KApQnV%2wymupOI07TZND~zx% z*zFByMf2c_;?sbTL)P30Nj`g9f8RWd;xJ+OqX+%x-x(q)H?!Ik* z>snf7p99^bZa*2k3p~N{1WU=tCp>TyhFCoeG{gsX7p)Xl;h4^D7HHrAbc$MUe65?s zqwyE+#4qqUB=}wwS_OjDCpQn|7HUKusDkB*sQ;VX2EfPX;miIpZ*YS6kit~38-(({L3CVBc~|8+&C1!crim} z-7Uh*^8Oyds{?{mO_Y(DzV0atoF;+ZA1ot9UdPj!x?K+8R$*rILI$%Lg~MZCCG z^bm>s%s~7H&o+P*y5!f=Z8}8{GB!erFlbVL_g+)DA|hOmH2tSpXfAQO2Fu#ICggK_ zR9+?}I84i>OGA@NPd#6h-OTBhQwssu#My|IOm<1qwW(r|uAaiMeRKX6_C)t~8fwHb zQQLX7>{y@{i-SA{?`=c=D-D*bV|k$nAA(NRc0jGJZ4{2l`Sv5{lTT?bB&9I@kj2D|Z~ zqvukfb>s{j=Utsk*YIro+2>m=XLl&xENfW%QlEqasC5!FR|1PBx>XiTg&S1iG)O} z%Sf!2-et<%Tz+*)y!@JU{V=vQbQYQt7T5RG61O!xo*pbe_(jDYgB16`-X=fieAn!l z8h%O1L8b2GJj1e>KJm%;cjzTp8rtqq5GuBj^S9aI#q^s=k{a*IMDxdv9;AQe$hYY?QRShR>Ro09#AEciXiFa(n7S7CP9E@Iu z>_k}BaJt$v9hiP&0VB5XFV%?{DEe&-dQ4!y!&2$nhs?iPJQx!Jw$*^7Zapy_5C+`2 z(wWqXC?(Wtbk|cr+q?Q&j;wo>s3q81RSf2&jtEiwPv%qC;`Kn$M^s=&BN9N=J4e3V zh))Sz_;+$Y5m8E3dZ&K(pG3IK?F>V;8ss0BtldJ|CMISYobGZ+sH=xpfp@fN&bqWX z@T&UBZQSsP9lt4<%hPH8IcX=H;s2|B;Uum5~p_Mh|scpE3+O#A3WY~o}+;A^R&Zl<4HxY(VR zX800)kM$zjD`{f`8()RQcM45tB2m5+E!7380u3YH6AV{pK*!dIAryN@jA^b`-IXiO zn$bB*??fE=D2QFb)WGL@69pn3)L87+b?-PLuwfO?ZvUUHjDh+$M}eU1$I<(N_SWk; zC>QoW4W)x`lqYw;lN2%l*wqt+U*KK4*}9Z|EhNv~lsd6_(VRX)G=@jlw1sJKm1Hs( zxV{^j)Q;5;%;WYF_smZTA~^O1;XT=>s|0_p8CHl-9NcGg9b{kz$Z=YXKzRMzhF{D+xs+oQ3xVn!4Qh+$c4Ulca&6=y{qc zSHZ-yn3DSrG2HOe5sf*1yB>n>*czh!Nezm%G>R74xP;-(602nWx!S>0F`Hm0ar%E+ z!QxU!!;#F@zBYe@jjSvqckG*usr-Rm0XNuvI2w#J4pl`)se-a+tB--c6IjyiV&_^oG`A~81bU(W-~kd^`m&^%1?jmWIQr-4)S(0R0rF;QA*EU8kh^P zn)_xr=H^@HsFBxv#Y29Ud7NS&mHGUdMRYVO!%EBU32!HhMMZ>r#WRmFsO*Hk%2L6+ znwr3j2GI)K{;&=IN{yLiekaYN-vcAcQRsl3f~+yE%S0z}fzxjp+#~jF&mDW!L(p(Q zCzI{2&tjP}689!cE)toh=H5_2nko}eK88a*VvEq4DZ12WLL|q3bm35%6)7nF`T*!Y zqzF4c+Wi(ghIOTF2h^3FjyUQ?NWRo_1|JvvxZ43>tb9Y12-C=F^k;&CzoWDK=QSN@ z7QKt`Ot=exZc-NEvS6AT=yB#o~%j4 zB8Z*88iitz@F{1I7wVfU^?QoYuMN$?>x`1jvTdvk@*NtLUif+5&Z9D^UXy$+k7n_C z?*&?ttgu)TkwMX>-U))XAiN!;B_nNlZ4E}f6vmm-I|sznJAEG58c-zY-(vYe81yXJ zZPmTS!A;@1!QXbCuuqVK0g!&@ zj*!39K-E+|d4Ol%iJ$lo2sEjyMi2KsWM63~pM4Z|YPNp19^-K&ZZXkIn&l@ zCDGF_K8lsqdGFzowM~cE*#M7Y#pbE~u(Ff$ZCOZ2mQu z`i#>8BtYs=q}~*i;_X4xnPgvQzt&X;=KRq$$F} zZv2BM0Ze4|l2)@hPH9>M4uwKLpf4>!4b!1o`ZdQVYm+bC*alRFCL#|uA5pUA4@31z zVjD0rR6byS9puqnpT_5Da>;Pv-SKoxc=^8~3KUhF!%PyQNNP)zlSCZrHV7+=>*K3; z{58Z`qSlRm))ml0XMI@*yfzy#O-9*W!wm)CPosbv_ahH>Kku$nud86Sn`-6CV?q#D z=1XPv6Dq(fe$1T4;Xbqt%|HFzLP}DJ79@{U5$7b|qA>{jvcI2|Fo-|Q_> z;4v(@o0H$r2AtoB$+?K~$;PS;F|{t`23-kx*9My#*XK|I|IK0qGJBijo`=7pJII%R z$KtnZCCv}Zf&S?;OkV(-r8PgGf7T-L%t=1_KCx0GHQpo?_^OSzPZqmmHL@G9}kd|ALout;4NLSSE^0lTA zFz8;wBJwbjS$0wD%N#=f^UorEw7nD=@NS$U%AQsd=iH*$qWjx(W5|^%wdF;%Ywb)u ziqX&7tgD{oT^>OB&qUU^q+ZpA@SM`N7f0|VZ6PFZjeLAlv)6Gr0HLzH@?>X<@1@q5 z-U;k!X^9bjHcHS>^IN;5P#~!W9nQBJZr5(l-b0V)WFQ+U^^WDm$rP=GFgSfbx(!I~ zDo&YtPBafUoN|#fbO+XWv_S$7wg)dV9QgVD60pOd-5oN@>b2-3t%Aq}`B@&NT5YY9 zXjyNOwvMOo3S<#~O%{=tDh>xw#`Y>P=<>2FRpLv#6jBJ*r^1?)PK)3EP8U?*YNS2R zagg2gUJIIT7|Ce*xdzuLT5Y zC^`P!K8oY&cfryuy-Ess_N6Pqd*F)5(*4{RETz}TgoQ>RpNyXG4y+w*&g0#Q9Q-G^bk*TS^k z@O=b2em&I5g6j7RD^*&WYf~?;i)W*zy7LQ=1B4?iwu2QeU@W{lEyJqC&2fZTwb87F zr5|wP`J;l*whQww=AdfiASseXfZ}f!jon!1`7azuE{nKL)Gc0>+Em~7dA&n?JJ6}g z!+CF$QIv>B_p~y|Q0WeSydxc3tjbYzqHV~(VF!$-zXg`pX81FxHSU$-!xoH0JR|jx zN=vot=El+=Z`8`PGAFgJv*Juz35V^^)Dp(T^|zubap*!mW{B=f%?~!twq?trwl95rVlERqv6}%*l=vbr7G0i3g4pg+9o8%ujp6-H zup^HCpNE3V`GN@zQ|7#DEMBMs$MroHn31bT!2;Bvno2*(1rME zPFGiQTZN`Bzo%RwKUR&%@t@KXdvaQ2GvOpTCV>?BSO33aNK#|l|uyoGUI!k$nKzefuL<5)UXB~(xp%)E1hgpLjQJ;_+JN!<|}3Wo>Zngb_#l`P4I(EXxa18J(Z6pd+b!W z6BcyD!_Op+R>NEhY&r<-R%4%FQJ&RL*&DgS1I=C;Iq|24HLPfO=DlV+2LD6roRWKc z=)_^8_`hZc4mSS>kAwezX>j%wnhCqonYP9JG_`jzr3LO6F4`qeo|F&Pg_qi1C z`TE<&XlizTV_Mm-kcK1!a~C=7`O2pY_cMZZclQqkCnk??9JCE#`40Y5lDhUfRJqOs z6Beb;TtU_~3jyl#1wUct=3ih&2QhaJsDt8Z?B81-&!iFizOU#>7?^Bd0~lRjVGIh` za~dAv8f!oJ_y+n6CRe+J76~r5F33$&2nAW_$+y4Yo-sa5?|*9%k_~_pyrSuEJBRG; zxH`v=;$HL5!oh3DRyGFDO^f?!OTUFJe`q!qOW1>M#OzFa0gCfF`9^I+&9t}EgmaU= zS>&1o_=Kwa>6>&;k5D&d-G}NucD|ZBaX6=@^|gnDr_)9QGKi&l5T(>M=0lN(%+1%U z{ofyzS-iCAcO`uOrXFJb>z0twFuj$_7ntkVn42gnOgu9OdYOKYlON4~yDWUa&;zxl zH(;)PPn+3Mv$B_N)IdPpc$+V{I&rL4_RXDwl_L2^wGApO0(hdpR9=LA!*q2#xz(01 zh<1+g<@E1V_KH6ZyR~#`1Q_s`e`ANMy+wQZqz}ALjMpF|I~giVFt()EWCQ@Jw^F}8 zRBSvK`pE{OypoqDg#Ffe1(pc+Lsz&~$*&v_CdoqOA+c1u(08iA?=H_M%{pjlmzqs{ zjg11#8t&z#VTqEK;3`gGGN(L8isNbDST-KW5eL2lSOdGO)U(eF=T}1)LN7rU*rE#z z)U%Y#r#~7NT^gc-Z&ubuVbO{euzL^#CQsrg#Vbb#yj#c#zd+K)XSoKuVn0TxzYtW0 z&g+|&u^v+Dh4bb|(RY=M5U1FsD8v&aaMo3RXOaT);0V5Hk$)=*e{Pi`?+kC!iJy`Y z$h~&`^fc*9{im74iCApNN9doysrASR{;jTZL$39_hK*z|W@6l>%Ire3et{D7NX zRwkQVs|{w=*DU)mPfd#k#a*sb@mg)x=GVECfXJnZUqO+z9Oj8DnGRFqr=QI)p9B2I z>3mc;ayQifkUphZ-f2w_>gk@Ml99Q8=E6T9;5mn()?9G_#5 zs7!^ETWiOZ+S}f0r2hc6uA8VmQE6osj2MBx>ojCF^Bp|qS9msNwj}-*xGhr#UvZ|& zPWJ{5Mo!7SdH7ze=M+FEVdmaCeu(Su)~WK-wvrc3%8Dy5D$UmK@;1Zi7)Bt|>7_>4 z;d&8LQ}xX7q=W+#yu5^STPNNF*ps9H*@VK5_m2~Fk{sq}XqDekK8Req+RGR^CLTSw z9y_5$W@pRyG+{8kq)!?Dj<+9&^A5oJ;v;Kf^XL0>S`NvWo?$8;8qk#QqAE+MZYXafpidRT|6sSHFQzzm=Q87NB9dzk2iz!ohO#_7`t=Q zk$ypwWAgL36OzRPNC{U?J;)Gqs|(lGoYD>38qEK5ukP2@6-< zgS}qS!uKxtvUwY|8f2Ru@G{n6HB??vhaPs`k7&PIF!OF-$mV4m>>nh*EM#Tl<6rUO zD;hu2Hu9I3!e70=%yMA7;EM8!2({kd5~=1K-+}q>+OMQ69Dao9;~eo99DaWmZqPrJ z1|C|LO`4N(F_*aHXtt02a(_ke_IFsp@F4cS=x)^BFlML_FTZtXU2)okZHNm1=DY8| zpW;M`%>;<+bH3{i&fmcqh2DV{G`#1TqCZPQyn_K~_dZ5A^d&e7gl%c;a0mepFif$b zd;*{d^s-#zT(2rCREhqEp^|HDIK03Gju&oOmGS`kUfUtAzBs=Ra$!Jbd7oXVQ@M3K z^oB=~4po0lFe#zjq9hT=)=9YPV8e!j-_qxzE6fG z_ajlHhO}MaeStdVKMGj~?e828^rO%8{@C}hT{S7VA5Y`{?vx_a(%=Tmvse{8Wzbbj#f!v#)eAzP8adPB0F#0fL$bEfUl3IgPv+ zYs}h142eSD`h;Wqex+`EXNJJ!AaNYu3{DiKbU$1(hp_o7|pmVy_Bk9cn)@4Dn3eUlY5 z-1UXDwR2zn%SU&euVp~6ulU1k6W8;$fh1M^NCUA@CGRm-`mjSXaLbLL-6&l-`|@E> z6-<7okQ3?i{y=+c%lAvb{z-~A6_{$-I(0D_CROn5%&(i(x9

802Lwx%8CRJrZ_Z zpZs~__-}#s2dZ>=^&a*^RuM6e^*dQ3li@ZZ^~I7f3^9u>nVaAnqO$=F(OSNxtj}e6 z;itF7HtIh+%u8pS)wKzhmu(PJ&URiAmGRLJXwmay^uA znYVOj`IZ(u0QM>Sk|%io6RZELkj4`Few9%CfY&i&lFEK_tP;@3CuW)cEj{xyO}?OM z>ydBFT_#vAxO#DV&__9k<{q!4hKIeozIZ=sk8@#KpUvYP+GB3B4s2t{SL5t%k1(BE^C5)!l5I=M#!kSCba2>6^jf={n{-gfOo*c@K=QUV*d?>^0_i)!2Nsr~m65H$TVo{@{C&N3z4cPN4Xq zP}w_EIe-;aM^hS~rxT2kL%1j9l{JF?x^re%RwI)&aMB~lc;T*R&7#;#Z`PmA0J~-= z)p6rjHUop-^8tsg2#RTosAHcr4~Fv`Mdtu3l8OrF3i_||5%S8W?(Y5)U?~+Ob|QR2AS)z42&@@p|Unt2ToTn+#JdICJKtWeup9#y7GL!?cJhF>|IHQK|&ZN9$Ibn z^_*MugvTy74@7Rwq@DZagOyB|JJx_sVnsXIUFBuieES6tRO7j^+6Ct>@3DJ(q40S7msEyfq5^iQ}*oE~F@?_ylVB zMlbMd#_CfX`3_Z?rL#k#SZLl}0)48If->9^_TZ1|D3AJlpIb?wg~$xlI+O zAd&g2)srAMOm6RO8NTdKO(e>EKY8mai$C=0L8Q-YgTPVs=1XlJYTL}SE9Nlv5kfU% zZns200y>l_T4vkeaNe9?cs|aGUK7|mv?lDoSvGcl@$^Vm`tpxRnBop_^7Ihb7Mmv$ zawAp?=&DG}@4OKK<){O=C)HyRsur1xzsBPZg4Z3l?&mq+p0^b(+4nbPLNAP#Z5uPz zo|#R@CvEakviNU~H0gKtYrN-ZFPCi{rXU}rK@<8i&D?2wN%Q%z&2{kS-blHdM@g{!% zQPCjE@8t#^Z*uS8djE+0@+`J=yi9)`9394UZ$#K*;_{cKXZ-{Qc%AEH81>gFM$Ol~ z^IBIKl6ZQsx5SgYzh0k&Da}|nI#HgE`F!xPNPUF!hOuq!jAhPCAD-bh>vcX?Y&n*g#?DRLNs|}so|c;S9ozHiIDbp~$*Z6INk~kN zVy`X2I5Gv;-sf>MN5&9Xvba*O*{6D#AO%%mZnckO=@ry_Emh+kJF>~mKc1axrb+J5 zw+SkIY+4IPZ3jr1)&dgq)CZuhNJK6hD5O!`w|j~pmRD$;x)fX~j@`xl$5~Z}nZiNp zx}$wWi`Ulau4YNBq9r3!x(VU^!6cV@2-v0-K{l<4^eH~Rs_*tiUm=7aBk943iodz} zn`<{5-IN$0#u5$?O};Xg(d_8ySR)FJzE|D&9$jP?V($Yp`OdLqAd^@Vq3TcMgPSKQ zdG1-jRgPrb;mcyS9K1uEDVYs5G-=t+8n<4@aZa(G?>h9eB`;c!Nv43tB~9oK$02fA zjYS$;b(g=X+veH5LF`o(eg1NL>wMf*U{>pTEyzRu7^O#PB!Z#m{-Jo6&K7gulRDX$ zn~Fbuuk>}2O=1=7SJ96>$f5Gau zJDG`K#+Xx4l?0!M5`lovhD&$w89QQ<3nz=LDFp1zVG|7d$^GN)5) z*Ac$YIowr9+wvbuw#RS6hLjF;t3U<%j2F5o*0=sapX!1REgZqMVx~FA*crfOXTKPP z{_<|pS-`A^lG{kzmgG7|Q0XaVIC7u1b!UUe`){iTbov~ZwW}k8@s%7yv#2CZTn&0p zWBvXDNFR&Eq}q?o%g_;~nyLDxVD*Oy=@o+evmti25t(DNJ^ zH1RKjHk?qhQ**s&2YhHLFbfH5<{Q}0m4cK>j}y;wmH!mm-pDiizWD0H(w}n;$dv-= zdSFX)iTV`m>p`Rr7f#Pu0=oO}^jc;lt6I3}mnJ&MeC$&xSV%(=8-baegLO(!Pd2WD ztKz-_E84O6%@FlWZdUlnfll?80}bf_yH7<{=%=#dX8=fUax0*xpNjd zmmI@FuE<$(Zb>MH2(v>6m&1C2>k zNCu~#IbSz&H&KM`bDf5yP_OnLy2__bkczis^zzZnx}mz@M>a|av^9-7zTc;Ihp~1& zovAO8K2?>%*S=AeOd9hvhE@XLGOTcIOu{p%@KVN^$vT7m?Ec$5e>A!?8bM;!z!dspxk92E;3{4hlVa5H>kn zJo~3_?DcfLNqG@qtK@rW!>pN}W%{_sGiHje+5qc7Bf88CrP7*rU(;D+%B3wUTr+SHb%v}2d_C8l@ zBF)v?b?V{|lOo+NT=SBjdTEOcYUN9i$uR!gf{GVVd*^4h+|HtF7Z?}{QRGSml;ifG z-t;q~foTU3Zwkz;q;+Yg^B( zs!029JgRq9kj0D?|94TIvcY2Dr}dH)ZaIkEFA6Lsj13nA>R+*lt_~*dcIXvUMV|N) z71So!c`cJ<^MM%jXi_Qg(cdrN*9D?HWt%V8EwgY(qgAU4kH=c%Gcq)-0<6wPoT?}C z4-|W$j;?IGt_O&726Rhf`aD`HC1W7D++hQSZ6*n~j~QzC2UsW=>o_nFAL^I?tB+;X zVd1O*0ROPmCHsAfo9y=;PnG4cn0{2i!3<|4@H}Pc09K#}Vf*zht>BTjz60g96Q$DZ zt_zl9zp;5DSr_yic{rgDd}LGD^`-xF(M0I!SEv6&m3ioIQ4Gq;GV;wJK%C-%q$>*W z^Vq~hevG*}J?Hztwe&PIG~Mx6Km;Rsyf<+C&hb?};|sbdtyV|hvxMxBWTu{bdXZhK zb%7c4B_*#Y4-p?{A*uabXDTP|ibD(raG{7FZ4YcjGdYRvCvV@k_1`e%lDQ1LI`dw5 zqclPIL-$;>*ZAR?SK)BL`p=jf6uVDoddHh=3($4vD$M6K9~r03`*x1=2Y$?{qW-}; znnEAGnXG+1P}n*GG4Q|GIM2ZmIP=%e-WlR(f2krXR8G>sMzw>Q6V=vY5Z5A@d~^7nNo$@rCAVbo)p3sp+2cR8~SQw z$dJpP#_P4>r!8}w*q}Xx_~ALV7|9r$L)!aiU`hl$N&@@cb5;N727YXO+dnejAPM$b zOpwVB&Z$(0+ac>$e;qA!&vP*ynMmV*g`A0e@yM5X>%tS=?o+%wLe{I>EZgO>hr#<( zFQ6L3pl{FsEDhp2b{!D)HE0O`J?9mWqP3gw{c{Bc^~LV^j`MH`qv!$PHux*d*iY9E zbmBD!bXsw{DIFlm4{>1@bvU#}oZj-C+{_h5T+-;=yo71SWp2O4>L<6Ly|j6O-8k*Q zt_->XqT&;klU`7JFAmE0Q@6X@~$ zId?cPpdPnO+m&3t&eP^s|E8{mpvwaWfCr=2JO| z?Eet&S~Vf3b50T`actFUH|gCofL;HnnExmxP8J`eY+M(QX#bvV(b=~}s7rK3PgJNA z@%4d%gT+FxQ&?3GxQYq0E9ct(@VObfDo=-nXjZ+@VP+L9^YKy73)!5~+7p}3*?UaU(C<63}sFVhBdbLjpK$d6>gO!1cFp>X3b zY4R8KFh6LbjAio6c$YHDv9^e775;li)S@NsDdJ=K=U#cWtHex_f)qZA7kCIPp{ho` zI)fG&-en4h^W^zuo*BfB&|oWm#vuaiUN`vGQtd~M#0F!yEvGr{#S7=MuH+XxUH6k| z%t5Wb$$W6!+K1+1h#dx9vt_1#ae%@?n1F1cq4B_nVU?W9ZjHEQ7q}=q=3;2^$A3jh zBpXdiZbeB=wA;72?H!n)Xupi%d8=EKrt!f+NZqeKZuBy%c$ihORq7}pQm*++;_&#~ za%Hb`tY^@$YYMCwU(+jm5vTIUMKo?}C`%IjceY<5 z2z76^tqlnTRxRL`)cP{<<@v*9vJYJ!Xebuq6o-z6rncJF_t=s`_T|5mICu&^Z8X`4 zyGl#Aw%o-)t;(Nc@XHytl|z>pHnK}G85XqjDUW}JXbXLu%1maMwuu~MeS2JsH3=vL z@&d8AhDTsgD$EW0Vm}PI|6#OnTknsTXhF0~#7)&2+}lmch%Fh3MKAJXRGA4G3;3y% z2%5l{TFaFmEBK>3ZBBYIE_xsO|83g*jGa{py)G)qVOb#%>3Fj-uyNu&^yLujZRBM( z{k_~SAw4GYX)dCSdEVgajeiQ)(5W-S4zgMASHCHm=jsf&HB%QdbOD2Y3zsAmKJ`;Y z-mDF1e7VM^c5t1Mzt;Ec=;=R&A*{Wj-hHrA;xTwB;hqEgDlXLU^l>jdJ{&ulpN-d& za_!fT(4JRoqv-!qpyfi6T2kXqg*J@fAs5S2`tPiZ?j*Iby&4iak)j23N3i0U??44) z1D*B0DrTOHmYC#<7LJJ)2D|mfNljYcvSy?Iy~AM@)&$nSuI>^~7D_50Tr3N*tbFEs zuSnjev8WW9f7`rVrO8gdD8O^P>aSVkC(pGX(3<1RjP$skcc}s?*X6VhUdy?0VqAyX zsGp~Gcs3e+??a52dZX0EhM+5q1&se7Sy{tq32$l8#^6w{2JVimFA}iQyJLi?wUdRd zdA&$ky|07Yd-5-re69j$QHo!Q1a!a)v%BXil!VDKoWMzU=u|%Vva6vs*iJuY(5eLN zSqZ-3RGLuEgVZmt>pA**?=p>F|EfYd>kX~Z0G>nCw|~tpI+UO{rnq4KBH@2YI)$4s(X6sDdPJG9X%p5O$0kgn3zO*hRTGd?Fs z={`@I&eRGS0RJ2eo9x!-9yhrt0XB5by7(O(wUh6V1C!Z5HSkxFIK;afyv03}D^ukG z+YKxP0MK;UcFAI<%r1BLxF9e0*cmYToT1+1Ec_BmXO$e~5Pw=}^-_?St3|q18 zow^iz1*Y`pm888=&81Fh(`&YYT9j8ejKH)r|Ku85=^wV)6ut3jv7@cOzlBfLbf@0b zEB{E3x_}KoODy-9E~M_Lz9GG^Y`3%=58Mn5&cNK1J7ws z2{4zQ8$Cmqdc~IISa6nzfuD&$1Syp{Y7fofpFqExMnq_H~Yze-MFGscy zUl_5=xy0~ubLzxg^^GdH5c-%(RiPN$_)6$c>Gh}eR0(d=|Ktz7t^LDOkUcW9dz}bV zdlC;&nDjL8{C98H>P1hTigU+twm(6x`Jo|z*Jn~OCLPWAEE?ybBDCnT+{bEa7U|f4#`n7XR;3l*2XHt8~ z;pR6~Up_pE>5hH|OvJ!(I5}tYyzqA0p%e{VnrFVQ_=m)pTbER^b11DUV+F7%+L>L0 zkFZN8|G7Hu>Xx~qm0vE3Z1l)4x+xu}s{Z79z=E$mhuT*mU7?KWo3l0ZI4eK2m_1ss zYYQMSd&$2s+ny+wQ{6bf;C99o+I08gl$lS}pYbYGwJ2uC$AiuSX`(;!>Q(dhZ>N$$p~TS&8Oy-8_lkeTf$Ayz+m@XRj?1Vg zIR>CAvQ!GR+dy{E6C+Rb!}4{Zo!fB7v%BanaC~53lUx4uz?JeohIy&k}7>F2yaQw9$A4-hw#h7s-LATXdMDTi}l|FnMdozd6X&pOR%n3DmJRQhH*^_}!V=x87AH ziM4(3-{S<$QMh;ho|YnxBa6YG>a}LN(!U|RD@?3?vDt2zc@wk zQIr*p?+%}#f&V+8oBm<-GhERc`)LP_F& zUx_R$rqGM09j~ZeOD|%>?@B!G!lp4zycG>h?*d!H)7w=-4`li0-oSES6)~AADN6mLgns`L)->KOK?0~H z$sJZ_4s($uw#keF)0W$eD#Jx!mU?9xEU9`=5kqss=FM@8=?(Z`Of`p&NP=Cm!A9i4 zxxA}q(OmnwYm|{V1{a6dTR!@jlSrMny$Q+gG*qB;3=v<_hU!~x$3AnrnaCfsg4Zm0 zjTNug7pr9}{YH7I@r(^0rVPvhooZ3(E<`E16kK7{Io<$|7p2Vxk2w@=n{PJm{C|*& z$9)yj8Xi6Y1rnWdF4zypMei}eLmeO%# zQ;$Oj#>C42T2i&INQoFiZ$^QS$GR?5P8HNZE@&7OS`E4|`$pHU2ow2=+lsO{wAfKs zd%+l6bdcie2zvL`WZsgZ7swhSroju=G|6##htIz^VqhfPNg+ktoW>2ZswhWFzz`p! z^XWEA^as%1(?ECEWx8+DCfI>c1bKQ1LV#ySOVX>rEo(SM=4|K#aDeT0C6zu1mm&o| zcYV+J`wxq$@#4sZwAdJ^KEz_QFbem5yO&%Q#SB9ke2;=(r4w{dNev)dQxy;C=BceN zgIKL44@rs&Jy6S!p-JPryWV<}7)JA{Yq{M^Vk7WulkSNIpB7oV)%wXm8mrwfR#$Ks z*3eE$l@D>*Z(lznLXA=;7@`su9=T&KO7$BFiRmL(y*O%*hY`~W^w&&y2WW|(#)VHT zJ~qq4&gMjBFXunBxKJIRXy}wtM{#>*i;ayGeeX7eZIn%u&ZMNq%RP}D9U%j(&HZg7 z_+C%KuEV#Oes?=GX5Pw;@9SyI~7G?eC<65bR9IaC7p42{U7a|cbPtMVOzFkt&*+xxVcSeG@6k4IiT`k9f?kE(C%JBYT;A%l7|8ZRnSg~3K zzwZ0@S91Z^E>zGLE;ej&T#r)$r80&^vSh$|swe+eL6I{msblLsC@h}bqVa@|G#1}j zxaBDW<$JAb@MN8CkO-@MAj29r@z@D=1z3wt@M(fD>8t_&orcw!Acrci{=qk8{X9b> z;2%2gN=1J!{J18XjXrs>kUyGgQq}7o$r}7SLTB1fK}Dcy=PKoL-_6SJ9#3>JH$ua* zS3g{SjAnb_is!SB!D{A}^{lHzP^{?6EC+;8dgHWXf%s+SnzsFd4ug+}W*d6bEuP?< z3<7;!6eK`Ee>wxS4Ji3q{%NAud+h2pCtEad%pUk4{`gaW?9X}0Z}KhK+W`{a-wL|z zX}*XR3peoJVCyJ@-ZG!E#VQVNNgO*wE%-tg6`PdZ*jr|d4SM_G*_5Gc#c#ykA~@l% zHzSHVBWSgeZw!1OwUOyiHv?-s$uRFn;lP{-&mW18hKt>oXLErzIj0n=>4{ZdIcZFK z9+ZNi$3=3ZDwFxItw2wH5oT1A5z+~-4`U}1!oL0Lj7ixN2|?HdjaTzuy1=ksr9CR( z5OaMcxw*#;r!iXBt=`6*qgzJeBP|J-Nc%zW{70&9x@#mAoCAQlFOkduujfY>Xw zIv={%w24&m^*mg6>p>e>PQ@$LITj`v72{Z2VvIESZnw$YENgV~h5zs_rxjr7o%a~W z{e%C&Xr*+5y+OJj3RotAGF(iL3Tr^;8bF>0nmW_oW~}(-I$BA8xg)2{JjO<5{d^q~ zP!Q@~L%&B1&Q8pm3DuNjunMy+8lLHyVk}0zbXOUu5(2M0oi6*`kmP=+Iv@| zKZRPO{cF$_Q3!fmplxtI% z9x&|WVuzfM&crA0#|`)gE)5LAsl9$Ifb@*0OS0GQ5*xO6NI3j%CtDqLLk%k`{!`dm zHTdx8xg0*?LyPBr?Zl<}9q}$K!Rs6~X%MY;2UGhnNbycOf9vmpoi+k+B)VNzYlhIy zxm)s(%DK|-ruTj>I=lnA{6~z-Y}avqGm5A>Pk(uX4A|K6nE^x(8)$q2T8M?XZu$kN zWDiD?$>@KC$-=bnT*)la?G5*rLqU-cGCgK;Xxe^za?w#EXFCC1s6lXXUUot}-3FrS z&{LTdQ@rW6sq*5z3*kD+)@Jtedy#U^Ub}n@g_KEu7hUc+>>@|Ruam)Xym5M?7z&<< zs2b5XrR~3*$2W(g?g*`#VA!nL;#$SP|JVpj^De!%e4_XZlxMWlJg~lBGJns!<^>Xrfsz=@I$Adm zWK-PICm+E@jgAH^R>kR1gl1H4`S5Q02lC|w#X2e-6cY5*(II6Il5vqQt{~-8Sf6v%_FYlUH8(^a+hbLuOI@wMipnnf`8KxX1!^bg*Q=RD*o);AQco8oMlVG~ zN)70IoZwrn(rh?#Bd?-HUP1goj9)a za70}j`D_;0;56XZJm>L3XD%%P<1mlXaYgymD@X0~D@UXWjOEpm83;u{`tiN$Oy+py zJ$&t6n7tR{XzpC|_j|`fSFiMow)Y9#x7RQpK!51q+b#iL4k2A*W&OGrc*r~hSQljJ zFRj=SYSrTiG%)W?`;v9veh8af)N@3JIwp7>!>&hvjBnNZfT71)xD#jo z%>n_`&}U{Vr?k?(rp*iE3m#Ol<1sRB*B8czgj)|}!YuM@0~EM;>gmne($!5PE`H8Js{eZF|8LV_xb8uu z6Dvs}2+zx20%s%pSM{?=_gj;)=5i!jKSY85IBaR=Fvz8MOK$QMxm<}5EjYiVZC3KE zXKcH@Rbkh%6y6ux*C|$#ky(O#(t!KZ{FWk5jVaQ9A-IKl7pm~<)gEBpjO7QrrM-e* zA`ZV&&Bc1rf5u#%_^IA>22iY`<+G2kb#m=Ec3Vd#oMgb%;!HFvjLOtpuG(@9ia$>cV7CqTFOTk?~*q=eAiu6V!7&#UuA*Z@Vmuf{Q!R5UW>m9VHbHGoIhi ztKEG|e<}%_h^$T5^##$Go7Y-aSDyU%yZq+Qg_gc!I%rb=8MIf|2a*od<`uoW;uo}| zJubE1{7Yi^W)#Cp27SfmeS3qJIJIC=s+IJ1%LmZs3d@82_F)0$vVmq0CI=@i3~6BF z!sS1ToZZY0EG5rj~vWK@xh8oF~j(-N^U1DKO|^m zS*&k`St^hXSTZBtWuQ{nA3EWlaS}&)9#zAWslh*PmqO?AG0v_v>LP!)GAXIQr_gI$ z@IYS7#gnfd`RYYdf6sEX znLMM^j_|%Or?}S`JFoe*i+EeuPf$o+H4Nwds3_iTd&JxCBaxSaZ{26dQ<@{G>kpne z`t-i(zuBUF-vz@Q**CyO!*uc1O?DN1nn64Ks_cckkK~d7hgs(_sHBpjnQ`e3w~HBE z`+h;cm8Nja8%xjkIL$NSo^!TA?naBr;B-zpM&(IBH+}m%BV5;5J7YNY-4sz+)AzqQ zC{G@svYx*!go~&ju5yw<&C{TFCyOKkwc=A3g<`V0*O5{GZfC1CL&(jHT{#+Z?8h{W zUV~o-%;&3WE(<5}vdv5H0R&HciYrBooJHkTqT3$yC7Qh|<{jU#cB_rof*yUs?8*cE zcUA<5?s^%N7`RF2sTcxeL_8r@T$<|zXlcjIh>@`zN}4=sestbxdoZlp35p{WgWR7T z0_n%_JZv1dC_u#Lhvo3z&p4aC0~^lbvF2i-F@yOif0&iNgX6nwMj3O2@v&x~cSG$OoT)=v(8Y_2h>Z zu1Sb5{GO5jVfpsINBvlJDR~dmvT2Vl1SZi!wkz+G?2j_35EZx ziuHRQmfqCKS-*F_GLMNJnELHiMt*(Q)*XdiPDZz*{HQIHq!+)s<;ntR{z$?0V=&Oa zouFZ-?)=QomSl`US_jkj7m~o zemDMhONO@cy~-6Cz~Pv=a++IW%(Xm_?CtZRcl>*$98jIzgMsqI^ds%b!#9cA*&c~d z6Zz>+*sWT_!yt)*xRez<-W{$E?df0zB0C(k4_p}V+-*w*2%MR7+|DA%lH%s)0N{bZ z;aAm*E~)?WUm$9I_0kafA1e6JGS1dlA{C7qe7Iiq4~NGZR9K~)K7BZQ^@O$|&tg1w zouuRlg$}~qEpt(XA8JDx@6}E^Js%zaYJiAU>=DI>L%znK6rYhA2MGQXq>^mJ%C^L^ z;I{!?U;6yHT5%`UQGQXe@AqD}#~BE$c)swHBs%$z%0KGJ@`t~!5j}EIo|qBY3#dFG z{vLV`#;UyLa#iB-J8SQybbm2DCR>Lr|8%PgZyN35ypr);zX_0!UkJ>|6g~>JT#4ek z;RumeQ0C{;6OoDto84xaYo5+1&<_IeBWPDl#rkgEN)voPPxsqaplxg}4c;v|7m!r; z7}wCkTVU*B3G6Ab@O;BZU62Y)jeeDmip&`}IuouGuNMN+=c;-9D(1-^ns7^Wc-=s; z=TM>RRP|6a!axLMWCX9Sa&55mAnVWyfhqOykk<%g7nR8)~Q!OVs?l*kc7u!6*EM>eQV) zw0_plq*=VLv{z;E?cwNz$(Tce%pbhG70nHN8>>Dz|0|g0cWQPdW})1znbDS`#|JSW zZzVi9Uz{8&igZ~JlqSDOI2>hq2v&H^yw}v~f0i5yd935NDnN{HbFZCC`#XtT)Wx`xOVjGlYMNkihh;pQT9_Ajh^9b6-e+8Qjo65pxm!#i&&xf_%v zt(31EIg19~?+HqapS@SEf>yu6!+P>!J3vN&6tovnjc^)8ENjsK>ev`;CH~}hmnVaf z;O12nBDMa)2~u{sb6#~l)a66;{g{?iJ+WwV>C-K1@^&C}W?zewG+C@HE3EicG|kDIi+uOYIfa^ap5o_PZi`yVIj8qb}lNsBfx37W6fdesvGl|1Mken%8O0 zUf55BMzpAJSEOsoFFTJ@&gMBKU<)FKjiQvx^}tUC(Hl;^K*)a6CY7>dX%!QicP4&? zho4`Po@v^V`&&0D^fC}`P*t*?)G2y8SFm-x17n%7LVKXa>76@@l}Jv~3=q4H>whGQ z+9pWc%hEzdv&RG`oB=rg#_vapIp0*}a}efxKRl8pPfo#;He_kupU|#{|AijR{i6zC zCc*I8xo*@;=k^k@j4vzN*zOoJ^pi4S#mqnG<4nRyyVl&xEir}Aubf=xi=7e7^qRlj z9buFo9scXCH7BS~&maF@bzF9;8DtlrMUl!#ZsX9{{e^7z){zpYtX2a@M_Rsxss#oq&c)DjT%{&K_zm;#*5?S59qg|el@j`3o-8|MlJ{bZ6U0^Z*v&|%hi;}oRhMCyWz>UQR)@2m z%CW8YU5P{(^rca2Ya4C)JiD#aT+mmAyeBp}6 zEuWkJZa!_SaYFF=kg0Qd1MpP6_YiCOWAz6sq4f9L3B>Xg5erAj6}>eHy6G#! zlG6nG%B7-^l;)1b)do%AbMRlyyU~!>)pHrK6!!3y;MJ%Xim@FgyQtdtM?y&b-_i50 zrn@k8(?Xw=>yoiv&&P*B=o>~($&Be{A6{Z%;H;Y3pX7*8=LIR}yI)dBs7)hZJ5_|+ z$j@~_3&)GFmLAv7gf2G+{27mzVnbd_<$Vf)KJS70(!l6a<~WUM;hQ^yxoBT=Q0+Fd z@3oBc2+i-}%>1u`C~Sp|q3t^?Un7Xc$I(XZwm-Xar>k`KGlB1&8@j%4-H#%CcDwQB ze4WDcJ%ScJ?x3eX2!DU53CCParRm30Hg+1>k`uh%EA0uyTqM^_dWwb3xL@)ey7!pz z)k_jQ*hlczzJbO3j+cP6Z!4eG-i2FQ9E4sg`^gY+Cge?tdi6c}$a@0-!W|@%!0-Gp-T}O%Ws9%5LbbYvPRAvJg)aH$d`o4 zTUdv1OK{s)bovl>NxNjV#QmUnF%)~LO*D`FJne73 zZLq;@$4;CXc*vz94kn|IV!;_o(bbZ5xHJ92~vu ziXHBM&*Q4}_{BX9g6r_1VR9_XVSqQdtH}9vT}%Glk6}ulT0fypQ5T<3E>VSwCw=XW zb}mVCJZ~EOaKtF&&K zK@pZjwuZ2tx8Q|)E|wpU3%6dChF1%Pb`FZRA@&7aK%-rt?doum>EhAU*oC)XOOnvC z-fY6jG1i;kVfyByZ)cSO!ovlw07X(&1B90}DS?j7PT^v=eApD| z5BEMUR9_cIgcf%b@t?5jf&eipz|k11e+8(y->Y2zQz(IyiY$REZSr6**X>F2ca?JqYe|n)i|&7nmy66eLuTi%JCW%(<{q#M#ZNQwuH?_ofY;#^vps z{N=X7;&7MQs`g?iZlY%?w?*UWNr9=zu71=9iQKZA?ZTzQv0&L796D*6+;+nya+#mA zeq3E9uX-*l~R`{DghjXLoM$AVlP>&p(1(e=N&lAKP*(-Wlnq^8n@qAb%%_rO#> z$9MfHH#yA2#LY3+B!#48q^#AySpUBjL*KbA>(@Sr+t52y?Nswfs7e{|4f^-4g^NAhfO9AYSq8J(8<26|P1 zgYBY3Ao%a3G?}t61H3Ith;G)Qa}u2d1%x`3q$i)u>!x<0aIt>*h#c4m=(i_IOTy*$ zEn5o>D}uC=H^Qd@%RFVcfNS{QHesX(dvGmWJmKRnnN}!B-_+9*#UF@|&Th|8htv za}CFl)&I2#9rbYSnvAlCTQX8o$kO*Qs5rW~QSQpICZ2g~Sy@3Z71HPlZX4IXF`(H% z^4Zg=dSB88uWxDje{GW%FN?OgwX&L{2Kheug#QSL)GkD?xzTMO%u(6t8dkIAOE}7H z{V++`4ZzhXL~Q}A6auhd+d7rPXP*ovXy(lcl-ZIld?!a3)c^E}jI?RQJ?h5EmUNp> zEc&inFuED*@z*xLN4d@HpEovX1=EoFsa`KQ1Pn8L6UDi)pCuBrih_4-KHdvlApl>A z0#=rVeUIfOZ=r&F<%6dlGTOTc>xn2N{F`mh(4XtNGXMHybq7P(wnj;^*=e+x7-l1Ti(wEkNq4yuCsm| zpUlifefyM*a0k_11;PUhO%{S;NgeU9MFdmLb=LXu)dcCW4D=sY#~e!9-uYRk$l!sC z#1q>Yon91%qGo#r#|Y<=as_&X2sb}{&Ke-ZeM7qZCafQQl7%O5yNf8TFS{VQFoae` z>(?*Mhu^$`o8V*IX3tZ|J zB3-}x68V(rukEyh{2*Rs(DcHvM_bKN>ezT|X@yC{Kf!$96~*k9UzM$s=6@`dHg_du zBh{}sXlo+#x`e*|XhZ)2I9((K(x~|7Xt@l_?MWc1O_&t-?Fc?FX&ATg_GSK*HU zx~xQQC_HXEw8+0Ek44&k@?>G=S-KU`lMy&1svkjDU%1g?t-8}{3o?TP1*}a)~GhG#{l8`d28HGGq5oF z)k~(1zlhJb_}pqU6cW0ke)eD{$`%Ejo&N(x?fx0m+Quz160F;%;=Dl8E)WzDFtCmS zHWkvj0s;QVy1VvX*iU^$e^YfP{f-z5=zZ{m6MNG=a9Wj|$?Jbkzt(^nbG=WKpMaQAez4h{C&VP$jw~8I!?>`d@EjW*GArfTW-I4%ThyC-noeK?{;L73I zL%se)b)SHa4EFXYoVAwlSrmn9%|{(F?EeudC2zo*QC*E%;jO`){K0R0t?v)JV)O3ggCg~;nM7e zP~Kirou8!J(0D?-s1Uzpx`K1D-uTJbu;xZ>7uYWqsS%1Y@0QokY8ST={|>fyi`?s(boDUtI@fp5*Ma61))oyj z86{##UC%i9zBc8|mLILE*GT_-DbZ~DE5G|*((rIr}(<`o#gOsx$h98Z-$#$rGcuX7J;0i?KbI8DtpMG zEVTmWUo3mBuZKgU`W#)wzHGnAH|S1-7&<@2b%<<7>_V5`tiOl=SH3SM&0S()f9~+8 zdOXBE-Y&~g8m`L&kpw8>{fcXP{d>ZIm@f#(#>mjRn#>yclQnO&IEJNftj zL#7<5U1m$U7#{b*OZV#6308^y1_9RH#5N84-F=8^p2@EbDtc`C9}PJ z8tZhIuveJWORw?aQ{H117Y_Gd1ObV{{HE!lhgu&T5E9eSU`)lS(;paj9ejo<-(qwqw9gK^q{T6Xd zW3HDHcFYOF4j=VIUg|jCLUvL9*X5mE%VCaoKWoF}k9TJgQ{&&=4ZJJC zb6YfWQoCKhjeFrsi|Yd&iS6$L^)k?O%wa5I4vJkgo%B)o_*(}V@~wr;X{)+ zkT8M4qG+H{Pm~YzxiFsRu|C``&jCq^Nr*dQFMWT;b8_l1lq;T-XH{8maUZw@{Z8v~ z^+NRcxJuD1haw`d@#UdxZ56hFmQSWt&m7X@qeIMlVz+`GSFe0r*Unnmql~gYHQiu- zoh(hgbac6eypmc$0o#23JaNVcQ5riGv;H&+F*HrUTpCF5LByVZ>xJ;~2PbBrsmBcg zBcX(JwGI}Bp9EhcOb=bN+06BKIEa(T&21!Fbf}0?SEf+ z2wh6{z9nK~mUZ^r`A;)C88;l>d4y!2u80Q3t{!WwA$1$fDuWY6`(Adfw278WPy8o7 zapV&Ox=N$PsSF&koc!1S)}iBW+7}YyM!Vkkk!@4;X#~=7IhxpNskc6s2$P4G>j#FK z1EWp*fl;^bi=gXYIH<$62w)NDI!B-eX8C?|;(WPE;yo8CI(`U(}; z>>LL``=j#IjA|ecc)N-SF-4As(OqEtsaiabz^MV3r3^`f8W^bOEWxP=g^x!6D>Cjr zcQBdC)DUGEXk?2<`YbZ3x*e^Y1Kux@>_Q;g-h9IS7Ys!xkRa2JtDZR+Hj|mgV;6dq z$Y<53oR!rR8^ITp&W#g}iRWrtz=+R^RL#~)(Qwvv?Wix~S(Rg^HUSQ~e7WFYrzAnb z&kf1nSQdTDaJ>vI&~VI`ijGba;$m)Y`gW-0^9h5Gc6@@a2N zf*39!qFfi}6eJxSpvtSNr&-#fiVOZ3r%yk-|0<&c`CF(H_2IjK=(r0K*B1jx@=Wq> zsF$Ge)5(RZ?@zW%|0)SNyMjsz=b%q&igMbP9XcDG?^oj)E-OnUXX)Bsc2S;C$d}h& z@~78Qwo;G7;0Tc*t|1_gHgui-KKdH*Z^oY6IBBw{$ILCRRK{}X#zo0&tjfoi-#6;7 zlqNZ(fwf6b{`ov?dF{LD{6}t$#XG9y`PXBNCb)CcvGB9oatx&8hbuzTszxb+){bW;TPz(xj{ zPq1jA%w4ihmrEB;@;I{gNHU0RrGo<*`@#f+3kZ;S9YJQHwrqRU`!E( zFYr&>{t2zT?W**mRZxO6{3nCG+lZH^M2{31WXnB`_6CKq1MRZuZ#wjEFHxwv40lsz zVy$!*p8ZB3QImUV2WC=Bav6aplLHF4mSQ@=lK-@OV(`t8#x3>G*8pBN64R6NaHp@~ z+i|s{(hX4xiETp6<&8Mt>2Eepr?BjA(Sh{xnMMR~{p44JT@OHl#1{BdDY*dq41STv z#@sQz_?Tn+nNfeAuD#29XC%Ins|U~#t9|P~!0^f5>uQ1Z*7_&q4_%nTwrnC0OMw&} z$9|zr;}yW4RhNyEGG=16VlTIXZrNX<<-^DDYjdk}|HbH|jr{mXKzQO>WKHYtKhN?YB<*4+rZ0a%w{>+X93c}1(Nnjx*pR3i>(LW!5lP_6a4?>t9Iy!~Z1c;CRF6?gi zV)WyfPWz+aMcGdL;;aR38T=1k>-7S8Qh$dLWmla=J88SWN#WR23_Y6QL}iFUk)#44 z?Kd1+-cC`Sr#!@{5kOzCuvdG*GYOAZ%}wdHMNg`ABVpAa6MB%MszMZC9b}96UNDuj zzx#KH{AU=bZf*@A8ezxj-jhggboo@qLT?cj%83i8S>>K-WSH){)}4B6hpje3{($wD zMHxpO^zM6(1akhivqpuL;BT&`o3Z@ocs_*QJi2|&A0B7uTqXj18oa}5{FTquRvcaV zN#qwK*tr-7@d#yvM@r;4k(?pd0=I66gLc`3Hjn*8Cf@No)DHk}De~uv zuOpBh(!T$pj@zDDKUg*i?^)DB@SzGMPGKpnWO?AO%==jv>hS3~iq$SC3-);V6y&+G z=DdY9L<!|OAHy@+v1Rug8m({7eszeB^qVVeY;)GXOV{%Pb9ji^ZK-ZdP85=Q zwdN%#q-QbssJ@(*D#AL^H}EC2wS|vwFV;zHk(m;|wjl_SlVGiu@;!r4G>}WdWO98A zUv|j0d4JuwozQZ|rEzYBE1zw-)fMSm<-ePBc#LY`1I(AC2idPmbfi+YpB41Yqk5X{ zYfpO&%H5K>4FdgDoJYG29S@njA%`B1$DXj3*wb z3!j?%Fdv>l%h!kJR!Zy+8QD{pXa$K88NLpt9Y_zCL|GwXY!BL7GSq!|mvdVB-oz@w zzvh3Wz4ceq{~Q1RQc6iFX;3-@1f&_LNSAMvAiu}G+ z&tXPmyV72tH%9A&Uj2;N_!68jqTu7$#9fXS3~)6(vmc^%F8j!4zm4DD&N54ob*Ia1956A%nzbnXeAx1+>F`z=7?N?5g!B(76ZXiV;JNWX4%xkBq5VaX3b#`w-+o>FbM2Wz zE&p}u&SE4ih3MjDLGdQCp5pMFZ61}|Go4_tR80EGzE^I7|7%*v?nArHWG#=Eh7-nI zRM4|4+6QgkxVR-B}QM8yYstOd$`XBpMP|douE!@N}FUXY;Tz@VCaH zW^KI*V<#-sUp^B;<{#jXha_Ly@Cn~8C%V4f1@nmFV5i(LB>z)*)fgg2IcJJia+~#i zX1a*`)Tu+~h+1b|`;?MS7x$Sr?8LTN{c`AgPQknB|F{BgRAsF4=MmQb)xUqoVnO>( z@NEAFq7X^nk3D@IM}}(>r~xnXhXn>zLFz!Lo*KSPrXQW0i`gIkgG(F*c77rG7kzgA zwjA$IF}}H;n>0C==%>>#PYN$w{=feW-TyB>*dq7;X8`{{eDKYg>y9+0F$Tj?6w{Nr zS+X8Ht76C;4@eg}PByFYhpO_E_itW5N#kVa?)@qKkeFBZ$6%?4Vf?Y=hJgXuKdsRG zQy=)bUyqKs^T_RQa}y^69L2jUh0?>T>?}SRDx(6nR4I&UeD$ot?u`uQU>02QxP!_> z#_^psj>!yCi(8uwK0m~b=Hq6|a1*n*li6UcS@6vj?&fMk4iiV8Yk5AnJvvS-Ui(5f zZb`IYW?%BQ1D+@4)pc$uT)eE|M)`KMHSN(RfdkgyJa(8R^H!fs) zlM2H{`S7@H1gND@TEBlgR>szcE%W_WCs}u9J~llXz%hN;g_)f7Luc7Xs3~I{cRzZQ)lD&--%$wxmiuY1-KEZxb+Cu|Pl9UA?Hz5SN4d=1Q!>f^$gKpTi z-OL%5Pm(i>oYJrmuCWH~d^6-T#=hnmbQzCIQylVSzt6+ecj?NzD2eoZ%SaeJ#6T2; zC5Y$b-$lkOl)voBZq$L|K=~}=cf+!{nrHBV07y)H$Ww~V4STJoa& zIue2%l?p)-A0K`oVFL-jJ7lxyq1%vVfMAwa=ecBJFFha0Uq6WtS|<`u@>V25ZJf2L zoM#sKYNoT7U1-yNvf+|3LFC2rV7GXAupG9JYb}tg!$VDrtvFR!>q^`fJRu4%@nD#F^)VyI%L4dC2YVd9GMPnvJ95f^y7J zW-zfmub|U9pYxNiuhg##{$okBYNCb$Gdl86`!IsY>o?zIcx(SyI;11GSpTqYQJv61 zp4m%jfQb!Kn*-v1WmHyt`dzwaMa`luSNH-YHmv+)=QW-a0hQjOeO16${DV)ha;M`U zL=>BwITtJ41E-}Cz*apdpL*uE!D)7b`NSbJEjPJtfgJw2GGj0SaY&#z6mAc>K2(&u z{RayUM~t6`5Bb7Ceb^UPa&f}=yhPG#I&~9)#0e)gEyHI2c`SC2A})AOp4R+<)Q2|7 zc7!&3#J=-OQqbM&r?|RbM|{PI6%$m!YT|1N8vbNCa5R9^$M(biO#XcLy`514XW71aJW*!2&f$xD(IG^zmOfN!JHS%zEqGHl zaBNtA5EE(*XFN$=pM^y6%RIRu%FV@5H-`u3uf!<)`FlZ8JdD+DIg?~R5w0N}4ePCU zJyMZ*iVR$v^DWsaHWCR3l|}U=KfI^SB9S0oLT| zU70IRVyl-tOe^|)LcmK@=s;gstrQr1G4l9qcAI7|eC6P%40Hha8pwT%=djvS0;b~2 z5p!V*_Rey05Iv{=)}?^qIEncoTMJEgTN^th-}L5T$?y}@`3bMCsYWl!j;qwrJ@8mE zY%PjN+3%BgQbc5Z1yBPGBQ1_oENW^mg!}FlY|*DqF08RFj+(7ArZJdesE`STf)8Og zq;Q{&zM-m|V5phu^VOVSI{8_0xzd-+`4i{#&Eeax>TY5S3kHh0uarWefJ~f61pYU0aI#? zr|Xfp}?pscwS8~IY9+uGe&-cUh0LCE{96RYwh<+-;BCj8;W~khCVB&TO0D$ zKST#T=m9Q#a#Ha9jmxpx(L~ec_$2YMeI%1Mw7peIo0M3UFJRD;8xTA20)gyGwZI0 zFzPDr;AD-)^I&1jeQeE+Ja)wrJR5~^%L8U;Ra|`hiZNcq`IP^#DRFh<`eR6Kb}BGq zTZ4^A8^TIng3#9IH?-18HzbFIq&bLz3Zl#gR}f`T08K%eqCq?0;Zk-05ov1cL* z?ldX(@0+aY{I8bzs(&w5gNeMD+DJN?X>UJp!n{AcfSo(QWzrs@nR96nwUr-&6ia@Q zN9DcXe`;O=8LF@Ulp6Ggd2MoD(hAaS9v!!Vmb+B3+!%(b4L9Y)!mw(Da3o2US zX&Fq@R3>~nAMhtZJ;!nH9raLnoMT(?M80Mhjw4j`9Q#}=7;zQCkkIP~y}dO>3!DnO z{D-bSyT9aoTGBSUUqyd1vTk77z>#>J)3j(l$rjhNR$2JzV|jVuAcDy(Nd-IyZWy+n zX<7ngtP6$-k9EJ2~N~zk`;Y80A2x`h+G3b?laMT2)tbiVcS4h;U1}}ug!o=Kk z8a8%zaSt6g{;VNmNN{gr1EVm?E!b+tzbBqm_Na=`m_c^62h7EdR)X8t0uD z!@l>D{dSKj!o&i}m=mmavi2R|5S*|$Jg~!5Cmd=f2E>N|V%qBQAh?-XoeI(CTlO8y zi&~LXC8+{kgy`~C@_{O-g?+nvCb1P+D)q)2>3UO7W;dMFBGh9eZ?xpC-_X`Hitf^j zaq|Pdi}^%PEZYzsy|D>V#Vhh~5?%NRbG8pE`zMibFYcRvus6@q-WjG>6cfg5LAPxr zvjbr8Eps9Y7|D8{ud4QF;|Tiyokwv)W&HpB6+99BgqyO)8p079z1Nx&Nxx1v+O;WT zGF#3wGxH)xY%OYVu<^UB%%&99z;z{+Z7_R}VtsBZlj~a{I*qYIlHB%uqsqA4{7+vg z03@)2l+iY-`2`%lo9 z+MG}R&0TlKLpO1YmvS}fMh{+2YT4F$AkYzCcV-e87Bk*PR49C(f)DIS+Usmw3gLcoMMauXXn1IwJn>ryKgE$EmMmY|c7bW6YGP;}!Tv zJ_#6>TB1iP-b($N&a3)`ud6_9S_(?5ZiKF;Y~T6tKQ0nwgw1gzDPX9VJV5IX#|wS8 zJgqwLCBR+Ja8tkg@SrEc#P!MXc@9jtF~fW2+lUBmIGl9|C!KbE7`J73vFfjP#<01G$H@9&CQ+=%4Jx2_Rwce#E)F)_v9 zQ{AFM)c0D`hamRD2Wf+1XjC!rQ0SFE>e2oF{JRU?uIU2t(+(XwEitMz>cKBuH1Yar z^o645qz1$)1=dW}?ev)m5nqA>2$;j28+9D%+~blD##O)g?eWZwg2jO@=uQUg(q}J5 zV2vqgEGVNQC}CyT6k`6h-|VwBsF4zAUMsBH zq02Oilcn`DN#%=N`0p>x4cl5%-VQd1?*UMfqWv#LE%j`|L5p_*0Y&eB1#+s)(Fk3? zSK0i7)`xc(%rB6pZehB`cWgm56ikaSA$q>9(!ug*J^#y9s~!BTwVGGVHpnFqb{)Lg zGvHi~oLwqz;JIdsJ)R=OxyOL>`{sSpPXeMQ0bk^9BYTzDg4O<$>R{b`v=}3U_yc zisSnpK8JxhWs{6}p%@F1L<7{6O+?0B|jPTMSiwAaNsz z*^6wQ0S`W!7g8&|bsOYL`toFx#|p4_Nf|dCIq;#FWb}cy>u3)t?6N>>QUgVfT4W{#^uUG`CUXsHdhMSw%FTc?|B~f9^~) z^c4AL?~GjL#j`SM{SyFP`|AgeZL=ZWF172Ha0INOpjE?H%a-CInwW+*28gl`efj5S zreE3u`zGEYy8Xq4Qq$(Mm)_z5yHvLdF*Eg-b>`BHb|~WUW#3`jBZ}ApHLT(@6=j?B?#Zi zJX5}*ALUWPK z@;dxI`6B2?AQA#E={R#4r#3;DwEuOfBtGSO+%BCZ*TeQx3^V*V0r%#h-I=rxO2@sV zNVMAZK0Dty`JVk(CW^xIWiuLC-wV!kOhi9^d?qp5Ry$@hOnd(rd+I)8B9uBoB z`Z(HW55fL5nG~0%D!AQb#~l3znuDi>X4l)|5L0I&-&A8AeTueXQdRGov~WGTuIr## zxW|ov?CPg!51Fa+!!w*TP*7ukGWh&T0P0%R9A7QFnzSPrfzXqM$!8;v2d^*TBT6op zoxGyK-^~aRvutzXGAvV~IZ>yG+TGcN`yiX{W zIsQ*Q&1m;<Zf-F z>zMsnrFt09!N|qM9SsdnUP||i@3pp|RRNDoC>6a1OF?g02`zn=Ly$1S1nqp*nraTf zD)68N=vd{3VQnCQq2!_0S!5?4>$+0Hejoivk=1_AX?a`rbfmYwjhjOKfqW%JNNdxu zJcT&A{Vb?BfC#YB!@Y9w1v>rRHzD`SumrmIAajH@Vc}U-s@b~?-IcLZIp?k~_ZrU% z^~lszPW_`?E_fm@_C=jgz*h#vF38knP<9sbC9J^|OL!{b!Am*56dS0g#L3sM6(H18 zyKTJ4;}w?hU>zPGxwO)I;rui%kOH9~ednBJm)3p7Dlb1_kL)tfCh0cW)tDkLJ|FR&iH9sJ zo0C8Dz#{2ml1p-ZmOK~|vy@Uoi0XhdSyciWO~0)n2AnJlejo96^ z73_c3qfyNr;t1AYJ&21};J@!Qq?RzE98~vIrmMaAuH{q|(cBXE0df34Y$r$T@|EXA6;7@;LcXnl&?l2DqF|m%!M?E(Eea^?dD#Qmzo8dKW;;YrKU?=i={e z*R+QWU3OUwB9WJMmM?i`PnO~Y+4ApvkCtPY9oW1GdOvTsfX3I8wqiqgXW85l-?bL9 zy2EmQ|E=1hkZ#Tq0zJfW*#~~Cc%@mkT>)z+PNKUS?$sUhzR&5Ey^E7GLwX=G&OosY z)w{n#E-odt72XPV_0O+~y6%6#V&~`Gnl4vIDPqhdg$G#irJ=Os8}7rO&p=bw`hC^oO@eo5ELiK}4n$Cx!ku z$cJ;9k^hu6?cs(4(-#wCbSCRPUDHx7#*Qe(;r>;uk|ca*Qpb0E4^C${ z|Ls&_5$$E3FkJ5B5aKP1>bhCG7oD}lwI^~BY$DtZo;~o-o{m2`+L8!aAL=lmpc4h)3sr+CSs# za+#YFyf9q4zulLaCgXDlaYR|DO{XQEf7X_yaweY(2a=gcf`SoaUGe6ZybsKv`tG;8 zd0DIY8yP+zM)tpVWvay~_)$oES$c-L5lI`TA*l>AOuYXz{&CEf;!lAJ5BH(JZ#tU3 zWoq(CQ=n}TRT!i0o|vVVE>>bKC}LztQks<+Fm^&TF!l;Uf8c_k(G73Hpk1k#q0j zjn_-g6dv@DrL{PFipl<5G2nxZjheSy%Xaa!{j85{(?1u4rF7^d;gjKi z-G~WXPhaFI(JzqukqI7Y1g=*R`INJ_MVh^UJ?HWSt!%Ep3bdG)nl@(wWqaJ{JZqg$ z((YaOSUNcninCsa8w7aW$sib@_Bp>|vub^Vdng}AIvg8lYul3;c>;dQ>715`{pG#b zU{Aog-QadS`5sK`nK1_6__Bx!Pd?G77X$fib_|YSI6V*z=N4> z`RH&8sX)0!--khGBG#(dRcwIX-b>{fiM(V%gZKCOxh99b9jG>w^C#Dre!hZ%Lf!*@ z4Cb|`^cRi4GGfnd@@VYj-H)ZYB2R~O{;2VRrXP*4oZ1gDtEBxY!M|&JBqpJMDPu?w zzb4jw|6lkwqVOgU!h#h`CV>#`Dcv)`A`j53^XH7XEUP4tDK~kL{K{aL!tv03t<9|E``ou!B(GnbLM9nov$p6K}T|kF?j$;l8h_t zKLbK|KOFkr$SMwC_~z~j8PEMoyU$DqaS}h0Idh%!=?Mb2Xc}71RyJ}5=aB|F#0Anq z6CmHz!Z20s42!i({=~qahiQtF%zhKUrB~&TW2r@n!E`|IxLPvZ+oVTpq=NeOPuyyT z5(z-xwk54=eJ7JySo$oDkjvSa9Z=(Sm_{c=!F1{JG}@Df5V z-IbIS5^n8D*#4>F)kEym`}Bc4$Up`G#jFXO~E895N3pxn>lDH6u?@`X4 zj)!%Ewe#msFFuAKT8Gzd1F8IQWDQpWzHIlri-q6yOGoQ%5>$JKOKJbDB}9~yV!tmy zjkI%5Pm{)JX2nEw?9C4^I)E^XpdJ-NV7|^Ib}hHYth2`&MqLE`O7b zBMxtV^#(ggM^37=2vSc5(klob{S2_V$YgYFoT_g=qbjO!wa ztPo)>aeS`L^KLhq5q_k&^pS|*QB(r?^Di_F1&hNl}q$1PnjoDd1?8CD}vg?IAb3)fYUMO z*P;n2$)iR7yMARUuoCJIWC+^#IQBME03ZoG$;ui_v_&wXnEpUCzH`cD5Ul-KW!2zeX{P z_z4Q}_B*J}jn`#+0^?PC$HJ89E;JPLz;zpM(>4nW!p|+jp;elJqu=bYDdsN#J zdSUHuJC-2NxWYe*l2U!2dZwxVrR%7S4op!LKk25vi@+{g*c#`|v{Ta%{*y9hPALjSolLQWcUn8D0F*wk+{BaI(~y1!!} z`jj{3X;Ug4U$v>T?b3tNklx_DZg4_TUjFoJAp>=~gBR=YSW&HiXFdiUj6HOkXW}d- zUFj;KDrE0|kF|vJHbzjVuZP#ap8~$gu8)ic|C^shD&m?Rz^}X{O=RUxR$q6@ogl&} zG({SeS3k8rcJ-P1Cm-ZYBzKw|wtAFR;VCzpCUhV%hnf7ld>%aYN2y`1f6niQGx+)u zfP%H??cq-`3i#xZHK~;PhfSOEmcKsTG2FZUY6!gI zS?w_G)`X<5>zA;WIqtGR6NB>}KY+_<8%>xC~o$)iPq=@6t;`&-8QQdN)v)@05m?08KO z!dTd97c^fUdofuT*ii6LBSYm`E~3!0l7kNi(y^oGBwM~Bxv`y2HF}Fc{S5Q8BJnN|pE7d>O52)4r)ljZEUKn8^!PUQ{y^*&fjnvU} z#UGKJnly75a!PW(=q~Ydn)IqQ%oY`%6&d(coH)PjFP`-@?%mrDJkJU9_bXBe7=J2j zr&x0Pq4(^~U=@S2ri0u_k28$@@K|wA8b(3-(D2`91RK?8}SgHy!sqcr`DvhL?n99oD^r72@ix zjV&$$E!bx48YD+RnnLUdX5@BJ9++x2&{sRW#Y8N*nQJq>@MbMkFg`^bpDdo~=%1US zL&Wm1^Ujdek|OnFp4`;e^$%V(bfYMp>)*fsFc_51R=!R9bvike`?0^gFRwtTGeYFO z>fX%GtDyy}&rCNyxg(wl?WY%r6~ORlth3hB5;r6osd+yI660XKZ^8pelYxc|36`3V zKvlPJfJN7T^R44OKR)FweO6RPwD{9_D}3sDjOHf2Fj`@3&U9lDDV&o<^5pn=?_ZfV zesrev5)=EUj{Ow!Tg7k`Mq!!|sNBt_Nbd3j98#Y@>ku0%HtifbeZlzN{~hN1^X_rk zDm};~bgT86Y*DPplhCcuA{!>Qbo+6U=Q>0rNbupDyz&xT8UVS+mZ;%(`Me^KsT97D z=|%#5dv7iYH_CHB54RQ+zRj;XJGe}%t}9FP(CKyhMns46&-u3=G|f@0usuLZ6b9U=tg%rSoQV+$FM4LIFSy#T5 zWq)O>nPxQhPd&@uOS9I01a_uekKwD=*)-cj_{Ng$Z%7{hJNHWa>()U9 zDby2*(I#0sL!RED4}JM^X>0En@h0eL#{|h!BU740E=55%%lQ&Lr%$Az%Bx^WwC3u)i{~{jq3F`x5Fd!B zbCw(ZFmTR%O1VTW1*T>A8pw1hMvh}XQy{-T2(0<}f~cf#z{DN&m7+=owm&B&;Zaiy zR-{r3c}-VP`q1`NhoA_CTsq2)APR(u!5^NL05Ah`BL;xPn8q$t-7y|JVEkgE(B&zj z_2AfB3Ydg2X4_o{<@xZx-`KVE+}m_+*ry6``#c(`L&`s`W2i0pkYIB=RsHjBZ#>Ok)*ov# zoLpV8fu^qO?^t>E^nly=xu0$Gc8nvprpL}vQZ?$&GuDZE=f}PLc$)iin8k!lnw%}G z>H)c^G1Botxm-!Zb{#>fso+-#xl%T((ViF8;q#C&7ILv;BN?C%OLw(z%RQ{S8)Z0+ zb7WuG0gIq_bH1w3EZX#NJ9!|AL&09%ETMbA#*NAO*(F2Y+oF1?%q0C-L_qXksCAb2 zE_Y+Z>^%=E697B)GoRW5CkG~jb9TYfz#1`n0kRpn=;1bs#Q-7Jp5VTDmmCaUUG0tf zx_R^o)~m^QE7zHE%ab93T%}-2=P&Pj%F2_i1F{wBI`_p9 z%HT;)u2-LyLxT{)rP!u3sNWA`NH#OAUz7DDb#GNyMG8aj1SGaj>*y|7a))3%Gl#2kAIuz_SC2==}Z%k`aA$A)P8vBxt-S61qkjbj4j#4ISr+pBX+*7V|;m; zIe}dc|jY)%;94g64Jg%;Z#<4YdQXUR`83x!(&QeM_9`i~#er8p^k} z(!#*LJK@Q=IjN ztYCO=9!c|R4DF4Vr4!6)=&C0=rypq~>_xW}F%$W!1#{ac@tzNPgJvG7#E*XkU{4H5Y;baZQ+pjI?F~A-b z$g5mz8FCts^@x@hsbNRnm>mNKx7+%A=m@Mx9E%7o~l+n`tO|vk^8>eNnhH9Ujhf5iCx# z)WH+uIab&6ilWs(0hG63uu@q=f-F^)x%>5MvBUqMnuClgq5JvyDAQkZ@b%TN;_<#9 zXKw%0)wY@^*NHN2sbMhd%@g&A{`PB5W;hX2++hjBX%8;*HB6Bua;n~->n;Fod|?aE z(hNC_Uw9CU}%FX=V*v~mQs$RY4{J1?$ z^1HfyyCLg(8#L9!*dWhCHCH)4XG1?%sMI3~tl?LV-Hm^oOwr>GGkt)5H}%KZS^g;D z(r6T8#zd*6>!O|HekHDr?4(%!5O$eSve3xMEbvSkNzVYkh^mmAQv7O9z{UXBKlWVz z>}Ft4qxn6MEi7mAMmD4kgfh6VKK7D0PB%>aQc^^oHiIa<98-st5jje zQMn+_T;!?Tp}g>ri&NRpM19M3QCVNM{-(7KG8o8#5dY(@N^=;^JpiwovpSf2fwbT5 zPFw8J1&ny0`0=bY+NB7=BF(vR!5Bp2E17Z?Px6?RaFs zk-k7&*4G(%l*;pm)OVzp;kVaxjxGz%81?#k+w0)PKMo?fvYg`SG*K${y;Iib_G>Kn z^C#wVFz^HTK{ZC-FaS=i7oyp&#AJxzh3yqwm&yk*2Xru$#} zIk)ptyh#4=lRgoTHlez%?uF&Y*t*4}r(`wO4z^qnS6kocjg zK7PmO(lPONkFwynv13{#_`YHswNll#-PY=HJ+{@sOAriwzhWK>l!W6W$^$B2b`|99 z9x+<2n+ypED4E2!wPygGE`vR~N&BXDvOe-I4KwA5Ns{POCQp+md0TzInq?#U^ru%^ zgv2V$)NZ2~2KJfR*z-~1mac#kliQ4d|n&D{aqUVPn)lRHFEUjdV zfj_4wTq!AfO}1Oi8phY|;|wky3ds`+J+^(-{V*D*ocGTebSaw)|G(Qq+7|EXje)t2!>F)GW)>UFKRf__bg2X6v=p(?mfL zbaUa=^tl(WQ6Bg85`D!GobMMhdaf$P&}~D&4m=>ejmT82*YGR;u>W2ZY<=7Qa^_0b zkMVATP;Da6evCHM2Nu>CpHW-o+naflWMs{e?mg8l^m}O>8TO{v$y-_QWcX(VnDIH{ zklC7FhjkXZbL!AA=JJ?5cUDQJHum|#ap~pTxPh*|5r3_ccp+6=&j%tqKRzhMwVCo{ z=mH$)c(#b6BT;*F6AW1f8k3AQg~B5UVHBz{PiE|8oW%=e$lREp@*aEA#7$c2e80cImI5<7!)7s&*1OJ^Hx$L4F3k_)I zD_7pW0_H)42W6E>L?R|`Zi6+t)y|ouIrn!H1IqsFz)vy?KU0|_l2Xy>SF3OIzp_ED z=0?r(n1Whq{ z`Mm=ZS0k5Ibv4~g=|s;dZg25?9?+NNwUVyXkFiX4A6KoMNz{*^PM%Rs=?&5}PM4=`7)Tf}R1 zv>e|ngaVm9Xwv~qe=yR-a#Z{fBB8x{Bw{JL-qJ+R2xDJ5U>~SlySHx=9T17X2@JR0 ztktOw)#TJ!%8#=*;q6nchk4AM385H`#Xz#Q+M`yB;JL=jM0qBz5=$CCi~tp*Lcn`G zH{mRwX*ZJ~DGg#rN$FOdCqVhACu2O8xY3=|N(uohWUAn*ifJMdmWMUv_6G%ZtK>w& zjEno+hKg{fLBO8%t6X24J~RZG4Em@&~)^63V&L%@ef=hW~Ir z)4Jz_molhr{4B!$Ce!`Nsh1U*gR&@2KUlai!CBGhUZU}ezw8CB$9sjiIVdDhHfPjy zh1hY@-??pJSo+uuIiPyHa(>H#Mcd}bR@z9`IwflBhx(=om@BWCE06t- z<{H^>9cL9`ui!plAAZyAzC0!@Byc%bT6s20++0Pq_FcqrXDK3gYAC)o%ux$uEs6{I<}Ow$={c_ODn zeLw>N20Zg&Iq@{Rlu^Lh0bcz62zk}N2Yz~vF{)!kxJE9UtILk%73F~ivrUO3ydc4M zv5`(}WG8(u8)1Pm{>s~A2>sNt>Z(w`Gr2&7Pe)76d$y;RL2 zCYZ$1jvbLGFQH#L1Zr@uVc)%7H_oGYUugMh4)o$>Grk|18ym()$qd6a!@1%XLn+_toeuIe@ z&WLFPfIY14l)d55n!O%m*oq%s%|)atf1uJ#1YvXroj!BWGqX>x-KW(4)}$uhkzWVh z6(8?cUpaw_AtTO{c}Rkr^}v<3IFqv-Q+$@ZqL#!rN4`?T=5ZqV+RvYw7-wt*iUCo- zb?!S~iN1NCQ^{4P)FlIkSeSvm7{WUsNplob;^H!Ean@ij;8tc?^IicV(8z#Pbf}%? z^Sx=(08uD5;?>KHKJ|9F9x5lctc8e=`%Ct2>sT5P9jlhgPBlky4zo$4&&!X7M!@mQ zRJb}HD<`V|;BA+aRo~5%`>i?-0X>`tm5XHJM^jaG%jXq|dLK03V$?+Cd5m1*ko-Qm z9#a^c>ftz|yUBThl7V<^%{3E)f=E}1S_bnpq%MQ>Ff=at z*V2Gih-^9waiu;+v-~S(bsICbFq5iz$R@mRZG95rVK9=3+9g=h5N`^Sk4Nrv)5kbY z!jx)8FCWP({8y1S$0i*o@;;;s=d|Rb2xv1!GBtwV8J5HwU|G~L8JT65+M+r~`0fD3 zc3DOK+O>ENor&X&>#=X*?F(-&s^~mN3dT{X0w~V8&|0zdnI$*tFF5i=6W7@ znCB3oxjQO_^dco9SLp6r6|R;LXLOjBW|Se=WAReP>?>nM^Q$!o=9L&MQG$`Z!urRD z!2m8~n*Quqnqskx^jgMJRZgIY`}eoIiQ%boZ`VAwLwRa|IA0ht;j|A&=CD}&tr$#5`^ADLV8w!UEQ#SDM zhGnhDj#;BDL+A9q@K#^6^VNAk?+5@7UEC$|B*t*2d(^1oSwCAqRJSj|D)nhj&fM{y zx07R%@i}h7A{a^nn|1EVSf+J>PN^xt&w46X3&__BtNckJBftr=!`0S-^*z^+;1FXl zUpX|E=ra688jgXRiPDKv)IL__s44RUbcqiHvRt;w-2LlQ?AmX}7oc)6uynkO=n?+L z5aIU5SkvSsl*%Bz9EI|6$0|eZlXZH+E62WEThVn=b*y3UwjLoEm$OV-C~$;!u7mn(o)8Y~ zoC3X1qtJoQ5x?%wtl`f;$G&pO@X;F!5L&QnVXWN+Ec?V$iHDlny>(-{a=QE$#D%_S z&9oCOA!^6FPt;+%CrGk+S_jU^Qc=RinfHDrfMRVe1%Rc>*R=O*xoT88-t6l+oYfU` zxjU^nUUZ^j@aDwEM?AJ`_cIQS<;eH&ja5e1p2_<@(7er?eWPe)$V}tQOrB|WNx7I$ z@0&kPOi*kg{lN2YG1$5Kz+kfl?moB^$z17i`LV3nEvkx72L98-CDPns#L1@|6mZ8> zuH~FhzV)D+a+lzZ?q=<200}y$n5>GzE?4G02<8dopQHw0aM2FthhL69D*UK ztL3b2N*(0c9AQTM+;bk?;W&h$0+vY|?MDCBN*{~%{0eMoeMUmp zi)$Fi_&@rp zqHOUrU0A@6&3lifOuH~qmpWgnQ?B#0BK~dBCT|iILN|%{&z6Osnk_Y~XATFg#tIYz zjQ&Gf4yHN@q4mo~KT93A`IdrAE%tjIK7-ef7_8ahmx0-9wTMheY5apm;+;+AaCU<^ zx{6ZcnFk&Coh}gxE*~SdNCIHAbs3IsVGxy?`I_laB&xd6&^ITN;=M}w)Vr6dW;0cv z@B{}F|MIFj#F0oCL8NiA4wJ3pE5fHcPLyypznGjCwII*Di8pdQsZ1*SVIz$mh@6)r zPfKji_w4m*0^g3wy>nlZC8p2}#dWr=)A3%=C!_2LTCgs9jtm;hH~PC2ngE5j+ghY+ zd3?zlgsR|IHPH(^(C`tl%l?=p+X6H-U&bbndZa4fj&)u1RfB$UH?Pk={+N`lNYS;- zc-ocM$5A{Oz8E~13;t@qs`BE)$+&wwe}&I2!J8x~mq7qMgzq*a{Ze0$!QSuV3R*|+fMC4){dR8FgPk8W;l+NvZ`#Bxg+3N} z*bM*Uv)USl_sTQuSb_?rgPH^(Bt%ME_E?N?hijfw!u`OwUl0&tN$otlk8tpZV6SNX5;K zB#+`mMNiMgKR%HiTAEtf&(=Jyu%5(*wS7BnwT4GA2;MtP&;{FlKq+Nu@H0in;yqQe z>k*~{zil}H>B8UUMH0t_500Xq9mN;&!MR0tFU|Dky z#s{Bz>QMB|IlJiF0D94#FcyY5#zsQdt-%0_drNGkvfzlL{4#q)RpD|b3Xd47hYG2M zz8su(`$tc{)}Ptn&>s8uocxrI>)Y840a`asXU{ts#I8P-(OwGG>lOKBps5se%|-@^Jiwyo>^L%eH!FkE z$d)V^(HxZQGR@akuxWdu`1(SSj`8CsXKsoIjDv??5-%mrb}+u}DM&Wp5B$9pdOoaF ze>=DDh29J5--z1qk>;3W%0Ak84PWj@SedZKsP#Du_B19tmXo_Ax#2+E&7~Nv>M4`} zKEYA}s)p9cQy_wM)zjF%gH7%5p5t?>W_q-`(72ZQsW=dUBz zLx)ClFR`-2%e^`#hriSuOMkXe!Dsp6wOYOHCwC|rcm&r(RUcoyp;W!PVp4NxQT2It zrtt}BVi}aG-rhR=ozazS*AyH+dlR({Z1( zvRn8y$S^6G|GSn}x3c)#3X5pk&*LH0Gu0s(pBHcc)9xneF@v0B=X=NQBb_ZxCe_U^{h{>l-(r#HSyBG&xqvLzYJ6zkij z{5p9lb}sB%nHEJRsy0PW7jskM3oL!V$_Nr3&j-t|j%HHy7j&X@?|l6{p;9w2=yW+h zfAGO-aY-<#_$w#YWGw7K-(Z?%V`QNM!M-sbk!bNkN^SmaX9^keu^RYY^wr`T*Ql&SGb=;w~@LGJR!1|2x~8b8D=zBT`rMgKJ&UJNp1lB<=G^ z9b+-eqH!p^fHfBUPSEh=X{Z%snQZNU#YoU><40A>juuYyV;(h?uy?0Ik%?BnZ1Ze% zyL`rqb7Tg^(H8a()hel1v8 zWZk&RJ%ZFP$4dY*pjy%`m8{{*B#F${3AJeFEiGxzx47Fld(!hsqEX{&Tue#l1f0{U zcS1T{Dc!^ZygQhTE8#pu9Es}pSDVP->PBVQJ4r&Xx$XkF6wLbI|guvz*E;;AAH zJx!#{+V!DH>!;e!Ev_eJFf&A^DRZt~Ew`w1mHE|M1E;)hT&vq#ZaK*~w`wsE5$Aq! zNLB&*}L^EQ3rq42CU|k4|%G42LGh0*?O{F`cR&ARTbK*#pg?S2JxE z1vb>A(TxD`Wp|? zNqatU{ZyjnD5VyEOTX~ceVBr!KUQ^vA=O^aDv zR!6sZeES-~1>8%06Dc(T$Gdm|A>VMKE*zzAz8@A}}gUk%ek9K-7Oal-g=jwLmk7?Z>AEOIxy=PtNrv3T# zUbi@mp5Kg2lk_p#A|>_)sa4EEOtbnUKbrMZYCI&Y!SGpk(8H{rsfNY6r-VId8}q`W zN~bL1vst4J38dh61+3t4$+Otl&+cQp3A+M{>`(i?9W{Q$)+)+fL{_fcaDNUwn0kM;QA7KQ zQ2hLq#I~mExt&fRv%w=nr!}T=e$hY51dDW5;(m<>%`q&ujnGyGUwxh|W8QW48!OJD zTA;{de|?B*KHRKoV*A&L=J>0MpsBXP&Ce?}(ieDUKI;gqcx}V))~EjTYiQVC7dS?R zpk)u+0GHa{%F`%ospRN$sd83^YwgEs=^u!aSe+@Jq!+gpmAP^DBOpxUk-T-un=cXR z*%V0vr3#IB!vk4N;k4EZ-LvHU^^vYbiTbkO+3(n@XkvOeE0Edy#KjLKY=8pyeg2@1 zvpKxlG!x$uUHWG88sUYW!*vZh(*Fr-W#zl+DT~G!#=fgp;P*tQDVWZfCTR`<9h@iC z-D3=ikbpTO8^QRv>fpEWy^*1(N3`I?hPW&r;#Yx{@%(JoAQ8Sbus5bfZMZfYS7IEfK>Hxb$%8h4!@f3c8$FM{T#(1^ZJ@PpqhWxUsiMA=BH| zPbbN8#VD{~?^4qnn+*RX2{Y}tx4ydn5?1_zW8J}ckUq*mU51x>SnZ%f$4}jM3wKS~?jtRFev`u65Oer9^tE(WKYpXE7 zdcB490&_j7tTMQ&IPy|)4EWY|-h#pC;P}rK-rtdeks*KGqX%!^Dr%9)H6j>#^`@9* z`g|iI+t#l2m3tJ@$(O-g;;TOrmB5}JwwJ_7_O^<3j7M6yrgoAq%#7GB=06l$&Jmb% zpVhITcccZ@$5MPjiR0T-1Mbj8PT>Pir|R>Ex0A&+!8HTC7Ik$eMkS9BOZ7o2Hi2V~ z|M+GF+Wzq+>g=@2<&|l{F7$3V*5%UH}!ooARYZ>&D3F_V<3e4jK*3uvQ3<&u9Wqk_A z?FD_~4hp7)!0rvGowMoLQLLvreD~EZ!=l-9h6MeMhJ?3x$8Ef9f6&T`KrzxozHUS{6r=95&fF!$@AOYc z&sYb7i=66~By4=snS9gEeENe(WW+qoG!u|`_nkt?{Cwm1G!*OjvOo2B#(5ummIm

wmp-}fX=Y9;T(7emHcj}%Pi_zG%{1t0D1PNdSTlc7eJd4TVotSe@d=lY3D1XR%nJwRq)%)P9TvObf@x6?#nlF8=mg|i>-ZQZnEfHLQ!()NUsnprK* z@%vZ}n>XM4{!fYXQw`IDFA5*Rc^?V!n@i@=`NIrT~be*tHZ0n9$fj=uMeBUhbbNSUcU@}H@g6e%*k9NmEP`D5 z+i(2x3X`4vNg!Si@Pj+7Oh^)08<7u~JH}w~hHFQoFhN!RyJvjiLMHsPEylK zDV|J!3g_L89^G>_sIcpj7BJ>_V-Q;f5Yj`Pp|J-{vG&}rBH6#tmC?GN1@iNC`<5#+ zF@AGf<3zTj4doNkddG1PGR>OB*!3yh!B7RaptZ3s*+}_?>sWDQXB)POKIa8VGF53h z4H%)s6i{)v9o|Dp7yOhAUjdb_9^Y}*?m*xUVoVBY?tGkW+(N_aS%y=CzaM)EXPU+r z+3RR2jOxMS{l1@0?#kvB`Q>DVLPKPNP5#wgS-y8PjwdCJX4igNI&fViL_R8=3{aQ5 z8Rlj8@~Yg~3%-HeF{N!9wXAaU$lM`iBY}Q~|4Gi|rn8&AV~Rub8^La4J`&lIdqx%S&tzt;(6y%CGU?`Nt z^#XrOpu4|IO?^yh_M7W~Y`k7wbH28WG_(rI))F_3^lHCVnk-NjFdgv5>W5zjT-cdy z9g;Qwu~uMQvN#I2owpPs!x~a1EBR)n3k%1*_b3j1W|I{pxd(r$tJl1O zCD-siH!8VfZlFXe>ZX%G|KWVj+ze3WKS z?~7q^3T64(ZO6_fSt_jkBZ;=u6(8gS-bNl|ncSVfbFvDVCZu_z69BiwO$ScuvBCB9 z$7adEf^*XSgP=JYus0|A53w+d1W!`0FF#au!w*G>zaN~6-RJFDv}wp_m{PR`TwV>^ zb8r*#M;G#R^(~FV;9q=c9&jxz6M!*SXgNOce$1SU_W!;BVi7J++%73%6Hf`WZ_aiK zFdXS&I3`UdW04VUG^ijRL*I}~zn zMn0m+OEQ@;>`1L(&`jGSaXumg!IR5&M*aA<>$3_w>PN$lLjG-!^!xUXcDjLXhNHg8 zDpRz37{<1m@kZ+3hnMYB*B4OCepXYi?g$^ZL3w@V^b;4oZ6(7-t3UAf__e!Xrr`L^ z!AEzl<3ZhSzu@#>j}_RoC+O?Xa};=n#t1p-Hetjx5=M=UX&cLUDYl}M$PABkgd2Tr{_G-U_*K`$k*8A-?eeOp zazei+4jCQBH$HCpN;qcmdYh>J*Bqu;Wlsw{rb4$3MPmpi z1P{g>ma4Rs>5tDZv73@8GK|!_A6APA%n}T==dh~`tz3uH=on`W=)oAV za|>+JWL9clPV7FN|MRa?_jdy2zQ(uuca=yfXmQ)9B~fL~#*dkMBxQhYJw|_Z)#Ce_ zj;&&z-I0c5LZ#0s%}<(Xk}o&r(uxPOk6`bVrAsQLPa_@NPlS=w_B9`Nlg~4_AFrQ| z4X^yA<>~%Z_tZHR72i?g3EmBZH$pyQdtSGvhpJdhT3XH3oaw)XUnN(gq@Bd~EriLJ z*rN9#zUcht_g2T>DGlvD!8;dcl{Gtq^%xL+Fa6Zdz=o(1tiCukUpX*(LHy5iyP)~` zpcA1c@6{O(FF2bX*0g?q;F@Xt8!>uFz$V*d#7)?)tmJw&Hfs+qOYSF}I~%yJ_Q%p4 zhs;mi#)n-j8=5pdbqaI+1W&w2%v0W(l9P+lTIu)M(;dU_7sh5TI6y4-4=cSMm&?6@ zrO5e)o&KJ z-nG3$nXIa}RN1$AUg(KyAGPa|_AR!M4@dbHa-J_hD(F(w!kpymSow;s>$Rpo&ISx% zd&F4||BDbnW%rNN!N1kMt!F;iyc~Ao!?CqhoA%9gQKgOMr6oV_Bi+#p_wI^zeMSLz z7f@Y-rkWTBMzH?hy;GBaYU9u4a=&G5Y{VWge;IOm^G3OZ*qt`=D<#oLbxXK)x zW4ed3(}IjlCM_O<4DF<0fD%WZQ|Qk%u(XT{mYw{4ne zr-TvBouhQ@HvRa{9942FA_NBw84GR(kHARKJQ{6aG5q7(SH~@uF77;8Buj1eH{keX z%Wk8S2*nroOzekh_G6J6?^NpJwK2DSFX;GvP)oTJ4u%(`x4tm+S$rgawzQ`F*zufw z+I@st*|0woCs&bdi_+6DI_+* z4;DEw_0*FcRS`&A=5Mz##rB+4B{+?@41|(y$w9YNfp{DcdWf_d8m$AKfmSg-)^c|~ z_V3YIGJ`+-dF9rUS;wVJZ0_&wrN#l>bl;z|kajo2ZJyM|pq+|F!maZ`kIubM%MK}( zstfO3_~hD5dTooKO7qSs(+?x=U|&1TX9QK*1`i#|V)t8y`KQMPR<@VajS(gh>}Tm? zJ9LJjlk7W$FLR;6+Q4($tPBJ0tv zQ8L?_HiRo`_j0Fi`w1gTR>Dvs=i4>V>Ycog(CndQ1ZJ%V%`uN3Eq!k5wutk>bu(^w zH2MLat$BI^aw=8)T0v$+-72Xv2fcJU1t_L0242xf{sIK|&7E>9AM;S+YyZP#_gW4_ zsVv`z8(;3eET0IB1$9haV(;M@T4XEhuzQvZC=j28Z=YH%_heb*$DGuoXInE=b&~{* zVV3lY%PW2tjyv2|4%}Xl=+oMev7J8d?&hZZUfNHJWHnjlcei8#m-Bv2{cf**=vy_D z-|OeHHy-2kHGNSb7QtHsuY4bQ=YG``I#2@Dx(LW;in*S3;p_G7FoX7A~_0T)vPLj5Ayb zMEX~tmS4-7Mc)WCoUU->98?HTLJZ7eDrD`l1-3tMmyAeP*mMXvYc1oBnaQVq<)StV z4><;+aLCKtPxQu5XwK#Tut1(9+ufIBi~qn7y}C%LLnZRi%_`(+nT*G|pNO%kK#AmE z2^|Ba-W8}}kz)-q~*p z#1*V;GG}->qY`QQ?|fTj-6fPvD&yO*R3<>oC0X0m#~O+0_m)X`Nl25Sv-L_Fu3==; zuaa?gq5qzhjT!kVA?rvv7Xy(e{$=Aj4Dd^%+QnR!)>RHkuKmS(0%`=Ak|fa$z(z1pB2m@I~ zAma*o|Ie`hGkMWBnFu#|&eXq%*F`PAh5sPGqZjo>TmDmtW!J@5l{~VZaQsg-2U!9A zU)>^mWFc?+|8!3{u4!RW|D~2O`9u4Q_%F4LNruFht@r;k|4+4I8Vi^a%b_-{RdX+7 zTv@kH=g|M$Ik36^ZvX$qf$Yx7PmY~7E4QUd53`w%bP1P!?!e2Px#4~ARvWjzS1dUW zLygr&{9dOqObBwuYe{IF|jY10{f~={~sO`Q~2s>|7*fy7vzJ$rz34Kxx>!< zxL+Ny_o<&``4#g~ZyhdWsK*_n1|G55bU76`MLq7vS_*B*6`q3Q=@h{tty01f))3cD>u2?YX1{ z=GiMN-N%`6E=lL{Sw7ot;NQX@tTV#&~6_cBHR zBdv;q@=?)LLjLo@Qz;t2t%NmPepo9Vz$$b?d{7K=e+|=A5~Q5xCV@aMwW4)srV{LL zOToIKBd*TzAUtS}ZNnXHF0U;|h(;fc0@^()wlrw%meg;)5_e}$REgV^G+kkcQIu~~ zfcJQwnzFhzxVbR%X^&*FMt(@XhNZ=|O@0APfoZ|EGiSC6E%0L%keaf>o<`7tXj*$b z`E?bnFRMMdxp%#`z zy~T8OLy`k;##{f4uTKGPncWGuY+%w7j27t&@Kz7Ox?pf!5|H40mqh&8*E`%YpU!l_ zRjETAU#T{Co?;MlwFM&ZvyCUhvSIHfTiRnRt(});5S2^M_xCnwa*bx?xQAAP+lB5F z;8tl*&MxW3XLDkNMRE}@G4_5@bZB#Q^JQk!)fz77=;7M@KLM}3tmUgH(oYMwZ^W-+ zKIdT9RU(^i8^jq3{g=&E6-aStL^}K-cE>S8NT$p{j{Jv`I#D4=IRBiW1P_Bp{0zrE z1d2?JU`PEy!==Cr_raBK_rm#2zr#$w*JG!Q3lVk8>Ah6pHku-rHsgelM>9=bu=7UTJMqUFt?R!v>yJNsJohI zkT7`$jeHKARgy0FQF}qs9YWYta3a?28REHV;LX_7zwXa)Nh)RmfUsX&U^~S}Il7n4 z5a|#ifs82yW@ax-PPE%a)n{__OWeApP-lt#Y!d~wzu|{JzKuB^<=!q z%&Hge2m5<`sW*ntOKH09zr?FQx*i%`5P*uXa3;rEbUH=d-({Kt!-)mgnfLOr6M&NL z)AbrMs}vJ?b`++qVo5H1l(*`^-bm4^#M@U|cQPe^i> z?MZ+B^{vK~co#RSS$~Roy&_yqtd{sR#}mW~4S9aP za{erGfQj0jzsagewc|))iTSv2U2o2^WmNCb^>l>mj~3cZPYBk8AN_b9m5I`Q?~;m@Q!O=yw3`pCdF^AD-c~)0#k)G6Eex7w-NH7-)qNs5wNH z2S+(zI!RuTWyE!s7CaYOdYj`QT*qt(7a{6~d?(&)dBd@bBRpGs*50)zAv49gbKx`x$Sitf8w|lE zi+zt)7oj2m+C$zBOHt&)gXE?+Yl|NPW_!8l+gB~pkS`E4{z8!lknZHr@wN+x@ z&Jj=6LMSu$%Lz=~a(Sij5!w;TBkSJ>dKwd-o-rvI#QR-q+v0rD_5IS<)6eJKni4qFKl*vMY48yh{ zFH*T#F{y**ZwNwRpDpcS2KXEJQ3I%_;l0R}dh2v--smvupPh`UV!DI3(?eXh#}Y}{ zn5jFv4*trE#XVHoqU}`V0}-e0oQ%;BhQw)j;h=)T^cR*dZEvyFcIHk>SVjAl3ZL_v*H_u1uUi4#JjSrB& zY40nB_$pKWIA6W9$mbZWU=!|29?v*aHMf-jUKx%*R$&(|5?iN=Ps_9LAfk0&0pC(+ zQPY{KoVsiB#{}{wu)$B-hw4J!vwn}d*eSTR8iS9&6Vso)Y1H&P?&ydd^y)^y+m}Q| zy5{^xL^{#3WAy2y^$(XAFzhi#s>ltbq5as)rc3Tc4|HAI+Ee4-rdUUqiX8PMrlZoY z5}h8^HKqbLJvgP(pC7ACQ-yccYfs4M?kd>Z_>aMOTWYGrTzR`YzJRX~Z9sbr4Ahr- zl>F3WGBe8m;j=n6}N$y&4ecZ(|heaBTPC)c!kOob^+ec_mU7%nnP zU+Bp_%7a&{@G~h|5(hVkFH^fd@#-Jl;U8m@7RYQjmM$bmBY^P}1vNTRx<0S%GjaQn z3Dc?P@+g9)DpurqZ*?>eSL_Qfi%HtFD|7=cO;?GOA3slI`k)xqITGfaH&7wDf7BR}&sz zC@-)8+x1IRhy0?3MyXZ^IqqU=>+_E-bC`Az9{U71(xFS-n7s?l8hUYaw@U!RgMN0> zEx%Wnc;~uEesqHN)QDI~EL$Q~pq6SMS5BW7NGX%xCQSEoiz-~*=^+ra#OrZBhD;_# zzR#kLHofpc#kVAb6H)=8t$egLcr7wHI=331bq_hJH2 zg(8KxvCw_GJm?_P{8<)yg$mkDTj&~LjEWnj!Cr-2=R{CmH_sFTvP>pm3g4R|Kb4s8Nzrq zap~dE+pUjKz=&N~Z$m>+5fiW36v?KPEry-aV^Rs*YHdoDQx9 z%c9F+J{Ievq<)pi)Mdi3=-x?D+ArlL#vq;A6+dXc@2O>gIKY2B=b9|;e;o0$)3Kdj z{c%BqQ@?Te)G+T_8+GW5Nubd;)he}=-%2#17lc!^3&1h^?uBanQmysb)aS~Qbt%;I zk5QW*8SQ`kuCcb4)sf9lI9`8Bf7askk{#jep2%lz-x^-##U?(yZ}2PbMc$nNkI9Xc zeh_&YVj+@y+&fmvRxAjtsKpm7`3^D{5TlQ0*HQOI)XuiLQ;6%~H+;V0sRk#a588SI zs>R2IpkIxoq}9Bk$l7;6)XRoz-t6F^$xiD-p~u>q6R}=-UbtmQ#oV2b%eCLQo0r7l zZhJtN7v>B*Rlb-(5k?4*LM3YJFcE-MX11CQ`Kp+ zk0yS&arb>b1+n`ZXAs?R;kEcDy1-{wzn;`hmwpaxX~5FvZ{v0!p?nWcm6YA0A5DoF zeSv6jv_m%~{Ms3}VVLdKhHa;6^zSgR%UuF-qcxjaJ;nyZQdo0-#Cw>xcU`VTn>?F%y|une_f~QL!!(6^GNl@j8*93o zdl1$C0+4|98q-8>6h3PuTG!Rg(s|E&a@hz=l#tQy~|wZGih;Zpd||GzlAf_1_h?Si)UF0WgOU zpG2ZVrL&PXh`=`wihLXEI~#J#0Olx;daWNad*ZEQ2dBo!qcz^X+ElYFn#vWJ$?w{L z=d91mdiG{%m6=4Fw2K{LD&ncp!A%Vi4BWk+;$B%u3+&-L4x(r zT&uG`*~guIGOdwU^4Wp*o7Zj^!bfg~7yjVGja5$I@Hb-evkUZQ0@ORW>ay(ek-DBD zht!qi3Vrois_XK`@98r)du9hhKA3B77PbOwhF>l#*Bj#A!c!2Y?b!sfyhuKul>OEC z&S#E!5I8+=NSmcY7RKnPHF4~!VEn0kx=k`~sa!M{I;0IhaJJ?)dtqQSRosjQ z25H~sdO65L;lJb3f6VpVC{s$wG}Z|9Wlu-e{{rpp6d&XoAfYOL#%*kn!Z1&bQgWx| z{peDG1@^9d7$jVt+sxoq7wy`E!xeH~=Luu5WKcngRm(L+8RjK%Zc8<2;7gDh&jSM; z-|sTg0j;aF>WlIA_M2r!-bX#j*_fsEbGde=8o(KaGHb+{+(-*t_tA)0KLEiUU2!vv zmP<5&3r1w{oh6o#1C}}mtP9Q}+*vK)OCq1hScjO0p@#6DIkk|M_V``PGnwigusC1&fF-OZQ-c%0jLMo<$vVJDmklpKgYb;JYDYR)7_Qyyj}84 zC-eLbJWW|v%TvNtrdqlDYnt61id8vKWkB

    12$FulS>k+CGvhX%C6yF&H&(RGZy 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�T&>d_mG|ajc@E#k9*Zyz` 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
    |f{X`yN>SI8s+*^^+<;E}Thv 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/fade-in.png b/vendor/assets/javascripts/locomotive/aloha/img/fade-in.png new file mode 100644 index 0000000000000000000000000000000000000000..e20c212f2d0708cd680587c05539df88a4d4ba75 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3-oXyUC{msk8u}5LY1m|NsBO!orS@j&FfuW9b8!t04hAZytgLKrZwCshsi^_QjZMugP0ih1-5|0+ zskw9KE?v5G*|KFoa}FLnc({S8c<|uWt5;_OZXN^LBv=yU7tFxG2m(w@fB!+i zY1{p0fs%fnE{-7*my;8YFiEUX);P)Tl+pCYiK)wJPDaxjqeGvJVqT;bb$r~=@o@pC zQO5_Pu8zfAM&2D-ABv3^av5=)I>mWv(M(OEKDxeflnX0O)p|Odjsd;d4@Z7m`)zs9COiYbU z&D>mEfg%M31%-u$Ky!dnOP4NPwrm;DkOKz}T)%$({{8!}UcIV}>FEX9CsGpR7Yw8s zL4b*giJAHD-+v%*M4EjiP(0Yv#W6(Ua&p2UCW#d)CvWumUAVWcI zy@uNPE-ej}BZ`Vg4t8j1sGd;K?8p<`Zn1ung+BKxh22dZimdKI;Vst0BoLg-~a#s literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/gentics-logo.png b/vendor/assets/javascripts/locomotive/aloha/img/gentics-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f7bb12b55a45105e211a290d9ba045b0d15af676 GIT binary patch literal 2094 zcmV+}2+{Y6P)X1^@s6wkGG*000N|NklbS0+KxoLuzV8F;o)OZOf(UB1x1_WUS1~P9xh#-QP z2QT>GgNW#i&x#=8JPa~351Naut!YfB({0k#UFmdJ)u~hG_P^}w@}UyJD`?1i+_2aB z)^D-czYVV;u8tA_n=e-<&R*R9_LIMPNuT)DjqjbiG=1c?pT~6WJUD}>s%SEJ z*K*Tff#CX#MpLTR5>1B2#PaeIsyS!RY!PGP#M%l!J3sr8#_|K!2A)1YzE-!Be+B*< z;HBNj%}2989H07aq&SZ1tfT(gL(YwV?A_e-I>)}6nf~L_yM6SEQuoiTIg=zu)T0V1 zK~dy%Iyu|J2}N0O?%WHIgu_RUa_gz%j3;{t8H5rm9*GGP6WzSv@FMSD8619UW5rA_ zZB3A5Z(urWuPP&c_GIm6FLn!cpc#>fWr>C5(@*D%$KQWtcj@%p%9*Gcf+td-8ei!z z61?Nmr7c!h2Mh+Qw6-NhMd=bkLRE<*k}6RQF(_gb6Q-P6TmJ4nZ#eu(Ie^(+3B%1N z)NkLJ(nQ46s3wX~lCUI+#FT;S&vkIe&b9ik+uCLsUrrG1q6su9BEoDw;@R^TdH6jK z0+H>V5iyi_ElFg=lps2yC{ZDz5F@#Vwe>#3?fuVW(Qdu1-n;Tbv|9s{?P3U$r3?u< zDlMuBNfEF}HY#hsxl)>odTh{>QFQ{;gC<0TPFX-^u&v|Bk!50X99rtLu+YOfOH;Lo zLNp#yL}MgZI664QY`@`|3s+d`clUE|{o~zkp_D7)tr3k=3M>XoLePU=&?NW_df^n^ zR%N*V3}*3GyhMtkK*X>=ozhy*+KHR6KGN%ygy3<`adfrM;ILsdsu|8&I%SU|OC6fp z^7CI_Lv6vt8`Vj97D zPY!igr3M_DTGVG`-COCDC2@QKqn51bG2PvvWEV9<8hVQnPK z47aQgaMrQAJ3~_&(U#Ya6F26I4}89TQC(X8N?DaVqzquK#Bp$goF~B7EQv*n^$R@mYq>eWj%|F z3v|27T)KFj$*gAH7B~k!37UkeYMCWy+QhVRj9bUBwpb1QgJsFG-0BntpX#{VYd}Vts#vr>Er+Qfv5iEq1!)_i}bz| zb>)MajAq$XjHUyyuuR>VW6hY%_0g0=d>NwASZmW?DEgfwRK>xzsVXTYk^$$Hs8jGy^WQe4q?d8Jvq?H|5d9)It@KYvvpXrg_}X8{wlKY%h4xwtvz%(*=(t2DJ| z-_Cg18PaT*Uw!N2=E85U+~(5K(tUTV{(36}PUiVv_fvV^`E=*dJ3pP8^WUFW*YBNl zPY!N-N>=H~;R3)WX)^!Euw-X^@jL&w zde`l@yzpwhKL+}{?eMpMa*l`J{-&a;s$bMC_r<87=D=4O%h~5f{O>Pru;u@8zQeS)T?oQ>KAr~lmD=qfBq*=T`VWFhV?=J5<@I7Ffv5z^=fcdhtzU22cTmr>mdK II;Vst0Coi*D*ylh literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/maximize.png b/vendor/assets/javascripts/locomotive/aloha/img/maximize.png new file mode 100644 index 0000000000000000000000000000000000000000..c686332126c549b280f88e7489065e595bdd2276 GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~#0(^7eq%odq&Ne7LR|m<|8EQiQ_aLy00o&! zg8YIR{^?8;QU>zmJzX3_IIbrrIIyi+DCiK>(8%iHwKj?={js{@t_zF|2eg=H9%^2( Q2&k07)78&qol`;+0Q}$~k^lez literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/multisplit-base.jpg b/vendor/assets/javascripts/locomotive/aloha/img/multisplit-base.jpg new file mode 100644 index 0000000000000000000000000000000000000000..85522a5d7cbfb77e54d7051282bb88cdc13bddef GIT binary patch literal 929 zcmex=i3*BJ!6k`h{6D}T z$ibk+V8YBO$iO7X$SlbC{|JLL10w?yGb1Ad0qDsn+Mu9?(yo#gZUDGb0-WYODmVY#?)o1I}g)f3?rQ zYC6^EcrGiO=l7dqN$=TodrTf$`EBdxKIg%doObrX%8iR`p6~l|Jd4ji;N{-o_dybD>(c$M7UU)nkRUBPrH1j=&jhX zrVNeBq{T`$6=mNSd-tEVQ9sMJvf!$-nDh#N+jo=vjwIbPoOJbtDo?Zu)`)fp#ExaKO|>R35vnP9m5yCQKBiBOk!TSR_YKA(44 z?0TG0;h_YPo~s^H%l@po`qglocda+eFQ;bLl?y?giGyLYd^X{DJ7XIhV^?*!rI_ESky;e2 bx>KMb_qdL@kDKt^ciJ-_9ov7>iNP8G3Ajro literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/multisplit-open.gif b/vendor/assets/javascripts/locomotive/aloha/img/multisplit-open.gif new file mode 100644 index 0000000000000000000000000000000000000000..2c6f2fca4846ade397e610baac69f8dbe7960f61 GIT binary patch literal 211 zcmZ?wbhEHb|NsB~{ylo| zQNz=@=U!ekoD;s{(siG$>8f))xv~vA8jdmtC;_)yS4j~+dG=FFLE*RI{WcklW0=kMRY|Ni~E+q6%Xz(DaR z3GxdDhDuOqRB1(JQ)_$Igh`X8OrJ4p4p95@m21~;*tBKaj@<_i9y)a7=!w&3&YnGg z`SRr(H*Vg(bMOBB`;VVJd;a{z>$mUTefaeGi+$Hg`2-n)IzeXJY0wHXdX->I{gez50eVIk|i;*|aN<_*hl zZ!6lzxL$el_qu%P6{{{EI>V%2zxB)u!Lxx=&v;$o`Xh5&@wvoJ7M-cCCz;M1%flO`p$h5SU!bzJZ zEIu$})3L+%-kmvf=Ju;EcfJGV{|6W3R{|9=mIV0)GdMiEkp|>=d%8G=RNU%4?A?80v9Z^YZA8as&YaOiG2qAVzYLj+o?N|k`)kPFX7%epMT)pIgD?z$ zz0k7x#eWfQHil2%e>0rE^YzTbTVLW%P1UySD{rve8ZZphV4}^gtsg#oV8j^<1D2Tp2_^}JGDwbz00000NkvXXu0mjfU=gFa literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/img/text_indent_remove.png b/vendor/assets/javascripts/locomotive/aloha/img/text_indent_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..1651b074ebe5f830c23c909d04ed3282cb8892aa GIT binary patch literal 351 zcmV-l0igbgP)$KO_&&&86Lj*&d?hr!$_. +*/ + +// define jquery and ext modules. They need to be available in global namespace +define('aloha/jquery',[], function() { + return Aloha.jQuery; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ext',[], function() { + + // Ext seems to have an onClick handler that uses + // QuickTips, but the handler doesn't initialize + // QuickTips and therefore causes an error. + // The bug occurred with the Gentics Content Node + // integration, but if it's really a bug in Ext, then + // it's a good idea to always initialize QuickTips here. + Ext.QuickTips.init(); + + return Ext; +}); + +define('vendor/jquery.json-2.2.min',['aloha/jquery'], +function($) {$.toJSON=function(o) +{if(typeof(JSON)=='object'&&JSON.stringify) +return JSON.stringify(o);var type=typeof(o);if(o===null) +return"null";if(type=="undefined") +return undefined;if(type=="number"||type=="boolean") +return o+"";if(type=="string") +return $.quoteString(o);if(type=='object') +{if(typeof o.toJSON=="function") +return $.toJSON(o.toJSON());if(o.constructor===Date) +{var month=o.getUTCMonth()+1;if(month<10)month='0'+month;var day=o.getUTCDate();if(day<10)day='0'+day;var year=o.getUTCFullYear();var hours=o.getUTCHours();if(hours<10)hours='0'+hours;var minutes=o.getUTCMinutes();if(minutes<10)minutes='0'+minutes;var seconds=o.getUTCSeconds();if(seconds<10)seconds='0'+seconds;var milli=o.getUTCMilliseconds();if(milli<100)milli='0'+milli;if(milli<10)milli='0'+milli;return'"'+year+'-'+month+'-'+day+'T'+ +hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} +if(o.constructor===Array) +{var ret=[];for(var i=0;i -1; + }:*/ + + function(arr, val) { + var i = arr.length; + while (i--) { + if (arr[i] === val) { + return true; + } + } + return false; + }; + + // Opera 11 puts HTML elements in the null namespace, it seems, and IE 7 has undefined namespaceURI + function isHtmlNamespace(node) { + var ns; + return typeof node.namespaceURI == UNDEF || ((ns = node.namespaceURI) === null || ns == "http://www.w3.org/1999/xhtml"); + } + + function parentElement(node) { + var parent = node.parentNode; + return (parent.nodeType == 1) ? parent : null; + } + + function getNodeIndex(node) { + var i = 0; + while( (node = node.previousSibling) ) { + i++; + } + return i; + } + + function getNodeLength(node) { + var childNodes; + return isCharacterDataNode(node) ? node.length : ((childNodes = node.childNodes) ? childNodes.length : 0); + } + + function getCommonAncestor(node1, node2) { + var ancestors = [], n; + for (n = node1; n; n = n.parentNode) { + ancestors.push(n); + } + + for (n = node2; n; n = n.parentNode) { + if (arrayContains(ancestors, n)) { + return n; + } + } + + return null; + } + + function isAncestorOf(ancestor, descendant, selfIsAncestor) { + var n = selfIsAncestor ? descendant : descendant.parentNode; + while (n) { + if (n === ancestor) { + return true; + } else { + n = n.parentNode; + } + } + return false; + } + + function getClosestAncestorIn(node, ancestor, selfIsAncestor) { + var p, n = selfIsAncestor ? node : node.parentNode; + while (n) { + p = n.parentNode; + if (p === ancestor) { + return n; + } + n = p; + } + return null; + } + + function isCharacterDataNode(node) { + var t = node.nodeType; + return t == 3 || t == 4 || t == 8 ; // Text, CDataSection or Comment + } + + function insertAfter(node, precedingNode) { + var nextNode = precedingNode.nextSibling, parent = precedingNode.parentNode; + if (nextNode) { + parent.insertBefore(node, nextNode); + } else { + parent.appendChild(node); + } + return node; + } + + // Note that we cannot use splitText() because it is bugridden in IE 9. + function splitDataNode(node, index) { + var newNode = node.cloneNode(false); + newNode.deleteData(0, index); + node.deleteData(index, node.length - index); + insertAfter(newNode, node); + return newNode; + } + + function getDocument(node) { + if (node.nodeType == 9) { + return node; + } else if (typeof node.ownerDocument != UNDEF) { + return node.ownerDocument; + } else if (typeof node.document != UNDEF) { + return node.document; + } else if (node.parentNode) { + return getDocument(node.parentNode); + } else { + throw new Error("getDocument: no document found for node"); + } + } + + function getWindow(node) { + var doc = getDocument(node); + if (typeof doc.defaultView != UNDEF) { + return doc.defaultView; + } else if (typeof doc.parentWindow != UNDEF) { + return doc.parentWindow; + } else { + throw new Error("Cannot get a window object for node"); + } + } + + function getIframeDocument(iframeEl) { + if (typeof iframeEl.contentDocument != UNDEF) { + return iframeEl.contentDocument; + } else if (typeof iframeEl.contentWindow != UNDEF) { + return iframeEl.contentWindow.document; + } else { + throw new Error("getIframeWindow: No Document object found for iframe element"); + } + } + + function getIframeWindow(iframeEl) { + if (typeof iframeEl.contentWindow != UNDEF) { + return iframeEl.contentWindow; + } else if (typeof iframeEl.contentDocument != UNDEF) { + return iframeEl.contentDocument.defaultView; + } else { + throw new Error("getIframeWindow: No Window object found for iframe element"); + } + } + + function getBody(doc) { + return util.isHostObject(doc, "body") ? doc.body : doc.getElementsByTagName("body")[0]; + } + + function getRootContainer(node) { + var parent; + while ( (parent = node.parentNode) ) { + node = parent; + } + return node; + } + + /** + * This is a very ugly workaround for an IE9 issue Before comparing DOM + * elements "normalize" them. There are cases, where anchorNode and + * focusNode in a nativeselection point to DOM elements with same + * parentNode, same previousSibling and same nextSibling, but the nodes + * themselves are not the same + * If such nodes are compared in the comparePoints method, an error occurs. + * To fix this, we move to the previousSibling/nextSibling/parentNode and back, to hopefully get + * the "correct" node in the DOM + * @param node node to fix + * @return normalized node + */ + function fixNode(node) { + if (!node) { + return; + } + if (node.previousSibling) { + return node.previousSibling.nextSibling; + } else if (node.nextSibling) { + return node.nextSibling.previousSibling; + } else if (node.parentNode) { + return node.parentNode.firstChild; + } else { + return node; + } + } + + function comparePoints(nodeA, offsetA, nodeB, offsetB) { + // fix the nodes before comparing them + nodeA = fixNode(nodeA); + nodeB = fixNode(nodeB); + // See http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing + var nodeC, root, childA, childB, n; + if (nodeA == nodeB) { + + // Case 1: nodes are the same + return offsetA === offsetB ? 0 : (offsetA < offsetB) ? -1 : 1; + } else if ( (nodeC = getClosestAncestorIn(nodeB, nodeA, true)) ) { + + // Case 2: node C (container B or an ancestor) is a child node of A + return offsetA <= getNodeIndex(nodeC) ? -1 : 1; + } else if ( (nodeC = getClosestAncestorIn(nodeA, nodeB, true)) ) { + + // Case 3: node C (container A or an ancestor) is a child node of B + return getNodeIndex(nodeC) < offsetB ? -1 : 1; + } else { + + // Case 4: containers are siblings or descendants of siblings + root = getCommonAncestor(nodeA, nodeB); + childA = (nodeA === root) ? root : getClosestAncestorIn(nodeA, root, true); + childB = (nodeB === root) ? root : getClosestAncestorIn(nodeB, root, true); + + if (childA === childB) { + // This shouldn't be possible + + throw new Error("comparePoints got to case 4 and childA and childB are the same!"); + } else { + n = root.firstChild; + while (n) { + if (n === childA) { + return -1; + } else if (n === childB) { + return 1; + } + n = n.nextSibling; + } + throw new Error("Should not be here!"); + } + } + } + + function fragmentFromNodeChildren(node) { + var fragment = getDocument(node).createDocumentFragment(), child; + while ( (child = node.firstChild) ) { + fragment.appendChild(child); + } + return fragment; + } + + function inspectNode(node) { + if (!node) { + return "[No node]"; + } + if (isCharacterDataNode(node)) { + return '"' + node.data + '"'; + } else if (node.nodeType == 1) { + var idAttr = node.id ? ' id="' + node.id + '"' : ""; + return "<" + node.nodeName + idAttr + ">[" + node.childNodes.length + "]"; + } else { + return node.nodeName; + } + } + + /** + * @constructor + */ + function NodeIterator(root) { + this.root = root; + this._next = root; + } + + NodeIterator.prototype = { + _current: null, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + var n = this._current = this._next; + var child, next; + if (this._current) { + child = n.firstChild; + if (child) { + this._next = child; + } else { + next = null; + while ((n !== this.root) && !(next = n.nextSibling)) { + n = n.parentNode; + } + this._next = next; + } + } + return this._current; + }, + + detach: function() { + this._current = this._next = this.root = null; + } + }; + + function createIterator(root) { + return new NodeIterator(root); + } + + /** + * @constructor + */ + function DomPosition(node, offset) { + this.node = node; + this.offset = offset; + } + + DomPosition.prototype = { + equals: function(pos) { + return this.node === pos.node & this.offset == pos.offset; + }, + + inspect: function() { + return "[DomPosition(" + inspectNode(this.node) + ":" + this.offset + ")]"; + } + }; + + /** + * @constructor + */ + function DOMException(codeName) { + this.code = this[codeName]; + this.codeName = codeName; + this.message = "DOMException: " + this.codeName; + } + + DOMException.prototype = { + INDEX_SIZE_ERR: 1, + HIERARCHY_REQUEST_ERR: 3, + WRONG_DOCUMENT_ERR: 4, + NO_MODIFICATION_ALLOWED_ERR: 7, + NOT_FOUND_ERR: 8, + NOT_SUPPORTED_ERR: 9, + INVALID_STATE_ERR: 11 + }; + + DOMException.prototype.toString = function() { + return this.message; + }; + + api.dom = { + arrayContains: arrayContains, + isHtmlNamespace: isHtmlNamespace, + parentElement: parentElement, + getNodeIndex: getNodeIndex, + getNodeLength: getNodeLength, + getCommonAncestor: getCommonAncestor, + isAncestorOf: isAncestorOf, + getClosestAncestorIn: getClosestAncestorIn, + isCharacterDataNode: isCharacterDataNode, + insertAfter: insertAfter, + splitDataNode: splitDataNode, + getDocument: getDocument, + getWindow: getWindow, + getIframeWindow: getIframeWindow, + getIframeDocument: getIframeDocument, + getBody: getBody, + getRootContainer: getRootContainer, + comparePoints: comparePoints, + inspectNode: inspectNode, + fragmentFromNodeChildren: fragmentFromNodeChildren, + createIterator: createIterator, + DomPosition: DomPosition + }; + + api.DOMException = DOMException; +});rangy.createModule("DomRange", function(api, module) { + api.requireModules( ["DomUtil"] ); + + + var dom = api.dom; + var DomPosition = dom.DomPosition; + var DOMException = api.DOMException; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Utility functions + + function isNonTextPartiallySelected(node, range) { + return (node.nodeType != 3) && + (dom.isAncestorOf(node, range.startContainer, true) || dom.isAncestorOf(node, range.endContainer, true)); + } + + function getRangeDocument(range) { + return dom.getDocument(range.startContainer); + } + + function dispatchEvent(range, type, args) { + var listeners = range._listeners[type]; + if (listeners) { + for (var i = 0, len = listeners.length; i < len; ++i) { + listeners[i].call(range, {target: range, args: args}); + } + } + } + + function getBoundaryBeforeNode(node) { + return new DomPosition(node.parentNode, dom.getNodeIndex(node)); + } + + function getBoundaryAfterNode(node) { + return new DomPosition(node.parentNode, dom.getNodeIndex(node) + 1); + } + + function insertNodeAtPosition(node, n, o) { + var firstNodeInserted = node.nodeType == 11 ? node.firstChild : node; + if (dom.isCharacterDataNode(n)) { + if (o == n.length) { + dom.insertAfter(node, n); + } else { + n.parentNode.insertBefore(node, o == 0 ? n : dom.splitDataNode(n, o)); + } + } else if (o >= n.childNodes.length) { + n.appendChild(node); + } else { + n.insertBefore(node, n.childNodes[o]); + } + return firstNodeInserted; + } + + function cloneSubtree(iterator) { + var partiallySelected; + for (var node, frag = getRangeDocument(iterator.range).createDocumentFragment(), subIterator; node = iterator.next(); ) { + partiallySelected = iterator.isPartiallySelectedSubtree(); + + node = node.cloneNode(!partiallySelected); + if (partiallySelected) { + subIterator = iterator.getSubtreeIterator(); + node.appendChild(cloneSubtree(subIterator)); + subIterator.detach(true); + } + + if (node.nodeType == 10) { // DocumentType + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + frag.appendChild(node); + } + return frag; + } + + function iterateSubtree(rangeIterator, func, iteratorState) { + var it, n; + iteratorState = iteratorState || { stop: false }; + for (var node, subRangeIterator; node = rangeIterator.next(); ) { + //log.debug("iterateSubtree, partially selected: " + rangeIterator.isPartiallySelectedSubtree(), nodeToString(node)); + if (rangeIterator.isPartiallySelectedSubtree()) { + // The node is partially selected by the Range, so we can use a new RangeIterator on the portion of the + // node selected by the Range. + if (func(node) === false) { + iteratorState.stop = true; + return; + } else { + subRangeIterator = rangeIterator.getSubtreeIterator(); + iterateSubtree(subRangeIterator, func, iteratorState); + subRangeIterator.detach(true); + if (iteratorState.stop) { + return; + } + } + } else { + // The whole node is selected, so we can use efficient DOM iteration to iterate over the node and its + // descendant + it = dom.createIterator(node); + while ( (n = it.next()) ) { + if (func(n) === false) { + iteratorState.stop = true; + return; + } + } + } + } + } + + function deleteSubtree(iterator) { + var subIterator; + while (iterator.next()) { + if (iterator.isPartiallySelectedSubtree()) { + subIterator = iterator.getSubtreeIterator(); + deleteSubtree(subIterator); + subIterator.detach(true); + } else { + iterator.remove(); + } + } + } + + function extractSubtree(iterator) { + + for (var node, frag = getRangeDocument(iterator.range).createDocumentFragment(), subIterator; node = iterator.next(); ) { + + + if (iterator.isPartiallySelectedSubtree()) { + node = node.cloneNode(false); + subIterator = iterator.getSubtreeIterator(); + node.appendChild(extractSubtree(subIterator)); + subIterator.detach(true); + } else { + iterator.remove(); + } + if (node.nodeType == 10) { // DocumentType + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + frag.appendChild(node); + } + return frag; + } + + function getNodesInRange(range, nodeTypes, filter) { + //log.info("getNodesInRange, " + nodeTypes.join(",")); + var filterNodeTypes = !!(nodeTypes && nodeTypes.length), regex; + var filterExists = !!filter; + if (filterNodeTypes) { + regex = new RegExp("^(" + nodeTypes.join("|") + ")$"); + } + + var nodes = []; + iterateSubtree(new RangeIterator(range, false), function(node) { + if ((!filterNodeTypes || regex.test(node.nodeType)) && (!filterExists || filter(node))) { + nodes.push(node); + } + }); + return nodes; + } + + function inspect(range) { + var name = (typeof range.getName == "undefined") ? "Range" : range.getName(); + return "[" + name + "(" + dom.inspectNode(range.startContainer) + ":" + range.startOffset + ", " + + dom.inspectNode(range.endContainer) + ":" + range.endOffset + ")]"; + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // RangeIterator code partially borrows from IERange by Tim Ryan (http://github.com/timcameronryan/IERange) + + /** + * @constructor + */ + function RangeIterator(range, clonePartiallySelectedTextNodes) { + this.range = range; + this.clonePartiallySelectedTextNodes = clonePartiallySelectedTextNodes; + + + + if (!range.collapsed) { + this.sc = range.startContainer; + this.so = range.startOffset; + this.ec = range.endContainer; + this.eo = range.endOffset; + var root = range.commonAncestorContainer; + + if (this.sc === this.ec && dom.isCharacterDataNode(this.sc)) { + this.isSingleCharacterDataNode = true; + this._first = this._last = this._next = this.sc; + } else { + this._first = this._next = (this.sc === root && !dom.isCharacterDataNode(this.sc)) ? + this.sc.childNodes[this.so] : dom.getClosestAncestorIn(this.sc, root, true); + this._last = (this.ec === root && !dom.isCharacterDataNode(this.ec)) ? + this.ec.childNodes[this.eo - 1] : dom.getClosestAncestorIn(this.ec, root, true); + } + + } + } + + RangeIterator.prototype = { + _current: null, + _next: null, + _first: null, + _last: null, + isSingleCharacterDataNode: false, + + reset: function() { + this._current = null; + this._next = this._first; + }, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + // Move to next node + var current = this._current = this._next; + if (current) { + this._next = (current !== this._last) ? current.nextSibling : null; + + // Check for partially selected text nodes + if (dom.isCharacterDataNode(current) && this.clonePartiallySelectedTextNodes) { + if (current === this.ec) { + + (current = current.cloneNode(true)).deleteData(this.eo, current.length - this.eo); + } + if (this._current === this.sc) { + + (current = current.cloneNode(true)).deleteData(0, this.so); + } + } + } + + return current; + }, + + remove: function() { + var current = this._current, start, end; + + if (dom.isCharacterDataNode(current) && (current === this.sc || current === this.ec)) { + start = (current === this.sc) ? this.so : 0; + end = (current === this.ec) ? this.eo : current.length; + if (start != end) { + current.deleteData(start, end - start); + } + } else { + if (current.parentNode) { + current.parentNode.removeChild(current); + } else { + + } + } + }, + + // Checks if the current node is partially selected + isPartiallySelectedSubtree: function() { + var current = this._current; + return isNonTextPartiallySelected(current, this.range); + }, + + getSubtreeIterator: function() { + var subRange; + if (this.isSingleCharacterDataNode) { + subRange = this.range.cloneRange(); + subRange.collapse(); + } else { + subRange = new Range(getRangeDocument(this.range)); + var current = this._current; + var startContainer = current, startOffset = 0, endContainer = current, endOffset = dom.getNodeLength(current); + + if (dom.isAncestorOf(current, this.sc, true)) { + startContainer = this.sc; + startOffset = this.so; + } + if (dom.isAncestorOf(current, this.ec, true)) { + endContainer = this.ec; + endOffset = this.eo; + } + + updateBoundaries(subRange, startContainer, startOffset, endContainer, endOffset); + } + return new RangeIterator(subRange, this.clonePartiallySelectedTextNodes); + }, + + detach: function(detachRange) { + if (detachRange) { + this.range.detach(); + } + this.range = this._current = this._next = this._first = this._last = this.sc = this.so = this.ec = this.eo = null; + } + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Exceptions + + /** + * @constructor + */ + function RangeException(codeName) { + this.code = this[codeName]; + this.codeName = codeName; + this.message = "RangeException: " + this.codeName; + } + + RangeException.prototype = { + BAD_BOUNDARYPOINTS_ERR: 1, + INVALID_NODE_TYPE_ERR: 2 + }; + + RangeException.prototype.toString = function() { + return this.message; + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + /** + * Currently iterates through all nodes in the range on creation until I think of a decent way to do it + * TODO: Look into making this a proper iterator, not requiring preloading everything first + * @constructor + */ + function RangeNodeIterator(range, nodeTypes, filter) { + this.nodes = getNodesInRange(range, nodeTypes, filter); + this._next = this.nodes[0]; + this._position = 0; + } + + RangeNodeIterator.prototype = { + _current: null, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + this._current = this._next; + this._next = this.nodes[ ++this._position ]; + return this._current; + }, + + detach: function() { + this._current = this._next = this.nodes = null; + } + }; + + var beforeAfterNodeTypes = [1, 3, 4, 5, 7, 8, 10]; + var rootContainerNodeTypes = [2, 9, 11]; + var readonlyNodeTypes = [5, 6, 10, 12]; + var insertableNodeTypes = [1, 3, 4, 5, 7, 8, 10, 11]; + var surroundNodeTypes = [1, 3, 4, 5, 7, 8]; + + function createAncestorFinder(nodeTypes) { + return function(node, selfIsAncestor) { + var t, n = selfIsAncestor ? node : node.parentNode; + while (n) { + t = n.nodeType; + if (dom.arrayContains(nodeTypes, t)) { + return n; + } + n = n.parentNode; + } + return null; + }; + } + + var getRootContainer = dom.getRootContainer; + var getDocumentOrFragmentContainer = createAncestorFinder( [9, 11] ); + var getReadonlyAncestor = createAncestorFinder(readonlyNodeTypes); + var getDocTypeNotationEntityAncestor = createAncestorFinder( [6, 10, 12] ); + + function assertNoDocTypeNotationEntityAncestor(node, allowSelf) { + if (getDocTypeNotationEntityAncestor(node, allowSelf)) { + throw new RangeException("INVALID_NODE_TYPE_ERR"); + } + } + + function assertNotDetached(range) { + if (!range.startContainer) { + throw new DOMException("INVALID_STATE_ERR"); + } + } + + function assertValidNodeType(node, invalidTypes) { + if (!dom.arrayContains(invalidTypes, node.nodeType)) { + throw new RangeException("INVALID_NODE_TYPE_ERR"); + } + } + + function assertValidOffset(node, offset) { + if (offset < 0 || offset > (dom.isCharacterDataNode(node) ? node.length : node.childNodes.length)) { + throw new DOMException("INDEX_SIZE_ERR"); + } + } + + function assertSameDocumentOrFragment(node1, node2) { + if (getDocumentOrFragmentContainer(node1, true) !== getDocumentOrFragmentContainer(node2, true)) { + throw new DOMException("WRONG_DOCUMENT_ERR"); + } + } + + function assertNodeNotReadOnly(node) { + if (getReadonlyAncestor(node, true)) { + throw new DOMException("NO_MODIFICATION_ALLOWED_ERR"); + } + } + + function assertNode(node, codeName) { + if (!node) { + throw new DOMException(codeName); + } + } + + function isOrphan(node) { + return !dom.arrayContains(rootContainerNodeTypes, node.nodeType) && !getDocumentOrFragmentContainer(node, true); + } + + function isValidOffset(node, offset) { + return offset <= (dom.isCharacterDataNode(node) ? node.length : node.childNodes.length); + } + + function assertRangeValid(range) { + assertNotDetached(range); + if (isOrphan(range.startContainer) || isOrphan(range.endContainer) || + !isValidOffset(range.startContainer, range.startOffset) || + !isValidOffset(range.endContainer, range.endOffset)) { + throw new Error("Range error: Range is no longer valid after DOM mutation (" + range.inspect() + ")"); + } + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Test the browser's innerHTML support to decide how to implement createContextualFragment + var styleEl = document.createElement("style"); + var htmlParsingConforms = false; + try { + styleEl.innerHTML = "x"; + htmlParsingConforms = (styleEl.firstChild.nodeType == 3); // Opera incorrectly creates an element node + } catch (e) { + // IE 6 and 7 throw + } + + api.features.htmlParsingConforms = htmlParsingConforms; + + var createContextualFragment = htmlParsingConforms ? + + // Implementation as per HTML parsing spec, trusting in the browser's implementation of innerHTML. See + // discussion and base code for this implementation at issue 67. + // Spec: http://html5.org/specs/dom-parsing.html#extensions-to-the-range-interface + // Thanks to Aleks Williams. + function(fragmentStr) { + // "Let node the context object's start's node." + var node = this.startContainer; + var doc = dom.getDocument(node); + + // "If the context object's start's node is null, raise an INVALID_STATE_ERR + // exception and abort these steps." + if (!node) { + throw new DOMException("INVALID_STATE_ERR"); + } + + // "Let element be as follows, depending on node's interface:" + // Document, Document Fragment: null + var el = null; + + // "Element: node" + if (node.nodeType == 1) { + el = node; + + // "Text, Comment: node's parentElement" + } else if (dom.isCharacterDataNode(node)) { + el = dom.parentElement(node); + } + + // "If either element is null or element's ownerDocument is an HTML document + // and element's local name is "html" and element's namespace is the HTML + // namespace" + if (el === null || ( + el.nodeName == "HTML" + && dom.isHtmlNamespace(dom.getDocument(el).documentElement) + && dom.isHtmlNamespace(el) + )) { + + // "let element be a new Element with "body" as its local name and the HTML + // namespace as its namespace."" + el = doc.createElement("body"); + } else { + el = el.cloneNode(false); + } + + // "If the node's document is an HTML document: Invoke the HTML fragment parsing algorithm." + // "If the node's document is an XML document: Invoke the XML fragment parsing algorithm." + // "In either case, the algorithm must be invoked with fragment as the input + // and element as the context element." + el.innerHTML = fragmentStr; + + // "If this raises an exception, then abort these steps. Otherwise, let new + // children be the nodes returned." + + // "Let fragment be a new DocumentFragment." + // "Append all new children to fragment." + // "Return fragment." + return dom.fragmentFromNodeChildren(el); + } : + + // In this case, innerHTML cannot be trusted, so fall back to a simpler, non-conformant implementation that + // previous versions of Rangy used (with the exception of using a body element rather than a div) + function(fragmentStr) { + assertNotDetached(this); + var doc = getRangeDocument(this); + var el = doc.createElement("body"); + el.innerHTML = fragmentStr; + + return dom.fragmentFromNodeChildren(el); + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + var rangeProperties = ["startContainer", "startOffset", "endContainer", "endOffset", "collapsed", + "commonAncestorContainer"]; + + var s2s = 0, s2e = 1, e2e = 2, e2s = 3; + var n_b = 0, n_a = 1, n_b_a = 2, n_i = 3; + + function RangePrototype() {} + + RangePrototype.prototype = { + attachListener: function(type, listener) { + this._listeners[type].push(listener); + }, + + compareBoundaryPoints: function(how, range) { + assertRangeValid(this); + assertSameDocumentOrFragment(this.startContainer, range.startContainer); + + var nodeA, offsetA, nodeB, offsetB; + var prefixA = (how == e2s || how == s2s) ? "start" : "end"; + var prefixB = (how == s2e || how == s2s) ? "start" : "end"; + nodeA = this[prefixA + "Container"]; + offsetA = this[prefixA + "Offset"]; + nodeB = range[prefixB + "Container"]; + offsetB = range[prefixB + "Offset"]; + return dom.comparePoints(nodeA, offsetA, nodeB, offsetB); + }, + + insertNode: function(node) { + assertRangeValid(this); + assertValidNodeType(node, insertableNodeTypes); + assertNodeNotReadOnly(this.startContainer); + + if (dom.isAncestorOf(node, this.startContainer, true)) { + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + + // No check for whether the container of the start of the Range is of a type that does not allow + // children of the type of node: the browser's DOM implementation should do this for us when we attempt + // to add the node + + var firstNodeInserted = insertNodeAtPosition(node, this.startContainer, this.startOffset); + this.setStartBefore(firstNodeInserted); + }, + + cloneContents: function() { + assertRangeValid(this); + + var clone, frag; + if (this.collapsed) { + return getRangeDocument(this).createDocumentFragment(); + } else { + if (this.startContainer === this.endContainer && dom.isCharacterDataNode(this.startContainer)) { + clone = this.startContainer.cloneNode(true); + clone.data = clone.data.slice(this.startOffset, this.endOffset); + frag = getRangeDocument(this).createDocumentFragment(); + frag.appendChild(clone); + return frag; + } else { + var iterator = new RangeIterator(this, true); + clone = cloneSubtree(iterator); + iterator.detach(); + } + return clone; + } + }, + + canSurroundContents: function() { + assertRangeValid(this); + assertNodeNotReadOnly(this.startContainer); + assertNodeNotReadOnly(this.endContainer); + + // Check if the contents can be surrounded. Specifically, this means whether the range partially selects + // no non-text nodes. + var iterator = new RangeIterator(this, true); + var boundariesInvalid = (iterator._first && (isNonTextPartiallySelected(iterator._first, this)) || + (iterator._last && isNonTextPartiallySelected(iterator._last, this))); + iterator.detach(); + return !boundariesInvalid; + }, + + surroundContents: function(node) { + assertValidNodeType(node, surroundNodeTypes); + + if (!this.canSurroundContents()) { + throw new RangeException("BAD_BOUNDARYPOINTS_ERR"); + } + + // Extract the contents + var content = this.extractContents(); + + // Clear the children of the node + if (node.hasChildNodes()) { + while (node.lastChild) { + node.removeChild(node.lastChild); + } + } + + // Insert the new node and add the extracted contents + insertNodeAtPosition(node, this.startContainer, this.startOffset); + node.appendChild(content); + + this.selectNode(node); + }, + + cloneRange: function() { + assertRangeValid(this); + var range = new Range(getRangeDocument(this)); + var i = rangeProperties.length, prop; + while (i--) { + prop = rangeProperties[i]; + range[prop] = this[prop]; + } + return range; + }, + + toString: function() { + assertRangeValid(this); + var sc = this.startContainer; + if (sc === this.endContainer && dom.isCharacterDataNode(sc)) { + return (sc.nodeType == 3 || sc.nodeType == 4) ? sc.data.slice(this.startOffset, this.endOffset) : ""; + } else { + var textBits = [], iterator = new RangeIterator(this, true); + + iterateSubtree(iterator, function(node) { + // Accept only text or CDATA nodes, not comments + + if (node.nodeType == 3 || node.nodeType == 4) { + textBits.push(node.data); + } + }); + iterator.detach(); + return textBits.join(""); + } + }, + + // The methods below are all non-standard. The following batch were introduced by Mozilla but have since + // been removed from Mozilla. + + compareNode: function(node) { + assertRangeValid(this); + + var parent = node.parentNode; + var nodeIndex = dom.getNodeIndex(node); + + if (!parent) { + throw new DOMException("NOT_FOUND_ERR"); + } + + var startComparison = this.comparePoint(parent, nodeIndex), + endComparison = this.comparePoint(parent, nodeIndex + 1); + + if (startComparison < 0) { // Node starts before + return (endComparison > 0) ? n_b_a : n_b; + } else { + return (endComparison > 0) ? n_a : n_i; + } + }, + + comparePoint: function(node, offset) { + assertRangeValid(this); + assertNode(node, "HIERARCHY_REQUEST_ERR"); + assertSameDocumentOrFragment(node, this.startContainer); + + if (dom.comparePoints(node, offset, this.startContainer, this.startOffset) < 0) { + return -1; + } else if (dom.comparePoints(node, offset, this.endContainer, this.endOffset) > 0) { + return 1; + } + return 0; + }, + + createContextualFragment: createContextualFragment, + + toHtml: function() { + assertRangeValid(this); + var container = getRangeDocument(this).createElement("div"); + container.appendChild(this.cloneContents()); + return container.innerHTML; + }, + + // touchingIsIntersecting determines whether this method considers a node that borders a range intersects + // with it (as in WebKit) or not (as in Gecko pre-1.9, and the default) + intersectsNode: function(node, touchingIsIntersecting) { + assertRangeValid(this); + assertNode(node, "NOT_FOUND_ERR"); + if (dom.getDocument(node) !== getRangeDocument(this)) { + return false; + } + + var parent = node.parentNode, offset = dom.getNodeIndex(node); + assertNode(parent, "NOT_FOUND_ERR"); + + var startComparison = dom.comparePoints(parent, offset, this.endContainer, this.endOffset), + endComparison = dom.comparePoints(parent, offset + 1, this.startContainer, this.startOffset); + + return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0; + }, + + + isPointInRange: function(node, offset) { + assertRangeValid(this); + assertNode(node, "HIERARCHY_REQUEST_ERR"); + assertSameDocumentOrFragment(node, this.startContainer); + + return (dom.comparePoints(node, offset, this.startContainer, this.startOffset) >= 0) && + (dom.comparePoints(node, offset, this.endContainer, this.endOffset) <= 0); + }, + + // The methods below are non-standard and invented by me. + + // Sharing a boundary start-to-end or end-to-start does not count as intersection. + intersectsRange: function(range, touchingIsIntersecting) { + assertRangeValid(this); + + if (getRangeDocument(range) != getRangeDocument(this)) { + throw new DOMException("WRONG_DOCUMENT_ERR"); + } + + var startComparison = dom.comparePoints(this.startContainer, this.startOffset, range.endContainer, range.endOffset), + endComparison = dom.comparePoints(this.endContainer, this.endOffset, range.startContainer, range.startOffset); + + return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0; + }, + + intersection: function(range) { + if (this.intersectsRange(range)) { + var startComparison = dom.comparePoints(this.startContainer, this.startOffset, range.startContainer, range.startOffset), + endComparison = dom.comparePoints(this.endContainer, this.endOffset, range.endContainer, range.endOffset); + + var intersectionRange = this.cloneRange(); + + if (startComparison == -1) { + intersectionRange.setStart(range.startContainer, range.startOffset); + } + if (endComparison == 1) { + intersectionRange.setEnd(range.endContainer, range.endOffset); + } + return intersectionRange; + } + return null; + }, + + union: function(range) { + if (this.intersectsRange(range, true)) { + var unionRange = this.cloneRange(); + if (dom.comparePoints(range.startContainer, range.startOffset, this.startContainer, this.startOffset) == -1) { + unionRange.setStart(range.startContainer, range.startOffset); + } + if (dom.comparePoints(range.endContainer, range.endOffset, this.endContainer, this.endOffset) == 1) { + unionRange.setEnd(range.endContainer, range.endOffset); + } + return unionRange; + } else { + throw new RangeException("Ranges do not intersect"); + } + }, + + containsNode: function(node, allowPartial) { + if (allowPartial) { + return this.intersectsNode(node, false); + } else { + return this.compareNode(node) == n_i; + } + }, + + containsNodeContents: function(node) { + return this.comparePoint(node, 0) >= 0 && this.comparePoint(node, dom.getNodeLength(node)) <= 0; + }, + + containsRange: function(range) { + return this.intersection(range).equals(range); + }, + + containsNodeText: function(node) { + var nodeRange = this.cloneRange(); + nodeRange.selectNode(node); + var textNodes = nodeRange.getNodes([3]); + if (textNodes.length > 0) { + nodeRange.setStart(textNodes[0], 0); + var lastTextNode = textNodes.pop(); + nodeRange.setEnd(lastTextNode, lastTextNode.length); + var contains = this.containsRange(nodeRange); + nodeRange.detach(); + return contains; + } else { + return this.containsNodeContents(node); + } + }, + + createNodeIterator: function(nodeTypes, filter) { + assertRangeValid(this); + return new RangeNodeIterator(this, nodeTypes, filter); + }, + + getNodes: function(nodeTypes, filter) { + assertRangeValid(this); + return getNodesInRange(this, nodeTypes, filter); + }, + + getDocument: function() { + return getRangeDocument(this); + }, + + collapseBefore: function(node) { + assertNotDetached(this); + + this.setEndBefore(node); + this.collapse(false); + }, + + collapseAfter: function(node) { + assertNotDetached(this); + + this.setStartAfter(node); + this.collapse(true); + }, + + getName: function() { + return "DomRange"; + }, + + equals: function(range) { + return Range.rangesEqual(this, range); + }, + + inspect: function() { + return inspect(this); + } + }; + + function copyComparisonConstantsToObject(obj) { + obj.START_TO_START = s2s; + obj.START_TO_END = s2e; + obj.END_TO_END = e2e; + obj.END_TO_START = e2s; + + obj.NODE_BEFORE = n_b; + obj.NODE_AFTER = n_a; + obj.NODE_BEFORE_AND_AFTER = n_b_a; + obj.NODE_INSIDE = n_i; + } + + function copyComparisonConstants(constructor) { + copyComparisonConstantsToObject(constructor); + copyComparisonConstantsToObject(constructor.prototype); + } + + function createRangeContentRemover(remover, boundaryUpdater) { + return function() { + assertRangeValid(this); + + var sc = this.startContainer, so = this.startOffset, root = this.commonAncestorContainer; + + var iterator = new RangeIterator(this, true); + + // Work out where to position the range after content removal + var node, boundary; + if (sc !== root) { + node = dom.getClosestAncestorIn(sc, root, true); + boundary = getBoundaryAfterNode(node); + sc = boundary.node; + so = boundary.offset; + } + + // Check none of the range is read-only + iterateSubtree(iterator, assertNodeNotReadOnly); + + iterator.reset(); + + // Remove the content + var returnValue = remover(iterator); + iterator.detach(); + + // Move to the new position + boundaryUpdater(this, sc, so, sc, so); + + return returnValue; + }; + } + + function createPrototypeRange(constructor, boundaryUpdater, detacher) { + function createBeforeAfterNodeSetter(isBefore, isStart) { + return function(node) { + assertNotDetached(this); + assertValidNodeType(node, beforeAfterNodeTypes); + assertValidNodeType(getRootContainer(node), rootContainerNodeTypes); + + var boundary = (isBefore ? getBoundaryBeforeNode : getBoundaryAfterNode)(node); + (isStart ? setRangeStart : setRangeEnd)(this, boundary.node, boundary.offset); + }; + } + + function setRangeStart(range, node, offset) { + var ec = range.endContainer, eo = range.endOffset; + if (node !== range.startContainer || offset !== this.startOffset) { + // Check the root containers of the range and the new boundary, and also check whether the new boundary + // is after the current end. In either case, collapse the range to the new position + if (getRootContainer(node) != getRootContainer(ec) || dom.comparePoints(node, offset, ec, eo) == 1) { + ec = node; + eo = offset; + } + boundaryUpdater(range, node, offset, ec, eo); + } + } + + function setRangeEnd(range, node, offset) { + var sc = range.startContainer, so = range.startOffset; + if (node !== range.endContainer || offset !== this.endOffset) { + // Check the root containers of the range and the new boundary, and also check whether the new boundary + // is after the current end. In either case, collapse the range to the new position + if (getRootContainer(node) != getRootContainer(sc) || dom.comparePoints(node, offset, sc, so) == -1) { + sc = node; + so = offset; + } + boundaryUpdater(range, sc, so, node, offset); + } + } + + function setRangeStartAndEnd(range, node, offset) { + if (node !== range.startContainer || offset !== this.startOffset || node !== range.endContainer || offset !== this.endOffset) { + boundaryUpdater(range, node, offset, node, offset); + } + } + + constructor.prototype = new RangePrototype(); + + api.util.extend(constructor.prototype, { + setStart: function(node, offset) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeStart(this, node, offset); + }, + + setEnd: function(node, offset) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeEnd(this, node, offset); + }, + + setStartBefore: createBeforeAfterNodeSetter(true, true), + setStartAfter: createBeforeAfterNodeSetter(false, true), + setEndBefore: createBeforeAfterNodeSetter(true, false), + setEndAfter: createBeforeAfterNodeSetter(false, false), + + collapse: function(isStart) { + assertRangeValid(this); + if (isStart) { + boundaryUpdater(this, this.startContainer, this.startOffset, this.startContainer, this.startOffset); + } else { + boundaryUpdater(this, this.endContainer, this.endOffset, this.endContainer, this.endOffset); + } + }, + + selectNodeContents: function(node) { + // This doesn't seem well specified: the spec talks only about selecting the node's contents, which + // could be taken to mean only its children. However, browsers implement this the same as selectNode for + // text nodes, so I shall do likewise + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + + boundaryUpdater(this, node, 0, node, dom.getNodeLength(node)); + }, + + selectNode: function(node) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, false); + assertValidNodeType(node, beforeAfterNodeTypes); + + var start = getBoundaryBeforeNode(node), end = getBoundaryAfterNode(node); + boundaryUpdater(this, start.node, start.offset, end.node, end.offset); + }, + + extractContents: createRangeContentRemover(extractSubtree, boundaryUpdater), + + deleteContents: createRangeContentRemover(deleteSubtree, boundaryUpdater), + + canSurroundContents: function() { + assertRangeValid(this); + assertNodeNotReadOnly(this.startContainer); + assertNodeNotReadOnly(this.endContainer); + + // Check if the contents can be surrounded. Specifically, this means whether the range partially selects + // no non-text nodes. + var iterator = new RangeIterator(this, true); + var boundariesInvalid = (iterator._first && (isNonTextPartiallySelected(iterator._first, this)) || + (iterator._last && isNonTextPartiallySelected(iterator._last, this))); + iterator.detach(); + return !boundariesInvalid; + }, + + detach: function() { + detacher(this); + }, + + splitBoundaries: function() { + assertRangeValid(this); + + + var sc = this.startContainer, so = this.startOffset, ec = this.endContainer, eo = this.endOffset; + var startEndSame = (sc === ec); + + if (dom.isCharacterDataNode(ec) && eo > 0 && eo < ec.length) { + dom.splitDataNode(ec, eo); + + } + + if (dom.isCharacterDataNode(sc) && so > 0 && so < sc.length) { + + sc = dom.splitDataNode(sc, so); + if (startEndSame) { + eo -= so; + ec = sc; + } else if (ec == sc.parentNode && eo >= dom.getNodeIndex(sc)) { + eo++; + } + so = 0; + + } + boundaryUpdater(this, sc, so, ec, eo); + }, + + normalizeBoundaries: function() { + assertRangeValid(this); + + var sc = this.startContainer, so = this.startOffset, ec = this.endContainer, eo = this.endOffset; + + var mergeForward = function(node) { + var sibling = node.nextSibling; + if (sibling && sibling.nodeType == node.nodeType) { + ec = node; + eo = node.length; + node.appendData(sibling.data); + sibling.parentNode.removeChild(sibling); + } + }; + + var mergeBackward = function(node) { + var sibling = node.previousSibling; + if (sibling && sibling.nodeType == node.nodeType) { + sc = node; + var nodeLength = node.length; + so = sibling.length; + node.insertData(0, sibling.data); + sibling.parentNode.removeChild(sibling); + if (sc == ec) { + eo += so; + ec = sc; + } else if (ec == node.parentNode) { + var nodeIndex = dom.getNodeIndex(node); + if (eo == nodeIndex) { + ec = node; + eo = nodeLength; + } else if (eo > nodeIndex) { + eo--; + } + } + } + }; + + var normalizeStart = true; + + if (dom.isCharacterDataNode(ec)) { + if (ec.length == eo) { + mergeForward(ec); + } + } else { + if (eo > 0) { + var endNode = ec.childNodes[eo - 1]; + if (endNode && dom.isCharacterDataNode(endNode)) { + mergeForward(endNode); + } + } + normalizeStart = !this.collapsed; + } + + if (normalizeStart) { + if (dom.isCharacterDataNode(sc)) { + if (so == 0) { + mergeBackward(sc); + } + } else { + if (so < sc.childNodes.length) { + var startNode = sc.childNodes[so]; + if (startNode && dom.isCharacterDataNode(startNode)) { + mergeBackward(startNode); + } + } + } + } else { + sc = ec; + so = eo; + } + + boundaryUpdater(this, sc, so, ec, eo); + }, + + collapseToPoint: function(node, offset) { + assertNotDetached(this); + + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeStartAndEnd(this, node, offset); + } + }); + + copyComparisonConstants(constructor); + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Updates commonAncestorContainer and collapsed after boundary change + function updateCollapsedAndCommonAncestor(range) { + range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset); + range.commonAncestorContainer = range.collapsed ? + range.startContainer : dom.getCommonAncestor(range.startContainer, range.endContainer); + } + + function updateBoundaries(range, startContainer, startOffset, endContainer, endOffset) { + var startMoved = (range.startContainer !== startContainer || range.startOffset !== startOffset); + var endMoved = (range.endContainer !== endContainer || range.endOffset !== endOffset); + + range.startContainer = startContainer; + range.startOffset = startOffset; + range.endContainer = endContainer; + range.endOffset = endOffset; + + updateCollapsedAndCommonAncestor(range); + dispatchEvent(range, "boundarychange", {startMoved: startMoved, endMoved: endMoved}); + } + + function detach(range) { + assertNotDetached(range); + range.startContainer = range.startOffset = range.endContainer = range.endOffset = null; + range.collapsed = range.commonAncestorContainer = null; + dispatchEvent(range, "detach", null); + range._listeners = null; + } + + /** + * @constructor + */ + function Range(doc) { + this.startContainer = doc; + this.startOffset = 0; + this.endContainer = doc; + this.endOffset = 0; + this._listeners = { + boundarychange: [], + detach: [] + }; + updateCollapsedAndCommonAncestor(this); + } + + createPrototypeRange(Range, updateBoundaries, detach); + + api.rangePrototype = RangePrototype.prototype; + + Range.rangeProperties = rangeProperties; + Range.RangeIterator = RangeIterator; + Range.copyComparisonConstants = copyComparisonConstants; + Range.createPrototypeRange = createPrototypeRange; + Range.inspect = inspect; + Range.getRangeDocument = getRangeDocument; + Range.rangesEqual = function(r1, r2) { + return r1.startContainer === r2.startContainer && + r1.startOffset === r2.startOffset && + r1.endContainer === r2.endContainer && + r1.endOffset === r2.endOffset; + }; + + api.DomRange = Range; + api.RangeException = RangeException; +});rangy.createModule("WrappedRange", function(api, module) { + api.requireModules( ["DomUtil", "DomRange"] ); + + /** + * @constructor + */ + var WrappedRange; + var dom = api.dom; + var DomPosition = dom.DomPosition; + var DomRange = api.DomRange; + + + + /*----------------------------------------------------------------------------------------------------------------*/ + + /* + This is a workaround for a bug where IE returns the wrong container element from the TextRange's parentElement() + method. For example, in the following (where pipes denote the selection boundaries): + +
    • | a
    • b |
    + + var range = document.selection.createRange(); + alert(range.parentElement().id); // Should alert "ul" but alerts "b" + + This method returns the common ancestor node of the following: + - the parentElement() of the textRange + - the parentElement() of the textRange after calling collapse(true) + - the parentElement() of the textRange after calling collapse(false) + */ + function getTextRangeContainerElement(textRange) { + var parentEl = textRange.parentElement(); + + var range = textRange.duplicate(); + range.collapse(true); + var startEl = range.parentElement(); + range = textRange.duplicate(); + range.collapse(false); + var endEl = range.parentElement(); + var startEndContainer = (startEl == endEl) ? startEl : dom.getCommonAncestor(startEl, endEl); + + return startEndContainer == parentEl ? startEndContainer : dom.getCommonAncestor(parentEl, startEndContainer); + } + + function textRangeIsCollapsed(textRange) { + return textRange.compareEndPoints("StartToEnd", textRange) == 0; + } + + // Gets the boundary of a TextRange expressed as a node and an offset within that node. This function started out as + // an improved version of code found in Tim Cameron Ryan's IERange (http://code.google.com/p/ierange/) but has + // grown, fixing problems with line breaks in preformatted text, adding workaround for IE TextRange bugs, handling + // for inputs and images, plus optimizations. + function getTextRangeBoundaryPosition(textRange, wholeRangeContainerElement, isStart, isCollapsed) { + var workingRange = textRange.duplicate(); + + workingRange.collapse(isStart); + var containerElement = workingRange.parentElement(); + + // Sometimes collapsing a TextRange that's at the start of a text node can move it into the previous node, so + // check for that + // TODO: Find out when. Workaround for wholeRangeContainerElement may break this + if (!dom.isAncestorOf(wholeRangeContainerElement, containerElement, true)) { + containerElement = wholeRangeContainerElement; + + } + + + + // Deal with nodes that cannot "contain rich HTML markup". In practice, this means form inputs, images and + // similar. See http://msdn.microsoft.com/en-us/library/aa703950%28VS.85%29.aspx + if (!containerElement.canHaveHTML) { + return new DomPosition(containerElement.parentNode, dom.getNodeIndex(containerElement)); + } + + var workingNode = dom.getDocument(containerElement).createElement("span"); + var comparison, workingComparisonType = isStart ? "StartToStart" : "StartToEnd"; + var previousNode, nextNode, boundaryPosition, boundaryNode; + + // Move the working range through the container's children, starting at the end and working backwards, until the + // working range reaches or goes past the boundary we're interested in + do { + containerElement.insertBefore(workingNode, workingNode.previousSibling); + workingRange.moveToElementText(workingNode); + } while ( (comparison = workingRange.compareEndPoints(workingComparisonType, textRange)) > 0 && + workingNode.previousSibling); + + // We've now reached or gone past the boundary of the text range we're interested in + // so have identified the node we want + boundaryNode = workingNode.nextSibling; + + if (comparison == -1 && boundaryNode && dom.isCharacterDataNode(boundaryNode)) { + // This is a character data node (text, comment, cdata). The working range is collapsed at the start of the + // node containing the text range's boundary, so we move the end of the working range to the boundary point + // and measure the length of its text to get the boundary's offset within the node. + workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange); + + + var offset; + + if (/[\r\n]/.test(boundaryNode.data)) { + /* + For the particular case of a boundary within a text node containing line breaks (within a
     element,
    +                for example), we need a slightly complicated approach to get the boundary's offset in IE. The facts:
    +
    +                - Each line break is represented as \r in the text node's data/nodeValue properties
    +                - Each line break is represented as \r\n in the TextRange's 'text' property
    +                - The 'text' property of the TextRange does not contain trailing line breaks
    +
    +                To get round the problem presented by the final fact above, we can use the fact that TextRange's
    +                moveStart() and moveEnd() methods return the actual number of characters moved, which is not necessarily
    +                the same as the number of characters it was instructed to move. The simplest approach is to use this to
    +                store the characters moved when moving both the start and end of the range to the start of the document
    +                body and subtracting the start offset from the end offset (the "move-negative-gazillion" method).
    +                However, this is extremely slow when the document is large and the range is near the end of it. Clearly
    +                doing the mirror image (i.e. moving the range boundaries to the end of the document) has the same
    +                problem.
    +
    +                Another approach that works is to use moveStart() to move the start boundary of the range up to the end
    +                boundary one character at a time and incrementing a counter with the value returned by the moveStart()
    +                call. However, the check for whether the start boundary has reached the end boundary is expensive, so
    +                this method is slow (although unlike "move-negative-gazillion" is largely unaffected by the location of
    +                the range within the document).
    +
    +                The method below is a hybrid of the two methods above. It uses the fact that a string containing the
    +                TextRange's 'text' property with each \r\n converted to a single \r character cannot be longer than the
    +                text of the TextRange, so the start of the range is moved that length initially and then a character at
    +                a time to make up for any trailing line breaks not contained in the 'text' property. This has good
    +                performance in most situations compared to the previous two methods.
    +                */
    +                var tempRange = workingRange.duplicate();
    +                var rangeLength = tempRange.text.replace(/\r\n/g, "\r").length;
    +
    +                offset = tempRange.moveStart("character", rangeLength);
    +                while ( (comparison = tempRange.compareEndPoints("StartToEnd", tempRange)) == -1) {
    +                    offset++;
    +                    tempRange.moveStart("character", 1);
    +                }
    +            } else {
    +                offset = workingRange.text.length;
    +            }
    +            boundaryPosition = new DomPosition(boundaryNode, offset);
    +        } else {
    +
    +
    +            // If the boundary immediately follows a character data node and this is the end boundary, we should favour
    +            // a position within that, and likewise for a start boundary preceding a character data node
    +            previousNode = (isCollapsed || !isStart) && workingNode.previousSibling;
    +            nextNode = (isCollapsed || isStart) && workingNode.nextSibling;
    +
    +
    +
    +            if (nextNode && dom.isCharacterDataNode(nextNode)) {
    +                boundaryPosition = new DomPosition(nextNode, 0);
    +            } else if (previousNode && dom.isCharacterDataNode(previousNode)) {
    +                boundaryPosition = new DomPosition(previousNode, previousNode.length);
    +            } else {
    +                boundaryPosition = new DomPosition(containerElement, dom.getNodeIndex(workingNode));
    +            }
    +        }
    +
    +        // Clean up
    +        workingNode.parentNode.removeChild(workingNode);
    +
    +        return boundaryPosition;
    +    }
    +
    +    // Returns a TextRange representing the boundary of a TextRange expressed as a node and an offset within that node.
    +    // This function started out as an optimized version of code found in Tim Cameron Ryan's IERange
    +    // (http://code.google.com/p/ierange/)
    +    function createBoundaryTextRange(boundaryPosition, isStart) {
    +        var boundaryNode, boundaryParent, boundaryOffset = boundaryPosition.offset;
    +        var doc = dom.getDocument(boundaryPosition.node);
    +        var workingNode, childNodes, workingRange = doc.body.createTextRange();
    +        var nodeIsDataNode = dom.isCharacterDataNode(boundaryPosition.node);
    +
    +        if (nodeIsDataNode) {
    +            boundaryNode = boundaryPosition.node;
    +            boundaryParent = boundaryNode.parentNode;
    +        } else {
    +            childNodes = boundaryPosition.node.childNodes;
    +            boundaryNode = (boundaryOffset < childNodes.length) ? childNodes[boundaryOffset] : null;
    +            boundaryParent = boundaryPosition.node;
    +        }
    +
    +        // Position the range immediately before the node containing the boundary
    +        workingNode = doc.createElement("span");
    +
    +        // Making the working element non-empty element persuades IE to consider the TextRange boundary to be within the
    +        // element rather than immediately before or after it, which is what we want
    +        workingNode.innerHTML = "&#feff;";
    +
    +        // insertBefore is supposed to work like appendChild if the second parameter is null. However, a bug report
    +        // for IERange suggests that it can crash the browser: http://code.google.com/p/ierange/issues/detail?id=12
    +        if (boundaryNode) {
    +            boundaryParent.insertBefore(workingNode, boundaryNode);
    +        } else {
    +            boundaryParent.appendChild(workingNode);
    +        }
    +
    +        workingRange.moveToElementText(workingNode);
    +        workingRange.collapse(!isStart);
    +
    +        // Clean up
    +        boundaryParent.removeChild(workingNode);
    +
    +        // Move the working range to the text offset, if required
    +        if (nodeIsDataNode) {
    +            workingRange[isStart ? "moveStart" : "moveEnd"]("character", boundaryOffset);
    +        }
    +
    +        return workingRange;
    +    }
    +
    +    /*----------------------------------------------------------------------------------------------------------------*/
    +
    +    if (api.features.implementsDomRange && (!api.features.implementsTextRange || !api.config.preferTextRange)) {
    +        // This is a wrapper around the browser's native DOM Range. It has two aims:
    +        // - Provide workarounds for specific browser bugs
    +        // - provide convenient extensions, which are inherited from Rangy's DomRange
    +
    +        (function() {
    +            var rangeProto;
    +            var rangeProperties = DomRange.rangeProperties;
    +            var canSetRangeStartAfterEnd;
    +
    +            function updateRangeProperties(range) {
    +                var i = rangeProperties.length, prop;
    +                while (i--) {
    +                    prop = rangeProperties[i];
    +                    range[prop] = range.nativeRange[prop];
    +                }
    +            }
    +
    +            function updateNativeRange(range, startContainer, startOffset, endContainer,endOffset) {
    +                var startMoved = (range.startContainer !== startContainer || range.startOffset != startOffset);
    +                var endMoved = (range.endContainer !== endContainer || range.endOffset != endOffset);
    +
    +                // Always set both boundaries for the benefit of IE9 (see issue 35)
    +                if (startMoved || endMoved) {
    +                    range.setEnd(endContainer, endOffset);
    +                    range.setStart(startContainer, startOffset);
    +                }
    +            }
    +
    +            function detach(range) {
    +                range.nativeRange.detach();
    +                range.detached = true;
    +                var i = rangeProperties.length, prop;
    +                while (i--) {
    +                    prop = rangeProperties[i];
    +                    range[prop] = null;
    +                }
    +            }
    +
    +            var createBeforeAfterNodeSetter;
    +
    +            WrappedRange = function(range) {
    +                if (!range) {
    +                    throw new Error("Range must be specified");
    +                }
    +                this.nativeRange = range;
    +                updateRangeProperties(this);
    +            };
    +
    +            DomRange.createPrototypeRange(WrappedRange, updateNativeRange, detach);
    +
    +            rangeProto = WrappedRange.prototype;
    +
    +            rangeProto.selectNode = function(node) {
    +                this.nativeRange.selectNode(node);
    +                updateRangeProperties(this);
    +            };
    +
    +            rangeProto.deleteContents = function() {
    +                this.nativeRange.deleteContents();
    +                updateRangeProperties(this);
    +            };
    +
    +            rangeProto.extractContents = function() {
    +                var frag = this.nativeRange.extractContents();
    +                updateRangeProperties(this);
    +                return frag;
    +            };
    +
    +            rangeProto.cloneContents = function() {
    +                return this.nativeRange.cloneContents();
    +            };
    +
    +            // TODO: Until I can find a way to programmatically trigger the Firefox bug (apparently long-standing, still
    +            // present in 3.6.8) that throws "Index or size is negative or greater than the allowed amount" for
    +            // insertNode in some circumstances, all browsers will have to use the Rangy's own implementation of
    +            // insertNode, which works but is almost certainly slower than the native implementation.
    +/*
    +            rangeProto.insertNode = function(node) {
    +                this.nativeRange.insertNode(node);
    +                updateRangeProperties(this);
    +            };
    +*/
    +
    +            rangeProto.surroundContents = function(node) {
    +                this.nativeRange.surroundContents(node);
    +                updateRangeProperties(this);
    +            };
    +
    +            rangeProto.collapse = function(isStart) {
    +                this.nativeRange.collapse(isStart);
    +                updateRangeProperties(this);
    +            };
    +
    +            rangeProto.cloneRange = function() {
    +                return new WrappedRange(this.nativeRange.cloneRange());
    +            };
    +
    +            rangeProto.refresh = function() {
    +                updateRangeProperties(this);
    +            };
    +
    +            rangeProto.toString = function() {
    +                return this.nativeRange.toString();
    +            };
    +
    +            // Create test range and node for feature detection
    +
    +            var testTextNode = document.createTextNode("test");
    +            dom.getBody(document).appendChild(testTextNode);
    +            var range = document.createRange();
    +
    +            /*--------------------------------------------------------------------------------------------------------*/
    +
    +            // Test for Firefox 2 bug that prevents moving the start of a Range to a point after its current end and
    +            // correct for it
    +
    +            range.setStart(testTextNode, 0);
    +            range.setEnd(testTextNode, 0);
    +
    +            try {
    +                range.setStart(testTextNode, 1);
    +                canSetRangeStartAfterEnd = true;
    +
    +                rangeProto.setStart = function(node, offset) {
    +                    this.nativeRange.setStart(node, offset);
    +                    updateRangeProperties(this);
    +                };
    +
    +                rangeProto.setEnd = function(node, offset) {
    +                    this.nativeRange.setEnd(node, offset);
    +                    updateRangeProperties(this);
    +                };
    +
    +                createBeforeAfterNodeSetter = function(name) {
    +                    return function(node) {
    +                        this.nativeRange[name](node);
    +                        updateRangeProperties(this);
    +                    };
    +                };
    +
    +            } catch(ex) {
    +
    +
    +                canSetRangeStartAfterEnd = false;
    +
    +                rangeProto.setStart = function(node, offset) {
    +                    try {
    +                        this.nativeRange.setStart(node, offset);
    +                    } catch (ex) {
    +                        this.nativeRange.setEnd(node, offset);
    +                        this.nativeRange.setStart(node, offset);
    +                    }
    +                    updateRangeProperties(this);
    +                };
    +
    +                rangeProto.setEnd = function(node, offset) {
    +                    try {
    +                        this.nativeRange.setEnd(node, offset);
    +                    } catch (ex) {
    +                        this.nativeRange.setStart(node, offset);
    +                        this.nativeRange.setEnd(node, offset);
    +                    }
    +                    updateRangeProperties(this);
    +                };
    +
    +                createBeforeAfterNodeSetter = function(name, oppositeName) {
    +                    return function(node) {
    +                        try {
    +                            this.nativeRange[name](node);
    +                        } catch (ex) {
    +                            this.nativeRange[oppositeName](node);
    +                            this.nativeRange[name](node);
    +                        }
    +                        updateRangeProperties(this);
    +                    };
    +                };
    +            }
    +
    +            rangeProto.setStartBefore = createBeforeAfterNodeSetter("setStartBefore", "setEndBefore");
    +            rangeProto.setStartAfter = createBeforeAfterNodeSetter("setStartAfter", "setEndAfter");
    +            rangeProto.setEndBefore = createBeforeAfterNodeSetter("setEndBefore", "setStartBefore");
    +            rangeProto.setEndAfter = createBeforeAfterNodeSetter("setEndAfter", "setStartAfter");
    +
    +            /*--------------------------------------------------------------------------------------------------------*/
    +
    +            // Test for and correct Firefox 2 behaviour with selectNodeContents on text nodes: it collapses the range to
    +            // the 0th character of the text node
    +            range.selectNodeContents(testTextNode);
    +            if (range.startContainer == testTextNode && range.endContainer == testTextNode &&
    +                    range.startOffset == 0 && range.endOffset == testTextNode.length) {
    +                rangeProto.selectNodeContents = function(node) {
    +                    this.nativeRange.selectNodeContents(node);
    +                    updateRangeProperties(this);
    +                };
    +            } else {
    +                rangeProto.selectNodeContents = function(node) {
    +                    this.setStart(node, 0);
    +                    this.setEnd(node, DomRange.getEndOffset(node));
    +                };
    +            }
    +
    +            /*--------------------------------------------------------------------------------------------------------*/
    +
    +            // Test for WebKit bug that has the beahviour of compareBoundaryPoints round the wrong way for constants
    +            // START_TO_END and END_TO_START: https://bugs.webkit.org/show_bug.cgi?id=20738
    +
    +            range.selectNodeContents(testTextNode);
    +            range.setEnd(testTextNode, 3);
    +
    +            var range2 = document.createRange();
    +            range2.selectNodeContents(testTextNode);
    +            range2.setEnd(testTextNode, 4);
    +            range2.setStart(testTextNode, 2);
    +
    +            if (range.compareBoundaryPoints(range.START_TO_END, range2) == -1 &
    +                    range.compareBoundaryPoints(range.END_TO_START, range2) == 1) {
    +                // This is the wrong way round, so correct for it
    +
    +
    +                rangeProto.compareBoundaryPoints = function(type, range) {
    +                    range = range.nativeRange || range;
    +                    if (type == range.START_TO_END) {
    +                        type = range.END_TO_START;
    +                    } else if (type == range.END_TO_START) {
    +                        type = range.START_TO_END;
    +                    }
    +                    return this.nativeRange.compareBoundaryPoints(type, range);
    +                };
    +            } else {
    +                rangeProto.compareBoundaryPoints = function(type, range) {
    +                    return this.nativeRange.compareBoundaryPoints(type, range.nativeRange || range);
    +                };
    +            }
    +
    +            /*--------------------------------------------------------------------------------------------------------*/
    +
    +            // Test for existence of createContextualFragment and delegate to it if it exists
    +            if (api.util.isHostMethod(range, "createContextualFragment")) {
    +                rangeProto.createContextualFragment = function(fragmentStr) {
    +                    return this.nativeRange.createContextualFragment(fragmentStr);
    +                };
    +            }
    +
    +            /*--------------------------------------------------------------------------------------------------------*/
    +
    +            // Clean up
    +            dom.getBody(document).removeChild(testTextNode);
    +            range.detach();
    +            range2.detach();
    +        })();
    +
    +        api.createNativeRange = function(doc) {
    +            doc = doc || document;
    +            return doc.createRange();
    +        };
    +    } else if (api.features.implementsTextRange) {
    +        // This is a wrapper around a TextRange, providing full DOM Range functionality using rangy's DomRange as a
    +        // prototype
    +
    +        WrappedRange = function(textRange) {
    +            this.textRange = textRange;
    +            this.refresh();
    +        };
    +
    +        WrappedRange.prototype = new DomRange(document);
    +
    +        WrappedRange.prototype.refresh = function() {
    +            var start, end;
    +
    +            // TextRange's parentElement() method cannot be trusted. getTextRangeContainerElement() works around that.
    +            var rangeContainerElement = getTextRangeContainerElement(this.textRange);
    +
    +            if (textRangeIsCollapsed(this.textRange)) {
    +                end = start = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, true, true);
    +            } else {
    +
    +                start = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, true, false);
    +                end = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, false, false);
    +            }
    +
    +            this.setStart(start.node, start.offset);
    +            this.setEnd(end.node, end.offset);
    +        };
    +
    +        DomRange.copyComparisonConstants(WrappedRange);
    +
    +        // Add WrappedRange as the Range property of the global object to allow expression like Range.END_TO_END to work
    +        var globalObj = (function() { return this; })();
    +        if (typeof globalObj.Range == "undefined") {
    +            globalObj.Range = WrappedRange;
    +        }
    +
    +        api.createNativeRange = function(doc) {
    +            doc = doc || document;
    +            return doc.body.createTextRange();
    +        };
    +    }
    +
    +    if (api.features.implementsTextRange) {
    +        WrappedRange.rangeToTextRange = function(range) {
    +            if (range.collapsed) {
    +                var tr = createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
    +
    +
    +
    +                return tr;
    +
    +                //return createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
    +            } else {
    +                var startRange = createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
    +                var endRange = createBoundaryTextRange(new DomPosition(range.endContainer, range.endOffset), false);
    +                var textRange = dom.getDocument(range.startContainer).body.createTextRange();
    +                textRange.setEndPoint("StartToStart", startRange);
    +                textRange.setEndPoint("EndToEnd", endRange);
    +                return textRange;
    +            }
    +        };
    +    }
    +
    +    WrappedRange.prototype.getName = function() {
    +        return "WrappedRange";
    +    };
    +
    +    api.WrappedRange = WrappedRange;
    +
    +    api.createRange = function(doc) {
    +        doc = doc || document;
    +        return new WrappedRange(api.createNativeRange(doc));
    +    };
    +
    +    api.createRangyRange = function(doc) {
    +        doc = doc || document;
    +        return new DomRange(doc);
    +    };
    +
    +    api.createIframeRange = function(iframeEl) {
    +        return api.createRange(dom.getIframeDocument(iframeEl));
    +    };
    +
    +    api.createIframeRangyRange = function(iframeEl) {
    +        return api.createRangyRange(dom.getIframeDocument(iframeEl));
    +    };
    +
    +    api.addCreateMissingNativeApiListener(function(win) {
    +        var doc = win.document;
    +        if (typeof doc.createRange == "undefined") {
    +            doc.createRange = function() {
    +                return api.createRange(this);
    +            };
    +        }
    +        doc = win = null;
    +    });
    +});rangy.createModule("WrappedSelection", function(api, module) {
    +    // This will create a selection object wrapper that follows the Selection object found in the WHATWG draft DOM Range
    +    // spec (http://html5.org/specs/dom-range.html)
    +
    +    api.requireModules( ["DomUtil", "DomRange", "WrappedRange"] );
    +
    +    api.config.checkSelectionRanges = true;
    +
    +    var BOOLEAN = "boolean",
    +        windowPropertyName = "_rangySelection",
    +        dom = api.dom,
    +        util = api.util,
    +        DomRange = api.DomRange,
    +        WrappedRange = api.WrappedRange,
    +        DOMException = api.DOMException,
    +        DomPosition = dom.DomPosition,
    +        getSelection,
    +        selectionIsCollapsed,
    +        CONTROL = "Control";
    +
    +
    +
    +    function getWinSelection(winParam) {
    +        return (winParam || window).getSelection();
    +    }
    +
    +    function getDocSelection(winParam) {
    +        return (winParam || window).document.selection;
    +    }
    +
    +    // Test for the Range/TextRange and Selection features required
    +    // Test for ability to retrieve selection
    +    var implementsWinGetSelection = api.util.isHostMethod(window, "getSelection"),
    +        implementsDocSelection = api.util.isHostObject(document, "selection");
    +
    +    var useDocumentSelection = implementsDocSelection && (!implementsWinGetSelection || api.config.preferTextRange);
    +
    +    if (useDocumentSelection) {
    +        getSelection = getDocSelection;
    +        api.isSelectionValid = function(winParam) {
    +            var doc = (winParam || window).document, nativeSel = doc.selection;
    +
    +            // Check whether the selection TextRange is actually contained within the correct document
    +            return (nativeSel.type != "None" || dom.getDocument(nativeSel.createRange().parentElement()) == doc);
    +        };
    +    } else if (implementsWinGetSelection) {
    +        getSelection = getWinSelection;
    +        api.isSelectionValid = function() {
    +            return true;
    +        };
    +    } else {
    +        module.fail("Neither document.selection or window.getSelection() detected.");
    +    }
    +
    +    api.getNativeSelection = getSelection;
    +
    +    var testSelection = getSelection();
    +    var testRange = api.createNativeRange(document);
    +    var body = dom.getBody(document);
    +
    +    // Obtaining a range from a selection
    +    var selectionHasAnchorAndFocus = util.areHostObjects(testSelection, ["anchorNode", "focusNode"] &&
    +                                     util.areHostProperties(testSelection, ["anchorOffset", "focusOffset"]));
    +    api.features.selectionHasAnchorAndFocus = selectionHasAnchorAndFocus;
    +
    +    // Test for existence of native selection extend() method
    +    var selectionHasExtend = util.isHostMethod(testSelection, "extend");
    +    api.features.selectionHasExtend = selectionHasExtend;
    +
    +    // Test if rangeCount exists
    +    var selectionHasRangeCount = (typeof testSelection.rangeCount == "number");
    +    api.features.selectionHasRangeCount = selectionHasRangeCount;
    +
    +    var selectionSupportsMultipleRanges = false;
    +    var collapsedNonEditableSelectionsSupported = true;
    +
    +    if (util.areHostMethods(testSelection, ["addRange", "getRangeAt", "removeAllRanges"]) &&
    +            typeof testSelection.rangeCount == "number" && api.features.implementsDomRange) {
    +
    +        (function() {
    +            var iframe = document.createElement("iframe");
    +            body.appendChild(iframe);
    +
    +            var iframeDoc = dom.getIframeDocument(iframe);
    +            iframeDoc.open();
    +            iframeDoc.write("12");
    +            iframeDoc.close();
    +
    +            var sel = dom.getIframeWindow(iframe).getSelection();
    +            var docEl = iframeDoc.documentElement;
    +            var iframeBody = docEl.lastChild, textNode = iframeBody.firstChild;
    +
    +            // Test whether the native selection will allow a collapsed selection within a non-editable element
    +            var r1 = iframeDoc.createRange();
    +            r1.setStart(textNode, 1);
    +            r1.collapse(true);
    +            sel.addRange(r1);
    +            collapsedNonEditableSelectionsSupported = (sel.rangeCount == 1);
    +            sel.removeAllRanges();
    +
    +            // Test whether the native selection is capable of supporting multiple ranges
    +            var r2 = r1.cloneRange();
    +            r1.setStart(textNode, 0);
    +            r2.setEnd(textNode, 2);
    +            sel.addRange(r1);
    +            sel.addRange(r2);
    +
    +            selectionSupportsMultipleRanges = (sel.rangeCount == 2);
    +
    +            // Clean up
    +            r1.detach();
    +            r2.detach();
    +
    +            body.removeChild(iframe);
    +        })();
    +    }
    +
    +    api.features.selectionSupportsMultipleRanges = selectionSupportsMultipleRanges;
    +    api.features.collapsedNonEditableSelectionsSupported = collapsedNonEditableSelectionsSupported;
    +
    +    // ControlRanges
    +    var implementsControlRange = false, testControlRange;
    +
    +    if (body && util.isHostMethod(body, "createControlRange")) {
    +        testControlRange = body.createControlRange();
    +        if (util.areHostProperties(testControlRange, ["item", "add"])) {
    +            implementsControlRange = true;
    +        }
    +    }
    +    api.features.implementsControlRange = implementsControlRange;
    +
    +    // Selection collapsedness
    +    if (selectionHasAnchorAndFocus) {
    +        selectionIsCollapsed = function(sel) {
    +            return sel.anchorNode === sel.focusNode && sel.anchorOffset === sel.focusOffset;
    +        };
    +    } else {
    +        selectionIsCollapsed = function(sel) {
    +            return sel.rangeCount ? sel.getRangeAt(sel.rangeCount - 1).collapsed : false;
    +        };
    +    }
    +
    +    function updateAnchorAndFocusFromRange(sel, range, backwards) {
    +        var anchorPrefix = backwards ? "end" : "start", focusPrefix = backwards ? "start" : "end";
    +        sel.anchorNode = range[anchorPrefix + "Container"];
    +        sel.anchorOffset = range[anchorPrefix + "Offset"];
    +        sel.focusNode = range[focusPrefix + "Container"];
    +        sel.focusOffset = range[focusPrefix + "Offset"];
    +    }
    +
    +    function updateAnchorAndFocusFromNativeSelection(sel) {
    +        var nativeSel = sel.nativeSelection;
    +        sel.anchorNode = nativeSel.anchorNode;
    +        sel.anchorOffset = nativeSel.anchorOffset;
    +        sel.focusNode = nativeSel.focusNode;
    +        sel.focusOffset = nativeSel.focusOffset;
    +    }
    +
    +    function updateEmptySelection(sel) {
    +        sel.anchorNode = sel.focusNode = null;
    +        sel.anchorOffset = sel.focusOffset = 0;
    +        sel.rangeCount = 0;
    +        sel.isCollapsed = true;
    +        sel._ranges.length = 0;
    +    }
    +
    +    function getNativeRange(range) {
    +        var nativeRange;
    +        if (range instanceof DomRange) {
    +            nativeRange = range._selectionNativeRange;
    +            if (!nativeRange) {
    +                nativeRange = api.createNativeRange(dom.getDocument(range.startContainer));
    +                nativeRange.setEnd(range.endContainer, range.endOffset);
    +                nativeRange.setStart(range.startContainer, range.startOffset);
    +                range._selectionNativeRange = nativeRange;
    +                range.attachListener("detach", function() {
    +
    +                    this._selectionNativeRange = null;
    +                });
    +            }
    +        } else if (range instanceof WrappedRange) {
    +            nativeRange = range.nativeRange;
    +        } else if (api.features.implementsDomRange && (range instanceof dom.getWindow(range.startContainer).Range)) {
    +            nativeRange = range;
    +        }
    +        return nativeRange;
    +    }
    +
    +    function rangeContainsSingleElement(rangeNodes) {
    +        if (!rangeNodes.length || rangeNodes[0].nodeType != 1) {
    +            return false;
    +        }
    +        for (var i = 1, len = rangeNodes.length; i < len; ++i) {
    +            if (!dom.isAncestorOf(rangeNodes[0], rangeNodes[i])) {
    +                return false;
    +            }
    +        }
    +        return true;
    +    }
    +
    +    function getSingleElementFromRange(range) {
    +        var nodes = range.getNodes();
    +        if (!rangeContainsSingleElement(nodes)) {
    +            throw new Error("getSingleElementFromRange: range " + range.inspect() + " did not consist of a single element");
    +        }
    +        return nodes[0];
    +    }
    +
    +    function isTextRange(range) {
    +        return !!range && typeof range.text != "undefined";
    +    }
    +
    +    function updateFromTextRange(sel, range) {
    +        // Create a Range from the selected TextRange
    +        var wrappedRange = new WrappedRange(range);
    +        sel._ranges = [wrappedRange];
    +
    +        updateAnchorAndFocusFromRange(sel, wrappedRange, false);
    +        sel.rangeCount = 1;
    +        sel.isCollapsed = wrappedRange.collapsed;
    +    }
    +
    +    function updateControlSelection(sel) {
    +        // Update the wrapped selection based on what's now in the native selection
    +        sel._ranges.length = 0;
    +        if (sel.docSelection.type == "None") {
    +            updateEmptySelection(sel);
    +        } else {
    +            var controlRange = sel.docSelection.createRange();
    +            if (isTextRange(controlRange)) {
    +                // This case (where the selection type is "Control" and calling createRange() on the selection returns
    +                // a TextRange) can happen in IE 9. It happens, for example, when all elements in the selected
    +                // ControlRange have been removed from the ControlRange and removed from the document.
    +                updateFromTextRange(sel, controlRange);
    +            } else {
    +                sel.rangeCount = controlRange.length;
    +                var range, doc = dom.getDocument(controlRange.item(0));
    +                for (var i = 0; i < sel.rangeCount; ++i) {
    +                    range = api.createRange(doc);
    +                    range.selectNode(controlRange.item(i));
    +                    sel._ranges.push(range);
    +                }
    +                sel.isCollapsed = sel.rangeCount == 1 && sel._ranges[0].collapsed;
    +                updateAnchorAndFocusFromRange(sel, sel._ranges[sel.rangeCount - 1], false);
    +            }
    +        }
    +    }
    +
    +    function addRangeToControlSelection(sel, range) {
    +        var controlRange = sel.docSelection.createRange();
    +        var rangeElement = getSingleElementFromRange(range);
    +
    +        // Create a new ControlRange containing all the elements in the selected ControlRange plus the element
    +        // contained by the supplied range
    +        var doc = dom.getDocument(controlRange.item(0));
    +        var newControlRange = dom.getBody(doc).createControlRange();
    +        for (var i = 0, len = controlRange.length; i < len; ++i) {
    +            newControlRange.add(controlRange.item(i));
    +        }
    +        try {
    +            newControlRange.add(rangeElement);
    +        } catch (ex) {
    +            throw new Error("addRange(): Element within the specified Range could not be added to control selection (does it have layout?)");
    +        }
    +        newControlRange.select();
    +
    +        // Update the wrapped selection based on what's now in the native selection
    +        updateControlSelection(sel);
    +    }
    +
    +    var getSelectionRangeAt;
    +
    +    if (util.isHostMethod(testSelection,  "getRangeAt")) {
    +        getSelectionRangeAt = function(sel, index) {
    +            try {
    +                return sel.getRangeAt(index);
    +            } catch(ex) {
    +                return null;
    +            }
    +        };
    +    } else if (selectionHasAnchorAndFocus) {
    +        getSelectionRangeAt = function(sel) {
    +            var doc = dom.getDocument(sel.anchorNode);
    +            var range = api.createRange(doc);
    +            range.setStart(sel.anchorNode, sel.anchorOffset);
    +            range.setEnd(sel.focusNode, sel.focusOffset);
    +
    +            // Handle the case when the selection was selected backwards (from the end to the start in the
    +            // document)
    +            if (range.collapsed !== this.isCollapsed) {
    +                range.setStart(sel.focusNode, sel.focusOffset);
    +                range.setEnd(sel.anchorNode, sel.anchorOffset);
    +            }
    +
    +            return range;
    +        };
    +    }
    +
    +    /**
    +     * @constructor
    +     */
    +    function WrappedSelection(selection, docSelection, win) {
    +        this.nativeSelection = selection;
    +        this.docSelection = docSelection;
    +        this._ranges = [];
    +        this.win = win;
    +        this.refresh();
    +    }
    +
    +    api.getSelection = function(win) {
    +        win = win || window;
    +        var sel = win[windowPropertyName];
    +        var nativeSel = getSelection(win), docSel = implementsDocSelection ? getDocSelection(win) : null;
    +        if (sel) {
    +            sel.nativeSelection = nativeSel;
    +            sel.docSelection = docSel;
    +            sel.refresh(win);
    +        } else {
    +            sel = new WrappedSelection(nativeSel, docSel, win);
    +            win[windowPropertyName] = sel;
    +        }
    +        return sel;
    +    };
    +
    +    api.getIframeSelection = function(iframeEl) {
    +        return api.getSelection(dom.getIframeWindow(iframeEl));
    +    };
    +
    +    var selProto = WrappedSelection.prototype;
    +
    +    function createControlSelection(sel, ranges) {
    +        // Ensure that the selection becomes of type "Control"
    +        var doc = dom.getDocument(ranges[0].startContainer);
    +        var controlRange = dom.getBody(doc).createControlRange();
    +        for (var i = 0, el; i < rangeCount; ++i) {
    +            el = getSingleElementFromRange(ranges[i]);
    +            try {
    +                controlRange.add(el);
    +            } catch (ex) {
    +                throw new Error("setRanges(): Element within the one of the specified Ranges could not be added to control selection (does it have layout?)");
    +            }
    +        }
    +        controlRange.select();
    +
    +        // Update the wrapped selection based on what's now in the native selection
    +        updateControlSelection(sel);
    +    }
    +
    +    // Selecting a range
    +    if (!useDocumentSelection && selectionHasAnchorAndFocus && util.areHostMethods(testSelection, ["removeAllRanges", "addRange"])) {
    +        selProto.removeAllRanges = function() {
    +            this.nativeSelection.removeAllRanges();
    +            updateEmptySelection(this);
    +        };
    +
    +        var addRangeBackwards = function(sel, range) {
    +            var doc = DomRange.getRangeDocument(range);
    +            var endRange = api.createRange(doc);
    +            endRange.collapseToPoint(range.endContainer, range.endOffset);
    +            sel.nativeSelection.addRange(getNativeRange(endRange));
    +            sel.nativeSelection.extend(range.startContainer, range.startOffset);
    +            sel.refresh();
    +        };
    +
    +        if (selectionHasRangeCount) {
    +            selProto.addRange = function(range, backwards) {
    +                if (implementsControlRange && implementsDocSelection && this.docSelection.type == CONTROL) {
    +                    addRangeToControlSelection(this, range);
    +                } else {
    +                    if (backwards && selectionHasExtend) {
    +                        addRangeBackwards(this, range);
    +                    } else {
    +                        var previousRangeCount;
    +                        if (selectionSupportsMultipleRanges) {
    +                            previousRangeCount = this.rangeCount;
    +                        } else {
    +                            this.removeAllRanges();
    +                            previousRangeCount = 0;
    +                        }
    +                        this.nativeSelection.addRange(getNativeRange(range));
    +
    +                        // Check whether adding the range was successful
    +                        this.rangeCount = this.nativeSelection.rangeCount;
    +
    +                        if (this.rangeCount == previousRangeCount + 1) {
    +                            // The range was added successfully
    +
    +                            // Check whether the range that we added to the selection is reflected in the last range extracted from
    +                            // the selection
    +                            if (api.config.checkSelectionRanges) {
    +                                var nativeRange = getSelectionRangeAt(this.nativeSelection, this.rangeCount - 1);
    +                                if (nativeRange && !DomRange.rangesEqual(nativeRange, range)) {
    +                                    // Happens in WebKit with, for example, a selection placed at the start of a text node
    +                                    range = new WrappedRange(nativeRange);
    +                                }
    +                            }
    +                            this._ranges[this.rangeCount - 1] = range;
    +                            updateAnchorAndFocusFromRange(this, range, selectionIsBackwards(this.nativeSelection));
    +                            this.isCollapsed = selectionIsCollapsed(this);
    +                        } else {
    +                            // The range was not added successfully. The simplest thing is to refresh
    +                            this.refresh();
    +                        }
    +                    }
    +                }
    +            };
    +        } else {
    +            selProto.addRange = function(range, backwards) {
    +                if (backwards && selectionHasExtend) {
    +                    addRangeBackwards(this, range);
    +                } else {
    +                    this.nativeSelection.addRange(getNativeRange(range));
    +                    this.refresh();
    +                }
    +            };
    +        }
    +
    +        selProto.setRanges = function(ranges) {
    +            if (implementsControlRange && ranges.length > 1) {
    +                createControlSelection(this, ranges);
    +            } else {
    +                this.removeAllRanges();
    +                for (var i = 0, len = ranges.length; i < len; ++i) {
    +                    this.addRange(ranges[i]);
    +                }
    +            }
    +        };
    +    } else if (util.isHostMethod(testSelection, "empty") && util.isHostMethod(testRange, "select") &&
    +               implementsControlRange && useDocumentSelection) {
    +
    +        selProto.removeAllRanges = function() {
    +            // Added try/catch as fix for issue #21
    +            try {
    +                this.docSelection.empty();
    +
    +                // Check for empty() not working (issue #24)
    +                if (this.docSelection.type != "None") {
    +                    // Work around failure to empty a control selection by instead selecting a TextRange and then
    +                    // calling empty()
    +                    var doc;
    +                    if (this.anchorNode) {
    +                        doc = dom.getDocument(this.anchorNode);
    +                    } else if (this.docSelection.type == CONTROL) {
    +                        var controlRange = this.docSelection.createRange();
    +                        if (controlRange.length) {
    +                            doc = dom.getDocument(controlRange.item(0)).body.createTextRange();
    +                        }
    +                    }
    +                    if (doc) {
    +                        var textRange = doc.body.createTextRange();
    +                        textRange.select();
    +                        this.docSelection.empty();
    +                    }
    +                }
    +            } catch(ex) {}
    +            updateEmptySelection(this);
    +        };
    +
    +        selProto.addRange = function(range) {
    +            if (this.docSelection.type == CONTROL) {
    +                addRangeToControlSelection(this, range);
    +            } else {
    +                WrappedRange.rangeToTextRange(range).select();
    +                this._ranges[0] = range;
    +                this.rangeCount = 1;
    +                this.isCollapsed = this._ranges[0].collapsed;
    +                updateAnchorAndFocusFromRange(this, range, false);
    +            }
    +        };
    +
    +        selProto.setRanges = function(ranges) {
    +            this.removeAllRanges();
    +            var rangeCount = ranges.length;
    +            if (rangeCount > 1) {
    +                createControlSelection(this, ranges);
    +            } else if (rangeCount) {
    +                this.addRange(ranges[0]);
    +            }
    +        };
    +    } else {
    +        module.fail("No means of selecting a Range or TextRange was found");
    +        return false;
    +    }
    +
    +    selProto.getRangeAt = function(index) {
    +        if (index < 0 || index >= this.rangeCount) {
    +            throw new DOMException("INDEX_SIZE_ERR");
    +        } else {
    +            return this._ranges[index];
    +        }
    +    };
    +
    +    var refreshSelection;
    +
    +    if (useDocumentSelection) {
    +        refreshSelection = function(sel) {
    +            var range;
    +            if (api.isSelectionValid(sel.win)) {
    +                range = sel.docSelection.createRange();
    +            } else {
    +                range = dom.getBody(sel.win.document).createTextRange();
    +                range.collapse(true);
    +            }
    +
    +
    +            if (sel.docSelection.type == CONTROL) {
    +                updateControlSelection(sel);
    +            } else if (isTextRange(range)) {
    +                updateFromTextRange(sel, range);
    +            } else {
    +                updateEmptySelection(sel);
    +            }
    +        };
    +    } else if (util.isHostMethod(testSelection, "getRangeAt") && typeof testSelection.rangeCount == "number") {
    +        refreshSelection = function(sel) {
    +            if (implementsControlRange && implementsDocSelection && sel.docSelection.type == CONTROL) {
    +                updateControlSelection(sel);
    +            } else {
    +                sel._ranges.length = sel.rangeCount = sel.nativeSelection.rangeCount;
    +                if (sel.rangeCount) {
    +                    for (var i = 0, len = sel.rangeCount; i < len; ++i) {
    +                        sel._ranges[i] = new api.WrappedRange(sel.nativeSelection.getRangeAt(i));
    +                    }
    +                    updateAnchorAndFocusFromRange(sel, sel._ranges[sel.rangeCount - 1], selectionIsBackwards(sel.nativeSelection));
    +                    sel.isCollapsed = selectionIsCollapsed(sel);
    +                } else {
    +                    updateEmptySelection(sel);
    +                }
    +            }
    +        };
    +    } else if (selectionHasAnchorAndFocus && typeof testSelection.isCollapsed == BOOLEAN && typeof testRange.collapsed == BOOLEAN && api.features.implementsDomRange) {
    +        refreshSelection = function(sel) {
    +            var range, nativeSel = sel.nativeSelection;
    +            if (nativeSel.anchorNode) {
    +                range = getSelectionRangeAt(nativeSel, 0);
    +                sel._ranges = [range];
    +                sel.rangeCount = 1;
    +                updateAnchorAndFocusFromNativeSelection(sel);
    +                sel.isCollapsed = selectionIsCollapsed(sel);
    +            } else {
    +                updateEmptySelection(sel);
    +            }
    +        };
    +    } else {
    +        module.fail("No means of obtaining a Range or TextRange from the user's selection was found");
    +        return false;
    +    }
    +
    +    selProto.refresh = function(checkForChanges) {
    +        var oldRanges = checkForChanges ? this._ranges.slice(0) : null;
    +        refreshSelection(this);
    +        if (checkForChanges) {
    +            var i = oldRanges.length;
    +            if (i != this._ranges.length) {
    +                return false;
    +            }
    +            while (i--) {
    +                if (!DomRange.rangesEqual(oldRanges[i], this._ranges[i])) {
    +                    return false;
    +                }
    +            }
    +            return true;
    +        }
    +    };
    +
    +    // Removal of a single range
    +    var removeRangeManually = function(sel, range) {
    +        var ranges = sel.getAllRanges(), removed = false;
    +        sel.removeAllRanges();
    +        for (var i = 0, len = ranges.length; i < len; ++i) {
    +            if (removed || range !== ranges[i]) {
    +                sel.addRange(ranges[i]);
    +            } else {
    +                // According to the draft WHATWG Range spec, the same range may be added to the selection multiple
    +                // times. removeRange should only remove the first instance, so the following ensures only the first
    +                // instance is removed
    +                removed = true;
    +            }
    +        }
    +        if (!sel.rangeCount) {
    +            updateEmptySelection(sel);
    +        }
    +    };
    +
    +    if (implementsControlRange) {
    +        selProto.removeRange = function(range) {
    +            if (this.docSelection.type == CONTROL) {
    +                var controlRange = this.docSelection.createRange();
    +                var rangeElement = getSingleElementFromRange(range);
    +
    +                // Create a new ControlRange containing all the elements in the selected ControlRange minus the
    +                // element contained by the supplied range
    +                var doc = dom.getDocument(controlRange.item(0));
    +                var newControlRange = dom.getBody(doc).createControlRange();
    +                var el, removed = false;
    +                for (var i = 0, len = controlRange.length; i < len; ++i) {
    +                    el = controlRange.item(i);
    +                    if (el !== rangeElement || removed) {
    +                        newControlRange.add(controlRange.item(i));
    +                    } else {
    +                        removed = true;
    +                    }
    +                }
    +                newControlRange.select();
    +
    +                // Update the wrapped selection based on what's now in the native selection
    +                updateControlSelection(this);
    +            } else {
    +                removeRangeManually(this, range);
    +            }
    +        };
    +    } else {
    +        selProto.removeRange = function(range) {
    +            removeRangeManually(this, range);
    +        };
    +    }
    +
    +    // Detecting if a selection is backwards
    +    var selectionIsBackwards;
    +    if (!useDocumentSelection && selectionHasAnchorAndFocus && api.features.implementsDomRange) {
    +        selectionIsBackwards = function(sel) {
    +            var backwards = false;
    +            if (sel.anchorNode) {
    +                backwards = (dom.comparePoints(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset) == 1);
    +            }
    +            return backwards;
    +        };
    +
    +        selProto.isBackwards = function() {
    +            return selectionIsBackwards(this);
    +        };
    +    } else {
    +        selectionIsBackwards = selProto.isBackwards = function() {
    +            return false;
    +        };
    +    }
    +
    +    // Selection text
    +    // This is conformant to the new WHATWG DOM Range draft spec but differs from WebKit and Mozilla's implementation
    +    selProto.toString = function() {
    +
    +        var rangeTexts = [];
    +        for (var i = 0, len = this.rangeCount; i < len; ++i) {
    +            rangeTexts[i] = "" + this._ranges[i];
    +        }
    +        return rangeTexts.join("");
    +    };
    +
    +    function assertNodeInSameDocument(sel, node) {
    +        if (sel.anchorNode && (dom.getDocument(sel.anchorNode) !== dom.getDocument(node))) {
    +            throw new DOMException("WRONG_DOCUMENT_ERR");
    +        }
    +    }
    +
    +    // No current browsers conform fully to the HTML 5 draft spec for this method, so Rangy's own method is always used
    +    selProto.collapse = function(node, offset) {
    +        assertNodeInSameDocument(this, node);
    +        var range = api.createRange(dom.getDocument(node));
    +        range.collapseToPoint(node, offset);
    +        this.removeAllRanges();
    +        this.addRange(range);
    +        this.isCollapsed = true;
    +    };
    +
    +    selProto.collapseToStart = function() {
    +        if (this.rangeCount) {
    +            var range = this._ranges[0];
    +            this.collapse(range.startContainer, range.startOffset);
    +        } else {
    +            throw new DOMException("INVALID_STATE_ERR");
    +        }
    +    };
    +
    +    selProto.collapseToEnd = function() {
    +        if (this.rangeCount) {
    +            var range = this._ranges[this.rangeCount - 1];
    +            this.collapse(range.endContainer, range.endOffset);
    +        } else {
    +            throw new DOMException("INVALID_STATE_ERR");
    +        }
    +    };
    +
    +    // The HTML 5 spec is very specific on how selectAllChildren should be implemented so the native implementation is
    +    // never used by Rangy.
    +    selProto.selectAllChildren = function(node) {
    +        assertNodeInSameDocument(this, node);
    +        var range = api.createRange(dom.getDocument(node));
    +        range.selectNodeContents(node);
    +        this.removeAllRanges();
    +        this.addRange(range);
    +    };
    +
    +    selProto.deleteFromDocument = function() {
    +        // Sepcial behaviour required for Control selections
    +        if (implementsControlRange && implementsDocSelection && this.docSelection.type == CONTROL) {
    +            var controlRange = this.docSelection.createRange();
    +            var element;
    +            while (controlRange.length) {
    +                element = controlRange.item(0);
    +                controlRange.remove(element);
    +                element.parentNode.removeChild(element);
    +            }
    +            this.refresh();
    +        } else if (this.rangeCount) {
    +            var ranges = this.getAllRanges();
    +            this.removeAllRanges();
    +            for (var i = 0, len = ranges.length; i < len; ++i) {
    +                ranges[i].deleteContents();
    +            }
    +            // The HTML5 spec says nothing about what the selection should contain after calling deleteContents on each
    +            // range. Firefox moves the selection to where the final selected range was, so we emulate that
    +            this.addRange(ranges[len - 1]);
    +        }
    +    };
    +
    +    // The following are non-standard extensions
    +    selProto.getAllRanges = function() {
    +        return this._ranges.slice(0);
    +    };
    +
    +    selProto.setSingleRange = function(range) {
    +        this.setRanges( [range] );
    +    };
    +
    +    selProto.containsNode = function(node, allowPartial) {
    +        for (var i = 0, len = this._ranges.length; i < len; ++i) {
    +            if (this._ranges[i].containsNode(node, allowPartial)) {
    +                return true;
    +            }
    +        }
    +        return false;
    +    };
    +
    +    selProto.toHtml = function() {
    +        var html = "";
    +        if (this.rangeCount) {
    +            var container = DomRange.getRangeDocument(this._ranges[0]).createElement("div");
    +            for (var i = 0, len = this._ranges.length; i < len; ++i) {
    +                container.appendChild(this._ranges[i].cloneContents());
    +            }
    +            html = container.innerHTML;
    +        }
    +        return html;
    +    };
    +
    +    function inspect(sel) {
    +        var rangeInspects = [];
    +        var anchor = new DomPosition(sel.anchorNode, sel.anchorOffset);
    +        var focus = new DomPosition(sel.focusNode, sel.focusOffset);
    +        var name = (typeof sel.getName == "function") ? sel.getName() : "Selection";
    +
    +        if (typeof sel.rangeCount != "undefined") {
    +            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
    +                rangeInspects[i] = DomRange.inspect(sel.getRangeAt(i));
    +            }
    +        }
    +        return "[" + name + "(Ranges: " + rangeInspects.join(", ") +
    +                ")(anchor: " + anchor.inspect() + ", focus: " + focus.inspect() + "]";
    +
    +    }
    +
    +    selProto.getName = function() {
    +        return "WrappedSelection";
    +    };
    +
    +    selProto.inspect = function() {
    +        return inspect(this);
    +    };
    +
    +    selProto.detach = function() {
    +        this.win[windowPropertyName] = null;
    +        this.win = this.anchorNode = this.focusNode = null;
    +    };
    +
    +    WrappedSelection.inspect = inspect;
    +
    +    api.Selection = WrappedSelection;
    +
    +    api.selectionPrototype = selProto;
    +
    +    api.addCreateMissingNativeApiListener(function(win) {
    +        if (typeof win.getSelection == "undefined") {
    +            win.getSelection = function() {
    +                return api.getSelection(this);
    +            };
    +        }
    +        win = null;
    +    });
    +});
    +
    +/*
    +    http://www.JSON.org/json2.js
    +    2011-02-23
    +
    +    Public Domain.
    +
    +    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
    +
    +    See http://www.JSON.org/js.html
    +
    +
    +    This code should be minified before deployment.
    +    See http://javascript.crockford.com/jsmin.html
    +
    +    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    +    NOT CONTROL.
    +
    +
    +    This file creates a global JSON object containing two methods: stringify
    +    and parse.
    +
    +        JSON.stringify(value, replacer, space)
    +            value       any JavaScript value, usually an object or array.
    +
    +            replacer    an optional parameter that determines how object
    +                        values are stringified for objects. It can be a
    +                        function or an array of strings.
    +
    +            space       an optional parameter that specifies the indentation
    +                        of nested structures. If it is omitted, the text will
    +                        be packed without extra whitespace. If it is a number,
    +                        it will specify the number of spaces to indent at each
    +                        level. If it is a string (such as '\t' or ' '),
    +                        it contains the characters used to indent at each level.
    +
    +            This method produces a JSON text from a JavaScript value.
    +
    +            When an object value is found, if the object contains a toJSON
    +            method, its toJSON method will be called and the result will be
    +            stringified. A toJSON method does not serialize: it returns the
    +            value represented by the name/value pair that should be serialized,
    +            or undefined if nothing should be serialized. The toJSON method
    +            will be passed the key associated with the value, and this will be
    +            bound to the value
    +
    +            For example, this would serialize Dates as ISO strings.
    +
    +                Date.prototype.toJSON = function (key) {
    +                    function f(n) {
    +                        // Format integers to have at least two digits.
    +                        return n < 10 ? '0' + n : n;
    +                    }
    +
    +                    return this.getUTCFullYear()   + '-' +
    +                         f(this.getUTCMonth() + 1) + '-' +
    +                         f(this.getUTCDate())      + 'T' +
    +                         f(this.getUTCHours())     + ':' +
    +                         f(this.getUTCMinutes())   + ':' +
    +                         f(this.getUTCSeconds())   + 'Z';
    +                };
    +
    +            You can provide an optional replacer method. It will be passed the
    +            key and value of each member, with this bound to the containing
    +            object. The value that is returned from your method will be
    +            serialized. If your method returns undefined, then the member will
    +            be excluded from the serialization.
    +
    +            If the replacer parameter is an array of strings, then it will be
    +            used to select the members to be serialized. It filters the results
    +            such that only members with keys listed in the replacer array are
    +            stringified.
    +
    +            Values that do not have JSON representations, such as undefined or
    +            functions, will not be serialized. Such values in objects will be
    +            dropped; in arrays they will be replaced with null. You can use
    +            a replacer function to replace those with JSON values.
    +            JSON.stringify(undefined) returns undefined.
    +
    +            The optional space parameter produces a stringification of the
    +            value that is filled with line breaks and indentation to make it
    +            easier to read.
    +
    +            If the space parameter is a non-empty string, then that string will
    +            be used for indentation. If the space parameter is a number, then
    +            the indentation will be that many spaces.
    +
    +            Example:
    +
    +            text = JSON.stringify(['e', {pluribus: 'unum'}]);
    +            // text is '["e",{"pluribus":"unum"}]'
    +
    +
    +            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
    +            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
    +
    +            text = JSON.stringify([new Date()], function (key, value) {
    +                return this[key] instanceof Date ?
    +                    'Date(' + this[key] + ')' : value;
    +            });
    +            // text is '["Date(---current time---)"]'
    +
    +
    +        JSON.parse(text, reviver)
    +            This method parses a JSON text to produce an object or array.
    +            It can throw a SyntaxError exception.
    +
    +            The optional reviver parameter is a function that can filter and
    +            transform the results. It receives each of the keys and values,
    +            and its return value is used instead of the original value.
    +            If it returns what it received, then the structure is not modified.
    +            If it returns undefined then the member is deleted.
    +
    +            Example:
    +
    +            // Parse the text. Values that look like ISO date strings will
    +            // be converted to Date objects.
    +
    +            myData = JSON.parse(text, function (key, value) {
    +                var a;
    +                if (typeof value === 'string') {
    +                    a =
    +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
    +                    if (a) {
    +                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
    +                            +a[5], +a[6]));
    +                    }
    +                }
    +                return value;
    +            });
    +
    +            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
    +                var d;
    +                if (typeof value === 'string' &&
    +                        value.slice(0, 5) === 'Date(' &&
    +                        value.slice(-1) === ')') {
    +                    d = new Date(value.slice(5, -1));
    +                    if (d) {
    +                        return d;
    +                    }
    +                }
    +                return value;
    +            });
    +
    +
    +    This is a reference implementation. You are free to copy, modify, or
    +    redistribute.
    +*/
    +
    +/*jslint evil: true, strict: false, regexp: false */
    +
    +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    +    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    +    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    +    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    +    test, toJSON, toString, valueOf
    +*/
    +
    +
    +// Create a JSON object only if one does not already exist. We create the
    +// methods in a closure to avoid creating global variables.
    +define( 'util/json2', [], function(){} );
    +
    +var JSON;
    +if (!JSON) {
    +    JSON = {};
    +}
    +
    +(function () {
    +    
    +
    +    function f(n) {
    +        // Format integers to have at least two digits.
    +        return n < 10 ? '0' + n : n;
    +    }
    +
    +    if (typeof Date.prototype.toJSON !== 'function') {
    +
    +        Date.prototype.toJSON = function (key) {
    +
    +            return isFinite(this.valueOf()) ?
    +                this.getUTCFullYear()     + '-' +
    +                f(this.getUTCMonth() + 1) + '-' +
    +                f(this.getUTCDate())      + 'T' +
    +                f(this.getUTCHours())     + ':' +
    +                f(this.getUTCMinutes())   + ':' +
    +                f(this.getUTCSeconds())   + 'Z' : null;
    +        };
    +
    +        String.prototype.toJSON      =
    +            Number.prototype.toJSON  =
    +            Boolean.prototype.toJSON = function (key) {
    +                return this.valueOf();
    +            };
    +    }
    +
    +    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
    +        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
    +        gap,
    +        indent,
    +        meta = {    // table of character substitutions
    +            '\b': '\\b',
    +            '\t': '\\t',
    +            '\n': '\\n',
    +            '\f': '\\f',
    +            '\r': '\\r',
    +            '"' : '\\"',
    +            '\\': '\\\\'
    +        },
    +        rep;
    +
    +
    +    function quote(string) {
    +
    +// If the string contains no control characters, no quote characters, and no
    +// backslash characters, then we can safely slap some quotes around it.
    +// Otherwise we must also replace the offending characters with safe escape
    +// sequences.
    +
    +        escapable.lastIndex = 0;
    +        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
    +            var c = meta[a];
    +            return typeof c === 'string' ? c :
    +                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    +        }) + '"' : '"' + string + '"';
    +    }
    +
    +
    +    function str(key, holder) {
    +
    +// Produce a string from holder[key].
    +
    +        var i,          // The loop counter.
    +            k,          // The member key.
    +            v,          // The member value.
    +            length,
    +            mind = gap,
    +            partial,
    +            value = holder[key];
    +
    +// If the value has a toJSON method, call it to obtain a replacement value.
    +
    +        if (value && typeof value === 'object' &&
    +                typeof value.toJSON === 'function') {
    +            value = value.toJSON(key);
    +        }
    +
    +// If we were called with a replacer function, then call the replacer to
    +// obtain a replacement value.
    +
    +        if (typeof rep === 'function') {
    +            value = rep.call(holder, key, value);
    +        }
    +
    +// What happens next depends on the value's type.
    +
    +        switch (typeof value) {
    +        case 'string':
    +            return quote(value);
    +
    +        case 'number':
    +
    +// JSON numbers must be finite. Encode non-finite numbers as null.
    +
    +            return isFinite(value) ? String(value) : 'null';
    +
    +        case 'boolean':
    +        case 'null':
    +
    +// If the value is a boolean or null, convert it to a string. Note:
    +// typeof null does not produce 'null'. The case is included here in
    +// the remote chance that this gets fixed someday.
    +
    +            return String(value);
    +
    +// If the type is 'object', we might be dealing with an object or an array or
    +// null.
    +
    +        case 'object':
    +
    +// Due to a specification blunder in ECMAScript, typeof null is 'object',
    +// so watch out for that case.
    +
    +            if (!value) {
    +                return 'null';
    +            }
    +
    +// Make an array to hold the partial results of stringifying this object value.
    +
    +            gap += indent;
    +            partial = [];
    +
    +// Is the value an array?
    +
    +            if (Object.prototype.toString.apply(value) === '[object Array]') {
    +
    +// The value is an array. Stringify every element. Use null as a placeholder
    +// for non-JSON values.
    +
    +                length = value.length;
    +                for (i = 0; i < length; i += 1) {
    +                    partial[i] = str(i, value) || 'null';
    +                }
    +
    +// Join all of the elements together, separated with commas, and wrap them in
    +// brackets.
    +
    +                v = partial.length === 0 ? '[]' : gap ?
    +                    '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
    +                    '[' + partial.join(',') + ']';
    +                gap = mind;
    +                return v;
    +            }
    +
    +// If the replacer is an array, use it to select the members to be stringified.
    +
    +            if (rep && typeof rep === 'object') {
    +                length = rep.length;
    +                for (i = 0; i < length; i += 1) {
    +                    if (typeof rep[i] === 'string') {
    +                        k = rep[i];
    +                        v = str(k, value);
    +                        if (v) {
    +                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
    +                        }
    +                    }
    +                }
    +            } else {
    +
    +// Otherwise, iterate through all of the keys in the object.
    +
    +                for (k in value) {
    +                    if (Object.prototype.hasOwnProperty.call(value, k)) {
    +                        v = str(k, value);
    +                        if (v) {
    +                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
    +                        }
    +                    }
    +                }
    +            }
    +
    +// Join all of the member texts together, separated with commas,
    +// and wrap them in braces.
    +
    +            v = partial.length === 0 ? '{}' : gap ?
    +                '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
    +                '{' + partial.join(',') + '}';
    +            gap = mind;
    +            return v;
    +        }
    +    }
    +
    +// If the JSON object does not yet have a stringify method, give it one.
    +
    +    if (typeof JSON.stringify !== 'function') {
    +        JSON.stringify = function (value, replacer, space) {
    +
    +// The stringify method takes a value and an optional replacer, and an optional
    +// space parameter, and returns a JSON text. The replacer can be a function
    +// that can replace values, or an array of strings that will select the keys.
    +// A default replacer method can be provided. Use of the space parameter can
    +// produce text that is more easily readable.
    +
    +            var i;
    +            gap = '';
    +            indent = '';
    +
    +// If the space parameter is a number, make an indent string containing that
    +// many spaces.
    +
    +            if (typeof space === 'number') {
    +                for (i = 0; i < space; i += 1) {
    +                    indent += ' ';
    +                }
    +
    +// If the space parameter is a string, it will be used as the indent string.
    +
    +            } else if (typeof space === 'string') {
    +                indent = space;
    +            }
    +
    +// If there is a replacer, it must be a function or an array.
    +// Otherwise, throw an error.
    +
    +            rep = replacer;
    +            if (replacer && typeof replacer !== 'function' &&
    +                    (typeof replacer !== 'object' ||
    +                    typeof replacer.length !== 'number')) {
    +                throw new Error('JSON.stringify');
    +            }
    +
    +// Make a fake root object containing our value under the key of ''.
    +// Return the result of stringifying the value.
    +
    +            return str('', {'': value});
    +        };
    +    }
    +
    +
    +// If the JSON object does not yet have a parse method, give it one.
    +
    +    if (typeof JSON.parse !== 'function') {
    +        JSON.parse = function (text, reviver) {
    +
    +// The parse method takes a text and an optional reviver function, and returns
    +// a JavaScript value if the text is a valid JSON text.
    +
    +            var j;
    +
    +            function walk(holder, key) {
    +
    +// The walk method is used to recursively walk the resulting structure so
    +// that modifications can be made.
    +
    +                var k, v, value = holder[key];
    +                if (value && typeof value === 'object') {
    +                    for (k in value) {
    +                        if (Object.prototype.hasOwnProperty.call(value, k)) {
    +                            v = walk(value, k);
    +                            if (v !== undefined) {
    +                                value[k] = v;
    +                            } else {
    +                                delete value[k];
    +                            }
    +                        }
    +                    }
    +                }
    +                return reviver.call(holder, key, value);
    +            }
    +
    +
    +// Parsing happens in four stages. In the first stage, we replace certain
    +// Unicode characters with escape sequences. JavaScript handles many characters
    +// incorrectly, either silently deleting them, or treating them as line endings.
    +
    +            text = String(text);
    +            cx.lastIndex = 0;
    +            if (cx.test(text)) {
    +                text = text.replace(cx, function (a) {
    +                    return '\\u' +
    +                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    +                });
    +            }
    +
    +// In the second stage, we run the text against regular expressions that look
    +// for non-JSON patterns. We are especially concerned with '()' and 'new'
    +// because they can cause invocation, and '=' because it can cause mutation.
    +// But just to be safe, we want to reject all unexpected forms.
    +
    +// We split the second stage into 4 regexp operations in order to work around
    +// crippling inefficiencies in IE's and Safari's regexp engines. First we
    +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
    +// replace all simple value tokens with ']' characters. Third, we delete all
    +// open brackets that follow a colon or comma or that begin the text. Finally,
    +// we look to see that the remaining characters are only whitespace or ']' or
    +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
    +
    +            if (/^[\],:{}\s]*$/
    +                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
    +                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
    +                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
    +
    +// In the third stage we use the eval function to compile the text into a
    +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
    +// in JavaScript: it can begin a block or an object literal. We wrap the text
    +// in parens to eliminate the ambiguity.
    +
    +                j = eval('(' + text + ')');
    +
    +// In the optional fourth stage, we recursively walk the new structure, passing
    +// each name/value pair to a reviver function for possible transformation.
    +
    +                return typeof reviver === 'function' ?
    +                    walk({'': j}, '') : j;
    +            }
    +
    +// If the text is not JSON parseable, then a SyntaxError is thrown.
    +
    +            throw new SyntaxError('JSON.parse');
    +        };
    +    }
    +}());
    +
    +/* Simple JavaScript Inheritance
    + * By John Resig http://ejohn.org/
    + * MIT Licensed.
    + */
    +// Inspired by base2 and Prototype
    +/*
    + * MODIFICATIONS: 
    + * * The name of the "constructor" method was changed from "init" to "_constructor"
    + * * Mixin Support using https://gist.github.com/1006243
    + * * Modified to be a require.js module
    + */
    +define('util/class',[],
    +function(){
    +  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
    + 
    +  // The base Class implementation (does nothing)
    +  // with doing that Class is available in the global namespace.
    +  this.Class = function(){};
    +
    +  // Create a new Class that inherits from this class
    +  Class.extend = function() {
    +    var _super = this.prototype;
    +
    +    // Instantiate a base class (but only create the instance,
    +    // don't run the init constructor)
    +    initializing = true;
    +    var prototype = new this();
    +    initializing = false;
    +
    +    // Copy the properties over onto the new prototype
    +	for(var i = 0; i < arguments.length; i++) {
    +      var prop = arguments[i];
    +      for (var name in prop) {
    +        // Check if we're overwriting an existing function
    +        prototype[name] = typeof prop[name] == "function" &&
    +          typeof _super[name] == "function" && fnTest.test(prop[name]) ?
    +          (function(name, fn){
    +            return function() {
    +              var tmp = this._super;
    +
    +              // Add a new ._super() method that is the same method
    +              // but on the super-class
    +              this._super = _super[name];
    +
    +              // The method only need to be bound temporarily, so we
    +              // remove it when we're done executing
    +              var ret = fn.apply(this, arguments);
    +              this._super = tmp;
    +
    +              return ret;
    +            };
    +          })(name, prop[name]) :
    +          prop[name];
    +      }
    +	}
    +
    +    // The dummy class constructor
    +    function Class() {
    +      // All construction is actually done in the _constructor method
    +      if ( !initializing && this._constructor )
    +        this._constructor.apply(this, arguments);
    +    }
    +
    +    // Populate our constructed prototype object
    +    Class.prototype = prototype;
    +
    +    // Enforce the constructor to be what we expect
    +    Class.constructor = Class;
    +
    +    // And make this class extendable
    +    Class.extend = arguments.callee;
    +
    +    return Class;
    +  
    +  };
    +
    +  	return this.Class;
    +  	
    +});
    +/*!
    + * This file is part of Aloha Editor
    + * Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com
    + * Licensed unter the terms of http://www.aloha-editor.com/license.html
    + */
    +// Ensure GENTICS Namespace
    +GENTICS = window.GENTICS || {};
    +GENTICS.Utils = GENTICS.Utils || {};
    +
    +define( 'util/lang', [], function(){} );
    +
    +// Start Closure
    +(function(window, undefined) {
    +	
    +	var
    +		jQuery = window.alohaQuery || window.jQuery, $ = jQuery,
    +		GENTICS = window.GENTICS,
    +		Class = window.Class,
    +		console = window.console;
    +
    +/**
    + * Takes over all properties from the 'properties' object to the target object.
    + * If a property in 'target' with the same name as a property in 'properties' is already defined it is overridden.
    + *
    + * Example:
    + *
    + * var o1 = {a : 1, b : 'hello'};
    + * var o2 = {a : 3, c : 'world'};
    + *
    + * GENTICS.Utils.applyProperties(o1, o2);
    + *
    + * Will result in an o1 object like this:
    + *
    + * {a : 3, b: 'hello', c: 'world'}
    + *
    + * @static
    + * @return void
    + */
    +GENTICS.Utils.applyProperties = function (target, properties) {
    +	var name;
    +	for (name in properties) {
    +		if (properties.hasOwnProperty(name)) {
    +			target[name] = properties[name];
    +		}
    +	}
    +};
    +
    +/**
    + * Generate a unique hexadecimal string with 4 charachters
    + * @return {string}
    + */
    +GENTICS.Utils.uniqeString4 = function () {
    +   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    +};
    +
    +/**
    + * Generate a unique value represented as a 32 character hexadecimal string,
    + * such as 21EC2020-3AEA-1069-A2DD-08002B30309D
    + * @return {string}
    + */
    +GENTICS.Utils.guid = function () {
    +	var S4 = GENTICS.Utils.uniqeString4;
    +	return (S4()+S4()+'-'+S4()+'-'+S4()+'-'+S4()+'-'+S4()+S4()+S4());
    +};
    +
    +})(window);
    +
    +
    +define('aloha/ecma5shims',[],
    +function(){
    +
    +  var shims = {
    +    // Function bind
    +    bind: function(owner){
    +      var obj = this.obj || this;
    +      var native_method = Function.prototype.bind;          
    +      var args= Array.prototype.slice.call(arguments, 1);
    +
    +      if(native_method){
    +        return native_method.apply(obj, arguments); 
    +      }
    +      else{
    +        return function() {
    +          return obj.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
    +        }
    +      }
    +    },
    +
    +    // String trim
    +    trim: function(){
    +      var obj = this.obj || this;
    +      var native_method = String.prototype.trim;
    +
    +      if(native_method){
    +        return native_method.call(obj); 
    +      }
    +      else {
    +        return obj.replace(/^\s+/, '').replace(/\s+$/, '');
    +      }
    +    },
    +
    +    // Array methods 
    +    indexOf: function(find, i /*opt*/){
    +      var obj = this.obj || this;
    +      var native_method = Array.prototype.indexOf;     
    +
    +      if(native_method){
    +        return native_method.call(obj, find, i); 
    +      }
    +      else {
    +        if (i===undefined) i= 0;
    +        if (i<0) i+= obj.length;
    +        if (i<0) i= 0;
    +        for (var n = obj.length; i= 0 && node2.sourceIndex >= 0 ?
    +            (node1.sourceIndex < node2.sourceIndex && 4) +
    +              (node1.sourceIndex > node2.sourceIndex && 2) :
    +            1);
    +    }
    +
    +    //get a node with a sourceIndex to use
    +    function getUseNode(node) {
    +      //if the node already has a sourceIndex, use that node
    +      if ("sourceIndex" in node) return node;
    +      //otherwise, insert a comment (which has a sourceIndex but minimal DOM impact) before the node and use that
    +      return node.parentNode.insertBefore(document.createComment(""), node);
    +    }
    +  };
    +
    +  $_.getComputedStyle = function(node, style){
    +    if('getComputedStyle' in window) {
    +      return window.getComputedStyle(node, style); 
    +    }
    +    else {
    +      if( node.currentStyle ) {
    +        return node.currentStyle;
    +      }
    +      return null;
    +    }
    +  };
    +     
    +  return $_;
    +});
    +
    +/*!
    +* This file is part of Aloha Editor Project http://aloha-editor.org
    +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
    +* Contributors http://aloha-editor.org/contribution.php 
    +* Licensed unter the terms of http://www.aloha-editor.org/license.html
    +*//*
    +* Aloha Editor is free software: you can redistribute it and/or modify
    +* it under the terms of the GNU Affero General Public License as published by
    +* the Free Software Foundation, either version 3 of the License, or
    +* (at your option) any later version.*
    +*
    +* Aloha Editor is distributed in the hope that it will be useful,
    +* but WITHOUT ANY WARRANTY; without even the implied warranty of
    +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    +* GNU Affero General Public License for more details.
    +*
    +* You should have received a copy of the GNU Affero General Public License
    +* along with this program. If not, see .
    +*/
    +
    +// Ensure GENTICS Namespace
    +GENTICS = window.GENTICS || {};
    +GENTICS.Utils = GENTICS.Utils || {};
    +
    +define('util/dom',['aloha/jquery', 'util/class', 'aloha/ecma5shims'],
    +function(jQuery, Class, $_) {
    +	
    +	
    +	var
    +		GENTICS = window.GENTICS,
    +//		Class = window.Class,
    +		// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1841493061
    +		Node = {
    +    		'ELEMENT_NODE' : 1,
    +    		'ATTRIBUTE_NODE': 2,
    +    		'TEXT_NODE': 3,
    +    		'CDATA_SECTION_NODE': 4,
    +    		'ENTITY_REFERENCE_NODE': 5,
    +    		'ENTITY_NODE': 6,
    +    		'PROCESSING_INSTRUCTION_NODE': 7,
    +    		'COMMENT_NODE': 8,
    +    		'DOCUMENT_NODE': 9,
    +    		'DOCUMENT_TYPE_NODE': 10,
    +    		'DOCUMENT_FRAGMENT_NODE': 11,
    +    		'NOTATION_NODE': 12,
    +    		//The two nodes are disconnected. Order between disconnected nodes is always implementation-specific.
    +    		'DOCUMENT_POSITION_DISCONNECTED': 0x01,
    +    		//The second node precedes the reference node.
    +    		'DOCUMENT_POSITION_PRECEDING': 0x02, 
    +    		//The node follows the reference node.
    +    		'DOCUMENT_POSITION_FOLLOWING': 0x04,
    +    		//The node contains the reference node. A node which contains is always preceding, too.
    +    		'DOCUMENT_POSITION_CONTAINS': 0x08,
    +    		//The node is contained by the reference node. A node which is contained is always following, too.
    +    		'DOCUMENT_POSITION_CONTAINED_BY': 0x10,
    +    		//The determination of preceding versus following is implementation-specific.
    +    		'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC': 0x20
    +    	};
    +
    +	
    +
    +/**
    + * @namespace GENTICS.Utils
    + * @class Dom provides methods to get information about the DOM and to manipulate it
    + * @singleton
    + */
    +var Dom = Class.extend({
    +	/**
    +	 * Regex to find word characters.
    +	 */
    +	wordRegex: /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0525\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971\u0972\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCB\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA65F\uA662-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/,
    +
    +	/**
    +	 * Regex to find non-word characters.
    +	 */
    +	nonWordRegex: /[^\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0525\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971\u0972\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCB\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA65F\uA662-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/,
    +
    +	/**
    +	 * Tags which can safely be merged
    +	 * @hide
    +	 */
    +	mergeableTags: ['b', 'code', 'del', 'em', 'i', 'ins', 'strong', 'sub', 'sup', '#text'],
    +
    +	/**
    +	 * Tags which do not mark word boundaries
    +	 * @hide
    +	 */
    +	nonWordBoundaryTags: ['a', 'b', 'code', 'del', 'em', 'i', 'ins', 'span', 'strong', 'sub', 'sup', '#text'],
    +
    +	/**
    +	 * Tags which are considered 'nonempty', even if they have no children (or not data)
    +	 * TODO: finish this list
    +	 * @hide
    +	 */
    +	nonEmptyTags: ['br'],
    +
    +	/**
    +	 * Tags which make up Flow Content or Phrasing Content, according to the HTML 5 specification,
    +	 * @see http://dev.w3.org/html5/spec/Overview.html#flow-content
    +	 * @see http://dev.w3.org/html5/spec/Overview.html#phrasing-content
    +	 * @hide
    +	 */
    +	tags: {
    +		'flow' : [ 'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio',
    +				'b', 'bdo', 'blockquote', 'br', 'button', 'canvas', 'cite', 'code',
    +				'command', 'datalist', 'del', 'details', 'dfn', 'div', 'dl', 'em',
    +				'embed', 'fieldset', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
    +				'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'iframe', 'img',
    +				'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'math',
    +				'menu', 'meter', 'nav', 'noscript', 'object', 'ol', 'output', 'p',
    +				'pre', 'progress', 'q', 'ruby', 'samp', 'script', 'section',
    +				'select', 'small', 'span', 'strong', 'style', 'sub', 'sup', 'svg',
    +				'table', 'textarea', 'time', 'ul', 'var', 'video', 'wbr', '#text' ],
    +		'phrasing' : [ 'a', 'abbr', 'area', 'audio', 'b', 'bdo', 'br', 'button',
    +				'canvas', 'cite', 'code', 'command', 'datalist', 'del', 'dfn',
    +				'em', 'embed', 'i', 'iframe', 'img', 'input', 'ins', 'kbd',
    +				'keygen', 'label', 'map', 'mark', 'math', 'meter', 'noscript',
    +				'object', 'output', 'progress', 'q', 'ruby', 'samp', 'script',
    +				'select', 'small', 'span', 'strong', 'sub', 'sup', 'svg',
    +				'textarea', 'time', 'var', 'video', 'wbr', '#text' ]
    +	},
    +
    +	/**
    +	 * Possible children of tags, according to the HTML 5
    +	 * specification.
    +	 * See http://dev.w3.org/html5/spec/Overview.html#elements-1
    +	 * Moved to http://www.whatwg.org/specs/web-apps/current-work/#elements-1
    +	 * @hide
    +	 */
    +	children: {
    +		'a' : 'phrasing', // transparent
    +		'abbr' : 'phrasing',
    +		'address' : 'flow',
    +		'area' : 'empty',
    +		'article' : 'flow',
    +		'aside' : 'flow',
    +		'audio' : 'source', // transparent
    +		'b' : 'phrasing',
    +		'base' : 'empty',
    +		'bdo' : 'phrasing',
    +		'blockquote' : 'phrasing',
    +		'body' : 'flow',
    +		'br' : 'empty',
    +		'button' : 'phrasing',
    +		'canvas' : 'phrasing', // transparent
    +		'caption' : 'flow',
    +		'cite' : 'phrasing',
    +		'code' : 'phrasing',
    +		'col' : 'empty',
    +		'colgroup' : 'col',
    +		'command' : 'empty',
    +		'datalist' : ['phrasing', 'option'],
    +		'dd' : 'flow',
    +		'del' : 'phrasing',
    +		'div' : 'flow',
    +		'details' : ['summary', 'flow'],
    +		'dfn' : 'flow',
    +		'dl' : ['dt','dd'],
    +		'dt' : 'phrasing', // varies
    +		'em' : 'phrasing',
    +		'embed' : 'empty',
    +		'fieldset' : ['legend', 'flow'],
    +		'figcaption': 'flow',
    +		'figure' :  ['figcaption', 'flow'],
    +		'footer' : 'flow',
    +		'form' : 'flow',
    +		'h1' : 'phrasing',
    +		'h2' : 'phrasing',
    +		'h3' : 'phrasing',
    +		'h4' : 'phrasing',
    +		'h5' : 'phrasing',
    +		'h6' : 'phrasing',
    +		//head
    +		'header' : 'flow',
    +		'hgroup' : ['h1','h2','h3','h4','h5','h6'],
    +		'hr' : 'empty',
    +		//html :)
    +		'i' : 'phrasing',
    +		'iframe' : '#text',
    +		'img' : 'empty',
    +		'input' : 'empty',
    +		'ins' : 'phrasing', // transparent
    +		'kbd' : 'phrasing',
    +		'keygen' : 'empty',
    +		'label' : 'phrasing',
    +		'legend' : 'phrasing',
    +		'li' : 'flow',
    +		'link' : 'empty',
    +		'map' : 'area', // transparent
    +		'mark' : 'phrasing',
    +		'menu' : ['li', 'flow'],
    +		'meta' : 'empty',
    +		'meter' : 'phrasing',
    +		'nav' : 'flow',
    +		'noscript' : 'phrasing', // varies
    +		'object' : 'param', // transparent
    +		'ol' : 'li',
    +		'optgroup' : 'option',
    +		'option' : '#text',
    +		'output' : 'phrasing',
    +		'p' : 'phrasing',
    +		'param' : 'empty',
    +		'pre' : 'phrasing',
    +		'progress' : 'phrasing',
    +		'q' : 'phrasing',
    +		'rp' : 'phrasing',
    +		'rt' : 'phrasing',
    +		'ruby' : ['phrasing', 'rt', 'rp'],
    +		's' : 'phrasing',
    +		'samp' : 'pharsing',
    +		'script' : '#script', //script
    +		'section' : 'flow',
    +		'select' : ['option', 'optgroup'],
    +		'small' : 'phrasing',
    +		'source' : 'empty',
    +		'span' : 'phrasing',
    +		'strong' : 'phrasing',
    +		'style' : 'phrasing', // varies
    +		'sub' : 'phrasing',
    +		'summary' : 'phrasing',
    +		'sup' : 'phrasing',
    +		'table' : ['caption', 'colgroup', 'thead', 'tbody', 'tfoot', 'tr'],
    +		'tbody' : 'tr',
    +		'td' : 'flow',
    +		'textarea' : '#text',
    +		'tfoot' : 'tr',
    +		'th' : 'phrasing',
    +		'thead' : 'tr',
    +		'time' : 'phrasing',
    +		'title' : '#text',
    +		'tr' : ['th', 'td'],
    +		'track' : 'empty',
    +		'ul' : 'li',
    +		'var' : 'phrasing',
    +		'video' : 'source', // transparent
    +		'wbr' : 'empty'
    +	},
    +
    +	/**
    +	 * List of nodenames of blocklevel elements
    +	 * TODO: finish this list
    +	 * @hide
    +	 */
    +	blockLevelElements: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'div', 'pre'],
    +
    +	/**
    +	 * List of nodenames of list elements
    +	 * @hide
    +	 */
    +	listElements: ['li', 'ol', 'ul'],
    +
    +	/**
    +	 * Splits a DOM element at the given position up until the limiting object(s), so that it is valid HTML again afterwards.
    +	 * @param {RangeObject} range Range object that indicates the position of the splitting.
    +	 *				This range will be updated, so that it represents the same range as before the split.
    +	 * @param {jQuery} limit Limiting node(s) for the split.
    +	 *				The limiting node will not be included in the split itself.
    +	 *				If no limiting object is set, the document body will be the limiting object.
    +	 * @param {boolean} atEnd If set to true, the DOM will be splitted at the end of the range otherwise at the start.
    +	 * @return {object} jQuery object containing the two root DOM objects of the split, true if the DOM did not need to be split or false if the DOM could not be split
    +	 * @method
    +	 */
    +	split: function (range, limit, atEnd) {
    +		var
    +			splitElement = jQuery(range.startContainer),
    +			splitPosition = range.startOffset,
    +			updateRange, path, parents,
    +			newDom, insertElement, secondPart,
    +			i, pathLength, element, jqelement, children, newElement,
    +			next, prev, offset;
    +
    +
    +		if (atEnd) {
    +			splitElement = jQuery(range.endContainer);
    +			splitPosition = range.endOffset;
    +		}
    +
    +		if (limit.length < 1) {
    +			limit = jQuery(document.body);
    +		}
    +
    +		// we may have to update the range if it is not collapsed and we are splitting at the start
    +		updateRange = (!range.isCollapsed() && !atEnd);
    +
    +		// find the path up to the highest object that will be splitted
    +		parents = splitElement.parents().get();
    +		parents.unshift(splitElement.get(0));
    +
    +		jQuery.each(parents, function(index, element) {
    +			var isLimit = limit.filter(
    +					function(){
    +						return this == element;
    +					}).length;
    +			if (isLimit) {
    +				if (index > 0) {
    +					path = parents.slice(0, index);
    +				}
    +				return false;
    +			}
    +		});
    +
    +		// nothing found to split -> return here
    +		if (! path) {
    +			return true;
    +		}
    +
    +		path = path.reverse();
    +
    +		// iterate over the path, create new dom nodes for every element and move
    +		// the contents right of the split to the new element
    +		for( i=0, pathLength = path.length; i < pathLength; ++i) {
    +			element = path[i];
    +			if (i === pathLength - 1) {
    +				// last element in the path -> we have to split it
    +
    +				// split the last part into two parts
    +				if (element.nodeType === 3) {
    +					// text node
    +					secondPart = document.createTextNode(element.data.substring(splitPosition, element.data.length));
    +					element.data = element.data.substring(0, splitPosition);
    +				} else {
    +					// other nodes
    +					jqelement = jQuery(element);
    +					children = jqelement.contents();
    +					newElement = jqelement.clone(false).empty();
    +					secondPart = newElement.append(children.slice(splitPosition, children.length)).get(0);
    +				}
    +
    +				// update the range if necessary
    +				if (updateRange && range.endContainer === element) {
    +					range.endContainer = secondPart;
    +					range.endOffset -= splitPosition;
    +					range.clearCaches();
    +				}
    +
    +				// add the second part
    +				if (insertElement) {
    +					insertElement.prepend(secondPart);
    +				} else {
    +					jQuery(element).after(secondPart);
    +				}
    +			} else {
    +				// create the new element of the same type and prepend it to the previously created element
    +				newElement = jQuery(element).clone(false).empty();
    +
    +				if (!newDom) {
    +					newDom = newElement;
    +				} else {
    +					insertElement.prepend(newElement);
    +				}
    +				insertElement = newElement;
    +
    +				// move all contents right of the split to the new element
    +				while ( true ) {
    +					next = path[i+1].nextSibling;
    +					if ( !next ) { break; }
    +					insertElement.append(next);
    +				}
    +
    +				// update the range if necessary
    +				if (updateRange && range.endContainer === element) {
    +					range.endContainer = newElement.get(0);
    +					prev = path[i+1];
    +					offset = 0;
    +					while ( true ) {
    +						prev = prev.previousSibling;
    +						if ( !prev ) { break; }
    +						offset++;
    +					}
    +					range.endOffset -= offset;
    +					range.clearCaches();
    +				}
    +			}
    +		}
    +
    +		// append the new dom
    +		jQuery(path[0]).after(newDom);
    +
    +		return jQuery([path[0], newDom ? newDom.get(0) : secondPart]);
    +	},
    +
    +	/**
    +	 * Check whether the HTML 5 specification allows direct nesting of the given DOM
    +	 * objects.
    +	 * @param {object} outerDOMObject
    +	 *            outer (nesting) DOM Object
    +	 * @param {object} innerDOMObject
    +	 *            inner (nested) DOM Object
    +	 * @return {boolean} true when the nesting is allowed, false if not
    +	 * @method
    +	 */
    +	allowsNesting: function (outerDOMObject, innerDOMObject) {
    +		if (!outerDOMObject || !outerDOMObject.nodeName || !innerDOMObject
    +				|| !innerDOMObject.nodeName) {
    +			return false;
    +		}
    +
    +		var outerNodeName = outerDOMObject.nodeName.toLowerCase(),
    +			innerNodeName = innerDOMObject.nodeName.toLowerCase();
    +
    +		if (!this.children[outerNodeName]) {
    +			return false;
    +		}
    +
    +		// check whether the nesting is configured by node names (like for table)
    +		if (this.children[outerNodeName] == innerNodeName) {
    +			return true;
    +		}
    +		if (jQuery.isArray(this.children[outerNodeName])
    +				&& jQuery.inArray(innerNodeName, this.children[outerNodeName]) >= 0) {
    +			return true;
    +		}
    +
    +		if (jQuery.isArray(this.tags[this.children[outerNodeName]])
    +				&& jQuery.inArray(innerNodeName,
    +						this.tags[this.children[outerNodeName]]) >= 0) {
    +			return true;
    +		}
    +
    +		return false;
    +	},
    +
    +	/**
    +	 * Apply the given markup additively to the given range. The given rangeObject will be modified if necessary
    +	 * @param {GENTICS.Utils.RangeObject} rangeObject range to which the markup shall be added
    +	 * @param {jQuery} markup markup to be applied as jQuery object
    +	 * @param {boolean} allownesting true when nesting of the added markup is allowed, false if not (default: false)
    +	 * @method
    +	 */
    +	addMarkup: function (rangeObject, markup, nesting) {
    +		// split partially contained text nodes at the start and end of the range
    +		if (rangeObject.startContainer.nodeType === 3 && rangeObject.startOffset > 0
    +				&& rangeObject.startOffset < rangeObject.startContainer.data.length) {
    +			this.split(rangeObject, jQuery(rangeObject.startContainer).parent(),
    +				false);
    +		}
    +		if (rangeObject.endContainer.nodeType === 3 && rangeObject.endOffset > 0
    +				&& rangeObject.endOffset < rangeObject.endContainer.data.length) {
    +			this.split(rangeObject, jQuery(rangeObject.endContainer).parent(),
    +				true);
    +		}
    +
    +		// get the range tree
    +		var rangeTree = rangeObject.getRangeTree();
    +		this.recursiveAddMarkup(rangeTree, markup, rangeObject, nesting);
    +
    +		// cleanup DOM
    +		this.doCleanup({'merge' : true, 'removeempty' : true}, rangeObject);
    +	},
    +
    +	/**
    +	 * Recursive helper method to add the given markup to the range
    +	 * @param rangeTree rangetree at the current level
    +	 * @param markup markup to be applied
    +	 * @param rangeObject range object, which eventually is updated
    +	 * @param nesting true when nesting of the added markup is allowed, false if not
    +	 * @hide
    +	 */
    +	recursiveAddMarkup: function (rangeTree, markup, rangeObject, nesting) {
    +		var i, innerRange, rangeLength;
    +
    +		// iterate through all rangetree objects of that level
    +		for ( i = 0, rangeLength = rangeTree.length; i < rangeLength; ++i) {
    +			// check whether the rangetree object is fully contained and the markup may be wrapped around the object
    +			if (rangeTree[i].type == 'full' && this.allowsNesting(markup.get(0), rangeTree[i].domobj)) {
    +				// we wrap the object, when
    +				// 1. nesting of markup is allowed or the node is not of the markup to be added
    +				// 2. the node an element node or a non-empty text node
    +				if ((nesting || rangeTree[i].domobj.nodeName != markup.get(0).nodeName)
    +						&& (rangeTree[i].domobj.nodeType !== 3 || jQuery
    +								.trim(rangeTree[i].domobj.data).length !== 0)) {
    +					// wrap the object
    +					jQuery(rangeTree[i].domobj).wrap(markup);
    +
    +					// TODO eventually update the range (if it changed)
    +
    +					// when nesting is not allowed, we remove the markup from the inner element
    +					if (!nesting && rangeTree[i].domobj.nodeType !== 3) {
    +						innerRange = new GENTICS.Utils.RangeObject();
    +						innerRange.startContainer = innerRange.endContainer = rangeTree[i].domobj.parentNode;
    +						innerRange.startOffset = 0;
    +						innerRange.endOffset = innerRange.endContainer.childNodes.length;
    +						this.removeMarkup(innerRange, markup, jQuery(rangeTree[i].domobj.parentNode));
    +					}
    +				}
    +			} else {
    +				// TODO check whether the object may be replaced by the given markup
    +				if (false) {
    +					// TODO replace
    +				} else {
    +					// recurse into the children (if any), but not if nesting is not
    +					// allowed and the object is of the markup to be added
    +					if ((nesting || (rangeTree[i].domobj && rangeTree[i].domobj.nodeName !== markup.get(0).nodeName))
    +						&& rangeTree[i].children && rangeTree[i].children.length > 0) {
    +						this.recursiveAddMarkup(rangeTree[i].children, markup);
    +					}
    +				}
    +			}
    +		}
    +	},
    +
    +	/**
    +	 * Find the highest occurrence of a node with given nodename within the parents
    +	 * of the start. When limit objects are given, the search stops there.
    +	 * The limiting object is of the found type, it won't be considered
    +	 * @param {DOMObject} start start object
    +	 * @param {String} nodeName name of the node to search for (case-insensitive)
    +	 * @param {jQuery} limit Limiting node(s) as jQuery object (if none given, the search will stop when there are no more parents)
    +	 * @return {DOMObject} the found DOM object or undefined
    +	 * @method
    +	 */
    +	findHighestElement: function (start, nodeName, limit) {
    +		nodeName = nodeName.toLowerCase();
    +
    +		// this will be the highest found markup object (up to a limit object)
    +		var highestObject,
    +		// blah
    +			testObject = start,
    +		// helper function to stop when we reach a limit object
    +			isLimit = limit ? function () {
    +			return limit.filter(
    +					function() {
    +						return testObject == this;
    +					}
    +			).length;
    +		} : function () {
    +			return false;
    +		};
    +
    +		// now get the highest parent that has the given markup (until we reached
    +		// one of the limit objects or there are no more parent nodes)
    +		while (!isLimit() && testObject) {
    +			if (testObject.nodeName.toLowerCase() === nodeName) {
    +				highestObject = testObject;
    +			}
    +			testObject = testObject.parentNode;
    +		}
    +
    +		return highestObject;
    +	},
    +
    +	/**
    +	 * Remove the given markup from the given range. The given rangeObject will be modified if necessary
    +	 * TODO: add parameter deep/shallow
    +	 * @param {GENTICS.Utils.RangeObject} rangeObject range from which the markup shall be removed
    +	 * @param {jQuery} markup markup to be removed as jQuery object
    +	 * @param {jQuery} limit Limiting node(s) as jQuery object
    +	 * @method
    +	 */
    +	removeMarkup: function (rangeObject, markup, limit) {
    +		var nodeName = markup.get(0).nodeName,
    +			startSplitLimit = this.findHighestElement(rangeObject.startContainer, nodeName, limit),
    +			endSplitLimit = this.findHighestElement(rangeObject.endContainer, nodeName, limit),
    +			didSplit = false,
    +			highestObject, root, rangeTree;
    +
    +		if (startSplitLimit && rangeObject.startOffset > 0) {
    +			// when the start is in the start of its container, we don't split
    +			this.split(rangeObject, jQuery(startSplitLimit).parent(), false);
    +			didSplit = true;
    +		}
    +
    +		if (endSplitLimit) {
    +			// when the end is in the end of its container, we don't split
    +			if (rangeObject.endContainer.nodeType === 3 && rangeObject.endOffset < rangeObject.endContainer.data.length) {
    +				this.split(rangeObject, jQuery(endSplitLimit).parent(), true);
    +				didSplit = true;
    +			}
    +			if (rangeObject.endContainer.nodeType === 1 && rangeObject.endOffset < rangeObject.childNodes.length) {
    +				this.split(rangeObject, jQuery(endSplitLimit).parent(), true);
    +				didSplit = true;
    +			}
    +		}
    +
    +		// when we split the DOM, we maybe need to correct the range
    +		if (didSplit) {
    +			rangeObject.correctRange();
    +		}
    +
    +		// find the highest occurrence of the markup
    +		highestObject = this.findHighestElement(rangeObject.getCommonAncestorContainer(), nodeName, limit);
    +		root = highestObject ? highestObject.parentNode : rangeObject.getCommonAncestorContainer();
    +
    +		if (root) {
    +			// construct the range tree
    +			rangeTree = rangeObject.getRangeTree(root);
    +	
    +			// remove the markup from the range tree
    +			this.recursiveRemoveMarkup(rangeTree, markup);
    +	
    +			// cleanup DOM
    +			this.doCleanup({'merge' : true, 'removeempty' : true}, rangeObject, root);
    +		}
    +	},
    +
    +	/**
    +	 * TODO: pass the range itself and eventually update it if necessary
    +	 * Recursive helper method to remove the given markup from the range
    +	 * @param rangeTree rangetree at the current level
    +	 * @param markup markup to be applied
    +	 * @hide
    +	 */
    +	recursiveRemoveMarkup: function (rangeTree, markup) {
    +		var i, rangeLength, content;
    +		// iterate over the rangetree objects of this level
    +		for (i = 0, rangeLength = rangeTree.length; i < rangeLength; ++i) {
    +			// check whether the object is the markup to be removed and is fully into the range
    +			if (rangeTree[i].type == 'full' && rangeTree[i].domobj.nodeName == markup.get(0).nodeName) {
    +				// found the markup, so remove it
    +				content = jQuery(rangeTree[i].domobj).contents();
    +				if (content.length > 0) {
    +					// when the object has children, we unwrap them
    +					content.first().unwrap();
    +				} else {
    +					// obj has no children, so just remove it
    +					jQuery(rangeTree[i].domobj).remove();
    +				}
    +			}
    +
    +			// if the object has children, we do the recursion now
    +			if (rangeTree[i].children) {
    +				this.recursiveRemoveMarkup(rangeTree[i].children, markup);
    +			}
    +		}
    +	},
    +
    +	/**
    +	 * Cleanup the DOM, starting with the given startobject (or the common ancestor container of the given range)
    +	 * ATTENTION: If range is a selection you need to update the selection after doCleanup
    +	 * Cleanup modes (given as properties in 'cleanup'):
    +	 * 
    +	 * - merge: merges multiple successive nodes of same type, if this is allowed, starting at the children of the given node (defaults to false)
    +	 * - removeempty: removes empty element nodes (defaults to false)
    +	 * 
    + * Example for calling this method:
    + * GENTICS.Utils.Dom.doCleanup({merge:true,removeempty:false}, range) + * @param {object} cleanup type of cleanup to be done + * @param {GENTICS.Utils.RangeObject} rangeObject range which is eventually updated + * @param {DOMObject} start start object, if not given, the commonancestorcontainer is used as startobject insted + * @return {boolean} true when the range (startContainer/startOffset/endContainer/endOffset) was modified, false if not + * @method + */ + doCleanup: function(cleanup, rangeObject, start) { + var that = this, prevNode, modifiedRange, startObject, startOffset, endOffset; + + if (typeof cleanup === 'undefined') { + cleanup = {}; + } + if (typeof cleanup.merge === 'undefined') { + cleanup.merge = false; + } + if (typeof cleanup.removeempty === 'undefined') { + cleanup.removeempty = false; + } + + if (typeof start === 'undefined' && rangeObject) { + start = rangeObject.getCommonAncestorContainer(); + } + // remember the previous node here (successive nodes of same type will be merged into this) + prevNode = false; + // check whether the range needed to be modified during merging + modifiedRange = false; + // get the start object + startObject = jQuery(start); + startOffset = rangeObject.startOffset; + endOffset = rangeObject.endOffset; + + // iterate through all sub nodes + startObject.contents().each(function(index) { + // decide further actions by node type + switch(this.nodeType) { + // found a non-text node + case 1: + if (prevNode && prevNode.nodeName == this.nodeName) { + // found a successive node of same type + + // now we check whether the selection starts or ends in the mother node after the current node + if (rangeObject.startContainer === startObject && startOffset > index) { + // there will be one less object, so reduce the startOffset by one + rangeObject.startOffset -= 1; + // set the flag for range modification + modifiedRange = true; + } + if (rangeObject.endContainer === startObject && endOffset > index) { + // there will be one less object, so reduce the endOffset by one + rangeObject.endOffset -= 1; + // set the flag for range modification + modifiedRange = true; + } + + // merge the contents of this node into the previous one + jQuery(prevNode).append(jQuery(this).contents()); + + // after merging, we eventually need to cleanup the prevNode again + modifiedRange |= that.doCleanup(cleanup, rangeObject, prevNode); + + // remove this node + jQuery(this).remove(); + + } else { + + // do the recursion step here + modifiedRange |= that.doCleanup(cleanup, rangeObject, this); + + // eventually remove empty elements + var removed = false; + if (cleanup.removeempty) { + if (GENTICS.Utils.Dom.isBlockLevelElement(this) && this.childNodes.length === 0) { +// jQuery(this).remove(); + removed = true; + } + if (jQuery.inArray(this.nodeName.toLowerCase(), that.mergeableTags) >= 0 + && jQuery(this).text().length === 0 && this.childNodes.length === 0) { +// jQuery(this).remove(); + removed = true; + } + } + + // when the current node was not removed, we eventually store it as previous (mergeable) tag + if (!removed) { + if (jQuery.inArray(this.nodeName.toLowerCase(), that.mergeableTags) >= 0) { + prevNode = this; + } else { + prevNode = false; + } + } else { + // now we check whether the selection starts or ends in the mother node of this + if (rangeObject.startContainer === this.parentNode && startOffset > index) { + // there will be one less object, so reduce the startOffset by one + rangeObject.startOffset = rangeObject.startOffset - 1; + // set the flag for range modification + modifiedRange = true; + } + if (rangeObject.endContainer === this.parentNode && endOffset > index) { + // there will be one less object, so reduce the endOffset by one + rangeObject.endOffset = rangeObject.endOffset - 1; + // set the flag for range modification + modifiedRange = true; + } + + // remove this text node + jQuery(this).remove(); + + } + } + + break; + // found a text node + case 3: + // found a text node + if (prevNode && prevNode.nodeType === 3 && cleanup.merge) { + // the current text node will be merged into the last one, so + // check whether the selection starts or ends in the current + // text node + if (rangeObject.startContainer === this) { + // selection starts in the current text node + + // update the start container to the last node + rangeObject.startContainer = prevNode; + + // update the start offset + rangeObject.startOffset += prevNode.nodeValue.length; + + // set the flag for range modification + modifiedRange = true; + + } else if (rangeObject.startContainer === prevNode.parentNode + && rangeObject.startOffset === that.getIndexInParent(prevNode) + 1) { + // selection starts right between the previous and current text nodes (which will be merged) + + // update the start container to the previous node + rangeObject.startContainer = prevNode; + + // set the start offset + rangeObject.startOffset = prevNode.nodeValue.length; + + // set the flag for range modification + modifiedRange = true; + } + + if (rangeObject.endContainer === this) { + // selection ends in the current text node + + // update the end container to be the last node + rangeObject.endContainer = prevNode; + + // update the end offset + rangeObject.endOffset += prevNode.nodeValue.length; + + // set the flag for range modification + modifiedRange = true; + + } else if (rangeObject.endContainer === prevNode.parentNode + && rangeObject.endOffset === that.getIndexInParent(prevNode) + 1) { + // selection ends right between the previous and current text nodes (which will be merged) + + // update the end container to the previous node + rangeObject.endContainer = prevNode; + + // set the end offset + rangeObject.endOffset = prevNode.nodeValue.length; + + // set the flag for range modification + modifiedRange = true; + } + + // now append the contents of the current text node into the previous + prevNode.data += this.data; + + // remove empty text nodes + } else if ( this.nodeValue === '' && cleanup.removeempty ) { + // do nothing here. + + // remember it as the last text node if not empty + } else if ( !(this.nodeValue === '' && cleanup.removeempty) ) { + prevNode = this; + // we are finish here don't delete this node + break; + } + + // now we check whether the selection starts or ends in the mother node of this + if (rangeObject.startContainer === this.parentNode && rangeObject.startOffset > index) { + // there will be one less object, so reduce the startOffset by one + rangeObject.startOffset = rangeObject.startOffset - 1; + // set the flag for range modification + modifiedRange = true; + } + if (rangeObject.endContainer === this.parentNode && rangeObject.endOffset > index) { + // there will be one less object, so reduce the endOffset by one + rangeObject.endOffset = rangeObject.endOffset - 1; + // set the flag for range modification + modifiedRange = true; + } + + // remove this text node + jQuery(this).remove(); + + break; + } + }); + + // eventually remove the startnode itself +// if (cleanup.removeempty +// && GENTICS.Utils.Dom.isBlockLevelElement(start) +// && (!start.childNodes || start.childNodes.length === 0)) { +// if (rangeObject.startContainer == start) { +// rangeObject.startContainer = start.parentNode; +// rangeObject.startOffset = GENTICS.Utils.Dom.getIndexInParent(start); +// } +// if (rangeObject.endContainer == start) { +// rangeObject.endContainer = start.parentNode; +// rangeObject.endOffset = GENTICS.Utils.Dom.getIndexInParent(start); +// } +// startObject.remove(); +// modifiedRange = true; +// } + + if (modifiedRange) { + rangeObject.clearCaches(); + } + + return modifiedRange; + }, + + /** + * Get the index of the given node within its parent node + * @param {DOMObject} node node to check + * @return {Integer} index in the parent node or false if no node given or node has no parent + * @method + */ + getIndexInParent: function (node) { + if (!node) { + return false; + } + + var + index = 0, + check = node.previousSibling; + + while(check) { + index++; + check = check.previousSibling; + } + + return index; + }, + + /** + * Check whether the given node is a blocklevel element + * @param {DOMObject} node node to check + * @return {boolean} true if yes, false if not (or null) + * @method + */ + isBlockLevelElement: function (node) { + if (!node) { + return false; + } + if (node.nodeType === 1 && jQuery.inArray(node.nodeName.toLowerCase(), this.blockLevelElements) >= 0) { + return true; + } else { + return false; + } + }, + + /** + * Check whether the given node is a linebreak element + * @param {DOMObject} node node to check + * @return {boolean} true for linebreak elements, false for everything else + * @method + */ + isLineBreakElement: function (node) { + if (!node) { + return false; + } + return node.nodeType === 1 && node.nodeName.toLowerCase() == 'br'; + }, + + /** + * Check whether the given node is a list element + * @param {DOMObject} node node to check + * @return {boolean} true for list elements (li, ul, ol), false for everything else + * @method + */ + isListElement: function (node) { + if (!node) { + return false; + } + return node.nodeType === 1 && jQuery.inArray(node.nodeName.toLowerCase(), this.listElements) >= 0; + }, + + /** + * This method checks, whether the passed dom object is a dom object, that would + * be split in cases of pressing enter. This currently is true for paragraphs + * and headings + * @param {DOMObject} el + * dom object to check + * @return {boolean} true for split objects, false for other + * @method + */ + isSplitObject: function(el) { + if (el.nodeType === 1){ + switch(el.nodeName.toLowerCase()) { + case 'p': + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + case 'li': + return true; + } + } + return false; + }, + + /** + * Starting with the given position (between nodes), search in the given direction to an adjacent notempty text node + * @param {DOMObject} parent parent node containing the position + * @param {Integer} index index of the position within the parent node + * @param {boolean} searchleft true when search direction is 'left' (default), false for 'right' + * @param {object} stopat define at which types of element we shall stop, may contain the following properties + *
    +	 * - blocklevel (default: true)
    +	 * - list (default: true)
    +	 * - linebreak (default: true)
    +	 * 
    + * @return {DOMObject} the found text node or false if none found + * @method + */ + searchAdjacentTextNode: function (parent, index, searchleft, stopat) { + if (!parent || parent.nodeType !== 1 || index < 0 || index > parent.childNodes.length) { + return false; + } + + if (typeof stopat === 'undefined') { + stopat = {'blocklevel' : true, 'list' : true, 'linebreak' : true}; + } + + if (typeof stopat.blocklevel === 'undefined') { + stopat.blocklevel = true; + } + if (typeof stopat.list === 'undefined') { + stopat.list = true; + } + if (typeof stopat.linebreak === 'undefined') { + stopat.linebreak = true; + } + + if (typeof searchleft === 'undefined') { + searchleft = true; + } + + var + nextNode, + currentParent = parent; + + // start at the node left/right of the given position + if (searchleft && index > 0) { + nextNode = parent.childNodes[index - 1]; + } + if (!searchleft && index < parent.childNodes.length) { + nextNode = parent.childNodes[index]; + } + + //currentParent is not a number therefore it is sufficient to directly test for it with while(currentParent) + //otherwise there would be an error if the object is null + while (currentParent) { + //while (typeof currentParent !== 'undefined') { + if (!nextNode) { + // no next node found, check whether the parent is a blocklevel element + if (stopat.blocklevel && this.isBlockLevelElement(currentParent)) { + // do not leave block level elements + return false; + } else if (stopat.list && this.isListElement(currentParent)) { + // do not leave list elements + return false; + } else { + // continue with the parent + nextNode = searchleft ? currentParent.previousSibling : currentParent.nextSibling; + currentParent = currentParent.parentNode; + } + } else if (nextNode.nodeType === 3 && jQuery.trim(nextNode.data).length > 0) { + // we are lucky and found a notempty text node + return nextNode; + } else if (stopat.blocklevel && this.isBlockLevelElement(nextNode)) { + // we found a blocklevel element, stop here + return false; + } else if (stopat.linebreak && this.isLineBreakElement(nextNode)) { + // we found a linebreak, stop here + return false; + } else if (stopat.list && this.isListElement(nextNode)) { + // we found a linebreak, stop here + return false; + } else if (nextNode.nodeType === 3) { + // we found an empty text node, so step to the next + nextNode = searchleft ? nextNode.previousSibling : nextNode.nextSibling; + } else { + // we found a non-blocklevel element, step into + currentParent = nextNode; + nextNode = searchleft ? nextNode.lastChild : nextNode.firstChild; + } + } + }, + + /** + * Insert the given DOM Object into the start/end of the given range. The method + * will find the appropriate place in the DOM tree for inserting the given + * object, and will eventually split elements in between. The given range will + * be updated if necessary. The updated range will NOT embrace the inserted + * object, which means that the object is actually inserted before or after the + * given range (depending on the atEnd parameter) + * + * @param {jQuery} + * object object to insert into the DOM + * @param {GENTICS.Utils.RangeObject} + * range range where to insert the object (at start or end) + * @param {jQuery} + * limit limiting object(s) of the DOM modification + * @param {boolean} + * atEnd true when the object shall be inserted at the end, false for + * insertion at the start (default) + * @param {boolean} + * true when the insertion shall be done, even if inserting the element + * would not be allowed, false to deny inserting unallowed elements (default) + * @return true if the object could be inserted, false if not. + * @method + */ + insertIntoDOM: function (object, range, limit, atEnd, force) { + // first find the appropriate place to insert the given object + var parentElements = range.getContainerParents(limit, atEnd), + that = this, + newParent, + container, offset, splitParts, contents; + + if (!limit) { + limit = jQuery(document.body); + } + + // if no parent elements exist (up to the limit), the new parent will be the + // limiter itself + if (parentElements.length === 0) { + newParent = limit.get(0); + } else { + jQuery.each(parentElements, function (index, parent) { + if (that.allowsNesting(parent, object.get(0))) { + newParent = parent; + return false; + } + }); + } + + if (typeof newParent === 'undefined' && limit.length > 0) { + // found no possible new parent, so split up to the limit object + newParent = limit.get(0); + } + + // check whether it is allowed to insert the element at all + if (!this.allowsNesting(newParent, object.get(0)) && !force) { + return false; + } + + if (typeof newParent !== 'undefined') { + // we found a possible new parent, so we split the DOM up to the new parent + splitParts = this.split(range, jQuery(newParent), atEnd); + if (splitParts === true) { + // DOM was not split (there was no need to split it), insert the new object anyway + container = range.startContainer; + offset = range.startOffset; + if (atEnd) { + container = range.endContainer; + offset = range.endOffset; + } + if (offset === 0) { + // insert right before the first element in the container + contents = jQuery(container).contents(); + if (contents.length > 0) { + contents.eq(0).before(object); + } else { + jQuery(container).append(object); + } + return true; + } else { + // insert right after the element at offset-1 + jQuery(container).contents().eq(offset-1).after(object); + return true; + } + } else if (splitParts) { + // if the DOM could be split, we insert the new object in between the split parts + splitParts.eq(0).after(object); + return true; + } else { + // could not split, so could not insert + return false; + } + } else { + // found no possible new parent, so we shall not insert + return false; + } + }, + + /** + * Remove the given DOM object from the DOM and modify the given range to reflect the user expected range after the object was removed + * TODO: finish this + * @param {DOMObject} object DOM object to remove + * @param {GENTICS.Utils.RangeObject} range range which eventually be modified + * @param {boolean} preserveContent true if the contents of the removed DOM object shall be preserved, false if not (default: false) + * @return true if the DOM object could be removed, false if not + * @hide + */ + removeFromDOM: function (object, range, preserveContent) { + if (preserveContent) { + // check whether the range will need modification + var indexInParent = this.getIndexInParent(object), + numChildren = jQuery(object).contents().length, + parent = object.parentNode; + + if (range.startContainer == parent && range.startOffset > indexInParent) { + range.startOffset += numChildren - 1; + } else if (range.startContainer == object) { + range.startContainer = parent; + range.startOffset = indexInParent + range.startOffset; + } + + if (range.endContainer == parent && range.endOffset > indexInParent) { + range.endOffset += numChildren - 1; + } else if (range.endContainer == object) { + range.endContainer = parent; + range.endOffset = indexInParent + range.endOffset; + } + + // we simply unwrap the children of the object + jQuery(object).contents().unwrap(); + + // optionally do cleanup + this.doCleanup({'merge' : true}, range, parent); + } else { + // TODO + } + }, + + /** + * Remove the content defined by the given range from the DOM. Update the given + * range object to be a collapsed selection at the place of the previous + * selection. + * @param rangeObject range object + * @return true if the range could be removed, false if not + */ + removeRange: function (rangeObject) { + if (!rangeObject) { + // no range given + return false; + } + if (rangeObject.isCollapsed()) { + // the range is collapsed, nothing to delete + return false; + } + + // split partially contained text nodes at the start and end of the range + if (rangeObject.startContainer.nodeType == 3 && rangeObject.startOffset > 0 + && rangeObject.startOffset < rangeObject.startContainer.data.length) { + this.split(rangeObject, jQuery(rangeObject.startContainer).parent(), + false); + } + if (rangeObject.endContainer.nodeType == 3 && rangeObject.endOffset > 0 + && rangeObject.endOffset < rangeObject.endContainer.data.length) { + this.split(rangeObject, jQuery(rangeObject.endContainer).parent(), + true); + } + + // construct the range tree + var rangeTree = rangeObject.getRangeTree(); + + // collapse the range + rangeObject.endContainer = rangeObject.startContainer; + rangeObject.endOffset = rangeObject.startOffset; + + // remove the markup from the range tree + this.recursiveRemoveRange(rangeTree, rangeObject); + + // do some cleanup + this.doCleanup({'merge' : true}, rangeObject); +// this.doCleanup({'merge' : true, 'removeempty' : true}, rangeObject); + + // clear the caches of the range object + rangeObject.clearCaches(); + }, + + recursiveRemoveRange: function (rangeTree, rangeObject) { + // iterate over the rangetree objects of this level + for (var i = 0; i < rangeTree.length; ++i) { + // check for nodes fully in the range + if (rangeTree[i].type == 'full') { + // if the domobj is the startcontainer, or the startcontainer is inside the domobj, we need to update the rangeObject + if (jQuery(rangeObject.startContainer).parents().andSelf().filter(rangeTree[i].domobj).length > 0) { + rangeObject.startContainer = rangeObject.endContainer = rangeTree[i].domobj.parentNode; + rangeObject.startOffset = rangeObject.endOffset = this.getIndexInParent(rangeTree[i].domobj); + } + + // remove the object from the DOM + jQuery(rangeTree[i].domobj).remove(); + } else if (rangeTree[i].type == 'partial' && rangeTree[i].children) { + // node partially selected and has children, so do recursion + this.recursiveRemoveRange(rangeTree[i].children, rangeObject); + } + } + }, + + /** + * Extend the given range to have start and end at the nearest word boundaries to the left (start) and right (end) + * @param {GENTICS.Utils.RangeObject} range range to be extended + * @param {boolean} fromBoundaries true if extending will also be done, if one or both ends of the range already are at a word boundary, false if not, default: false + * @method + */ + extendToWord: function (range, fromBoundaries) { + // search the word boundaries to the left and right + var leftBoundary = this.searchWordBoundary(range.startContainer, range.startOffset, true), + rightBoundary = this.searchWordBoundary(range.endContainer, range.endOffset, false); + + // check whether we must not extend the range from word boundaries + if (!fromBoundaries) { + // we only extend the range if both ends would be different + if (range.startContainer == leftBoundary.container && range.startOffset == leftBoundary.offset) { + return; + } + if (range.endContainer == rightBoundary.container && range.endOffset == rightBoundary.offset) { + return; + } + } + + // set the new boundaries + range.startContainer = leftBoundary.container; + range.startOffset = leftBoundary.offset; + range.endContainer = rightBoundary.container; + range.endOffset = rightBoundary.offset; + + // correct the range + range.correctRange(); + + // clear caches + range.clearCaches(); + }, + + /** + * Helper method to check whether the given DOM object is a word boundary. + * @param {DOMObject} object DOM object in question + * @return {boolean} true when the DOM object is a word boundary, false if not + * @hide + */ + isWordBoundaryElement: function (object) { + if (!object || !object.nodeName) { + return false; + } + return jQuery.inArray(object.nodeName.toLowerCase(), this.nonWordBoundaryTags) == -1; + }, + + /** + * Search for the next word boundary, starting at the given position + * @param {DOMObject} container container of the start position + * @param {Integer} offset offset of the start position + * @param {boolean} searchleft true for searching to the left, false for searching to the right (default: true) + * @return {object} object with properties 'container' and 'offset' marking the found word boundary + * @method + */ + searchWordBoundary: function (container, offset, searchleft) { + if (typeof searchleft === 'undefined') { + searchleft = true; + } + var boundaryFound = false, wordBoundaryPos, tempWordBoundaryPos, textNode; + while (!boundaryFound) { + // check the node type + if (container.nodeType === 3) { + // we are currently in a text node + + // find the nearest word boundary character + if (!searchleft) { + // search right + wordBoundaryPos = container.data.substring(offset).search(this.nonWordRegex); + if (wordBoundaryPos != -1) { + // found a word boundary + offset = offset + wordBoundaryPos; + boundaryFound = true; + } else { + // found no word boundary, so we set the position after the container + offset = this.getIndexInParent(container) + 1; + container = container.parentNode; + } + } else { + // search left + wordBoundaryPos = container.data.substring(0, offset).search(this.nonWordRegex); + tempWordBoundaryPos = wordBoundaryPos; + while (tempWordBoundaryPos != -1) { + wordBoundaryPos = tempWordBoundaryPos; + tempWordBoundaryPos = container.data.substring( + wordBoundaryPos + 1, offset).search(this.nonWordRegex); + if (tempWordBoundaryPos != -1) { + tempWordBoundaryPos = tempWordBoundaryPos + wordBoundaryPos + 1; + } + } + + if (wordBoundaryPos != -1) { + // found a word boundary + offset = wordBoundaryPos + 1; + boundaryFound = true; + } else { + // found no word boundary, so we set the position before the container + offset = this.getIndexInParent(container); + container = container.parentNode; + } + } + } else if (container.nodeType === 1) { + // we are currently in an element node (between nodes) + + if (!searchleft) { + // check whether there is an element to the right + if (offset < container.childNodes.length) { + // there is an element to the right, check whether it is a word boundary element + if (this.isWordBoundaryElement(container.childNodes[offset])) { + // we are done + boundaryFound = true; + } else { + // element to the right is no word boundary, so enter it + container = container.childNodes[offset]; + offset = 0; + } + } else { + // no element to the right, check whether the element itself is a boundary element + if (this.isWordBoundaryElement(container)) { + // we are done + boundaryFound = true; + } else { + // element itself is no boundary element, so go to parent + offset = this.getIndexInParent(container) + 1; + container = container.parentNode; + } + } + } else { + // check whether there is an element to the left + if (offset > 0) { + // there is an element to the left, check whether it is a word boundary element + if (this.isWordBoundaryElement(container.childNodes[offset - 1])) { + // we are done + boundaryFound = true; + } else { + // element to the left is no word boundary, so enter it + container = container.childNodes[offset - 1]; + offset = container.nodeType === 3 ? container.data.length : container.childNodes.length; + } + } else { + // no element to the left, check whether the element itself is a boundary element + if (this.isWordBoundaryElement(container)) { + // we are done + boundaryFound = true; + } else { + // element itself is no boundary element, so go to parent + offset = this.getIndexInParent(container); + container = container.parentNode; + } + } + } + } + } + + if (container.nodeType !== 3) { + textNode = this.searchAdjacentTextNode(container, offset, !searchleft); + if (textNode) { + container = textNode; + offset = searchleft ? 0 : container.data.length; + } + } + + return {'container' : container, 'offset' : offset}; + }, + + /** + * Check whether the given dom object is empty + * @param {DOMObject} domObject object to check + * @return {boolean} true when the object is empty, false if not + * @method + */ + isEmpty: function (domObject) { + // a non dom object is considered empty + if (!domObject) { + return true; + } + + // some tags are considered to be non-empty + if (jQuery.inArray(domObject.nodeName.toLowerCase(), this.nonEmptyTags) != -1) { + return false; + } + + // text nodes are not empty, if they contain non-whitespace characters + if (domObject.nodeType === 3) { + return domObject.data.search(/\S/) == -1; + } + + // all other nodes are not empty if they contain at least one child which is not empty + for (var i = 0, childNodes = domObject.childNodes.length; i < childNodes; ++i) { + if (!this.isEmpty(domObject.childNodes[i])) { + return false; + } + } + + // found no contents, so the element is empty + return true; + }, + + /** + * Set the cursor (collapsed selection) right after the given DOM object + * @param domObject DOM object + * @method + */ + setCursorAfter: function (domObject) { + var + newRange = new GENTICS.Utils.RangeObject(), + index = this.getIndexInParent(domObject), + targetNode, + offset; + + // selection cannot be set between to TEXT_NODEs + // if domOject is a Text node set selection at last position in that node + if ( domObject.nodeType == 3) { + targetNode = domObject; + offset = targetNode.nodeValue.length; + + // if domOject is a Text node set selection at last position in that node + } else if ( domObject.nextSibling && domObject.nextSibling.nodeType == 3) { + targetNode = domObject.nextSibling; + offset = 0; + } else { + targetNode = domObject.parentNode; + offset = this.getIndexInParent(domObject) + 1; + } + + newRange.startContainer = newRange.endContainer = targetNode; + newRange.startOffset = newRange.endOffset = offset; + + // select the range + newRange.select(); + + return newRange; + }, + + /** + * Select a DOM node + * will create a new range which spans the provided dom node and selects it afterwards + * @param domObject DOM object + * @method + */ + selectDomNode: function (domObject) { + var newRange = new GENTICS.Utils.RangeObject(); + newRange.startContainer = newRange.endContainer = domObject.parentNode; + newRange.startOffset = this.getIndexInParent(domObject); + newRange.endOffset = newRange.startOffset + 1; + newRange.select(); + }, + + /** + * Set the cursor (collapsed selection) at the start into the given DOM object + * @param domObject DOM object + * @method + */ + setCursorInto: function (domObject) { + // set a new range into the given dom object + var newRange = new GENTICS.Utils.RangeObject(); + newRange.startContainer = newRange.endContainer = domObject; + newRange.startOffset = newRange.endOffset = 0; + + // select the range + newRange.select(); + }, + + + /** + * "An editing host is a node that is either an Element with a contenteditable + * attribute set to the true state, or the Element child of a Document whose + * designMode is enabled." + * @param domObject DOM object + * @method + */ + isEditingHost: function (node) { + return node + && node.nodeType == 1 //ELEMENT_NODE + && (node.contentEditable == "true" + || (node.parentNode + && node.parentNode.nodeType == 9 //DOCUEMENT_NODE + && node.parentNode.designMode == "on")); + }, + + /** + * "Something is editable if it is a node which is not an editing host, does + * not have a contenteditable attribute set to the false state, and whose + * parent is an editing host or editable." + * @param domObject DOM object + * @method + */ + isEditable: function (node) { + // This is slightly a lie, because we're excluding non-HTML elements with + // contentEditable attributes. + return node + && !this.isEditingHost(node) + && (node.nodeType != 1 || node.contentEditable != "false") // ELEMENT_NODE + && (this.isEditingHost(node.parentNode) || this.isEditable(node.parentNode)); + }, + + /** + * "The editing host of node is null if node is neither editable nor an editing + * host; node itself, if node is an editing host; or the nearest ancestor of + * node that is an editing host, if node is editable." + * @param domObject DOM object + * @method + */ + getEditingHostOf: function(node) { + if (this.isEditingHost(node)) { + return node; + } else if (this.isEditable(node)) { + var ancestor = node.parentNode; + while (!this.isEditingHost(ancestor)) { + ancestor = ancestor.parentNode; + } + return ancestor; + } else { + return null; + } + }, + + /** + * + * "Two nodes are in the same editing host if the editing host of the first is + * non-null and the same as the editing host of the second." + * @param node1 DOM object + * @param node2 DOM object + * @method + */ + inSameEditingHost: function (node1, node2) { + return this.getEditingHostOf(node1) + && this.getEditingHostOf(node1) == this.getEditingHostOf(node2); + }, + + // "A block node is either an Element whose "display" property does not have + // resolved value "inline" or "inline-block" or "inline-table" or "none", or a + // Document, or a DocumentFragment." + isBlockNode: function (node) { + return node + && ((node.nodeType == $_.Node.ELEMENT_NODE && $_( ["inline", "inline-block", "inline-table", "none"] ).indexOf($_.getComputedStyle(node).display) == -1) + || node.nodeType == $_.Node.DOCUMENT_NODE + || node.nodeType == $_.Node.DOCUMENT_FRAGMENT_NODE); + }, + + /** + * Get the first visible child of the given node. + * @param node node + * @param includeNode when set to true, the node itself may be returned, otherwise only children are allowed + * @return first visible child or null if none found + */ + getFirstVisibleChild: function (node, includeNode) { + // no node -> no child + if (!node) { + return null; + } + + // check whether the node itself is visible + if ((node.nodeType == $_.Node.TEXT_NODE && this.isEmpty(node)) + || (node.nodeType == $_.Node.ELEMENT_NODE && node.offsetHeight == 0 && jQuery.inArray(node.nodeName.toLowerCase(), this.nonEmptyTags) === -1)) { + return null; + } + + // if the node is a text node, or does not have children, or is not editable, it is the first visible child + if (node.nodeType == $_.Node.TEXT_NODE + || (node.nodeType == $_.Node.ELEMENT_NODE && node.childNodes.length == 0) + || !jQuery(node).contentEditable()) { + return includeNode ? node : null; + } + + // otherwise traverse through the children + for (var i = 0; i < node.childNodes.length; ++i) { + var visibleChild = this.getFirstVisibleChild(node.childNodes[i], true); + if (visibleChild != null) { + return visibleChild; + } + } + + return null; + }, + + /** + * Get the last visible child of the given node. + * @param node node + * @param includeNode when set to true, the node itself may be returned, otherwise only children are allowed + * @return last visible child or null if none found + */ + getLastVisibleChild: function (node, includeNode) { + // no node -> no child + if (!node) { + return null; + } + + // check whether the node itself is visible + if ((node.nodeType == $_.Node.TEXT_NODE && this.isEmpty(node)) + || (node.nodeType == $_.Node.ELEMENT_NODE && node.offsetHeight == 0 && jQuery.inArray(node.nodeName.toLowerCase(), this.nonEmptyTags) === -1)) { + return null; + } + + // if the node is a text node, or does not have children, or is not editable, it is the first visible child + if (node.nodeType == $_.Node.TEXT_NODE + || (node.nodeType == $_.Node.ELEMENT_NODE && node.childNodes.length == 0) + || !jQuery(node).contentEditable()) { + return includeNode ? node : null; + } + + // otherwise traverse through the children + for (var i = node.childNodes.length - 1; i >= 0; --i) { + var visibleChild = this.getLastVisibleChild(node.childNodes[i], true); + if (visibleChild != null) { + return visibleChild; + } + } + + return null; + } +}); + + +/** + * Create the singleton object + * @hide + */ +GENTICS.Utils.Dom = new Dom(); + +return GENTICS.Utils.Dom; + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +// Do not add dependencies that require depend on aloha/core +define('aloha/pluginmanager',[ 'aloha/jquery', 'util/class' ], +function( jQuery, Class ) { + + + /** + * The Plugin Manager controls the lifecycle of all Aloha Plugins. + * + * @namespace Aloha + * @class PluginManager + * @singleton + */ + return new (Class.extend({ + plugins: {}, + + /** + * Initialize all registered plugins + * @return void + * @hide + */ + init: function(next, userPlugins) { + + var + me = this, + globalSettings = ( Aloha && Aloha.settings ) ? Aloha.settings.plugins||{}: {}, + i, + plugin, + pluginName; + + // Global to local settings + for ( pluginName in globalSettings ) { + + if ( globalSettings.hasOwnProperty( pluginName ) ) { + + plugin = this.plugins[pluginName] || false; + + if ( plugin ) { + plugin.settings = globalSettings[ pluginName ] || {}; + } + } + } + + // Default: All loaded plugins are enabled + if ( !userPlugins.length ) { + + for ( pluginName in this.plugins ) { + + if ( this.plugins.hasOwnProperty( pluginName ) ) { + userPlugins.push( pluginName ); + } + } + } + + // Enable Plugins specified by User + for ( i=0; i < userPlugins.length; ++i ) { + + pluginName = userPlugins[ i ]; + plugin = this.plugins[ pluginName ]||false; + + if ( plugin ) { + + plugin.settings = plugin.settings || {}; + + if ( typeof plugin.settings.enabled === 'undefined' ) { + plugin.settings.enabled = true; + } + + if ( plugin.settings.enabled ) { + if ( plugin.checkDependencies() ) { + plugin.init(); + } + } + } + } + + next(); + }, + + /** + * Register a plugin + * @param {Plugin} plugin plugin to register + */ + register: function( plugin ) { + + if ( !plugin.name ) { + throw new Error( 'Plugin does not have an name.' ); + } + + if ( this.plugins[ plugin.name ]) { + throw new Error( 'Already registered the plugin "' + plugin.name + '"!' ); + } + + this.plugins[ plugin.name ] = plugin; + }, + + /** + * Pass the given jQuery object, which represents an editable to all plugins, so that they can make the content clean (prepare for saving) + * @param obj jQuery object representing an editable + * @return void + * @hide + */ + makeClean: function(obj) { + var i, plugin; + // iterate through all registered plugins + for ( plugin in this.plugins ) { + if ( this.plugins.hasOwnProperty( plugin ) ) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'Passing contents of HTML Element with id { ' + obj.attr('id') + + ' } for cleaning to plugin { ' + plugin + ' }'); + } + this.plugins[plugin].makeClean(obj); + } + } + }, + + /** + * Expose a nice name for the Plugin Manager + * @hide + */ + toString: function() { + return 'pluginmanager'; + } + + }))(); +}); +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/core',[ + 'aloha/jquery', + 'aloha/pluginmanager' +], + +function ( jQuery, PluginManager ) { + + + + //---------------------------------------- + // Private variables + //---------------------------------------- + + /** + * Hash table that will be populated through the loadPlugins method. + * Maps the names of plugins with their urls for easy assess in the getPluginsUrl method + */ + var pluginPaths = {}; + + /** + * Base Aloha Object + * @namespace Aloha + * @class Aloha The Aloha base object, which contains all the core functionality + * @singleton + */ + jQuery.extend(true, Aloha, { + + /** + * The Aloha Editor Version we are using + * It should be set by us and updated for the particular branch + * @property + */ + version: '0.10.0', + + /** + * Array of editables that are managed by Aloha + * @property + * @type Array + */ + editables: [], + + /** + * The currently active editable is referenced here + * @property + * @type Aloha.Editable + */ + activeEditable: null, + + /** + * settings object, which will contain all Aloha settings + * @cfg {Object} object Aloha's settings + */ + settings: {}, + + /** + * defaults object, which will contain all Aloha defaults + * @cfg {Object} object Aloha's settings + */ + defaults: {}, + + /** + * Namespace for ui components + */ + ui: {}, + + /** + * This represents the name of the users OS. Could be: + * 'Mac', 'Linux', 'Win', 'Unix', 'Unknown' + * @property + * @type string + */ + OSName: 'Unknown', + + /** + * Which stage is the aloha init process at? + * @property + * @type string + */ + stage: 'loadingAloha', + + /** + * A list of loaded plugin names. Available after the + * "loadPlugins" stage. + * + * @property + * @type array + * @internal + */ + loadedPlugins: [], + + requirePaths: [], + /** + * Initialize the initialization process + */ + init: function () { + + // merge defaults and settings and provide all in settings + Aloha.settings = jQuery.extendObjects( true, {}, Aloha.defaults, Aloha.settings ); + + // initialize rangy. This is probably necessary here, + // because due to the current loading mechanism, rangy + // doesn't initialize itself in all browsers + if (window.rangy) { + window.rangy.init(); + } + + // Load & Initialise + Aloha.stage = 'loadPlugins'; + Aloha.loadPlugins(function(){ + Aloha.stage = 'initAloha'; + Aloha.initAloha(function(){ + Aloha.stage = 'initPlugins'; + Aloha.initPlugins(function(){ + Aloha.stage = 'initGui'; + Aloha.initGui(function(){ + Aloha.stage = 'alohaReady'; + Aloha.trigger('aloha-ready'); + }); + }); + }); + }); + }, + + /** + * Load Plugins + */ + loadPlugins: function (next) { + // contains an array like [common/format, common/block] + var configuredPluginsWithBundle = this.getPluginsToBeLoaded(); + + if (configuredPluginsWithBundle.length) { + var paths = {}, + pluginNames = [], + requiredInitializers = [], + pathsToPlugins = {}; + + // Background: We do not use CommonJS packages for our Plugins + // as this breaks the loading order when these modules have + // other dependencies. + // We "emulate" the commonjs modules with the path mapping. + /* require( + * { paths: { + * 'format': 'plugins/common/format/lib', + * 'format/nls': 'plugins/common/format/nls', + * ... for every plugin ... + * } + * }, + * ['format/format-plugin', ... for every plugin ...], + * next <-- when everything is loaded, we continue + */ + jQuery.each(configuredPluginsWithBundle, function (i, configuredPluginWithBundle) { + var tmp, bundleName, pluginName, bundlePath = ''; + + tmp = configuredPluginWithBundle.split('/'); + bundleName = tmp[0]; + pluginName = tmp[1]; + + // TODO assertion if pluginName or bundleName NULL _-> ERROR!! + + if (Aloha.settings.basePath) { + bundlePath = Aloha.settings.basePath; + } + + if (Aloha.settings.bundles && Aloha.settings.bundles[bundleName]) { + bundlePath += Aloha.settings.bundles[bundleName]; + } else { + bundlePath += '../plugins/' + bundleName; + } + + pluginNames.push(pluginName); + paths[pluginName] = bundlePath + '/' + pluginName + '/lib'; + + pathsToPlugins[pluginName] = bundlePath + '/' + pluginName; + + // As the "nls" path lies NOT inside /lib/, but is a sibling to /lib/, we need + // to register it explicitely. The same goes for the "css" folder. + jQuery.each(['nls', 'css', 'vendor', 'res'], function() { + paths[pluginName + '/' + this] = bundlePath + '/' + pluginName + '/' + this; + }); + + requiredInitializers.push(pluginName + '/' + pluginName + '-plugin'); + }); + + this.loadedPlugins = pluginNames; + this.requirePaths = paths; + + // Main Require.js loading call, which fetches all the plugins. + require( + { + context: 'aloha', + paths: paths, + locale: this.settings.locale || this.defaults.locale || 'en' + }, + requiredInitializers, + next + ); + + pluginPaths = pathsToPlugins; + } else { + next(); + } + }, + + /** + * Fetches plugins the user wants to have loaded. Returns all plugins the user + * has specified with the data-plugins property as array, with the bundle + * name in front. + * + * @return array + * @internal + */ + getPluginsToBeLoaded: function() { + // look for data-aloha-plugins attributes and load values + var + plugins = jQuery('[data-aloha-plugins]').data('aloha-plugins'); + + // Determine Plugins + if ( typeof plugins === 'string' && plugins !== "") { + return plugins.replace(/\s+/g, '').split(','); + } + // Return + return []; + + }, + + /** + * Returns list of loaded plugins (without Bundle name) + * + * @return array + */ + getLoadedPlugins: function() { + return this.loadedPlugins; + }, + + /** + * Returns true if a certain plugin is loaded, false otherwise. + */ + isPluginLoaded: function(pluginName) { + var found = false; + jQuery.each(this.loadedPlugins, function() { + if (pluginName.toString() === this.toString()) { + found = true; + } + }); + return found; + }, + + /** + * Initialise Aloha + */ + initAloha: function(next){ + // check browser version on init + // this has to be revamped, as + if (jQuery.browser.webkit && parseFloat(jQuery.browser.version) < 532.5 || // Chrome/Safari 4 + jQuery.browser.mozilla && parseFloat(jQuery.browser.version) < 1.9 || // FF 3.5 + jQuery.browser.msie && jQuery.browser.version < 7 || // IE 7 + jQuery.browser.opera && jQuery.browser.version < 11 ) { // right now, Opera needs some work + if (window.console && window.console.log) { + window.console.log( 'Your browser is not supported.' ); + } + } + + // register the body click event to blur editables + jQuery('html').mousedown(function(e) { + // if an Ext JS modal is visible, we don't want to loose the focus on + // the editable as we assume that the user must have clicked somewhere + // in the modal... where else could he click? + // loosing the editable focus in this case hinders correct table + // column/row deletion, as the table module will clean it's selection + // as soon as the editable is deactivated. Fusubscriberthermore you'd have to + // refocus the editable again, which is just strange UX + if (Aloha.activeEditable && !Aloha.isMessageVisible() && !Aloha.eventHandled) { + Aloha.activeEditable.blur(); + Aloha.activeEditable = null; + } + }).mouseup(function(e) { + Aloha.eventHandled = false; + }); + + // Initialise the base path to the aloha files + Aloha.settings.base = Aloha.getAlohaUrl(); + + // initialize the Log + Aloha.Log.init(); + + // initialize the error handler for general javascript errors + if ( Aloha.settings.errorhandling ) { + window.onerror = function (msg, url, linenumber) { + Aloha.Log.error(Aloha, 'Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber); + // TODO eventually add a message to the message line? + return true; + }; + } + + // OS detection + if (navigator.appVersion.indexOf('Win') != -1) { + Aloha.OSName = 'Win'; + } + if (navigator.appVersion.indexOf('Mac') != -1) { + Aloha.OSName = 'Mac'; + } + if (navigator.appVersion.indexOf('X11') != -1) { + Aloha.OSName = 'Unix'; + } + if (navigator.appVersion.indexOf('Linux') != -1) { + Aloha.OSName = 'Linux'; + } + + try { + // this will disable browsers image resizing facilities + // disable resize handles + var supported; + try { + supported = document.queryCommandSupported( 'enableObjectResizing' ); + } catch ( e ) { + supported = false; + Aloha.Log.log( 'enableObjectResizing is not supported.' ); + } + + if ( supported ) { + document.execCommand( 'enableObjectResizing', false, false); + Aloha.Log.log( 'enableObjectResizing disabled.' ); + } + } catch (e) { + Aloha.Log.error( e, 'Could not disable enableObjectResizing' ); + // this is just for others, who will not support disabling enableObjectResizing + } + // Forward + next(); + }, + + /** + * Loads plugins Aloha + * @return void + */ + initPlugins: function (next) { + PluginManager.init(function(){ + next(); + }, this.getLoadedPlugins() ); + }, + + /** + * Loads GUI components + * @return void + */ + initGui: function (next) { + + Aloha.RepositoryManager.init(); + + // activate registered editables + for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) { + if ( !Aloha.editables[i].ready ) { + Aloha.editables[i].init(); + } + } + + // Forward + next(); + }, + + /** + * Activates editable and deactivates all other Editables + * @param {Editable} editable the Editable to be activated + * @return void + */ + activateEditable: function (editable) { + + // blur all editables, which are currently active + for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) { + if (Aloha.editables[i] != editable && Aloha.editables[i].isActive) { + Aloha.editables[i].blur(); + } + } + + Aloha.activeEditable = editable; + }, + + /** + * Returns the current Editable + * @return {Editable} returns the active Editable + */ + getActiveEditable: function() { + return Aloha.activeEditable; + }, + + /** + * deactivated the current Editable + * @return void + */ + deactivateEditable: function () { + + if ( typeof Aloha.activeEditable === 'undefined' || Aloha.activeEditable === null ) { + return; + } + + // blur the editable + Aloha.activeEditable.blur(); + Aloha.activeEditable = null; + }, + + /** + * Gets an editable by an ID or null if no Editable with that ID registered. + * @param {string} id the element id to look for. + * @return {Aloha.Editable} editable + */ + getEditableById: function (id) { + + // if the element is a textarea than route to the editable div + if (jQuery('#'+id).get(0).nodeName.toLowerCase() === 'textarea' ) { + id = id + '-aloha'; + } + + // serach all editables for id + for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) { + if (Aloha.editables[i].getId() == id) { + return Aloha.editables[i]; + } + } + + return null; + }, + + /** + * Checks wheater an object is a registered Aloha Editable. + * @param {jQuery} obj the jQuery object to be checked. + * @return {boolean} + */ + isEditable: function (obj) { + for (var i=0, editablesLength = Aloha.editables.length; i < editablesLength; i++) { + if ( Aloha.editables[i].originalObj.get(0) === obj ) { + return true; + } + } + return false; + }, + + /** + * Logs a message to the console + * @param level Level of the log ("error", "warn" or "info", "debug") + * @param component Component that calls the log + * @param message log message + * @return void + * @hide + */ + log: function(level, component, message) { + if (typeof Aloha.Log !== "undefined") + Aloha.Log.log(level, component, message); + }, + + /** + * Register the given editable + * @param editable editable to register + * @return void + * @hide + */ + registerEditable: function (editable) { + Aloha.editables.push(editable); + }, + + /** + * Unregister the given editable. It will be deactivated and removed from editables. + * @param editable editable to unregister + * @return void + * @hide + */ + unregisterEditable: function (editable) { + + // Find the index + var id = Aloha.editables.indexOf( editable ); + // Remove it if really found! + if (id != -1) { + Aloha.editables.splice(id, 1); + } + }, + + /** + * String representation + * @hide + */ + toString: function () { + return 'Aloha'; + }, + + /** + * Check whether at least one editable was modified + * @method + * @return {boolean} true when at least one editable was modified, false if not + */ + isModified: function () { + // check if something needs top be saved + for (var i = 0; i < Aloha.editables.length; i++) { + if (Aloha.editables[i].isModified && Aloha.editables[i].isModified()) { + return true; + } + } + + return false; + }, + + /** + * Determines the Aloha Url + * @method + * @return {String} alohaUrl + */ + getAlohaUrl: function( suffix ) { + // aloha base path is defined by a script tag with 2 data attributes + var requireJs = jQuery('[data-aloha-plugins]'), + baseUrl = ( requireJs.length ) ? requireJs[0].src.replace( /\/?aloha.js$/ , '' ) : ''; + + return baseUrl; + }, + + /** + * Gets the Plugin Url + * @method + * @param {String} name + * @return {String} url + */ + getPluginUrl: function (name) { + var url; + + if (name) { + url = pluginPaths[name]; + if(url) { + //Check if url is absolute and attach base url if it is not + if(!url.match("^(\/|http[s]?:).*")) { + url = Aloha.getAlohaUrl() + '/' + url; + } + } + } + + return url; + } + + }); + + return Aloha; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/console',['aloha/core', 'util/class', 'aloha/jquery'], +function(Aloha, Class, jQuery ) { + + + var +// $ = jQuery, +// Aloha = window.Aloha, + console = window.console; +// Class = window.Class +// GENTICS = window.GENTICS; + +/** + * This is the aloha Log + * @namespace Aloha + * @class Log + * @singleton + */ +var alohaConsole = Class.extend({ + /** + * Initialize the logging + * @hide + */ + init: function() { + + // initialize the logging settings (if not present) + if (typeof Aloha.settings.logLevels === 'undefined' || !Aloha.settings.logLevels) { + Aloha.settings.logLevels = {'error' : true, 'warn' : true}; + } + + // initialize the logHistory settings (if not present) + if (typeof Aloha.settings.logHistory === 'undefined' || !Aloha.settings.logHistory) { + Aloha.settings.logHistory = {}; + } + // set the default values for the loghistory + if (!Aloha.settings.logHistory.maxEntries) { + Aloha.settings.logHistory.maxEntries = 100; + } + if (!Aloha.settings.logHistory.highWaterMark) { + Aloha.settings.logHistory.highWaterMark = 90; + } + if (!Aloha.settings.logHistory.levels) { + Aloha.settings.logHistory.levels = {'error' : true, 'warn' : true}; + } + this.flushLogHistory(); + + Aloha.trigger('aloha-logger-ready'); + }, + + /** + * Log History as array of Message Objects. Every object has the properties + * 'level', 'component' and 'message' + * @property + * @type Array + * @hide + */ + logHistory: [], + + /** + * Flag, which is set as soon as the highWaterMark for the log history is reached. + * This flag is reset on every call of flushLogHistory() + * @hide + */ + highWaterMarkReached: false, + + /** + * Logs a message to the console + * @method + * @param {String} level Level of the log ('error', 'warn' or 'info', 'debug') + * @param {String} component Component that calls the log + * @param {String} message log message + */ + log: function(level, component, message) { + + + // log ('Logging message'); + if ( typeof component === 'undefined' ) { + message = level; + } + if ( typeof component !== 'string' && component && component.toString ) { + component = component.toString(); + } + + // log ('warn', 'Warning message'); + if ( typeof message === 'undefined' ) { + message = component; + component = undefined; + } + + if (typeof level === 'undefined' || !level) { + level = 'log'; + } + + level = level.toLowerCase(); + + if ( typeof Aloha.settings.logLevels === "undefined" ) { + return; + } + + // now check whether the log level is activated + if ( !Aloha.settings.logLevels[ level ] ) { + return; + } + + component = component || "Unkown Aloha Component"; + + this.addToLogHistory({'level' : level, 'component' : component, 'message' : message, 'date' : new Date()}); + + switch (level) { + case 'error': + if (window.console && console.error) { + // FIXME: + // Using console.error rather than throwing an error is very + // problematic because we get not stack. + // We ought to consider doing the following: + // throw component + ': ' + message; + if(!component && !message) { + console.error("Error occured without message and component"); + } else { + console.error(component + ': ' + message); + } + } + break; + case 'warn': + if (window.console && console.warn) { + console.warn(component + ': ' + message); + } + break; + case 'info': + if (window.console && console.info) { + console.info(component + ': ' + message); + } + break; + case 'debug': + if (window.console && console.log) { + console.log(component + ' [' + level + ']: ' + message); + } + break; + default: + if (window.console && console.log) { + console.log(component + ' [' + level + ']: ' + message); + } + break; + } + }, + + /** + * Log a message of log level 'error' + * @method + * @param {String} component Component that calls the log + * @param {String} message log message + */ + error: function(component, message) { + this.log('error', component, message); + }, + + /** + * Log a message of log level 'warn' + * @method + * @param {String} component Component that calls the log + * @param {String} message log message + */ + warn: function(component, message) { + this.log('warn', component, message); + }, + + /** + * Log a message of log level 'info' + * @method + * @param {String} component Component that calls the log + * @param {String} message log message + */ + info: function(component, message) { + this.log('info', component, message); + }, + + /** + * Log a message of log level 'debug' + * @param {String} component Component that calls the log + * @param {String} message log message + */ + debug: function(component, message) { + this.log('debug', component, message); + }, + + /** + * Methods to mark function as deprecated for developers. + * @param {String} component String that calls the log + * @param {String} message log message + */ + deprecated: function(component, message) { + this.log( 'warn', component, message ); + // help the developer to locate the call. + if ( Aloha.settings.logLevels[ 'deprecated' ] ) { + throw new Error ( message ); + } + }, + + /** + * Check whether the given log level is currently enabled + * @param {String} level + * @return true when log level is enabled, false if not + */ + isLogLevelEnabled: function(level) { + return Aloha.settings && Aloha.settings.logLevels && Aloha.settings.logLevels[level]; + }, + + /** + * Check whether error logging is enabled + * @return true if error logging is enabled, false if not + */ + isErrorEnabled: function() { + return this.isLogLevelEnabled('error'); + }, + + /** + * Check whether warn logging is enabled + * @return true if warn logging is enabled, false if not + */ + isWarnEnabled: function() { + return this.isLogLevelEnabled('warn'); + }, + + /** + * Check whether info logging is enabled + * @return true if info logging is enabled, false if not + */ + isInfoEnabled: function() { + return this.isLogLevelEnabled('info'); + }, + + /** + * Check whether debug logging is enabled + * @return true if debug logging is enabled, false if not + */ + isDebugEnabled: function() { + return this.isLogLevelEnabled('debug'); + }, + + /** + * Add the given entry to the log history. Check whether the highWaterMark has been reached, and fire an event if yes. + * @param {Object} entry entry to be added to the log history + * @hide + */ + addToLogHistory: function(entry) { + + if ( !Aloha.settings.logHistory ) { + this.init(); + } + + // when maxEntries is set to something illegal, we do nothing (log history is disabled) + // check whether the level is one we like to have logged + if ( Aloha.settings.logHistory.maxEntries <= 0 + || !Aloha.settings.logHistory.levels[ entry.level ] + ) { + + return; + } + + // first add the entry as last element to the history array + this.logHistory.push( entry ); + + // check whether the highWaterMark was reached, if so, fire an event + if ( !this.highWaterMarkReached ) { + + if ( this.logHistory.length >= Aloha.settings.logHistory.maxEntries * Aloha.settings.logHistory.highWaterMark / 100 ) { + + // fire the event + Aloha.trigger('aloha-log-full'); + // set the flag (so we will not fire the event again until the logHistory is flushed) + this.highWaterMarkReached = true; + } + } + + // check whether the log is full and eventually remove the oldest entries + while ( this.logHistory.length > Aloha.settings.logHistory.maxEntries ) { + this.logHistory.shift(); + } + }, + + /** + * Get the log history + * @return log history as array of objects + * @hide + */ + getLogHistory: function() { + return this.logHistory; + }, + + /** + * Flush the log history. Remove all log entries and reset the flag for the highWaterMark + * @return void + * @hide + */ + flushLogHistory: function() { + this.logHistory = []; + this.highWaterMarkReached = false; + } +}); + +/** + * Create the Log object + * @hide + */ +alohaConsole = new alohaConsole(); + +// add to log namespace for compatiblility. +return Aloha.Log = Aloha.Console = alohaConsole; + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ +// Ensure GENTICS Namespace +GENTICS = window.GENTICS || {}; +GENTICS.Utils = GENTICS.Utils || {}; + +define('util/range',['aloha/jquery', 'util/dom', 'util/class', 'aloha/console', 'aloha/rangy-core'], +function(jQuery, Dom, Class, console) { + + + var + GENTICS = window.GENTICS, + rangy = window.rangy; + +/** + * @namespace GENTICS.Utils + * @class RangeObject + * Represents a selection range in the browser that + * has some advanced features like selecting the range. + * @param {object} param if boolean true is passed, the range will be deducted from the current browser selection. + * If another rangeObject is passed, it will be cloned. + * If nothing is passed, the rangeObject will be empty. + * @constructor + */ +GENTICS.Utils.RangeObject = Class.extend({ + _constructor: function(param){ + // Take the values from the passed object + if (typeof param === 'object') { + if (typeof param.startContainer !== 'undefined') { + this.startContainer = param.startContainer; + } + if (typeof param.startOffset !== 'undefined') { + this.startOffset = param.startOffset; + } + if (typeof param.endContainer !== 'undefined') { + this.endContainer = param.endContainer; + } + if (typeof param.endOffset !== 'undefined') { + this.endOffset = param.endOffset; + } + } else if (param === true) { + this.initializeFromUserSelection(); + } + }, + + /** + * DOM object of the start container of the selection. + * This is always has to be a DOM text node. + * @property startContainer + * @type {DOMObject} + */ + startContainer: undefined, + + /** + * Offset of the selection in the start container + * @property startOffset + * @type {Integer} + */ + startOffset: undefined, + + /** + * DOM object of the end container of the selection. + * This is always has to be a DOM text node. + * @property endContainer + * @type {DOMObject} + */ + endContainer: undefined, + + /** + * Offset of the selection in the end container + * @property endOffset + * @type {Integer} + */ + endOffset: undefined, + + /** + * Delete all contents selected by the current range + * @param rangeTree a GENTICS.Utils.RangeTree object may be provided to start from. This parameter is optional + */ + deleteContents: function () { + + Dom.removeRange(this); + + }, + + /** + * Output some log + * TODO: move this to Aloha.Log + * @param message log message to output + * @return void + * @deprecated + * @hide + */ + log: function(message) { + console.deprecated( 'Utils.RangeObject', 'log() is deprecated. use ' + + 'console.log() from module "aloha/console" instead: ' + message); + }, + + /** + * Method to test if a range object is collapsed. + * A range is considered collapsed if either no endContainer exists or the endContainer/Offset equal startContainer/Offset + * @return {boolean} true if collapsed, false otherwise + * @method + */ + isCollapsed: function() { + return ( + !this.endContainer || + (this.startContainer === this.endContainer && this.startOffset === this.endOffset) + ); + }, + + /** + * Method to (re-)calculate the common ancestor container and to get it. + * The common ancestor container is the DOM Object which encloses the + * whole range and is nearest to the start and end container objects. + * @return {DOMObject} get the common ancestor container + * @method + */ + getCommonAncestorContainer: function() { + if (this.commonAncestorContainer) { + // sometimes it's cached (or was set) + return this.commonAncestorContainer; + } + + // if it's not cached, calculate and then cache it + this.updateCommonAncestorContainer(); + + // now return it anyway + return this.commonAncestorContainer; + }, + + /** + * Get the parent elements of the startContainer/endContainer up to the given limit. When the startContainer/endContainer + * is no text element, but a node, the node itself is returned as first element. + * @param {jQuery} limit limit object (default: body) + * @param {boolean} fromStart true to fetch the parents from the startContainer, false for the endContainer + * @return {jQuery} parent elements of the startContainer/endContainer as jQuery objects + * @method + */ + getContainerParents: function (limit, fromEnd) { + // TODO cache the calculated parents + var + container = fromEnd ? this.endContainer : this.startContainer, + parents, limitIndex, + i; + + if (!container) { + return false; + } + + if ( typeof limit === 'undefined' || ! limit ) { + limit = jQuery('body'); + } + + + if (container.nodeType == 3) { + parents = jQuery(container).parents(); + } else { + parents = jQuery(container).parents(); + for (i = parents.length; i > 0; --i) { + parents[i] = parents[i - 1]; + } + parents[0] = container; + } + + // now slice this array + limitIndex = parents.index(limit); + + if (limitIndex >= 0) { + parents = parents.slice(0, limitIndex); + } + + return parents; + }, + + /** + * Get the parent elements of the startContainer up to the given limit. When the startContainer + * is no text element, but a node, the node itself is returned as first element. + * @param {jQuery} limit limit object (default: body) + * @return {jQuery} parent elements of the startContainer as jQuery objects + * @method + */ + getStartContainerParents: function(limit) { + return this.getContainerParents(limit, false); + }, + + /** + * Get the parent elements of the endContainer up to the given limit. When the endContainer is + * no text element, but a node, the node itself is returned as first element. + * @param {jQuery} limit limit object (default: body) + * @return {jQuery} parent elements of the endContainer as jQuery objects + * @method + */ + getEndContainerParents: function(limit) { + return this.getContainerParents(limit, true); + }, + + /** + * TODO: the commonAncestorContainer is not calculated correctly, if either the start or + * the endContainer would be the cac itself (e.g. when the startContainer is a textNode + * and the endContainer is the startContainer's parent

    ). in this case the cac will be set + * to the parent div + * Method to update a range object internally + * @param commonAncestorContainer (DOM Object); optional Parameter; if set, the parameter + * will be used instead of the automatically calculated CAC + * @return void + * @hide + */ + updateCommonAncestorContainer: function(commonAncestorContainer) { + // this will be needed either right now for finding the CAC or later for the crossing index + var parentsStartContainer = this.getStartContainerParents(), + parentsEndContainer = this.getEndContainerParents(), + i; + + // if no parameter was passed, calculate it + if (!commonAncestorContainer) { + // find the crossing between startContainer and endContainer parents (=commonAncestorContainer) + if (!(parentsStartContainer.length > 0 && parentsEndContainer.length > 0)) { + console.warn('could not find commonAncestorContainer'); + return false; + } + + for (i = 0; i < parentsStartContainer.length; i++) { + if (parentsEndContainer.index( parentsStartContainer[ i ] ) != -1) { + this.commonAncestorContainer = parentsStartContainer[ i ]; + break; + } + } + } else { + this.commonAncestorContainer = commonAncestorContainer; + } + + // if everything went well, return true :-) + console.debug(commonAncestorContainer? 'commonAncestorContainer was set successfully' : 'commonAncestorContainer was calculated successfully'); + return true; + }, + + /** + * Helper function for selection in IE. Creates a collapsed text range at the given position + * @param container container + * @param offset offset + * @return collapsed text range at that position + * @hide + */ + getCollapsedIERange: function(container, offset) { + // create a text range + var + ieRange = document.body.createTextRange(), + tmpRange, right, parent, left; + + // search to the left for the next element + left = this.searchElementToLeft(container, offset); + if (left.element) { + // found an element, set the start to the end of that element + tmpRange = document.body.createTextRange(); + tmpRange.moveToElementText(left.element); + ieRange.setEndPoint('StartToEnd', tmpRange); + + // and correct the start + if (left.characters !== 0) { + ieRange.moveStart('character', left.characters); + } else { + // this is a hack, when we are at the start of a text node, move the range anyway + ieRange.moveStart('character', 1); + ieRange.moveStart('character', -1); + } + } else { + // found nothing to the left, so search right + right = this.searchElementToRight(container, offset); + if (false && right.element) { + // found an element, set the start to the start of that element + tmpRange = document.body.createTextRange(); + tmpRange.moveToElementText(right.element); + ieRange.setEndPoint('StartToStart', tmpRange); + + // and correct the start + if (right.characters !== 0) { + ieRange.moveStart('character', -right.characters); + } else { + ieRange.moveStart('character', -1); + ieRange.moveStart('character', 1); + } + } else { + // also found no element to the right, use the container itself + parent = container.nodeType == 3 ? container.parentNode : container; + tmpRange = document.body.createTextRange(); + tmpRange.moveToElementText(parent); + ieRange.setEndPoint('StartToStart', tmpRange); + + // and correct the start + if (left.characters !== 0) { + ieRange.moveStart('character', left.characters); + } + } + } + ieRange.collapse(); + + return ieRange; + }, + + /** + * Sets the visible selection in the Browser based on the range object. + * If the selection is collapsed, this will result in a blinking cursor, + * otherwise in a text selection. + * @method + */ + select: function() { + var ieRange, endRange, startRange, range, sel; + + // create a range + range = rangy.createRange(); + + // set start and endContainer + range.setStart(this.startContainer,this.startOffset); + range.setEnd(this.endContainer, this.endOffset); + + // update the selection + sel = rangy.getSelection(); + sel.setSingleRange(range); + }, + + /** + * Starting at the given position, search for the next element to the left and count the number of characters are in between + * @param container container of the startpoint + * @param offset offset of the startpoint in the container + * @return object with 'element' (null if no element found) and 'characters' + * @hide + */ + searchElementToLeft: function (container, offset) { + var + checkElement, + characters = 0; + + if (container.nodeType === 3) { + // start is in a text node + characters = offset; + // begin check at the element to the left (if any) + checkElement = container.previousSibling; + } else { + // start is between nodes, begin check at the element to the left (if any) + if (offset > 0) { + checkElement = container.childNodes[offset - 1]; + } + } + + // move to the right until we find an element + while (checkElement && checkElement.nodeType === 3) { + characters += checkElement.data.length; + checkElement = checkElement.previousSibling; + } + + return {'element' : checkElement, 'characters' : characters}; + }, + + /** + * Starting at the given position, search for the next element to the right and count the number of characters that are in between + * @param container container of the startpoint + * @param offset offset of the startpoint in the container + * @return object with 'element' (null if no element found) and 'characters' + * @hide + */ + searchElementToRight: function (container, offset) { + var + checkElement, + characters = 0; + + if (container.nodeType === 3) { + // start is in a text node + characters = container.data.length - offset; + + // begin check at the element to the right (if any) + checkElement = container.nextSibling; + } else { + // start is between nodes, begin check at the element to the right (if any) + if (offset < container.childNodes.length) { + checkElement = container.childNodes[offset]; + } + } + + // move to the right until we find an element + while (checkElement && checkElement.nodeType === 3) { + characters += checkElement.data.length; + checkElement = checkElement.nextSibling; + } + + return {'element' : checkElement, 'characters' : characters}; + }, + + /** + * Method which updates the rangeObject including all extending properties like commonAncestorContainer etc... + * TODO: is this method needed here? or should it contain the same code as Aloha.Selection.prototype.SelectionRange.prototype.update? + * @return void + * @hide + */ + update: function(event) { + console.debug('now updating rangeObject'); + this.initializeFromUserSelection(event); + this.updateCommonAncestorContainer(); + }, + + /** + * Initialize the current range object from the user selection of the browser. + * @param event which calls the method + * @return void + * @hide + */ + initializeFromUserSelection: function(event) { + var + selection = rangy.getSelection(), + browserRange; + + if (!selection) { + return false; + } + + // check if a ragne exists + if ( !selection.rangeCount ) { + return false; + } + + // getBrowserRange + browserRange = selection.getRangeAt(0); + if (!browserRange) { + return false; + } + + // initially set the range to what the browser tells us + this.startContainer = browserRange.startContainer; + this.endContainer = browserRange.endContainer; + this.startOffset = browserRange.startOffset; + this.endOffset = browserRange.endOffset; + + // now try to correct the range + this.correctRange(); + return; + }, + + /** + * Correct the current range. The general goal of the algorithm is to have start + * and end of the range in text nodes if possible and the end of the range never + * at the beginning of an element or text node. Details of the algorithm can be + * found in the code comments + * @method + */ + correctRange: function() { + var + adjacentTextNode, + textNode, + checkedElement, + parentNode, + offset; + + this.clearCaches(); + if (this.isCollapsed()) { + // collapsed ranges are treated specially + + // first check if the range is not in a text node + if (this.startContainer.nodeType === 1) { + if (this.startOffset > 0 && this.startContainer.childNodes[this.startOffset - 1].nodeType === 3) { + // when the range is between nodes (container is an element + // node) and there is a text node to the left -> move into this text + // node (at the end) + this.startContainer = this.startContainer.childNodes[this.startOffset - 1]; + this.startOffset = this.startContainer.data.length; + this.endContainer = this.startContainer; + this.endOffset = this.startOffset; + return; + } + + if (this.startOffset > 0 && this.startContainer.childNodes[this.startOffset - 1].nodeType === 1) { + // search for the next text node to the left + adjacentTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(this.startContainer, this.startOffset, true); + if (adjacentTextNode) { + this.startContainer = this.endContainer = adjacentTextNode; + this.startOffset = this.endOffset = adjacentTextNode.data.length; + return; + } + // search for the next text node to the right + adjacentTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(this.startContainer, this.startOffset, false); + if (adjacentTextNode) { + this.startContainer = this.endContainer = adjacentTextNode; + this.startOffset = this.endOffset = 0; + return; + } + } + + if (this.startOffset < this.startContainer.childNodes.length && this.startContainer.childNodes[this.startOffset].nodeType === 3) { + // when the range is between nodes and there is a text node + // to the right -> move into this text node (at the start) + this.startContainer = this.startContainer.childNodes[this.startOffset]; + this.startOffset = 0; + this.endContainer = this.startContainer; + this.endOffset = 0; + return; + } + } + + // when the selection is in a text node at the start, look for an adjacent text node and if one found, move into that at the end + if (this.startContainer.nodeType === 3 && this.startOffset === 0) { + adjacentTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(this.startContainer.parentNode, GENTICS.Utils.Dom.getIndexInParent(this.startContainer), true); + if (adjacentTextNode) { + this.startContainer = this.endContainer = adjacentTextNode; + this.startOffset = this.endOffset = adjacentTextNode.data.length; + } + } + } else { + // expanded range found + + // correct the start, but only if between nodes + if (this.startContainer.nodeType === 1) { + // if there is a text node to the right, move into this + if (this.startOffset < this.startContainer.childNodes.length && this.startContainer.childNodes[this.startOffset].nodeType === 3) { + this.startContainer = this.startContainer.childNodes[this.startOffset]; + this.startOffset = 0; + } else if (this.startOffset < this.startContainer.childNodes.length && this.startContainer.childNodes[this.startOffset].nodeType === 1) { + // there is an element node to the right, so recursively check all first child nodes until we find a text node + textNode = false; + checkedElement = this.startContainer.childNodes[this.startOffset]; + while (textNode === false && checkedElement.childNodes && checkedElement.childNodes.length > 0) { + // go to the first child of the checked element + checkedElement = checkedElement.childNodes[0]; + // when this element is a text node, we are done + if (checkedElement.nodeType === 3) { + textNode = checkedElement; + } + } + + // found a text node, so move into it + if (textNode !== false) { + this.startContainer = textNode; + this.startOffset = 0; + } + } + } + + // check whether the start is inside a text node at the end + if (this.startContainer.nodeType === 3 && this.startOffset === this.startContainer.data.length) { + // check whether there is an adjacent text node to the right and if + // yes, move into it + adjacentTextNode = GENTICS.Utils.Dom + .searchAdjacentTextNode(this.startContainer.parentNode, GENTICS.Utils.Dom + .getIndexInParent(this.startContainer) + 1, false); + if (adjacentTextNode) { + this.startContainer = adjacentTextNode; + this.startOffset = 0; + } + } + + // now correct the end + if (this.endContainer.nodeType === 3 && this.endOffset === 0) { + // we are in a text node at the start + if (this.endContainer.previousSibling && this.endContainer.previousSibling.nodeType === 3) { + // found a text node to the left -> move into it (at the end) + this.endContainer = this.endContainer.previousSibling; + this.endOffset = this.endContainer.data.length; + } else if (this.endContainer.previousSibling && this.endContainer.previousSibling.nodeType === 1 && this.endContainer.parentNode) { + // found an element node to the left -> move in between + parentNode = this.endContainer.parentNode; + for (offset = 0; offset < parentNode.childNodes.length; ++offset) { + if (parentNode.childNodes[offset] == this.endContainer) { + this.endOffset = offset; + break; + } + } + this.endContainer = parentNode; + } + } + + if (this.endContainer.nodeType == 1 && this.endOffset === 0) { + // we are in an element node at the start, possibly move to the previous sibling at the end + if (this.endContainer.previousSibling) { + if (this.endContainer.previousSibling.nodeType === 3) { + // previous sibling is a text node, move end into here (at the end) + this.endContainer = this.endContainer.previousSibling; + this.endOffset = this.endContainer.data.length; + } else if ( + this.endContainer.previousSibling.nodeType === 1 + && this.endContainer.previousSibling.childNodes + && this.endContainer.previousSibling.childNodes.length > 0) { + // previous sibling is another element node with children, + // move end into here (at the end) + this.endContainer = this.endContainer.previousSibling; + this.endOffset = this.endContainer.childNodes.length; + } + } + } + + // correct the end, but only if between nodes + if (this.endContainer.nodeType == 1) { + // if there is a text node to the left, move into this + if (this.endOffset > 0 && this.endContainer.childNodes[this.endOffset - 1].nodeType === 3) { + this.endContainer = this.endContainer.childNodes[this.endOffset - 1]; + this.endOffset = this.endContainer.data.length; + } else if (this.endOffset > 0 && this.endContainer.childNodes[this.endOffset - 1].nodeType === 1) { + // there is an element node to the left, so recursively check all last child nodes until we find a text node + textNode = false; + checkedElement = this.endContainer.childNodes[this.endOffset - 1]; + while (textNode === false && checkedElement.childNodes && checkedElement.childNodes.length > 0) { + // go to the last child of the checked element + checkedElement = checkedElement.childNodes[checkedElement.childNodes.length - 1]; + // when this element is a text node, we are done + if (checkedElement.nodeType === 3) { + textNode = checkedElement; + } + } + + // found a text node, so move into it + if (textNode !== false) { + this.endContainer = textNode; + this.endOffset = this.endContainer.data.length; + } + } + } + } + }, + + /** + * Clear the caches for this range. This method must be called when the range itself (start-/endContainer or start-/endOffset) is modified. + * @method + */ + clearCaches: function () { + this.commonAncestorContainer = undefined; + }, + + /** + * Get the range tree of this range. + * The range tree will be cached for every root object. When the range itself is modified, the cache should be cleared by calling GENTICS.Utils.RangeObject.clearCaches + * @param {DOMObject} root root object of the range tree, if non given, the common ancestor container of the start and end containers will be used + * @return {RangeTree} array of RangeTree object for the given root object + * @method + */ + getRangeTree: function (root) { + // TODO cache rangeTrees + if (typeof root === 'undefined') { + root = this.getCommonAncestorContainer(); + } + + this.inselection = false; + return this.recursiveGetRangeTree(root); + }, + + /** + * Recursive inner function for generating the range tree. + * @param currentObject current DOM object for which the range tree shall be generated + * @return array of Tree objects for the children of the current DOM object + * @hide + */ + recursiveGetRangeTree: function (currentObject) { + // get all direct children of the given object + var jQueryCurrentObject = jQuery(currentObject), + childCount = 0, + that = this, + currentElements = []; + + jQueryCurrentObject.contents().each(function(index) { + var type = 'none', + startOffset = false, + endOffset = false, + collapsedFound = false, + noneFound = false, + partialFound = false, + fullFound = false, + i; + + // check for collapsed selections between nodes + if (that.isCollapsed() && currentObject === that.startContainer && that.startOffset === index) { + // insert an extra rangetree object for the collapsed range here + currentElements[childCount] = new GENTICS.Utils.RangeTree(); + currentElements[childCount].type = 'collapsed'; + currentElements[childCount].domobj = undefined; + that.inselection = false; + collapsedFound = true; + childCount++; + } + + if (!that.inselection && !collapsedFound) { + // the start of the selection was not yet found, so look for it now + // check whether the start of the selection is found here + + // check is dependent on the node type + switch(this.nodeType) { + case 3: // text node + if (this === that.startContainer) { + // the selection starts here + that.inselection = true; + + // when the startoffset is > 0, the selection type is only partial + type = that.startOffset > 0 ? 'partial' : 'full'; + startOffset = that.startOffset; + endOffset = this.length; + } + break; + case 1: // element node + if (this === that.startContainer && that.startOffset === 0) { + // the selection starts here + that.inselection = true; + type = 'full'; + } + if (currentObject === that.startContainer && that.startOffset === index) { + // the selection starts here + that.inselection = true; + type = 'full'; + } + break; + } + } + + if (that.inselection && !collapsedFound) { + if (type == 'none') { + type = 'full'; + } + // we already found the start of the selection, so look for the end of the selection now + // check whether the end of the selection is found here + + switch(this.nodeType) { + case 3: // text node + if (this === that.endContainer) { + // the selection ends here + that.inselection = false; + + // check for partial selection here + if (that.endOffset < this.length) { + type = 'partial'; + } + if (startOffset === false) { + startOffset = 0; + } + endOffset = that.endOffset; + } + break; + case 1: // element node + if (this === that.endContainer && that.endOffset === 0) { + that.inselection = false; + } + break; + } + if (currentObject === that.endContainer && that.endOffset <= index) { + that.inselection = false; + type = 'none'; + } + } + + // create the current selection tree entry + currentElements[childCount] = new GENTICS.Utils.RangeTree(); + currentElements[childCount].domobj = this; + currentElements[childCount].type = type; + if (type == 'partial') { + currentElements[childCount].startOffset = startOffset; + currentElements[childCount].endOffset = endOffset; + } + + // now do the recursion step into the current object + currentElements[childCount].children = that.recursiveGetRangeTree(this); + + // check whether a selection was found within the children + if (currentElements[childCount].children.length > 0) { + for ( i = 0; i < currentElements[childCount].children.length; ++i) { + switch(currentElements[childCount].children[i].type) { + case 'none': + noneFound = true; + break; + case 'full': + fullFound = true; + break; + case 'partial': + partialFound = true; + break; + } + } + + if (partialFound || (fullFound && noneFound)) { + // found at least one 'partial' DOM object in the children, or both 'full' and 'none', so this element is also 'partial' contained + currentElements[childCount].type = 'partial'; + } else if (fullFound && !partialFound && !noneFound) { + // only found 'full' contained children, so this element is also 'full' contained + currentElements[childCount].type = 'full'; + } + } + + childCount++; + }); + + // extra check for collapsed selections at the end of the current element + if (this.isCollapsed() + && currentObject === this.startContainer + && this.startOffset == currentObject.childNodes.length) { + currentElements[childCount] = new GENTICS.Utils.RangeTree(); + currentElements[childCount].type = 'collapsed'; + currentElements[childCount].domobj = undefined; + } + + return currentElements; + }, + + /** + * Find certain the first occurrence of some markup within the parents of either the start or the end of this range. + * The markup can be identified by means of a given comparator function. The function will be passed every parent (up to the eventually given limit object, which itself is not considered) to the comparator function as this. + * When the comparator function returns boolean true, the markup found and finally returned from this function as dom object.
    + * Example for finding an anchor tag at the start of the range up to the active editable object:
    + *

    +	 * range.findMarkup(
    +	 *   function() {
    +	 *     return this.nodeName.toLowerCase() == 'a';
    +	 *   },
    +	 *   jQuery(Aloha.activeEditable.obj)
    +	 * );
    +	 * 
    + * @param {function} comparator comparator function to find certain markup + * @param {jQuery} limit limit objects for limit the parents taken into consideration + * @param {boolean} atEnd true for searching at the end of the range, false for the start (default: false) + * @return {DOMObject} the found dom object or false if nothing found. + * @method + */ + findMarkup: function (comparator, limit, atEnd) { + var parents = this.getContainerParents(limit, atEnd), + returnValue = false; + jQuery.each(parents, function (index, domObj) { + if (comparator.apply(domObj)) { + returnValue = domObj; + return false; + } + }); + + return returnValue; + }, + + /** + * Get the text enclosed by this range + * @return {String} the text of the range + * @method + */ + getText: function() { + if (this.isCollapsed()) { + return ''; + } else { + return this.recursiveGetText(this.getRangeTree()); + } + }, + + recursiveGetText: function (tree) { + if (!tree) { + return ''; + } else { + var that = this, + text = ''; + jQuery.each(tree, function() { + if (this.type == 'full') { + // fully selected element/text node + text += jQuery(this.domobj).text(); + } else if (this.type == 'partial' && this.domobj.nodeType === 3) { + // partially selected text node + text += jQuery(this.domobj).text().substring(this.startOffset, this.endOffset); + } else if (this.type == 'partial' && this.domobj.nodeType === 1 && this.children) { + // partially selected element node + text += that.recursiveGetText(this.children); + } + }); + return text; + } + } +}); + +/** + * @namespace GENTICS.Utils + * @class RangeTree + * Class definition of a RangeTree, which gives a tree view of the DOM objects included in this range + * Structure: + *
    + * +
    + * |-domobj:  (NOT jQuery)
    + * |-type: defines if this node is marked by user [none|partial|full|collapsed]
    + * |-children: recursive structure like this
    + * 
    + */ +GENTICS.Utils.RangeTree = Class.extend({ + /** + * DOMObject, if the type is one of [none|partial|full], undefined if the type is [collapsed] + * @property domobj + * @type {DOMObject} + */ + domobj: {}, + + /** + * type of the participation of the dom object in the range. Is one of: + *
    +	 * - none the DOMObject is outside of the range
    +	 * - partial the DOMObject partially in the range
    +	 * - full the DOMObject is completely in the range
    +	 * - collapsed the current RangeTree element marks the position of a collapsed range between DOM nodes
    +	 * 
    + * @property type + * @type {String} + */ + type: null, + + /** + * Array of RangeTree objects which reflect the status of the child elements of the current DOMObject + * @property children + * @type {Array} + */ + children: [] +}); + + return GENTICS.Utils.RangeObject; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ +define('aloha/floatingmenu',['aloha/core', 'aloha/jquery', 'aloha/ext', 'util/class', 'aloha/console', 'vendor/jquery.store'], +function(Aloha, jQuery, Ext, Class, console) { + + var GENTICS = window.GENTICS; + + /** + * Constructor for a floatingmenu tab + * @namespace Aloha.FloatingMenu + * @class Tab + * @constructor + * @param {String} label label of the tab + */ + var Tab = Class.extend({ + _constructor: function(label) { + this.label = label; + this.groups = []; + this.groupMap = {}; + this.visible = true; + }, + + /** + * Get the group with given index. If it does not yet exist, create a new one + * @method + * @param {int} group group index of the group to get + * @return group object + */ + getGroup: function(group) { + var groupObject = this.groupMap[group]; + if (typeof groupObject === 'undefined') { + groupObject = new Group(); + this.groupMap[group] = groupObject; + this.groups.push(groupObject); + // TODO resort the groups + } + + return groupObject; + }, + + /** + * Get the EXT component representing the tab + * @return EXT component (EXT.Panel) + * @hide + */ + getExtComponent: function () { + var that = this; + + if (typeof this.extPanel === 'undefined') { + // generate the panel here + this.extPanel = new Ext.Panel({ + 'tbar' : [], + 'title' : this.label, + 'style': 'margin-top:0px', + 'bodyStyle': 'display:none', + 'autoScroll': true + }); + + // add the groups + jQuery.each(this.groups, function(index, group) { + // let each group generate its ext component and add them to the panel + that.extPanel.getTopToolbar().add(group.getExtComponent()); + }); + } + + return this.extPanel; + }, + + /** + * Recalculate the visibility of all groups within the tab + * @hide + */ + doLayout: function() { + var that = this; + + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'doLayout called for tab ' + this.label); + } + this.visible = false; + + // check all groups in this tab + jQuery.each(this.groups, function(index, group) { + that.visible |= group.doLayout(); + }); + + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'tab ' + this.label + (this.visible ? ' is ' : ' is not ') + 'visible now'); + } + + return this.visible; + } + }); + + /** + * Constructor for a floatingmenu group + * @namespace Aloha.FloatingMenu + * @class Group + * @constructor + */ + var Group = Class.extend({ + _constructor: function() { + this.buttons = []; + this.fields = []; + }, + + /** + * Add a button to this group + * @param {Button} buttonInfo to add to the group + */ + addButton: function(buttonInfo) { + if (buttonInfo.button instanceof Aloha.ui.AttributeField) { + if (this.fields.length < 2) { + this.fields.push(buttonInfo); + } else { + throw new Error("Too much fields in this group"); + } + } else { + // Every plugin API entryPoint (method) should be securised enough + // to avoid Aloha to block at startup even + // if a plugin is badly designed + if (typeof buttonInfo.button !== "undefined"){ + this.buttons.push(buttonInfo); + } + } + }, + + /** + * Get the EXT component representing the group (Ext.ButtonGroup) + * @return the Ext.ButtonGroup + * @hide + */ + getExtComponent: function () { + var that = this, l, + items = [], + buttonCount = 0, + columnCount = 0, + len, idx, half; + + + if (typeof this.extButtonGroup === 'undefined') { + + if (this.fields.length > 1) { + columnCount = 1; + } + + jQuery.each(this.buttons, function(index, button) { + // count the number of buttons (large buttons count as 2) + buttonCount += button.button.size == 'small' ? 1 : 2; + }); + columnCount = columnCount + Math.ceil(buttonCount / 2); + + len = this.buttons.length; + idx = 0; + half = Math.ceil(this.buttons.length / 2) - this.buttons.length % 2 ; + + if (this.fields.length > 0) { + that.buttons.push(this.fields[0]); + items.push(this.fields[0].button.getExtConfigProperties()); + } + + while (--len >= half) { + items.push(this.buttons[idx++].button.getExtConfigProperties()); + } + ++len; + if (this.fields.length > 1) { + that.buttons.push(this.fields[1]); + items.push(this.fields[1].button.getExtConfigProperties()); + } + while (--len >=0) { + items.push(this.buttons[idx++].button.getExtConfigProperties()); + } + + this.extButtonGroup = new Ext.ButtonGroup({ + 'columns' : columnCount, + 'items': items + }); + // jQuery.each(this.fields, function(id, field){ + // that.buttons.push(field); + // }); + // now find the Ext.Buttons and set to the GENTICS buttons + jQuery.each(this.buttons, function(index, buttonInfo) { + buttonInfo.button.extButton = that.extButtonGroup.findById(buttonInfo.button.id); + // the following code is a work arround because ExtJS initializes later. + // The ui wrapper store the information and here we use it... ugly. + // if there are any listeners added before initializing the extButtons + if ( buttonInfo.button.listenerQueue && buttonInfo.button.listenerQueue.length > 0 ) { + while ( true ) { + l = buttonInfo.button.listenerQueue.shift(); + if ( !l ) {break;} + buttonInfo.button.extButton.addListener(l.eventName, l.handler, l.scope, l.options); + } + } + if (buttonInfo.button.extButton.setObjectTypeFilter) { + if (buttonInfo.button.objectTypeFilter) { + buttonInfo.button.extButton.noQuery = false; + } + if ( buttonInfo.button.objectTypeFilter == 'all' ) { + buttonInfo.button.objectTypeFilter = null; + } + buttonInfo.button.extButton.setObjectTypeFilter(buttonInfo.button.objectTypeFilter); + if ( buttonInfo.button.displayField) { + buttonInfo.button.extButton.displayField = buttonInfo.button.displayField; + } + if ( buttonInfo.button.tpl ) { + buttonInfo.button.extButton.tpl = buttonInfo.button.tpl; + } + } + }); + } + + return this.extButtonGroup; + }, + + /** + * Recalculate the visibility of the buttons and the group + * @hide + */ + doLayout: function () { + var groupVisible = false, + that = this; + jQuery.each(this.buttons, function(index, button) { + if (typeof button.button !== "undefined") { + var extButton = that.extButtonGroup.findById(button.button.id), + buttonVisible = button.button.isVisible() && button.scopeVisible; + + if (!extButton) { + return; + } + + if (buttonVisible && extButton.hidden) { + extButton.show(); + } else if (!buttonVisible && !extButton.hidden) { + extButton.hide(); + } + + groupVisible |= buttonVisible; + } + }); + if (groupVisible && this.extButtonGroup.hidden) { + this.extButtonGroup.show(); + } else if (!groupVisible && !this.extButtonGroup.hidden) { + this.extButtonGroup.hide(); + } + + return groupVisible; + + } + }); + + /** + * Aloha's Floating Menu + * @namespace Aloha + * @class FloatingMenu + * @singleton + */ + var FloatingMenu = Class.extend({ + /** + * Define the default scopes + * @property + * @type Object + */ + scopes: { + 'Aloha.empty' : { + 'name' : 'Aloha.empty', + 'extendedScopes' : [], + 'buttons' : [] + }, + 'Aloha.global' : { + 'name' : 'Aloha.global', + 'extendedScopes' : ['Aloha.empty'], + 'buttons' : [] + }, + 'Aloha.continuoustext' : { + 'name' : 'Aloha.continuoustext', + 'extendedScopes' : ['Aloha.global'], + 'buttons' : [] + } + }, + + /** + * Array of tabs within the floatingmenu + * @hide + */ + tabs: [], + + /** + * 'Map' of tabs (for easy access) + * @hide + */ + tabMap: {}, + + /** + * Flag to mark whether the floatingmenu is initialized + * @hide + */ + initialized: false, + + /** + * Array containing all buttons + * @hide + */ + allButtons: [], + + /** + * top part of the floatingmenu position + * @hide + */ + top: 100, + + /** + * left part of the floatingmenu position + * @hide + */ + left: 100, + + /** + * store pinned status - true, if the FloatingMenu is pinned + * @property + * @type boolean + */ + pinned: false, + + /** + * just a reference to the jQuery(window) object, which is used quite often + */ + window: jQuery(window), + + /** + * define floating menu float behaviour. meant to be adjusted via + * GENTICS.Aloha.settings.floatingmenu.behaviour + * set it to 'float' for standard behaviour, or 'topalign' for a fixed fm + */ + behaviour: 'float', + + /** + * topalign offset to be used for topalign behavior + */ + topalignOffset: 90, + + /** + * topalign offset to be used for topalign behavior + */ + horizontalOffset: 0, + + /** + * will only be hounoured when behaviour is set to 'topalign'. Adds a margin, + * so the floating menu is not directly attached to the top of the page + */ + marginTop: 0, + + /** + * Define whether the floating menu shall be draggable or not via Aloha.settings.floatingmanu.draggable + * Default is: true + */ + draggable: true, + + /** + * A list of all buttons that have been added to the floatingmenu + * This needs to be tracked, as adding buttons twice will break the fm + */ + buttonsAdded: [], + + /** + * Will be initialized by checking Aloha.settings.toolbar, which will contain the config for + * the floating menu. If there is no config, tabs and groups will be generated programmatically + */ + fromConfig: false, + + /** + * Initialize the floatingmenu + * @hide + */ + init: function() { + + // check for behaviour setting of the floating menu + if (Aloha.settings.floatingmenu) { + + if (typeof Aloha.settings.floatingmenu.draggable === 'boolean') { + this.draggable = Aloha.settings.floatingmenu.draggable; + } + if (typeof Aloha.settings.floatingmenu.behaviour === 'string') { + this.behaviour = Aloha.settings.floatingmenu.behaviour; + } + if (typeof Aloha.settings.floatingmenu.topalignOffset !== 'undefined') { + this.topalignOffset = Aloha.settings.floatingmenu.topalignOffset; + } + if (typeof Aloha.settings.floatingmenu.horizontalOffset !== 'undefined') { + this.horizontalOffset = Aloha.settings.floatingmenu.horizontalOffset; + } + if (typeof Aloha.settings.floatingmenu.marginTop === 'number') { + this.marginTop = Aloha.settings.floatingmenu.marginTop; + } + //We just check for undefined + if (typeof Aloha.settings.floatingmenu.width !== 'undefined') { + //Try to pars it + try { + var parsed = parseInt(Aloha.settings.floatingmenu.width); + this.width = Aloha.settings.floatingmenu.width; + } catch(e) { + //do nothing. + } + } + } + + jQuery.storage = new jQuery.store(); + this.currentScope = 'Aloha.global'; + var that = this; + this.window.unload(function () { + // store fm position if the panel is pinned to be able to restore it next time + if (that.pinned) { + jQuery.storage.set('Aloha.FloatingMenu.pinned', 'true'); + jQuery.storage.set('Aloha.FloatingMenu.top', that.top); + jQuery.storage.set('Aloha.FloatingMenu.left', that.left); + if (Aloha.Log.isInfoEnabled()) { + Aloha.Log.info(this, 'stored FloatingMenu pinned position {' + that.left + + ', ' + that.top + '}'); + } + } else { + // delete old localStorages + jQuery.storage.del('Aloha.FloatingMenu.pinned'); + jQuery.storage.del('Aloha.FloatingMenu.top'); + jQuery.storage.del('Aloha.FloatingMenu.left'); + } + if (that.userActivatedTab) { + jQuery.storage.set('Aloha.FloatingMenu.activeTab', that.userActivatedTab); + } + }).resize(function () { + if (that.behaviour === 'float') { + if (that.pinned) { + that.fixPinnedPosition(); + that.refreshShadow(); + that.extTabPanel.setPosition(that.left, that.top); + } else { + var target = that.calcFloatTarget(Aloha.Selection.getRangeObject()); + if (target) { + that.floatTo(target); + } + } + } + }); + Aloha.bind('aloha-ready', function() { + that.generateComponent(); + that.initialized = true; + }); + + if (typeof Aloha.settings.toolbar === 'object') { + this.fromConfig = true; + } + }, + + /** + * jQuery reference to the extjs tabpanel + * @hide + */ + obj: null, + + /** + * jQuery reference to the shadow obj + * @hide + */ + shadow: null, + + /** + * jQuery reference to the panels body wrap div + * @hide + */ + panelBody: null, + + /** + * The panels width + * @hide + */ + width: 400, + + /** + * initialize tabs and groups according to the current configuration + */ + initTabsAndGroups: function () { + var that = this; + + // if there is no toolbar config tabs and groups have been initialized before + if (!this.fromConfig) { + return; + } + + jQuery.each(Aloha.settings.toolbar.tabs, function (tab, groups) { + // generate or retrieve tab + var tabObject = that.tabMap[tab]; + if (typeof tabObject === 'undefined') { + // the tab object does not yet exist, so create a new tab and add it to the list + tabObject = new Tab(tab); + that.tabs.push(tabObject); + that.tabMap[tab] = tabObject; + } + + // generate groups for current tab + jQuery.each(groups, function (group, buttons) { + var groupObject = tabObject.getGroup(group), + i; + + // now get all the buttons for that group + jQuery.each(buttons, function (j, button) { + if (jQuery.inArray(button, that.buttonsAdded) !== -1) { + // buttons must not be added twice + console.warn('Skipping button {' + button + '}. A button can\'t be added ' + + 'to the floating menu twice. Config key: {Aloha.settings.toolbar.' + + tab + '.' + group + '}'); + return; + } + + // now add the button to the group + for (i = 0; i < that.allButtons.length; i++) { + if (button === that.allButtons[i].button.name) { + groupObject.addButton(that.allButtons[i]); + // remember that we've added the button + that.buttonsAdded.push(that.allButtons[i].button.name); + break; + } + } + }); + }); + }); + }, + + /** + * Generate the rendered component for the floatingmenu + * @hide + */ + generateComponent: function () { + var that = this, pinTab; + + // initialize tabs and groups first + this.initTabsAndGroups(); + + // Initialize and configure the tooltips + Ext.QuickTips.init(); + Ext.apply(Ext.QuickTips.getQuickTip(), { + minWidth : 10 + }); + + + + if (this.extTabPanel) { + // TODO dispose of the ext component + } else { + + // Enable or disable the drag functionality + var dragConfiguration = false; + + if ( that.draggable ) { + dragConfiguration = { + insertProxy: false, + onDrag : function(e) { + var pel = this.proxy.getEl(); + this.x = pel.getLeft(true); + this.y = pel.getTop(true); + this.panel.shadow.hide(); + }, + endDrag : function(e) { + var top = (that.pinned) ? this.y - jQuery(document).scrollTop() : this.y; + + that.left = this.x; + that.top = top; + + this.panel.setPosition(this.x, top); + that.refreshShadow(); + this.panel.shadow.show(); + } + }; + } + // generate the tabpanel object + this.extTabPanel = new Ext.TabPanel({ + activeTab: 0, + width: that.width, // 336px this fits the multisplit button and 6 small buttons placed in 3 cols + plain: false, + draggable: dragConfiguration, + floating: {shadow: false}, + defaults: { + autoScroll: true + }, + layoutOnTabChange : true, + shadow: false, + cls: 'aloha-floatingmenu ext-root', + listeners : { + 'tabchange' : { + 'fn' : function(tabPanel, tab) { + if (tab.title != that.autoActivatedTab) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(that, 'User selected tab ' + tab.title); + } + // remember the last user-selected tab + that.userActivatedTab = tab.title; + } else { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(that, 'Tab ' + tab.title + ' was activated automatically'); + } + } + that.autoActivatedTab = undefined; + + // ok, this is kind of a hack: when the tab changes, we check all buttons for multisplitbuttons (which have the method setActiveDOMElement). + // if a DOM Element is queued to be set active, we try to do this now. + // the reason for this is that the active DOM element can only be set when the multisplit button is currently visible. + jQuery.each(that.allButtons, function(index, buttonInfo) { + if (typeof buttonInfo.button !== 'undefined' + && typeof buttonInfo.button.extButton !== 'undefined' + && buttonInfo.button.extButton !== null + && typeof buttonInfo.button.extButton.setActiveDOMElement === 'function') { + if (typeof buttonInfo.button.extButton.activeDOMElement !== 'undefined') { + buttonInfo.button.extButton.setActiveDOMElement(buttonInfo.button.extButton.activeDOMElement); + } + } + }); + + // adapt the shadow + that.extTabPanel.shadow.show(); + that.refreshShadow(); + } + } + }, + enableTabScroll : true + }); + + + } + // add the tabs + jQuery.each(this.tabs, function(index, tab) { + // let each tab generate its ext component and add them to the panel + try { + that.extTabPanel.add(tab.getExtComponent()); + } catch(e) { + Aloha.Log.error(that,"Error while inserting tab: " + e); + } + }); + + // add the dropshadow + this.extTabPanel.shadow = jQuery('
     
    '); + jQuery('body').append(this.extTabPanel.shadow); + + // add an empty pin tab item, store reference + pinTab = this.extTabPanel.add({ + title : ' ' + }); + + // finally render the panel to the body + this.extTabPanel.render(document.body); + + // finish the pin element after the FM has rendered (before there are noe html contents to be manipulated + jQuery(pinTab.tabEl) + .addClass('aloha-floatingmenu-pin') + .html(' ') + .mousedown(function (e) { + that.togglePin(); + // Note: this event is deliberately stopped here, although normally, + // we would set the flag GENTICS.Aloha.eventHandled instead. + // But when the event bubbles up, no tab would be selected and + // the floatingmenu would be rather thin. + e.stopPropagation(); + }); + + // a reference to the panels body needed for shadow size & position + this.panelBody = jQuery('div.aloha-floatingmenu div.x-tab-panel-bwrap'); + + // do the visibility + this.doLayout(); + + // bind jQuery reference to extjs obj + // this has to be done AFTER the tab panel has been rendered + this.obj = jQuery(this.extTabPanel.getEl().dom); + + if (jQuery.storage.get('Aloha.FloatingMenu.pinned') == 'true') { + this.togglePin(); + + this.top = parseInt(jQuery.storage.get('Aloha.FloatingMenu.top'),10); + this.left = parseInt(jQuery.storage.get('Aloha.FloatingMenu.left'),10); + + // do some positioning fixes + this.fixPinnedPosition(); + + if (Aloha.Log.isInfoEnabled()) { + Aloha.Log.info(this, 'restored FloatingMenu pinned position {' + this.left + ', ' + this.top + '}'); + } + + this.refreshShadow(); + } + + // set the user activated tab stored in a localStorage + if (jQuery.storage.get('Aloha.FloatingMenu.activeTab')) { + this.userActivatedTab = jQuery.storage.get('Aloha.FloatingMenu.activeTab'); + } + + // for now, position the panel somewhere + this.extTabPanel.setPosition(this.left, this.top); + + // mark the event being handled by aloha, because we don't want to recognize + // a click into the floatingmenu to be a click into nowhere (which would + // deactivate the editables) + this.obj.mousedown(function (e) { + e.originalEvent.stopSelectionUpdate = true; + Aloha.eventHandled = true; + // e.stopSelectionUpdate = true; + }); + this.obj.mouseup(function (e) { + e.originalEvent.stopSelectionUpdate = true; + Aloha.eventHandled = false; + }); + + // adjust float behaviour + if (this.behaviour === 'float') { + // listen to selectionChanged event + Aloha.bind('aloha-selection-changed',function(event, rangeObject) { + if (!that.pinned) { + var pos = that.calcFloatTarget(rangeObject); + if (pos) { + that.floatTo(pos); + } + } + }); + } else if (this.behaviour === 'topalign') { + // topalign will retain the user's pinned status + // TODO maybe the pin should be hidden in that case? + this.togglePin(false); + + // float the fm to each editable that is activated + Aloha.bind('aloha-editable-activated', function(event, data) { + var p = data.editable.obj.offset(); + p.top -= that.topalignOffset; + p.left += that.horizontalOffset; + if (p.top < jQuery(document).scrollTop()) { + // scrollpos is below top of editable + that.obj.css('top', jQuery(document).scrollTop() + that.marginTop); + that.obj.css('left', p.left); + that.togglePin(true); + } else { + // scroll pos is above top of editable + that.floatTo(p); + } + }); + + // fm scroll behaviour + jQuery(window).scroll(function () { + if (!Aloha.activeEditable) { + return; + } + var pos = Aloha.activeEditable.obj.offset(), + fmHeight = that.obj.height(), + scrollTop = jQuery(document).scrollTop(); + + if (scrollTop > (pos.top - fmHeight - 6 - that.marginTop)) { + // scroll pos is lower than top of editable + that.togglePin(true); + that.obj.css('top', that.marginTop); + } else if (scrollTop <= (pos.top - fmHeight - 6 - that.marginTop)) { + // scroll pos is above top of editable + if (that.behaviour === 'topalign') { + pos.top = Aloha.activeEditable.obj.offset().top - that.topalignOffset; + pos.left = Aloha.activeEditable.obj.offset().left + that.horizontalOffset; + } else { + pos.top -= fmHeight + 6; + } + that.togglePin(false); + that.floatTo(pos); + } else if (scrollTop > pos.top + Aloha.activeEditable.obj.height() - fmHeight) { + // scroll pos is below editable + that.togglePin(false); + } + }); + } + }, + + /** + * Fix the position of the pinned floatingmenu to keep it visible + */ + fixPinnedPosition: function() { + // if not pinned, do not fix the position + if (!this.pinned) { + return; + } + + // fix the position of the floatingmenu, to keep it visible + if (this.top < 30) { + // from top position, we want to have 30px margin + this.top = 30; + } else if (this.top > this.window.height() - this.extTabPanel.getHeight()) { + this.top = this.window.height() - this.extTabPanel.getHeight(); + } + if (this.left < 0) { + this.left = 0; + } else if (this.left > this.window.width() - this.extTabPanel.getWidth()) { + this.left = this.window.width() - this.extTabPanel.getWidth(); + } + }, + + /** + * reposition & resize the shadow + * the shadow must not be repositioned outside this method! + * position calculation is based on this.top and this.left coordinates + * @method + */ + refreshShadow: function (resize) { + if (this.panelBody) { + var props = { + 'top': this.top + 24, // 24px top offset to reflect tab bar height + 'left': this.left + }; + + if(typeof resize === 'undefined' || !resize) { + props.width = this.panelBody.width() + 'px'; + props.height = this.panelBody.height() + 'px'; + } + + this.extTabPanel.shadow.css(props); + } + }, + + /** + * toggles the pinned status of the floating menu + * @method + * @param {boolean} pinned set to true to activate pin, or set to false to deactivate pin. + * leave undefined to toggle pin status automatically + */ + togglePin: function(pinned) { + var el = jQuery('.aloha-floatingmenu-pin'); + + if (typeof pinned === 'boolean') { + this.pinned = !pinned; + } + + if (this.pinned) { + el.removeClass('aloha-floatingmenu-pinned'); + this.top = this.obj.offset().top; + + this.obj.removeClass('fixed').css({ + 'top': this.top + }); + + this.extTabPanel.shadow.removeClass('fixed'); + this.refreshShadow(); + + this.pinned = false; + } else { + el.addClass('aloha-floatingmenu-pinned'); + this.top = this.obj.offset().top - this.window.scrollTop(); + + this.obj.addClass('fixed').css({ + 'top': this.top // update position for fixed position + }); + + // do the same for the shadow + this.extTabPanel.shadow.addClass('fixed');//props.start + this.refreshShadow(); + + this.pinned = true; + } + }, + + /** + * Create a new scopes + * @method + * @param {String} scope name of the new scope (should be namespaced for uniqueness) + * @param {String} extendedScopes Array of scopes this scope extends. Can also be a single String if + * only one scope is extended, or omitted if the scope should extend + * the empty scope + */ + createScope: function(scope, extendedScopes) { + if (typeof extendedScopes === 'undefined') { + extendedScopes = ['Aloha.empty']; + } else if (typeof extendedScopes === 'string') { + extendedScopes = [extendedScopes]; + } + + // TODO check whether the extended scopes already exist + + if (this.scopes[scope]) { + // TODO what if the scope already exists? + } else { + // generate the new scope + this.scopes[scope] = {'name' : scope, 'extendedScopes' : extendedScopes, 'buttons' : []}; + } + }, + + /** + * Adds a button to the floatingmenu + * @method + * @param {String} scope the scope for the button, should be generated before (either by core or the plugin) + * @param {Button} button instance of Aloha.ui.button to add at the floatingmenu + * @param {String} tab label of the tab to which the button is added + * @param {int} group index of the button group in the tab, lowest index is left + */ + addButton: function(scope, button, tab, group) { + // check whether the scope exists + var + scopeObject = this.scopes[scope], + buttonInfo, tabObject, groupObject; + + if (!button.name) { + console.warn('Added button with iconClass {' + button.iconClass + '} which has no property "name"'); + } + + if (typeof scopeObject === 'undefined') { + Aloha.Log.error("Can't add button to given scope since the scope has not yet been initialized.", scope); + return false; + } + + // generate a buttonInfo object + buttonInfo = { 'button' : button, 'scopeVisible' : false }; + + // add the button to the list of all buttons + this.allButtons.push(buttonInfo); + + // add the button to the scope + scopeObject.buttons.push(buttonInfo); + + // if there is no toolbar config tabs and groups will be generated right away + if (!this.fromConfig) { + // get the tab object + tabObject = this.tabMap[tab]; + if (typeof tabObject === 'undefined') { + // the tab object does not yet exist, so create a new tab and add it to the list + tabObject = new Tab(tab); + this.tabs.push(tabObject); + this.tabMap[tab] = tabObject; + } + + // get the group + groupObject = tabObject.getGroup(group); + + // now add the button to the group + groupObject.addButton(buttonInfo); + } + + // finally, when the floatingmenu is already initialized, we need to create the ext component now + if (this.initialized) { + this.generateComponent(); + } + }, + + /** + * Recalculate the visibility of tabs, groups and buttons (depending on scope and button hiding) + * @hide + */ + doLayout: function () { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'doLayout called for FloatingMenu, scope is ' + this.currentScope); + } + + var that = this, + firstVisibleTab = false, + activeExtTab = this.extTabPanel.getActiveTab(), + activeTab = false, + floatingMenuVisible = false, + showUserActivatedTab = false, + pos; + + // let the tabs layout themselves + jQuery.each(this.tabs, function(index, tab) { + // remember the active tab + if (tab.extPanel == activeExtTab) { + activeTab = tab; + } + + // remember whether the tab is currently visible + var tabVisible = tab.visible; + + // let each tab generate its ext component and add them to the panel + if (tab.doLayout()) { + // found a visible tab, so the floatingmenu needs to be visible as well + floatingMenuVisible = true; + + // make sure the tabstrip is visible + if (!tabVisible) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(that, 'showing tab strip for tab ' + tab.label); + } + that.extTabPanel.unhideTabStripItem(tab.extPanel); + } + + // remember the first visible tab + if (!firstVisibleTab) { + // this is the first visible tab (in case we need to switch to it) + firstVisibleTab = tab; + } + + // check whether this visible tab is the last user activated tab and currently not active + if (that.userActivatedTab == tab.extPanel.title && tab.extPanel != activeExtTab) { + showUserActivatedTab = tab; + } + } else { + // make sure the tabstrip is hidden + if (tabVisible) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(that, 'hiding tab strip for tab ' + tab.label); + } + that.extTabPanel.hideTabStripItem(tab.extPanel); + } + } + }); + + // check whether the last tab which was selected by the user is visible and not the active tab + if (showUserActivatedTab) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'Setting active tab to ' + showUserActivatedTab.label); + } + this.extTabPanel.setActiveTab(showUserActivatedTab.extPanel); + } else if (typeof activeTab === 'object' && typeof firstVisibleTab === 'object') { + // now check the currently visible tab, whether it is visible and enabled + if (!activeTab.visible) { + if (Aloha.Log.isDebugEnabled()) { + Aloha.Log.debug(this, 'Setting active tab to ' + firstVisibleTab.label); + } + this.autoActivatedTab = firstVisibleTab.extPanel.title; + this.extTabPanel.setActiveTab(firstVisibleTab.extPanel); + } + } + + // set visibility of floatingmenu + if (floatingMenuVisible && this.extTabPanel.hidden) { + // set the remembered position + this.extTabPanel.show(); + this.refreshShadow(); + this.extTabPanel.shadow.show(); + this.extTabPanel.setPosition(this.left, this.top); + } else if (!floatingMenuVisible && !this.extTabPanel.hidden) { + // remember the current position + pos = this.extTabPanel.getPosition(true); + // restore previous position if the fm was pinned + this.left = pos[0] < 0 ? 100 : pos[0]; + this.top = pos[1] < 0 ? 100 : pos[1]; + this.extTabPanel.hide(); + this.extTabPanel.shadow.hide(); + } + + // let the Ext object render itself again + this.extTabPanel.doLayout(); + }, + + /** + * Set the current scope + * @method + * @param {String} scope name of the new current scope + */ + setScope: function(scope) { + // get the scope object + var scopeObject = this.scopes[scope]; + + if (typeof scopeObject === 'undefined') { + // TODO log an error + } else if (this.currentScope != scope) { + this.currentScope = scope; + + // first hide all buttons + jQuery.each(this.allButtons, function(index, buttonInfo) { + buttonInfo.scopeVisible = false; + }); + + // now set the buttons in the given scope to be visible + this.setButtonScopeVisibility(scopeObject); + + // finally refresh the layout + this.doLayout(); + } + }, + + /** + * Set the scope visibility of the buttons for the given scope. This method will call itself for the motherscopes of the given scope. + * @param scopeObject scope object + * @hide + */ + setButtonScopeVisibility: function(scopeObject) { + var that = this; + + // set all buttons in the given scope to be visible + jQuery.each(scopeObject.buttons, function(index, buttonInfo) { + buttonInfo.scopeVisible = true; + }); + + // now do the recursion for the motherscopes + jQuery.each(scopeObject.extendedScopes, function(index, scopeName) { + var motherScopeObject = that.scopes[scopeName]; + if (typeof motherScopeObject === 'object') { + that.setButtonScopeVisibility(motherScopeObject); + } + }); + }, + + /** + * returns the next possible float target dom obj + * the floating menu should only float to h1-h6, p, div, td and pre elements + * if the current object is not valid, it's parentNode will be considered, until + * the limit object is hit + * @param obj the dom object to start from (commonly this would be the commonAncestorContainer) + * @param limitObj the object that limits the range (this would be the editable) + * @return dom object which qualifies as a float target + * @hide + */ + nextFloatTargetObj: function (obj, limitObj) { + // if we've hit the limit object we don't care for it's type + if (!obj || obj == limitObj) { + return obj; + } + + // fm will only float to h1-h6, p, div, td + switch (obj.nodeName.toLowerCase()) { + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + case 'p': + case 'div': + case 'td': + case 'pre': + case 'ul': + case 'ol': + return obj; + default: + return this.nextFloatTargetObj(obj.parentNode, limitObj); + } + }, + + /** + * calculates the float target coordinates for a range + * @param range the fm should float to + * @return object containing left and top coordinates, like { left : 20, top : 43 } + * @hide + */ + calcFloatTarget: function(range) { + var + i, editableLength, target, + targetObj, scrollTop, top; + + // TODO in IE8 somteimes a broken range is handed to this function - investigate this + if (!Aloha.activeEditable || typeof range.getCommonAncestorContainer === 'undefined') { + return false; + } + + // check if the designated editable is disabled + for ( i = 0, editableLength = Aloha.editables.length; i < editableLength; i++) { + if (Aloha.editables[i].obj.get(0) == range.limitObject && + Aloha.editables[i].isDisabled()) { + return false; + } + } + + target = this.nextFloatTargetObj(range.getCommonAncestorContainer(), range.limitObject); + if ( ! target ) { + return false; + } + + targetObj = jQuery(target); + scrollTop = GENTICS.Utils.Position.Scroll.top; + if (!targetObj || !targetObj.offset()) { + return false; + } + top = targetObj.offset().top - this.obj.height() - 50; // 50px offset above the current obj to have some space above + + // if the floating menu would be placed higher than the top of the screen... + if ( top < scrollTop) { + top += 50 + GENTICS.Utils.Position.ScrollCorrection.top; + } + + // if the floating menu would float off the bottom of the screen + // we don't want it to move, so we'll return false + if (top > this.window.height() + this.window.scrollTop()) { + return false; + } + + return { + left : Aloha.activeEditable.obj.offset().left, + top : top + }; + }, + + /** + * float the fm to the desired position + * the floating menu won't float if it is pinned + * @method + * @param {Object} coordinate object which has a left and top property + */ + floatTo: function(position) { + // no floating if the panel is pinned + if (this.pinned) { + return; + } + + var that = this, + fmpos = this.obj.offset(); + + // move to the new position + if (fmpos.left != position.left || fmpos.top != position.top) { + this.obj.animate({ + top: position.top, + left: position.left + }, { + queue : false, + step : function (step, props) { + // update position reference + if (props.prop == 'top') { + that.top = props.now; + } else if (props.prop == 'left') { + that.left = props.now; + } + + that.refreshShadow(false); + } + }); + } + }, + + /** + * Hide the floatingmenu + */ + hide: function() { + if (this.obj) { + this.obj.hide(); + } + if (this.shadow) { + this.shadow.hide(); + } + }, + + /** + * Activate the tab containing the button with given name. + * If the button with given name is not found, nothing changes + * @param name name of the button + */ + activateTabOfButton: function(name) { + var tabOfButton = null; + + // find the tab containing the button + for (var t = 0; t < this.tabs.length && !tabOfButton; t++) { + var tab = this.tabs[t]; + for (var g = 0; g < tab.groups.length && !tabOfButton; g++) { + var group = tab.groups[g]; + for (var b = 0; b < group.buttons.length && !tabOfButton; b++) { + var button = group.buttons[b]; + if (button.button.name == name) { + tabOfButton = tab; + break; + } + } + } + } + + if (tabOfButton) { + this.userActivatedTab = tabOfButton.label; + this.doLayout(); + } + } + }); + + var menu = new FloatingMenu(); + menu.init(); + + // set scope to empty if deactivated + Aloha.bind('aloha-editable-deactivated', function() { + menu.setScope('Aloha.empty'); + }); + + // set scope to empty if the user selectes a non contenteditable area + Aloha.bind('aloha-selection-changed', function() { + if ( !Aloha.Selection.isSelectionEditable() && !Aloha.Selection.isFloatingMenuVisible() ) { + menu.setScope('Aloha.empty'); + } + }); + + return menu; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + + +define('aloha/selection',[ 'aloha/core', 'aloha/jquery', 'aloha/floatingmenu', 'util/class', 'util/range', 'aloha/rangy-core' ], +function(Aloha, jQuery, FloatingMenu, Class, Range) { + var +// $ = jQuery, +// Aloha = window.Aloha, +// Class = window.Class, + GENTICS = window.GENTICS; + + /** + * @namespace Aloha + * @class Selection + * This singleton class always represents the current user selection + * @singleton + */ + var Selection = Class.extend({ + _constructor: function(){ + // Pseudo Range Clone being cleaned up for better HTML wrapping support + this.rangeObject = {}; + + this.preventSelectionChangedFlag = false; // will remember if someone urged us to skip the next aloha-selection-changed event + + // define basics first + this.tagHierarchy = { + 'textNode' : [], + 'abbr' : ['textNode'], + 'b' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img','a','del','ins','u', 'cite', 'q', 'code', 'abbr', 'strong'], + 'pre' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img','a','del','ins','u', 'cite','q', 'code', 'abbr', 'code'], + 'blockquote' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img','a','del','ins','u', 'cite', 'q', 'code', 'abbr', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + 'ins' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img','a','u', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + 'ul' : ['li'], + 'ol' : ['li'], + 'li' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'del', 'ins', 'u', 'a'], + 'tr' : ['td','th'], + 'table' : ['tr'], + 'div' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img', 'ul', 'ol', 'table', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'del', 'ins', 'u', 'p', 'div', 'pre', 'blockquote', 'a'], + 'h1' : ['textNode', 'b', 'i', 'em', 'sup', 'sub', 'br', 'span', 'img','a', 'del', 'ins', 'u'] + }; + // now reference the basics for all other equal tags (important: don't forget to include + // the basics itself as reference: 'b' : this.tagHierarchy.b + this.tagHierarchy = { + 'textNode' : this.tagHierarchy.textNode, + 'abbr' : this.tagHierarchy.abbr, + 'br' : this.tagHierarchy.textNode, + 'img' : this.tagHierarchy.textNode, + 'b' : this.tagHierarchy.b, + 'strong' : this.tagHierarchy.b, + 'code' : this.tagHierarchy.b, + 'q' : this.tagHierarchy.b, + 'blockquote' : this.tagHierarchy.blockquote, + 'cite' : this.tagHierarchy.b, + 'i' : this.tagHierarchy.b, + 'em' : this.tagHierarchy.b, + 'sup' : this.tagHierarchy.b, + 'sub' : this.tagHierarchy.b, + 'span' : this.tagHierarchy.b, + 'del' : this.tagHierarchy.del, + 'ins' : this.tagHierarchy.ins, + 'u' : this.tagHierarchy.b, + 'p' : this.tagHierarchy.b, + 'pre' : this.tagHierarchy.pre, + 'a' : this.tagHierarchy.b, + 'ul' : this.tagHierarchy.ul, + 'ol' : this.tagHierarchy.ol, + 'li' : this.tagHierarchy.li, + 'td' : this.tagHierarchy.li, + 'div' : this.tagHierarchy.div, + 'h1' : this.tagHierarchy.h1, + 'h2' : this.tagHierarchy.h1, + 'h3' : this.tagHierarchy.h1, + 'h4' : this.tagHierarchy.h1, + 'h5' : this.tagHierarchy.h1, + 'h6' : this.tagHierarchy.h1, + 'table' : this.tagHierarchy.table + }; + + // When applying this elements to selection they will replace the assigned elements + this.replacingElements = { + 'h1' : ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','pre', 'blockquote'] + }; + this.replacingElements = { + 'h1' : this.replacingElements.h1, + 'h2' : this.replacingElements.h1, + 'h3' : this.replacingElements.h1, + 'h4' : this.replacingElements.h1, + 'h5' : this.replacingElements.h1, + 'h6' : this.replacingElements.h1, + 'pre' : this.replacingElements.h1, + 'p' : this.replacingElements.h1, + 'blockquote' : this.replacingElements.h1 + }; + this.allowedToStealElements = { + 'h1' : ['textNode'] + }; + this.allowedToStealElements = { + 'h1' : this.allowedToStealElements.h1, + 'h2' : this.allowedToStealElements.h1, + 'h3' : this.allowedToStealElements.h1, + 'h4' : this.allowedToStealElements.h1, + 'h5' : this.allowedToStealElements.h1, + 'h6' : this.allowedToStealElements.h1, + 'p' : this.tagHierarchy.b + }; + }, + + /** + * Class definition of a SelectionTree (relevant for all formatting / markup changes) + * TODO: remove this (was moved to range.js) + * Structure: + * + + * |-domobj: (NOT jQuery) + * |-selection: defines if this node is marked by user [none|partial|full] + * |-children: recursive structure like this + * @hide + */ + SelectionTree: function() { + this.domobj = {}; + this.selection = undefined; + this.children = []; + }, + + /** + * INFO: Method is used for integration with Gentics Aloha, has no use otherwise + * Updates the rangeObject according to the current user selection + * Method is always called on selection change + * @param objectClicked Object that triggered the selectionChange event + * @return true when rangeObject was modified, false otherwise + * @hide + */ + onChange: function(objectClicked, event) { + if (this.updateSelectionTimeout) { + window.clearTimeout(this.updateSelectionTimeout); + this.updateSelectionTimeout = undefined; + } + //we have to work around an IE bug that causes the user + //selection to be incorrectly set on the body element when + //the updateSelectionTimeout triggers. We remember the range + //from the time when this onChange is triggered and provide + //it instead of the current user selection when the timout + //is triggered. The bug is caused by selecting some text and + //then clicking once inside the selection (which collapses + //the selection). Interesting fact: when the timeout is + //increased to 500 milliseconds, the bug will not cause any + //problems since the selection will correct itself somehow. + var range = new Aloha.Selection.SelectionRange(true); + this.updateSelectionTimeout = window.setTimeout(function () { + Aloha.Selection._updateSelection(event, range); + }, 5); + }, + + /** + * prevents the next aloha-selection-changed event from being triggered + */ + preventSelectionChanged: function () { + this.preventSelectionChangedFlag = true; + }, + + /** + * will return wheter selection change event was prevented or not, and reset the preventSelectionChangedFlag + * @return {Boolean} true if aloha-selection-change event was prevented + */ + isSelectionChangedPrevented: function () { + var prevented = this.preventSelectionChangedFlag; + this.preventSelectionChangedFlag = false; + return prevented; + }, + + /** + * Checks if the current rangeObject common ancector container is edtiable + * @return {Boolean} true if current common ancestor is editable + */ + isSelectionEditable: function() { + return ( this.rangeObject.commonAncestorContainer && + jQuery( this.rangeObject.commonAncestorContainer ) + .contentEditable() ); + }, + + /** + * This method checks, if the current rangeObject common ancestor container has a 'data-aloha-floatingmenu-visible' Attribute. + * Needed in Floating Menu for exceptional display of floatingmenu. + */ + isFloatingMenuVisible: function() { + var visible = jQuery(Aloha.Selection.rangeObject + .commonAncestorContainer).attr('data-aloha-floatingmenu-visible'); + if(visible !== 'undefined'){ + if (visible === 'true'){ + return true; + } else { + return false; + } + } + return false; + }, + + /** + * INFO: Method is used for integration with Gentics Aloha, has no use otherwise + * Updates the rangeObject according to the current user selection + * Method is always called on selection change + * @param event jQuery browser event object + * @return true when rangeObject was modified, false otherwise + * @hide + */ + updateSelection: function(event) { + return this._updateSelection(event, null); + }, + + /** + * Internal version of updateSelection that adds the range parameter to be + * able to work around an IE bug that caused the current user selection + * sometimes to be on the body element. + * @param range a substitute for the current user selection. if not provided, + * the current user selection will be used. + * @hide + */ + _updateSelection: function(event, range) { + if (event !== undefined && event.originalEvent !== undefined && + event.originalEvent.stopSelectionUpdate === true) { + return false; + } + + if (typeof range === "undefined") { + return false; + } + + this.rangeObject = range || new Aloha.Selection.SelectionRange(true); + + // Only execute the workaround when a valid rangeObject was provided + if ( typeof this.rangeObject !== "undefined" && typeof this.rangeObject.startContainer !== "undefined" && this.rangeObject.endContainer !== "undefined") { + // workaround for a nasty IE bug that allows the user to select text nodes inside areas with contenteditable "false" + if ( (this.rangeObject.startContainer.nodeType === 3 && !jQuery(this.rangeObject.startContainer.parentNode).contentEditable()) + || (this.rangeObject.endContainer.nodeType === 3 && !jQuery(this.rangeObject.endContainer.parentNode).contentEditable())) { + Aloha.getSelection().removeAllRanges(); + return true; + } + } + + // find the CAC (Common Ancestor Container) and update the selection Tree + this.rangeObject.update(); + + // check if aloha-selection-changed event has been prevented + if (this.isSelectionChangedPrevented()) { + return true; + } + + // Only set the specific scope if an event was provided, which means + // that somehow an editable was selected + // TODO Bind code to aloha-selection-changed event to remove coupling to floatingmenu + if (event !== undefined) { + // Initiallly set the scope to 'continuoustext' + FloatingMenu.setScope('Aloha.continuoustext'); + } + + // throw the event that the selection has changed. Plugins now have the + // chance to react on the chancurrentElements[childCount].children.lengthged selection + Aloha.trigger('aloha-selection-changed', [ this.rangeObject, event ]); + + return true; + }, + + /** + * creates an object with x items containing all relevant dom objects. + * Structure: + * + + * |-domobj: (NOT jQuery) + * |-selection: defines if this node is marked by user [none|partial|full] + * |-children: recursive structure like this ("x.." because it's then shown last in DOM Browsers...) + * TODO: remove this (was moved to range.js) + * + * @param rangeObject "Aloha clean" range object including a commonAncestorContainer + * @return obj selection + * @hide + */ + getSelectionTree: function(rangeObject) { + if (!rangeObject) { // if called without any parameters, the method acts as getter for this.selectionTree + return this.rangeObject.getSelectionTree(); + } + if (!rangeObject.commonAncestorContainer) { + Aloha.Log.error(this, 'the rangeObject is missing the commonAncestorContainer'); + return false; + } + + this.inselection = false; + + // before getting the selection tree, we do a cleanup + if (GENTICS.Utils.Dom.doCleanup({'merge' : true}, rangeObject)) { + this.rangeObject.update(); + this.rangeObject.select(); + } + + return this.recursiveGetSelectionTree(rangeObject, rangeObject.commonAncestorContainer); + }, + + /** + * Recursive inner function for generating the selection tree. + * TODO: remove this (was moved to range.js) + * @param rangeObject range object + * @param currentObject current DOM object for which the selection tree shall be generated + * @return array of SelectionTree objects for the children of the current DOM object + * @hide + */ + recursiveGetSelectionTree: function (rangeObject, currentObject) { + // get all direct children of the given object + var jQueryCurrentObject = jQuery(currentObject), + childCount = 0, + that = this, + currentElements = []; + + jQueryCurrentObject.contents().each(function(index) { + var selectionType = 'none', + startOffset = false, + endOffset = false, + collapsedFound = false, + i, elementsLength, + noneFound = false, + partialFound = false, + fullFound = false; + + // check for collapsed selections between nodes + if (rangeObject.isCollapsed() && currentObject === rangeObject.startContainer && rangeObject.startOffset == index) { + // insert an extra selectiontree object for the collapsed selection here + currentElements[childCount] = new Aloha.Selection.SelectionTree(); + currentElements[childCount].selection = 'collapsed'; + currentElements[childCount].domobj = undefined; + that.inselection = false; + collapsedFound = true; + childCount++; + } + + if (!that.inselection && !collapsedFound) { + // the start of the selection was not yet found, so look for it now + // check whether the start of the selection is found here + + // check is dependent on the node type + switch(this.nodeType) { + case 3: // text node + if (this === rangeObject.startContainer) { + // the selection starts here + that.inselection = true; + + // when the startoffset is > 0, the selection type is only partial + selectionType = rangeObject.startOffset > 0 ? 'partial' : 'full'; + startOffset = rangeObject.startOffset; + endOffset = this.length; + } + break; + case 1: // element node + if (this === rangeObject.startContainer && rangeObject.startOffset === 0) { + // the selection starts here + that.inselection = true; + selectionType = 'full'; + } + if (currentObject === rangeObject.startContainer && rangeObject.startOffset === index) { + // the selection starts here + that.inselection = true; + selectionType = 'full'; + } + break; + } + } + + if (that.inselection && !collapsedFound) { + if (selectionType == 'none') { + selectionType = 'full'; + } + // we already found the start of the selection, so look for the end of the selection now + // check whether the end of the selection is found here + + switch(this.nodeType) { + case 3: // text node + if (this === rangeObject.endContainer) { + // the selection ends here + that.inselection = false; + + // check for partial selection here + if (rangeObject.endOffset < this.length) { + selectionType = 'partial'; + } + if (startOffset === false) { + startOffset = 0; + } + endOffset = rangeObject.endOffset; + } + break; + case 1: // element node + if (this === rangeObject.endContainer && rangeObject.endOffset === 0) { + that.inselection = false; + } + break; + } + if (currentObject === rangeObject.endContainer && rangeObject.endOffset <= index) { + that.inselection = false; + selectionType = 'none'; + } + } + + // create the current selection tree entry + currentElements[childCount] = new Aloha.Selection.SelectionTree(); + currentElements[childCount].domobj = this; + currentElements[childCount].selection = selectionType; + if (selectionType == 'partial') { + currentElements[childCount].startOffset = startOffset; + currentElements[childCount].endOffset = endOffset; + } + + // now do the recursion step into the current object + currentElements[childCount].children = that.recursiveGetSelectionTree(rangeObject, this); + elementsLength = currentElements[childCount].children.length; + + // check whether a selection was found within the children + if (elementsLength > 0) { + for ( i = 0; i < elementsLength; ++i) { + switch(currentElements[childCount].children[i].selection) { + case 'none': + noneFound = true; + break; + case 'full': + fullFound = true; + break; + case 'partial': + partialFound = true; + break; + } + } + + if (partialFound || (fullFound && noneFound)) { + // found at least one 'partial' selection in the children, or both 'full' and 'none', so this element is also 'partial' selected + currentElements[childCount].selection = 'partial'; + } else if (fullFound && !partialFound && !noneFound) { + // only found 'full' selected children, so this element is also 'full' selected + currentElements[childCount].selection = 'full'; + } + } + + childCount++; + }); + + // extra check for collapsed selections at the end of the current element + if (rangeObject.isCollapsed() + && currentObject === rangeObject.startContainer + && rangeObject.startOffset == currentObject.childNodes.length) { + currentElements[childCount] = new Aloha.Selection.SelectionTree(); + currentElements[childCount].selection = 'collapsed'; + currentElements[childCount].domobj = undefined; + } + + return currentElements; + }, + + /** + * Get the currently selected range + * @return {Aloha.Selection.SelectionRange} currently selected range + * @method + */ + getRangeObject: function() { + return this.rangeObject; + }, + + /** + * method finds out, if a node is within a certain markup or not + * @param rangeObj Aloha rangeObject + * @param startOrEnd boolean; defines, if start or endContainer should be used: false for start, true for end + * @param markupObject jQuery object of the markup to look for + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @param limitObject dom object which limits the search are within the dom. normally this will be the active Editable + * @return true, if the markup is effective on the range objects start or end node + * @hide + */ + isRangeObjectWithinMarkup: function(rangeObject, startOrEnd, markupObject, tagComparator, limitObject) { + var + domObj = !startOrEnd?rangeObject.startContainer:rangeObject.endContainer, + that = this, + parents = jQuery(domObj).parents(), + returnVal = false, + i = -1; + + // check if a comparison method was passed as parameter ... + if (typeof tagComparator !== 'undefined' && typeof tagComparator !== 'function') { + Aloha.Log.error(this,'parameter tagComparator is not a function'); + } + // ... if not use this as standard tag comparison method + if (typeof tagComparator === 'undefined') { + tagComparator = function(domobj, markupObject) { + return that.standardTextLevelSemanticsComparator(domobj, markupObject); // TODO should actually be this.getStandardTagComparator(markupObject) + }; + } + + if (parents.length > 0) { + parents.each(function() { + // the limit object was reached (normally the Editable Element) + if (this === limitObject) { + Aloha.Log.debug(that,'reached limit dom obj'); + return false; // break() of jQuery .each(); THIS IS NOT THE FUNCTION RETURN VALUE + } + if (tagComparator(this, markupObject)) { + if (returnVal === false) { + returnVal = []; + } + Aloha.Log.debug(that,'reached object equal to markup'); + i++; + returnVal[i] = this; + return true; // continue() of jQuery .each(); THIS IS NOT THE FUNCTION RETURN VALUE + } + }); + } + return returnVal; + }, + + /** + * standard method, to compare a domobj and a jquery object for sections and grouping content (e.g. p, h1, h2, ul, ....). + * is always used when no other tag comparator is passed as parameter + * @param domobj domobject to compare with markup + * @param markupObject jQuery object of the markup to compare with domobj + * @return true if objects are equal and false if not + * @hide + */ + standardSectionsAndGroupingContentComparator: function(domobj, markupObject) { + if (domobj.nodeType === 1) { + if (markupObject[0].tagName && Aloha.Selection.replacingElements[ domobj.tagName.toLowerCase() ] && Aloha.Selection.replacingElements[ domobj.tagName.toLowerCase() ].indexOf(markupObject[0].tagName.toLowerCase()) != -1) { + return true; + } + } else { + Aloha.Log.debug(this,'only element nodes (nodeType == 1) can be compared'); + } + return false; + }, + + /** + * standard method, to compare a domobj and a jquery object for their tagName (aka span elements, e.g. b, i, sup, span, ...). + * is always used when no other tag comparator is passed as parameter + * @param domobj domobject to compare with markup + * @param markupObject jQuery object of the markup to compare with domobj + * @return true if objects are equal and false if not + * @hide + */ + standardTagNameComparator : function(domobj, markupObject) { + if (domobj.nodeType === 1) { + if (domobj.tagName.toLowerCase() != markupObject[0].tagName.toLowerCase()) { + // Aloha.Log.debug(this, 'tag comparison for <' + domobj.tagName.toLowerCase() + '> and <' + markupObject[0].tagName.toLowerCase() + '> failed because tags are different'); + return false; + } + return true;//domobj.attributes.length + } else { + Aloha.Log.debug(this,'only element nodes (nodeType == 1) can be compared'); + } + return false; + }, + + /** + * standard method, to compare a domobj and a jquery object for text level semantics (aka span elements, e.g. b, i, sup, span, ...). + * is always used when no other tag comparator is passed as parameter + * @param domobj domobject to compare with markup + * @param markupObject jQuery object of the markup to compare with domobj + * @return true if objects are equal and false if not + * @hide + */ + standardTextLevelSemanticsComparator: function(domobj, markupObject) { + // only element nodes can be compared + if (domobj.nodeType === 1) { + if (domobj.tagName.toLowerCase() != markupObject[0].tagName.toLowerCase()) { + // Aloha.Log.debug(this, 'tag comparison for <' + domobj.tagName.toLowerCase() + '> and <' + markupObject[0].tagName.toLowerCase() + '> failed because tags are different'); + return false; + } + if (!this.standardAttributesComparator(domobj, markupObject)) { + return false; + } + return true;//domobj.attributes.length + } else { + Aloha.Log.debug(this,'only element nodes (nodeType == 1) can be compared'); + } + return false; + }, + + + /** + * standard method, to compare attributes of one dom obj and one markup obj (jQuery) + * @param domobj domobject to compare with markup + * @param markupObject jQuery object of the markup to compare with domobj + * @return true if objects are equal and false if not + * @hide + */ + standardAttributesComparator: function(domobj, markupObject) { + var i, attr, classString, classes, classes2, classLength, attrLength, domAttrLength; + + if (domobj.attributes && domobj.attributes.length && domobj.attributes.length > 0) { + for (i = 0, domAttrLength = domobj.attributes.length; i < domAttrLength; i++) { + attr = domobj.attributes[i]; + if (attr.nodeName.toLowerCase() == 'class' && attr.nodeValue.length > 0) { + classString = attr.nodeValue; + classes = classString.split(' '); + } + } + } + + if (markupObject[0].attributes && markupObject[0].attributes.length && markupObject[0].attributes.length > 0) { + for (i = 0, attrLength = markupObject[0].attributes.length; i < attrLength; i++) { + attr = markupObject[0].attributes[i]; + if (attr.nodeName.toLowerCase() == 'class' && attr.nodeValue.length > 0) { + classString = attr.nodeValue; + classes2 = classString.split(' '); + } + } + } + + if (classes && !classes2 || classes2 && !classes) { + Aloha.Log.debug(this, 'tag comparison for <' + domobj.tagName.toLowerCase() + '> failed because one element has classes and the other has not'); + return false; + } + if (classes && classes2 && classes.length != classes2.length) { + Aloha.Log.debug(this, 'tag comparison for <' + domobj.tagName.toLowerCase() + '> failed because of a different amount of classes'); + return false; + } + if (classes && classes2 && classes.length === classes2.length && classes.length !== 0) { + for (i = 0, classLength = classes.length; i < classLength; i++) { + if (!markupObject.hasClass(classes[ i ])) { + Aloha.Log.debug(this, 'tag comparison for <' + domobj.tagName.toLowerCase() + '> failed because of different classes'); + return false; + } + } + } + return true; + }, + + /** + * method finds out, if a node is within a certain markup or not + * @param rangeObj Aloha rangeObject + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return void; TODO: should return true if the markup applied successfully and false if not + * @hide + */ + changeMarkup: function(rangeObject, markupObject, tagComparator) { + var + tagName = markupObject[0].tagName.toLowerCase(), + newCAC, limitObject, + backupRangeObject, + relevantMarkupObjectsAtSelectionStart = this.isRangeObjectWithinMarkup(rangeObject, false, markupObject, tagComparator, limitObject), + relevantMarkupObjectsAtSelectionEnd = this.isRangeObjectWithinMarkup(rangeObject, true, markupObject, tagComparator, limitObject), + nextSibling, relevantMarkupObjectAfterSelection, + prevSibling, relevantMarkupObjectBeforeSelection, + extendedRangeObject; + + // if the element is a replacing element (like p/h1/h2/h3/h4/h5/h6...), which must not wrap each other + // use a clone of rangeObject + if (this.replacingElements[ tagName ]) { + // backup rangeObject for later selection; + backupRangeObject = rangeObject; + + // create a new range object to not modify the orginal + rangeObject = new this.SelectionRange(rangeObject); + + // either select the active Editable as new commonAncestorContainer (CAC) or use the body + if (Aloha.activeEditable) { + newCAC= Aloha.activeEditable.obj.get(0); + } else { + newCAC = jQuery('body'); + } + // update rangeObject by setting the newCAC and automatically recalculating the selectionTree + rangeObject.update(newCAC); + + // store the information, that the markupObject can be replaced (not must be!!) inside the jQuery markup object + markupObject.isReplacingElement = true; + } + // if the element is NOT a replacing element, then something needs to be selected, otherwise it can not be wrapped + // therefor the method can return false, if nothing is selected ( = rangeObject is collapsed) + else { + if (rangeObject.isCollapsed()) { + Aloha.Log.debug(this, 'early returning from applying markup because nothing is currently selected'); + return false; + } + } + + // is Start/End DOM Obj inside the markup to change + if (Aloha.activeEditable) { + limitObject = Aloha.activeEditable.obj[0]; + } else { + limitObject = jQuery('body'); + } + + if (!markupObject.isReplacingElement && rangeObject.startOffset === 0) { // don't care about replacers, because they never extend + if (prevSibling = this.getTextNodeSibling(false, rangeObject.commonAncestorContainer.parentNode, rangeObject.startContainer)) { + relevantMarkupObjectBeforeSelection = this.isRangeObjectWithinMarkup({startContainer : prevSibling, startOffset : 0}, false, markupObject, tagComparator, limitObject); + } + } + if (!markupObject.isReplacingElement && (rangeObject.endOffset === rangeObject.endContainer.length)) { // don't care about replacers, because they never extend + if (nextSibling = this.getTextNodeSibling(true, rangeObject.commonAncestorContainer.parentNode, rangeObject.endContainer)) { + relevantMarkupObjectAfterSelection = this.isRangeObjectWithinMarkup({startContainer: nextSibling, startOffset: 0}, false, markupObject, tagComparator, limitObject); + } + } + + // decide what to do (expand or reduce markup) + // Alternative A: from markup to no-markup: markup will be removed in selection; + // reapplied from original markup start to selection start + if (!markupObject.isReplacingElement && (relevantMarkupObjectsAtSelectionStart && !relevantMarkupObjectsAtSelectionEnd)) { + Aloha.Log.info(this, 'markup 2 non-markup'); + this.prepareForRemoval(rangeObject.getSelectionTree(), markupObject, tagComparator); + jQuery(relevantMarkupObjectsAtSelectionStart).addClass('preparedForRemoval'); + this.insertCroppedMarkups(relevantMarkupObjectsAtSelectionStart, rangeObject, false, tagComparator); + } + + // Alternative B: from markup to markup: + // remove selected markup (=split existing markup if single, shrink if two different) + else if (!markupObject.isReplacingElement && relevantMarkupObjectsAtSelectionStart && relevantMarkupObjectsAtSelectionEnd) { + Aloha.Log.info(this, 'markup 2 markup'); + this.prepareForRemoval(rangeObject.getSelectionTree(), markupObject, tagComparator); + this.splitRelevantMarkupObject(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd, rangeObject, tagComparator); + } + + // Alternative C: from no-markup to markup OR with next2markup: + // new markup is wrapped from selection start to end of originalmarkup, original is remove afterwards + else if (!markupObject.isReplacingElement && ((!relevantMarkupObjectsAtSelectionStart && relevantMarkupObjectsAtSelectionEnd) || relevantMarkupObjectAfterSelection || relevantMarkupObjectBeforeSelection )) { // + Aloha.Log.info(this, 'non-markup 2 markup OR with next2markup'); + // move end of rangeObject to end of relevant markups + if (relevantMarkupObjectBeforeSelection && relevantMarkupObjectAfterSelection) { + extendedRangeObject = new Aloha.Selection.SelectionRange(rangeObject); + extendedRangeObject.startContainer = jQuery(relevantMarkupObjectBeforeSelection[ relevantMarkupObjectBeforeSelection.length-1 ]).textNodes()[0]; + extendedRangeObject.startOffset = 0; + extendedRangeObject.endContainer = jQuery(relevantMarkupObjectAfterSelection[ relevantMarkupObjectAfterSelection.length-1 ]).textNodes().last()[0]; + extendedRangeObject.endOffset = extendedRangeObject.endContainer.length; + extendedRangeObject.update(); + this.applyMarkup(extendedRangeObject.getSelectionTree(), rangeObject, markupObject, tagComparator); + Aloha.Log.info(this, 'double extending previous markup(previous and after selection), actually wrapping it ...'); + + } else if (relevantMarkupObjectBeforeSelection && !relevantMarkupObjectAfterSelection && !relevantMarkupObjectsAtSelectionEnd) { + this.extendExistingMarkupWithSelection(relevantMarkupObjectBeforeSelection, rangeObject, false, tagComparator); + Aloha.Log.info(this, 'extending previous markup'); + + } else if (relevantMarkupObjectBeforeSelection && !relevantMarkupObjectAfterSelection && relevantMarkupObjectsAtSelectionEnd) { + extendedRangeObject = new Aloha.Selection.SelectionRange(rangeObject); + extendedRangeObject.startContainer = jQuery(relevantMarkupObjectBeforeSelection[ relevantMarkupObjectBeforeSelection.length-1 ]).textNodes()[0]; + extendedRangeObject.startOffset = 0; + extendedRangeObject.endContainer = jQuery(relevantMarkupObjectsAtSelectionEnd[ relevantMarkupObjectsAtSelectionEnd.length-1 ]).textNodes().last()[0]; + extendedRangeObject.endOffset = extendedRangeObject.endContainer.length; + extendedRangeObject.update(); + this.applyMarkup(extendedRangeObject.getSelectionTree(), rangeObject, markupObject, tagComparator); + Aloha.Log.info(this, 'double extending previous markup(previous and relevant at the end), actually wrapping it ...'); + + } else if (!relevantMarkupObjectBeforeSelection && relevantMarkupObjectAfterSelection) { + this.extendExistingMarkupWithSelection(relevantMarkupObjectAfterSelection, rangeObject, true, tagComparator); + Aloha.Log.info(this, 'extending following markup backwards'); + + } else { + this.extendExistingMarkupWithSelection(relevantMarkupObjectsAtSelectionEnd, rangeObject, true, tagComparator); + } + } + + // Alternative D: no-markup to no-markup: easy + else if (markupObject.isReplacingElement || (!relevantMarkupObjectsAtSelectionStart && !relevantMarkupObjectsAtSelectionEnd && !relevantMarkupObjectBeforeSelection && !relevantMarkupObjectAfterSelection)) { + Aloha.Log.info(this, 'non-markup 2 non-markup'); + this.applyMarkup(rangeObject.getSelectionTree(), rangeObject, markupObject, tagComparator, {setRangeObject2NewMarkup: true}); + } + + // remove all marked items + jQuery('.preparedForRemoval').zap(); + + // recalculate cac and selectionTree + rangeObject.update(); + + // update selection + if (markupObject.isReplacingElement) { + // this.setSelection(backupRangeObject, true); + backupRangeObject.select(); + } else { + // this.setSelection(rangeObject); + rangeObject.select(); + } + }, + + /** + * method compares a JS array of domobjects with a range object and decides, if the rangeObject spans the whole markup objects. method is used to decide if a markup2markup selection can be completely remove or if it must be splitted into 2 separate markups + * @param relevantMarkupObjectsAtSelectionStart JS Array of dom objects, which are parents to the rangeObject.startContainer + * @param relevantMarkupObjectsAtSelectionEnd JS Array of dom objects, which are parents to the rangeObject.endContainer + * @param rangeObj Aloha rangeObject + * @return true, if rangeObjects and markup objects are identical, false otherwise + * @hide + */ + areMarkupObjectsAsLongAsRangeObject: function(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd, rangeObject) { + var i, el, textNode, relMarkupEnd, relMarkupStart; + + if (rangeObject.startOffset !== 0) { + return false; + } + + for (i = 0, relMarkupStart = relevantMarkupObjectsAtSelectionStart.length; i < relMarkupStart; i++) { + el = jQuery(relevantMarkupObjectsAtSelectionStart[i]); + if (el.textNodes().first()[0] !== rangeObject.startContainer) { + return false; + } + } + + for (i = 0, relMarkupEnd = relevantMarkupObjectsAtSelectionEnd.length; i < relMarkupEnd; i++) { + el = jQuery(relevantMarkupObjectsAtSelectionEnd[i]); + textNode = el.textNodes().last()[0]; + if (textNode !== rangeObject.endContainer || textNode.length != rangeObject.endOffset) { + return false; + } + } + + return true; + }, + + /** + * method used to remove/split markup from a "markup2markup" selection + * @param relevantMarkupObjectsAtSelectionStart JS Array of dom objects, which are parents to the rangeObject.startContainer + * @param relevantMarkupObjectsAtSelectionEnd JS Array of dom objects, which are parents to the rangeObject.endContainer + * @param rangeObj Aloha rangeObject + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return true (always, since no "false" case is currently known...but might be added) + * @hide + */ + splitRelevantMarkupObject: function(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd, rangeObject, tagComparator) { + // mark them to be deleted + jQuery(relevantMarkupObjectsAtSelectionStart).addClass('preparedForRemoval'); + jQuery(relevantMarkupObjectsAtSelectionEnd).addClass('preparedForRemoval'); + + // check if the rangeObject is identical with the relevantMarkupObjects (in this case the markup can simply be removed) + if (this.areMarkupObjectsAsLongAsRangeObject(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd, rangeObject)) { + return true; + } + + // find intersection (this can always only be one dom element (namely the highest) because all others will be removed + var relevantMarkupObjectAtSelectionStartAndEnd = this.intersectRelevantMarkupObjects(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd); + + if (relevantMarkupObjectAtSelectionStartAndEnd) { + this.insertCroppedMarkups([relevantMarkupObjectAtSelectionStartAndEnd], rangeObject, false, tagComparator); + this.insertCroppedMarkups([relevantMarkupObjectAtSelectionStartAndEnd], rangeObject, true, tagComparator); + } else { + this.insertCroppedMarkups(relevantMarkupObjectsAtSelectionStart, rangeObject, false, tagComparator); + this.insertCroppedMarkups(relevantMarkupObjectsAtSelectionEnd, rangeObject, true, tagComparator); + } + return true; + }, + + /** + * method takes two arrays of bottom up dom objects, compares them and returns either the object closest to the root or false + * @param relevantMarkupObjectsAtSelectionStart JS Array of dom objects + * @param relevantMarkupObjectsAtSelectionEnd JS Array of dom objects + * @return dom object closest to the root or false + * @hide + */ + intersectRelevantMarkupObjects: function(relevantMarkupObjectsAtSelectionStart, relevantMarkupObjectsAtSelectionEnd) { + var intersection = false, i, elStart, j, elEnd, relMarkupStart, relMarkupEnd; + if (!relevantMarkupObjectsAtSelectionStart || !relevantMarkupObjectsAtSelectionEnd) { + return intersection; // we can only intersect, if we have to arrays! + } + relMarkupStart = relevantMarkupObjectsAtSelectionStart.length; + relMarkupEnd = relevantMarkupObjectsAtSelectionEnd.length; + for (i = 0; i < relMarkupStart; i++) { + elStart = relevantMarkupObjectsAtSelectionStart[i]; + for (j = 0; j < relMarkupEnd; j++) { + elEnd = relevantMarkupObjectsAtSelectionEnd[j]; + if (elStart === elEnd) { + intersection = elStart; + } + } + } + return intersection; + }, + + /** + * method used to add markup to a nonmarkup2markup selection + * @param relevantMarkupObjects JS Array of dom objects effecting either the start or endContainer of a selection (which should be extended) + * @param rangeObject Aloha rangeObject the markups should be extended to + * @param startOrEnd boolean; defines, if the existing markups should be extended forwards or backwards (is propably redundant and could be found out by comparing start or end container with the markup array dom objects) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return true + * @hide + */ + extendExistingMarkupWithSelection: function(relevantMarkupObjects, rangeObject, startOrEnd, tagComparator) { + var extendMarkupsAtStart, extendMarkupsAtEnd, objects, i, relMarkupLength, el, textnodes, nodeNr; + if (!startOrEnd) { // = Start + // start part of rangeObject should be used, therefor existing markups are cropped at the end + extendMarkupsAtStart = true; + } + if (startOrEnd) { // = End + // end part of rangeObject should be used, therefor existing markups are cropped at start (beginning) + extendMarkupsAtEnd = true; + } + objects = []; + for( i = 0, relMarkupLength = relevantMarkupObjects.length; i < relMarkupLength; i++){ + objects[i] = new this.SelectionRange(); + el = relevantMarkupObjects[i]; + if (extendMarkupsAtEnd && !extendMarkupsAtStart) { + objects[i].startContainer = rangeObject.startContainer; // jQuery(el).contents()[0]; + objects[i].startOffset = rangeObject.startOffset; + textnodes = jQuery(el).textNodes(true); + + nodeNr = textnodes.length - 1; + objects[i].endContainer = textnodes[ nodeNr ]; + objects[i].endOffset = textnodes[ nodeNr ].length; + objects[i].update(); + this.applyMarkup(objects[i].getSelectionTree(), rangeObject, this.getClonedMarkup4Wrapping(el), tagComparator, {setRangeObject2NewMarkup: true}); + } + if (!extendMarkupsAtEnd && extendMarkupsAtStart) { + textnodes = jQuery(el).textNodes(true); + objects[i].startContainer = textnodes[0]; // jQuery(el).contents()[0]; + objects[i].startOffset = 0; + objects[i].endContainer = rangeObject.endContainer; + objects[i].endOffset = rangeObject.endOffset; + objects[i].update(); + this.applyMarkup(objects[i].getSelectionTree(), rangeObject, this.getClonedMarkup4Wrapping(el), tagComparator, {setRangeObject2NewMarkup: true}); + } + } + return true; + }, + + /** + * method creates an empty markup jQuery object from a dom object passed as paramter + * @param domobj domobject to be cloned, cleaned and emptied + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return jQuery wrapper object to be passed to e.g. this.applyMarkup(...) + * @hide + */ + getClonedMarkup4Wrapping: function(domobj) { + var wrapper = jQuery(domobj).clone().removeClass('preparedForRemoval').empty(); + if (wrapper.attr('class').length === 0) { + wrapper.removeAttr('class'); + } + return wrapper; + }, + + /** + * method used to subtract the range object from existing markup. in other words: certain markup is removed from the selections defined by the rangeObject + * @param relevantMarkupObjects JS Array of dom objects effecting either the start or endContainer of a selection (which should be extended) + * @param rangeObject Aloha rangeObject the markups should be removed from + * @param startOrEnd boolean; defines, if the existing markups should be reduced at the beginning of the tag or at the end (is propably redundant and could be found out by comparing start or end container with the markup array dom objects) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return true + * @hide + */ + insertCroppedMarkups: function(relevantMarkupObjects, rangeObject, startOrEnd, tagComparator) { + var cropMarkupsAtEnd,cropMarkupsAtStart,textnodes,objects,i,el,textNodes; + if (!startOrEnd) { // = Start + // start part of rangeObject should be used, therefor existing markups are cropped at the end + cropMarkupsAtEnd = true; + } else { // = End + // end part of rangeObject should be used, therefor existing markups are cropped at start (beginning) + cropMarkupsAtStart = true; + } + objects = []; + for( i = 0; i'); ) + * @return void + * @hide + */ + changeMarkupOnSelection: function(markupObject) { + // change the markup + this.changeMarkup(this.getRangeObject(), markupObject, this.getStandardTagComparator(markupObject)); + + // merge text nodes + + GENTICS.Utils.Dom.doCleanup({'merge' : true}, this.rangeObject); + // update the range and select it + this.rangeObject.update(); + this.rangeObject.select(); + }, + + /** + * apply a certain markup to the selection Tree + * @param selectionTree SelectionTree Object markup should be applied to + * @param rangeObject Aloha rangeObject which will be modified to reflect the dom changes, after the markup was applied (only if activated via options) + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @param options JS object, with the following boolean properties: setRangeObject2NewMarkup, setRangeObject2NextSibling, setRangeObject2PreviousSibling + * @return void + * @hide + */ + applyMarkup: function(selectionTree, rangeObject, markupObject, tagComparator, options) { + var optimizedSelectionTree, i, el, breakpoint; + + options = options ? options : {}; + // first same tags from within fully selected nodes for removal + this.prepareForRemoval(selectionTree, markupObject, tagComparator); + + // first let's optimize the selection Tree in useful groups which can be wrapped together + optimizedSelectionTree = this.optimizeSelectionTree4Markup(selectionTree, markupObject, tagComparator); + breakpoint = true; + + // now iterate over grouped elements and either recursively dive into object or wrap it as a whole + for ( i = 0; i < optimizedSelectionTree.length; i++) { + el = optimizedSelectionTree[i]; + if (el.wrappable) { + this.wrapMarkupAroundSelectionTree(el.elements, rangeObject, markupObject, tagComparator, options); + } else { + Aloha.Log.debug(this,'dive further into non-wrappable object'); + this.applyMarkup(el.element.children, rangeObject, markupObject, tagComparator, options); + } + } + }, + + /** + * returns the type of the given markup (trying to match HTML5) + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @return string name of the markup type + * @hide + */ + getMarkupType: function(markupObject) { + var nn = jQuery(markupObject)[0].nodeName.toLowerCase(); + if (markupObject.outerHtml) { + Aloha.Log.debug(this, 'Node name detected: ' + nn + ' for: ' + markupObject.outerHtml()); + } + if (nn == '#text') {return 'textNode';} + if (this.replacingElements[ nn ]) {return 'sectionOrGroupingContent';} + if (this.tagHierarchy [ nn ]) {return 'textLevelSemantics';} + Aloha.Log.warn(this, 'unknown markup passed to this.getMarkupType(...): ' + markupObject.outerHtml()); + }, + + /** + * returns the standard tag comparator for the given markup object + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @return function tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @hide + */ + getStandardTagComparator: function(markupObject) { + var that = this, result; + switch(this.getMarkupType(markupObject)) { + case 'textNode': + result = function(p1, p2) { + return false; + }; + break; + + case 'sectionOrGroupingContent': + result = function(domobj, markupObject) { + return that.standardSectionsAndGroupingContentComparator(domobj, markupObject); + }; + break; + + case 'textLevelSemantics': + /* falls through */ + default: + result = function(domobj, markupObject) { + return that.standardTextLevelSemanticsComparator(domobj, markupObject); + }; + break; + } + return result; + }, + + /** + * searches for fully selected equal markup tags + * @param selectionTree SelectionTree Object markup should be applied to + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @return void + * @hide + */ + prepareForRemoval: function(selectionTree, markupObject, tagComparator) { + var that = this, i, el; + + // check if a comparison method was passed as parameter ... + if (typeof tagComparator !== 'undefined' && typeof tagComparator !== 'function') { + Aloha.Log.error(this,'parameter tagComparator is not a function'); + } + // ... if not use this as standard tag comparison method + if (typeof tagComparator === 'undefined') { + tagComparator = this.getStandardTagComparator(markupObject); + } + for ( i = 0; i 0) { + this.prepareForRemoval(el.children, markupObject, tagComparator); + } + + } + }, + + /** + * searches for fully selected equal markup tags + * @param selectionTree SelectionTree Object markup should be applied to + * @param rangeObject Aloha rangeObject the markup will be applied to + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @param tagComparator method, which is used to compare the dom object and the jQuery markup object. the method must accept 2 parameters, the first is the domobj, the second is the jquery object. if no method is specified, the method this.standardTextLevelSemanticsComparator is used + * @param options JS object, with the following boolean properties: setRangeObject2NewMarkup, setRangeObject2NextSibling, setRangeObject2PreviousSibling + * @return void + * @hide + */ + wrapMarkupAroundSelectionTree: function(selectionTree, rangeObject, markupObject, tagComparator, options) { + // first let's find out if theoretically the whole selection can be wrapped with one tag and save it for later use + var objects2wrap = [], // // this will be used later to collect objects + j = -1, // internal counter, + breakpoint = true, + preText = '', + postText = '', + prevOrNext, + textNode2Start, + textnodes, + newMarkup, + i, el, middleText; + + + + Aloha.Log.debug(this,'The formatting <' + markupObject[0].tagName + '> will be wrapped around the selection'); + + // now lets iterate over the elements + for (i = 0; i < selectionTree.length; i++) { + el = selectionTree[i]; + + // check if markup is allowed inside the elements parent + if (el.domobj && !this.canTag1WrapTag2(el.domobj.parentNode.tagName.toLowerCase(), markupObject[0].tagName.toLowerCase())) { + Aloha.Log.info(this,'Skipping the wrapping of <' + markupObject[0].tagName.toLowerCase() + '> because this tag is not allowed inside <' + el.domobj.parentNode.tagName.toLowerCase() + '>'); + continue; + } + + // skip empty text nodes + if (el.domobj && el.domobj.nodeType === 3 && jQuery.trim(el.domobj.nodeValue).length === 0) { + continue; + } + + // partial element, can either be a textnode and therefore be wrapped (at least partially) + // or can be a nodeType == 1 (tag) which must be dived into + if (el.domobj && el.selection == 'partial' && !markupObject.isReplacingElement) { + if (el.startOffset !== undefined && el.endOffset === undefined) { + j++; + preText += el.domobj.data.substr(0,el.startOffset); + el.domobj.data = el.domobj.data.substr(el.startOffset, el.domobj.data.length-el.startOffset); + objects2wrap[j] = el.domobj; + } else if (el.endOffset !== undefined && el.startOffset === undefined) { + j++; + postText += el.domobj.data.substr(el.endOffset, el.domobj.data.length-el.endOffset); + el.domobj.data = el.domobj.data.substr(0, el.endOffset); + objects2wrap[j] = el.domobj; + } else if (el.endOffset !== undefined && el.startOffset !== undefined) { + if (el.startOffset == el.endOffset) { // do not wrap empty selections + Aloha.Log.debug(this, 'skipping empty selection'); + continue; + } + j++; + preText += el.domobj.data.substr(0,el.startOffset); + middleText = el.domobj.data.substr(el.startOffset,el.endOffset-el.startOffset); + postText += el.domobj.data.substr(el.endOffset, el.domobj.data.length-el.endOffset); + el.domobj.data = middleText; + objects2wrap[j] = el.domobj; + } else { + // a partially selected item without selectionStart/EndOffset is a nodeType 1 Element on the way to the textnode + Aloha.Log.debug(this, 'diving into object'); + this.applyMarkup(el.children, rangeObject, markupObject, tagComparator, options); + } + } + // fully selected dom elements can be wrapped as whole element + if (el.domobj && (el.selection == 'full' || (el.selection == 'partial' && markupObject.isReplacingElement))) { + j++; + objects2wrap[j] = el.domobj; + } + } + + if (objects2wrap.length > 0) { + // wrap collected DOM object with markupObject + objects2wrap = jQuery(objects2wrap); + + // make a fix for text nodes in
  1. 's in ie + jQuery.each(objects2wrap, function(index, element) { + if (jQuery.browser.msie && element.nodeType == 3 + && !element.nextSibling && !element.previousSibling + && element.parentNode + && element.parentNode.nodeName.toLowerCase() == 'li') { + element.data = jQuery.trim(element.data); + } + }); + + newMarkup = objects2wrap.wrapAll(markupObject).parent(); + newMarkup.before(preText).after(postText); + + if (options.setRangeObject2NewMarkup) { // this is used, when markup is added to normal/normal Text + textnodes = objects2wrap.textNodes(); + + if (textnodes.index(rangeObject.startContainer) != -1) { + rangeObject.startOffset = 0; + } + if (textnodes.index(rangeObject.endContainer) != -1) { + rangeObject.endOffset = rangeObject.endContainer.length; + } + breakpoint=true; + } + if (options.setRangeObject2NextSibling){ + prevOrNext = true; + textNode2Start = newMarkup.textNodes(true).last()[0]; + if (objects2wrap.index(rangeObject.startContainer) != -1) { + rangeObject.startContainer = this.getTextNodeSibling(prevOrNext, newMarkup.parent(), textNode2Start); + rangeObject.startOffset = 0; + } + if (objects2wrap.index(rangeObject.endContainer) != -1) { + rangeObject.endContainer = this.getTextNodeSibling(prevOrNext, newMarkup.parent(), textNode2Start); + rangeObject.endOffset = rangeObject.endOffset - textNode2Start.length; + } + } + if (options.setRangeObject2PreviousSibling){ + prevOrNext = false; + textNode2Start = newMarkup.textNodes(true).first()[0]; + if (objects2wrap.index(rangeObject.startContainer) != -1) { + rangeObject.startContainer = this.getTextNodeSibling(prevOrNext, newMarkup.parent(), textNode2Start); + rangeObject.startOffset = 0; + } + if (objects2wrap.index(rangeObject.endContainer) != -1) { + rangeObject.endContainer = this.getTextNodeSibling(prevOrNext, newMarkup.parent(), textNode2Start); + rangeObject.endOffset = rangeObject.endContainer.length; + } + } + } + }, + + /** + * takes a text node and return either the next recursive text node sibling or the previous + * @param previousOrNext boolean, false for previous, true for next sibling + * @param commonAncestorContainer dom object to be used as root for the sibling search + * @param currentTextNode dom object of the originating text node + * @return dom object of the sibling text node + * @hide + */ + getTextNodeSibling: function(previousOrNext, commonAncestorContainer, currentTextNode) { + var textNodes = jQuery(commonAncestorContainer).textNodes(true), + newIndex, index; + + index = textNodes.index(currentTextNode); + if (index == -1) { // currentTextNode was not found + return false; + } + newIndex = index + (!previousOrNext ? -1 : 1); + return textNodes[newIndex] ? textNodes[newIndex] : false; + }, + + /** + * takes a selection tree and groups it into markup wrappable selection trees + * @param selectionTree rangeObject selection tree + * @param markupObject jQuery object of the markup to be applied (e.g. created with obj = jQuery(''); ) + * @return JS array of wrappable selection trees + * @hide + */ + optimizeSelectionTree4Markup: function(selectionTree, markupObject, tagComparator) { + var groupMap = [], + outerGroupIndex = 0, + innerGroupIndex = 0, + that = this, + i,j, + endPosition, startPosition; + + if (typeof tagComparator === 'undefined') { + tagComparator = function(domobj, markupObject) { + return that.standardTextLevelSemanticsComparator(markupObject); + }; + } + for( i = 0; i ?? + * .... many possibilities, here I realize the two described cases + */ + + // first find start element starting from the current element going backwards until sibling 0 + startPosition = i; + for (j = i-1; j >= 0; j--) { + if (this.canMarkupBeApplied2ElementAsWhole([ selectionTree[ j ] ], markupObject) && this.isMarkupAllowedToStealSelectionTreeElement(selectionTree[ j ], markupObject)) { + startPosition = j; + } else { + break; + } + } + + // now find the end element starting from the current element going forward until the last sibling + endPosition = i; + for (j = i+1; j < selectionTree.length; j++) { + if (this.canMarkupBeApplied2ElementAsWhole([ selectionTree[ j ] ], markupObject) && this.isMarkupAllowedToStealSelectionTreeElement(selectionTree[ j ], markupObject)) { + endPosition = j; + } else { + break; + } + } + + // now add the elements to the groupMap + innerGroupIndex = 0; + for (j = startPosition; j <= endPosition; j++) { + groupMap[outerGroupIndex].elements[innerGroupIndex] = selectionTree[j]; + groupMap[outerGroupIndex].elements[innerGroupIndex].selection = 'full'; + innerGroupIndex++; + } + innerGroupIndex = 0; + } else { + // normal text level semantics object, no siblings need to be selected + groupMap[outerGroupIndex].elements[innerGroupIndex] = selectionTree[i]; + innerGroupIndex++; + } + } else { + // if no, isolate it in its own group + if (groupMap[outerGroupIndex] !== undefined) { + outerGroupIndex++; + } + groupMap[outerGroupIndex] = {}; + groupMap[outerGroupIndex].wrappable = false; + groupMap[outerGroupIndex].element = selectionTree[i]; + innerGroupIndex = 0; + outerGroupIndex++; + } + } + } + return groupMap; + }, + + /** + * very tricky method, which decides, if a certain markup (normally a replacing markup element like p, h1, blockquote) + * is allowed to extend the user selection to other dom objects (represented as selectionTreeElement) + * to understand the purpose: if the user selection is collapsed inside e.g. some text, which is currently not + * wrapped by the markup to be applied, and therefor the markup does not have an equal markup to replace, then the DOM + * manipulator has to decide which objects to wrap. real example: + *
    + *

    headline

    + * some text blabla bla
    + * more text HERE THE | CURSOR BLINKING and even more bold text + *
    + * when the user now wants to apply e.g. a

    tag, what will be wrapped? it could be useful if the manipulator would actually + * wrap everything inside the div except the

    . but for this purpose someone has to decide, if the markup is + * allowed to wrap certain dom elements in this case the question would be, if the

    is allowed to wrap + * textNodes,
    and and

    . therefore this tricky method should answer the question for those 3 elements + * with true, but for for the

    it should return false. and since the method does not know this, there is a configuration + * for this + * + * @param selectionTree rangeObject selection tree element (only one, not an array of) + * @param markupObject lowercase string of the tag to be verified (e.g. "b") + * @return true if the markup is allowed to wrap the selection tree element, false otherwise + * @hide + */ + isMarkupAllowedToStealSelectionTreeElement: function(selectionTreeElement, markupObject) { + if (!selectionTreeElement.domobj) { + return false; + } + var nodeName = selectionTreeElement.domobj.nodeName.toLowerCase(), + markupName; + + nodeName = (nodeName == '#text') ? 'textNode' : nodeName; + markupName = markupObject[0].nodeName.toLowerCase(); + // if nothing is defined for the markup, it's now allowed + if (!this.allowedToStealElements[ markupName ]) { + return false; + } + // if something is defined, but the specifig tag is not in the list + if (this.allowedToStealElements[ markupName ].indexOf(nodeName) == -1) { + return false; + } + return true; + }, + + /** + * checks if a selection can be completey wrapped by a certain html tags (helper method for this.optimizeSelectionTree4Markup + * @param selectionTree rangeObject selection tree + * @param markupObject lowercase string of the tag to be verified (e.g. "b") + * @return true if selection can be applied as whole, false otherwise + * @hide + */ + canMarkupBeApplied2ElementAsWhole: function(selectionTree, markupObject) { + var htmlTag, i, el, returnVal; + + if (markupObject.jquery) { + htmlTag = markupObject[0].tagName; + } + if (markupObject.tagName) { + htmlTag = markupObject.tagName; + } + + returnVal = true; + for ( i = 0; i < selectionTree.length; i++) { + el = selectionTree[i]; + if (el.domobj && (el.selection != "none" || markupObject.isReplacingElement)) { + // Aloha.Log.debug(this, 'Checking, if <' + htmlTag + '> can be applied to ' + el.domobj.nodeName); + if (!this.canTag1WrapTag2(htmlTag, el.domobj.nodeName)) { + return false; + } + if (el.children.length > 0 && !this.canMarkupBeApplied2ElementAsWhole(el.children, markupObject)) { + return false; + } + } + } + return returnVal; + }, + + /** + * checks if a tag 1 (first parameter) can wrap tag 2 (second parameter). + * IMPORTANT: the method does not verify, if there have to be other tags in between + * Example: this.canTag1WrapTag2("table", "td") will return true, because the method does not take into account, that there has to be a "tr" in between + * @param t1 string: tagname of outer tag to verify, e.g. "b" + * @param t2 string: tagname of inner tag to verify, e.g. "b" + * @return true if tag 1 can wrap tag 2, false otherwise + * @hide + */ + canTag1WrapTag2: function(t1, t2) { + t1 = (t1 == '#text')?'textNode':t1.toLowerCase(); + t2 = (t2 == '#text')?'textNode':t2.toLowerCase(); + if (!this.tagHierarchy[ t1 ]) { + // Aloha.Log.warn(this, t1 + ' is an unknown tag to the method canTag1WrapTag2 (paramter 1). Sadfully allowing the wrapping...'); + return true; + } + if (!this.tagHierarchy[ t2 ]) { + // Aloha.Log.warn(this, t2 + ' is an unknown tag to the method canTag1WrapTag2 (paramter 2). Sadfully allowing the wrapping...'); + return true; + } + var t1Array = this.tagHierarchy[ t1 ], + returnVal = (t1Array.indexOf( t2 ) != -1) ? true : false; + return returnVal; + }, + + /** + * Check whether it is allowed to insert the given tag at the start of the + * current selection. This method will check whether the markup effective for + * the start and outside of the editable part (starting with the editable tag + * itself) may wrap the given tag. + * @param tagName {String} name of the tag which shall be inserted + * @return true when it is allowed to insert that tag, false if not + * @hide + */ + mayInsertTag: function (tagName) { + if (typeof this.rangeObject.unmodifiableMarkupAtStart == 'object') { + // iterate over all DOM elements outside of the editable part + for (var i = 0; i < this.rangeObject.unmodifiableMarkupAtStart.length; ++i) { + // check whether an element may not wrap the given + if (!this.canTag1WrapTag2(this.rangeObject.unmodifiableMarkupAtStart[i].nodeName, tagName)) { + // found a DOM element which forbids to insert the given tag, we are done + return false; + } + } + + // all of the found DOM elements allow inserting the given tag + return true; + } else { + Aloha.Log.warn(this, 'Unable to determine whether tag ' + tagName + ' may be inserted'); + return true; + } + }, + + /** + * String representation + * @return "Aloha.Selection" + * @hide + */ + toString: function() { + return 'Aloha.Selection'; + }, + + /** + * @namespace Aloha.Selection + * @class SelectionRange + * @extends GENTICS.Utils.RangeObject + * Constructor for a range object. + * Optionally you can pass in a range object that's properties will be assigned to the new range object. + * @param rangeObject A range object thats properties will be assigned to the new range object. + * @constructor + */ + SelectionRange: GENTICS.Utils.RangeObject.extend({ + _constructor: function(rangeObject){ + this._super(rangeObject); + // If a range object was passed in we apply the values to the new range object + if (rangeObject) { + if (rangeObject.commonAncestorContainer) { + this.commonAncestorContainer = rangeObject.commonAncestorContainer; + } + if (rangeObject.selectionTree) { + this.selectionTree = rangeObject.selectionTree; + } + if (rangeObject.limitObject) { + this.limitObject = rangeObject.limitObject; + } + if (rangeObject.markupEffectiveAtStart) { + this.markupEffectiveAtStart = rangeObject.markupEffectiveAtStart; + } + if (rangeObject.unmodifiableMarkupAtStart) { + this.unmodifiableMarkupAtStart = rangeObject.unmodifiableMarkupAtStart; + } + if (rangeObject.splitObject) { + this.splitObject = rangeObject.splitObject; + } + } + }, + + /** + * DOM object of the common ancestor from startContainer and endContainer + * @hide + */ + commonAncestorContainer: undefined, + + /** + * The selection tree + * @hide + */ + selectionTree: undefined, + + /** + * Array of DOM objects effective for the start container and inside the + * editable part (inside the limit object). relevant for the button status + * @hide + */ + markupEffectiveAtStart: [], + + /** + * Array of DOM objects effective for the start container, which lies + * outside of the editable portion (starting with the limit object) + * @hide + */ + unmodifiableMarkupAtStart: [], + + /** + * DOM object being the limit for all markup relevant activities + * @hide + */ + limitObject: undefined, + + /** + * DOM object being split when enter key gets hit + * @hide + */ + splitObject: undefined, + + /** + * Sets the visible selection in the Browser based on the range object. + * If the selection is collapsed, this will result in a blinking cursor, + * otherwise in a text selection. + * @method + */ + select: function() { + // Call Utils' select() + this._super(); + + // update the selection + Aloha.Selection.updateSelection(); + }, + + /** + * Method to update a range object internally + * @param commonAncestorContainer (DOM Object); optional Parameter; if set, the parameter + * will be used instead of the automatically calculated CAC + * @return void + * @hide + */ + update: function(commonAncestorContainer) { + this.updatelimitObject(); + this.updateMarkupEffectiveAtStart(); + this.updateCommonAncestorContainer(commonAncestorContainer); + + // reset the selectiontree (must be recalculated) + this.selectionTree = undefined; + }, + + /** + * Get the selection tree for this range + * TODO: remove this (was moved to range.js) + * @return selection tree + * @hide + */ + getSelectionTree: function () { + // if not yet calculated, do this now + if (!this.selectionTree) { + this.selectionTree = Aloha.Selection.getSelectionTree(this); + } + + return this.selectionTree; + }, + + /** + * TODO: move this to range.js + * Get an array of domobj (in dom tree order) of siblings of the given domobj, which are contained in the selection + * @param domobj dom object to start with + * @return array of siblings of the given domobj, which are also selected + * @hide + */ + getSelectedSiblings: function (domobj) { + var selectionTree = this.getSelectionTree(); + + return this.recursionGetSelectedSiblings(domobj, selectionTree); + }, + + /** + * TODO: move this to range.js + * Recursive method to find the selected siblings of the given domobj (which should be selected as well) + * @param domobj dom object for which the selected siblings shall be found + * @param selectionTree current level of the selection tree + * @return array of selected siblings of dom objects or false if none found + * @hide + */ + recursionGetSelectedSiblings: function (domobj, selectionTree) { + var selectedSiblings = false, + foundObj = false, + i; + + for ( i = 0; i < selectionTree.length; ++i) { + if (selectionTree[i].domobj === domobj) { + foundObj = true; + selectedSiblings = []; + } else if (!foundObj && selectionTree[i].children) { + // do the recursion + selectedSiblings = this.recursionGetSelectedSiblings(domobj, selectionTree[i].children); + if (selectedSiblings !== false) { + break; + } + } else if (foundObj && selectionTree[i].domobj && selectionTree[i].selection != 'collapsed' && selectionTree[i].selection != 'none') { + selectedSiblings.push(selectionTree[i].domobj); + } else if (foundObj && selectionTree[i].selection == 'none') { + break; + } + } + + return selectedSiblings; + }, + + /** + * TODO: move this to range.js + * Method updates member var markupEffectiveAtStart and splitObject, which is relevant primarily for button status and enter key behaviour + * @return void + * @hide + */ + updateMarkupEffectiveAtStart: function() { + // reset the current markup + this.markupEffectiveAtStart = []; + this.unmodifiableMarkupAtStart = []; + + var + parents = this.getStartContainerParents(), + limitFound = false, + splitObjectWasSet, + i, el; + + for ( i = 0; i < parents.length; i++) { + el = parents[i]; + if (!limitFound && (el !== this.limitObject)) { + this.markupEffectiveAtStart[ i ] = el; + if (!splitObjectWasSet && GENTICS.Utils.Dom.isSplitObject(el)) { + splitObjectWasSet = true; + this.splitObject = el; + } + } else { + limitFound = true; + this.unmodifiableMarkupAtStart.push(el); + } + } + if (!splitObjectWasSet) { + this.splitObject = false; + } + return; + }, + + /** + * TODO: remove this + * Method updates member var markupEffectiveAtStart, which is relevant primarily for button status + * @return void + * @hide + */ + updatelimitObject: function() { + if (Aloha.editables && Aloha.editables.length > 0) { + var parents = this.getStartContainerParents(), + editables = Aloha.editables, + i, el, j, editable; + for ( i = 0; i < parents.length; i++) { + el = parents[i]; + for ( j = 0; j < editables.length; j++) { + editable = editables[j].obj[0]; + if (el === editable) { + this.limitObject = el; + return true; + } + } + } + } + this.limitObject = jQuery('body'); + return true; + }, + + /** + * string representation of the range object + * @param verbose set to true for verbose output + * @return string representation of the range object + * @hide + */ + toString: function(verbose) { + if (!verbose) { + return 'Aloha.Selection.SelectionRange'; + } + return 'Aloha.Selection.SelectionRange {start [' + this.startContainer.nodeValue + '] offset ' + + this.startOffset + ', end [' + this.endContainer.nodeValue + '] offset ' + this.endOffset + '}'; + } + + }) // SelectionRange + + }); // Selection + + +/** + * This method implements an ugly workaround for a selection problem in ie: + * when the cursor shall be placed at the end of a text node in a li element, that is followed by a nested list, + * the selection would always snap into the first li of the nested list + * therefore, we make sure that the text node ends with a space and place the cursor right before it + */ +function nestedListInIEWorkaround ( range ) { + if (jQuery.browser.msie + && range.startContainer === range.endContainer + && range.startOffset === range.endOffset + && range.startContainer.nodeType == 3 + && range.startOffset == range.startContainer.data.length + && range.startContainer.nextSibling + && ["OL", "UL"].indexOf(range.startContainer.nextSibling.nodeName) !== -1) { + if (range.startContainer.data[range.startContainer.data.length-1] == ' ') { + range.startOffset = range.endOffset = range.startOffset-1; + } else { + range.startContainer.data = range.startContainer.data + ' '; + } + } +} + +function correctRange ( range ) { + nestedListInIEWorkaround(range); + return range; +} + + /** + * Implements Selection http://html5.org/specs/dom-range.html#selection + * @namespace Aloha + * @class Selection This singleton class always represents the + * current user selection + * @singleton + */ + var AlohaSelection = Class.extend({ + + _constructor : function( nativeSelection ) { + + this._nativeSelection = nativeSelection; + this.ranges = []; + + // will remember if urged to not change the selection + this.preventChange = false; + + }, + + /** + * Returns the element that contains the start of the selection. Returns null if there's no selection. + * @readonly + * @type Node + */ + anchorNode: null, + + /** + * Returns the offset of the start of the selection relative to the element that contains the start + * of the selection. Returns 0 if there's no selection. + * @readonly + * @type int + */ + anchorOffset: 0, + + /** + * Returns the element that contains the end of the selection. + * Returns null if there's no selection. + * @readonly + * @type Node + */ + focusNode: null, + + /** + * Returns the offset of the end of the selection relative to the element that contains the end + * of the selection. Returns 0 if there's no selection. + * @readonly + * @type int + */ + focusOffset: 0, + + /** + * Returns true if there's no selection or if the selection is empty. Otherwise, returns false. + * @readonly + * @type boolean + */ + isCollapsed: false, + + /** + * Returns the number of ranges in the selection. + * @readonly + * @type int + */ + rangeCount: 0, + + /** + * Replaces the selection with an empty one at the given position. + * @throws a WRONG_DOCUMENT_ERR exception if the given node is in a different document. + * @param parentNode Node of new selection + * @param offest offest of new Selection in parentNode + * @void + */ + collapse: function ( parentNode, offset ) { + this._nativeSelection.collapse( parentNode, offset ); + }, + + /** + * Replaces the selection with an empty one at the position of the start of the current selection. + * @throws an INVALID_STATE_ERR exception if there is no selection. + * @void + */ + collapseToStart: function() { + throw "NOT_IMPLEMENTED"; + }, + + /** + * @void + */ + extend: function ( parentNode, offset) { + + }, + + /** + * @param alter DOMString + * @param direction DOMString + * @param granularity DOMString + * @void + */ + modify: function ( alter, direction, granularity ) { + + }, + + /** + * Replaces the selection with an empty one at the position of the end of the current selection. + * @throws an INVALID_STATE_ERR exception if there is no selection. + * @void + */ + collapseToEnd: function() { + throw "NOT_IMPLEMENTED"; + }, + + /** + * Replaces the selection with one that contains all the contents of the given element. + * @throws a WRONG_DOCUMENT_ERR exception if the given node is in a different document. + * @param parentNode Node the Node fully select + * @void + */ + selectAllChildren: function( parentNode ) { + throw "NOT_IMPLEMENTED"; + }, + + /** + * Deletes the contents of the selection + */ + deleteFromDocument: function() { + throw "NOT_IMPLEMENTED"; + }, + + /** + * NB! + * We have serious problem in IE. + * The range that we get in IE is not the same as the range we had set, + * so even if we normalize it during getRangeAt, in IE, we will be + * correcting the range to the "correct" place, but still not the place + * where it was originally set. + * + * Returns the given range. + * The getRangeAt(index) method returns the indexth range in the list. + * NOTE: Aloha Editor only support 1 range! index can only be 0 + * @throws INDEX_SIZE_ERR DOM exception if index is less than zero or + * greater or equal to the value returned by the rangeCount. + * @param index int + * @return Range return the selected range from index + */ + getRangeAt: function ( index ) { + return correctRange( this._nativeSelection.getRangeAt( index ) ); + //if ( index < 0 || this.rangeCount ) { + // throw "INDEX_SIZE_ERR DOM"; + //} + //return this._ranges[index]; + }, + + /** + * Adds the given range to the selection. + * The addRange(range) method adds the given range Range object to the list of + * selections, at the end (so the newly added range is the new last range). + * NOTE: Aloha Editor only support 1 range! The added range will replace the + * range at index 0 + * see http://html5.org/specs/dom-range.html#selection note about addRange + * @throws an INVALID_NODE_TYPE_ERR exception if the given Range has a boundary point + * node that's not a Text or Element node, and an INVALID_MODIFICATION_ERR exception + * if it has a boundary point node that doesn't descend from a Document. + * @param range Range adds the range to the selection + * @void + */ + addRange: function( range ) { + // set readonly attributes + this._nativeSelection.addRange( range ); + // We will correct the range after rangy has processed the native + // selection range, so that our correction will be the final fix on + // the range according to the guarentee's that Aloha wants to make + this._nativeSelection._ranges[ 0 ] = correctRange( range ); + + // make sure, the old Aloha selection will be updated (until all implementations use the new AlohaSelection) + Aloha.Selection.updateSelection(); + }, + + /** + * Removes the given range from the selection, if the range was one of the ones in the selection. + * NOTE: Aloha Editor only support 1 range! The added range will replace the + * range at with index 0 + * @param range Range removes the range from the selection + * @void + */ + removeRange: function( range ) { + this._nativeSelection.removeRange(); + }, + + /** + * Removes all the ranges in the selection. + * @viod + */ + removeAllRanges: function() { + this._nativeSelection.removeAllRanges(); + }, + + /** + * prevents the next aloha-selection-changed event from + * being triggered + * @param flag boolean defines weather to update the selection on change or not + */ + preventedChange: function( flag ) { +// this.preventChange = typeof flag === 'undefined' ? false : flag; + }, + + /** + * will return wheter selection change event was prevented or not, and reset the + * preventSelectionChangedFlag + * @return boolean true if aloha-selection-change event + * was prevented + */ + isChangedPrevented: function() { +// return this.preventSelectionChangedFlag; + }, + + /** + * INFO: Method is used for integration with Gentics + * Aloha, has no use otherwise Updates the rangeObject + * according to the current user selection Method is + * always called on selection change + * + * @param event + * jQuery browser event object + * @return true when rangeObject was modified, false + * otherwise + * @hide + */ + refresh: function(event) { + + }, + + /** + * String representation + * + * @return "Aloha.Selection" + * @hide + */ + toString: function() { + return 'Aloha.Selection'; + }, + + getRangeCount: function() { + return this._nativeSelection.rangeCount; + } + + }); + + /** + * A wrapper for the function of the same name in the rangy core-depdency. + * This function should be preferred as it hides the global rangy object. + * For more information look at the following sites: + * http://html5.org/specs/dom-range.html + * @param window optional - specifices the window to get the selection of + */ + Aloha.getSelection = function( target ) { + var target = ( target !== document || target !== window ) ? window : target; + // Aloha.Selection.refresh() + // implement Aloha Selection + // TODO cache + return new AlohaSelection( window.rangy.getSelection( target ) ); + }; + + /** + * A wrapper for the function of the same name in the rangy core-depdency. + * This function should be preferred as it hides the global rangy object. + * Please note: when the range object is not needed anymore, + * invoke the detach method on it. It is currently unknown to me why + * this is required, but that's what it says in the rangy specification. + * For more information look at the following sites: + * http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html + * @param document optional - specifies which document to create the range for + */ + Aloha.createRange = function(givenWindow) { + return window.rangy.createRange(givenWindow); + }; + + var selection = new Selection(); + Aloha.Selection = selection; + + return selection; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/markup',[ 'aloha/core', 'util/class', 'aloha/jquery' ], +function( Aloha, Class, jQuery ) { + + + var +// Aloha = window.Aloha, +// Class = window.Class, + GENTICS = window.GENTICS; + +/** + * Markup object + */ +Aloha.Markup = Class.extend({ + /** + * Key handlers for special key codes + */ + keyHandlers: {}, + + /** + * Add a key handler for the given key code + * @param keyCode key code + * @param handler handler function + */ + addKeyHandler: function (keyCode, handler) { + if (!this.keyHandlers[keyCode]) { + this.keyHandlers[keyCode] = []; + } + + this.keyHandlers[keyCode].push(handler); + }, + + insertBreak: function () { + var range = Aloha.Selection.rangeObject,nonWSIndex,nextTextNode,newBreak; + if (!range.isCollapsed()) { + this.removeSelectedMarkup(); + } + + newBreak = jQuery('
    '); + GENTICS.Utils.Dom.insertIntoDOM(newBreak, range, Aloha.activeEditable.obj); + + nextTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(newBreak.parent().get(0), GENTICS.Utils.Dom.getIndexInParent(newBreak.get(0)) + 1, false); + if (nextTextNode) { + // trim leading whitespace + nonWSIndex = nextTextNode.data.search(/\S/); + if (nonWSIndex > 0) { + nextTextNode.data = nextTextNode.data.substring(nonWSIndex); + } + } + + range.startContainer = range.endContainer = newBreak.get(0).parentNode; + range.startOffset = range.endOffset = GENTICS.Utils.Dom.getIndexInParent(newBreak.get(0)) + 1; + range.correctRange(); + range.clearCaches(); + range.select(); + }, + + /** + * first method to handle key strokes + * @param event DOM event + * @param rangeObject as provided by Aloha.Selection.getRangeObject(); + * @return "Aloha.Selection" + */ + preProcessKeyStrokes: function(event) { + if (event.type != 'keydown') { + return false; + } + + var rangeObject = Aloha.Selection.rangeObject, + handlers, + i; + + if (this.keyHandlers[event.keyCode]) { + handlers = this.keyHandlers[event.keyCode]; + for ( i = 0; i < handlers.length; ++i) { + if (!handlers[i](event)) { + return false; + } + } + } + + // handle left (37) and right (39) keys for block detection + if (event.keyCode === 37 || event.keyCode === 39) { + return this.processCursor(rangeObject, event.keyCode); + } + + // BACKSPACE + if (event.keyCode === 8) { + event.preventDefault(); // prevent history.back() even on exception + Aloha.execCommand( 'delete', false ); + return false; + } + + // DELETE + if (event.keyCode === 46) { + Aloha.execCommand( 'forwarddelete', false ); + return false; + } + + // ENTER + if (event.keyCode === 13 ) { + if (event.shiftKey) { + Aloha.execCommand( 'insertlinebreak', false ); + return false; + } else { + Aloha.execCommand( 'insertparagraph', false ); + return false; + } + } + return true; + }, + + /** + * Processing of cursor keys + * will currently detect blocks (elements with contenteditable=false) + * and selects them (normally the cursor would jump right past them) + * + * For each block an 'aloha-block-selected' event will be triggered. + * + * @param range the current range object + * @param keyCode keyCode of current keypress + * @return false if a block was found to prevent further events, true otherwise + */ + processCursor: function(range, keyCode) { + var rt = range.getRangeTree(), // RangeTree reference + i = 0, + cursorLeft = keyCode === 37, + cursorRight = keyCode === 39, + nextSiblingIsBlock = false, // check whether the next sibling is a block (contenteditable = false) + cursorIsWithinBlock = false, // check whether the cursor is positioned within a block (contenteditable = false) + cursorAtLastPos = false, // check if the cursor is within the last position of the currently active dom element + obj; // will contain references to dom objects + + if ( !range.isCollapsed() ) { + return true; + } + + for (;i < rt.length; i++) { + if ( typeof rt[i].domobj !== 'undefined' ) { + cursorAtLastPos = range.startOffset === rt[i].domobj.length; + if (cursorAtLastPos) { + nextSiblingIsBlock = jQuery( rt[i].domobj.nextSibling ).attr('contenteditable') === 'false'; + cursorIsWithinBlock = jQuery( rt[i].domobj ).parents('[contenteditable=false]').length > 0; + + if ( cursorRight && nextSiblingIsBlock ) { + obj = rt[i].domobj.nextSibling; + GENTICS.Utils.Dom.selectDomNode( obj ); + Aloha.trigger( 'aloha-block-selected', obj ); + Aloha.Selection.preventSelectionChanged(); + return false; + } + + if ( cursorLeft && cursorIsWithinBlock ) { + obj = jQuery( rt[i].domobj ).parents('[contenteditable=false]').get(0); + GENTICS.Utils.Dom.selectDomNode( obj ); + Aloha.trigger( 'aloha-block-selected', obj ); + Aloha.Selection.preventSelectionChanged(); + return false; + } + } + } + } + }, + + /** + * method handling shiftEnter + * @param Aloha.Selection.SelectionRange of the current selection + * @return void + */ + processShiftEnter: function(rangeObject) { + this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject); + }, + + /** + * method handling Enter + * @param Aloha.Selection.SelectionRange of the current selection + * @return void + */ + processEnter: function(rangeObject) { + if (rangeObject.splitObject) { + // now comes a very evil hack for ie, when the enter is pressed in a text node in an li element, we just append an empty text node + // if (jQuery.browser.msie + // && GENTICS.Utils.Dom + // .isListElement(rangeObject.splitObject)) { + // jQuery(rangeObject.splitObject).append( + // jQuery(document.createTextNode(''))); + // } + + this.splitRangeObject(rangeObject); + } else { // if there is no split object, the Editable is the paragraph type itself (e.g. a p or h2) + this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject); + } + }, + + /** + * Insert the given html markup at the current selection + * @param html html markup to be inserted + */ + insertHTMLCode: function (html) { + var rangeObject = Aloha.Selection.rangeObject; + + this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject, jQuery(html)); + }, + + /** + * insert an HTML Break
    into current selection + * @param Aloha.Selection.SelectionRange of the current selection + * @return void + */ + insertHTMLBreak: function(selectionTree, rangeObject, inBetweenMarkup) { + var i, treeLength, el, jqEl, jqElBefore, jqElAfter, tmpObject, offset, checkObj; + + inBetweenMarkup = inBetweenMarkup ? inBetweenMarkup: jQuery('
    '); + for ( i = 0, treeLength = selectionTree.length; i < treeLength; i++) { + el = selectionTree[i]; + jqEl = el.domobj ? jQuery(el.domobj) : undefined; + if (el.selection !== 'none') { // before cursor, leave this part inside the splitObject + if (el.selection == 'collapsed') { + // collapsed selection found (between nodes) + if (i > 0) { + // not at the start, so get the element to the left + jqElBefore = jQuery(selectionTree[i-1].domobj); + // and insert the break after it + jqElBefore.after(inBetweenMarkup); + } else { + // at the start, so get the element to the right + jqElAfter = jQuery(selectionTree[1].domobj); + // and insert the break before it + jqElAfter.before(inBetweenMarkup); + } + + // now set the range + rangeObject.startContainer = rangeObject.endContainer = inBetweenMarkup[0].parentNode; + rangeObject.startOffset = rangeObject.endOffset = GENTICS.Utils.Dom.getIndexInParent(inBetweenMarkup[0]) + 1; + rangeObject.correctRange(); + } else if (el.domobj && el.domobj.nodeType === 3) { // textNode + // when the textnode is immediately followed by a blocklevel element (like p, h1, ...) we need to add an additional br in between + if (el.domobj.nextSibling + && el.domobj.nextSibling.nodeType == 1 + && Aloha.Selection.replacingElements[el.domobj.nextSibling.nodeName + .toLowerCase()]) { + // TODO check whether this depends on the browser + jqEl.after('
    '); + } + + if (this.needEndingBreak()) { + // when the textnode is the last inside a blocklevel element + // (like p, h1, ...) we need to add an additional br as very + // last object in the blocklevel element + checkObj = el.domobj; + while (checkObj) { + if (checkObj.nextSibling) { + checkObj = false; + } else { + // go to the parent + checkObj = checkObj.parentNode; + // found a blocklevel or list element, we are done + if (GENTICS.Utils.Dom.isBlockLevelElement(checkObj) || GENTICS.Utils.Dom.isListElement(checkObj)) { + break; + } + // reached the limit object, we are done + if (checkObj === rangeObject.limitObject) { + checkObj = false; + } + } + } + // when we found a blocklevel element, insert a break at the + // end. Mark the break so that it is cleaned when the + // content is fetched. + if (checkObj) { + jQuery(checkObj).append('
    '); + } + } + + // insert the break + jqEl.between(inBetweenMarkup, el.startOffset); + + // correct the range + // count the number of previous siblings + offset = 0; + tmpObject = inBetweenMarkup[0]; + while (tmpObject) { + tmpObject = tmpObject.previousSibling; + offset++; + } + + rangeObject.startContainer = inBetweenMarkup[0].parentNode; + rangeObject.endContainer = inBetweenMarkup[0].parentNode; + rangeObject.startOffset = offset; + rangeObject.endOffset = offset; + rangeObject.correctRange(); + } else if (el.domobj && el.domobj.nodeType === 1) { // other node, normally a break + if (jqEl.parent().find('br.aloha-ephemera').length === 0) { + // but before putting it, remove all: + jQuery(rangeObject.limitObject).find('br.aloha-ephemera').remove(); + // now put it: + jQuery(rangeObject.commonAncestorContainer).append(this.getFillUpElement(rangeObject.splitObject)); + } + jqEl.after(inBetweenMarkup); + + // now set the selection. Since we just added one break do the currect el + // the new position must be el's position + 1. el's position is the index + // of the el in the selection tree, which is i. then we must add + // another +1 because we want to be AFTER the object, not before. therefor +2 + rangeObject.startContainer = rangeObject.commonAncestorContainer; + rangeObject.endContainer = rangeObject.startContainer; + rangeObject.startOffset = i+2; + rangeObject.endOffset = i+2; + rangeObject.update(); + } + } + } + rangeObject.select(); + }, + + /** + * Check whether blocklevel elements need breaks at the end to visibly render a newline + * @return true if an ending break is necessary, false if not + */ + needEndingBreak: function () { + // currently, all browser except IE need ending breaks + return !jQuery.browser.msie; + }, + + /** + * Get the currently selected text or false if nothing is selected (or the selection is collapsed) + * @return selected text + */ + getSelectedText: function () { + var rangeObject = Aloha.Selection.rangeObject; + + if (rangeObject.isCollapsed()) { + return false; + } + + return this.getFromSelectionTree(rangeObject.getSelectionTree(), true); + }, + + /** + * Recursive function to get the selected text from the selection tree starting at the given level + * @param selectionTree array of selectiontree elements + * @param astext true when the contents shall be fetched as text, false for getting as html markup + * @return selected text from that level (incluiding all sublevels) + */ + getFromSelectionTree: function (selectionTree, astext) { + var text = '', i, treeLength, el, clone; + for ( i = 0, treeLength = selectionTree.length; i < treeLength; i++) { + el = selectionTree[i]; + if (el.selection == 'partial') { + if (el.domobj.nodeType === 3) { + // partial text node selected, get the selected part + text += el.domobj.data.substring(el.startOffset, el.endOffset); + } else if (el.domobj.nodeType === 1 && el.children) { + // partial element node selected, do the recursion into the children + if (astext) { + text += this.getFromSelectionTree(el.children, astext); + } else { + // when the html shall be fetched, we create a clone of the element and remove all the children + clone = jQuery(el.domobj).clone(false).empty(); + // then we do the recursion and add the selection into the clone + clone.html(this.getFromSelectionTree(el.children, astext)); + // finally we get the html of the clone + text += clone.outerHTML(); + } + } + } else if (el.selection == 'full') { + if (el.domobj.nodeType === 3) { + // full text node selected, get the text + text += jQuery(el.domobj).text(); + } else if (el.domobj.nodeType === 1 && el.children) { + // full element node selected, get the html of the node and all children + text += astext ? jQuery(el.domobj).text() : jQuery(el.domobj).outerHTML(); + } + } + } + + return text; + }, + + /** + * Get the currently selected markup or false if nothing is selected (or the selection is collapsed) + * @return selected markup + */ + getSelectedMarkup: function () { + var rangeObject = Aloha.Selection.rangeObject; + + if (rangeObject.isCollapsed()) { + return false; + } + + return this.getFromSelectionTree(rangeObject.getSelectionTree(), false); + }, + + /** + * Remove the currently selected markup + + */ + removeSelectedMarkup: function () { + var rangeObject = Aloha.Selection.rangeObject, newRange; + + if (rangeObject.isCollapsed()) { + return; + } + + newRange = new Aloha.Selection.SelectionRange(); + // remove the selection + this.removeFromSelectionTree(rangeObject.getSelectionTree(), newRange); + + // do a cleanup now (starting with the commonancestorcontainer) + newRange.update(); + GENTICS.Utils.Dom.doCleanup({'merge' : true, 'removeempty' : true}, Aloha.Selection.rangeObject); + Aloha.Selection.rangeObject = newRange; + + // need to set the collapsed selection now + newRange.correctRange(); + newRange.update(); + newRange.select(); + Aloha.Selection.updateSelection(); + }, + + /** + * Recursively remove the selected items, starting with the given level in the selectiontree + * @param selectionTree current level of the selectiontree + * @param newRange new collapsed range to be set after the removal + */ + removeFromSelectionTree: function (selectionTree, newRange) { + // remember the first found partially selected element node (in case we need + // to merge it with the last found partially selected element node) + var firstPartialElement, newdata, i, el, adjacentTextNode, treeLength; + + // iterate through the selection tree + for (i = 0, treeLength = selectionTree.length; i < treeLength; i++) { + el = selectionTree[i]; + // check the type of selection + if (el.selection == 'partial') { + if (el.domobj.nodeType === 3) { + // partial text node selected, so remove the selected portion + newdata = ''; + if (el.startOffset > 0) { + newdata += el.domobj.data.substring(0, el.startOffset); + } + if (el.endOffset < el.domobj.data.length) { + newdata += el.domobj.data.substring(el.endOffset, el.domobj.data.length); + } + el.domobj.data = newdata; + + // eventually set the new range (if not done before) + if (!newRange.startContainer) { + newRange.startContainer = newRange.endContainer = el.domobj; + newRange.startOffset = newRange.endOffset = el.startOffset; + } + } else if (el.domobj.nodeType === 1 && el.children) { + // partial element node selected, so do the recursion into the children + this.removeFromSelectionTree(el.children, newRange); + if (firstPartialElement) { + // when the first parially selected element is the same type + // of element, we need to merge them + if (firstPartialElement.nodeName == el.domobj.nodeName) { + // merge the nodes + jQuery(firstPartialElement).append(jQuery(el.domobj).contents()); + // and remove the latter one + jQuery(el.domobj).remove(); + } + } else { + // remember this element as first partially selected element + firstPartialElement = el.domobj; + } + } + } else if (el.selection == 'full') { + // eventually set the new range (if not done before) + if (!newRange.startContainer) { + adjacentTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(el.domobj.parentNode, GENTICS.Utils.Dom.getIndexInParent(el.domobj) + 1, false, {'blocklevel' : false}); + if (adjacentTextNode) { + newRange.startContainer = newRange.endContainer = adjacentTextNode; + newRange.startOffset = newRange.endOffset = 0; + } else { + newRange.startContainer = newRange.endContainer = el.domobj.parentNode; + newRange.startOffset = newRange.endOffset = GENTICS.Utils.Dom.getIndexInParent(el.domobj) + 1; + } + } + + // full node selected, so just remove it (will also remove all children) + jQuery(el.domobj).remove(); + } + } + }, + + /** + * split passed rangeObject without or with optional markup + * @param Aloha.Selection.SelectionRange of the current selection + * @param markup object (jQuery) to insert in between the split elements + * @return void + */ + splitRangeObject: function(rangeObject, markup) { + // UAAAA: first check where the markup can be inserted... *grrrrr*, then decide where to split + // object which is split up + var + splitObject = jQuery(rangeObject.splitObject), + selectionTree, insertAfterObject, followUpContainer; + + // update the commonAncestor with the splitObject (so that the selectionTree is correct) + rangeObject.update(rangeObject.splitObject); // set the splitObject as new commonAncestorContainer and update the selectionTree + + // calculate the selection tree. NOTE: it is necessary to do this before + // getting the followupcontainer, since getting the selection tree might + // possibly merge text nodes, which would lead to differences in the followupcontainer + selectionTree = rangeObject.getSelectionTree(); + + // object to be inserted after the splitObject + followUpContainer = this.getSplitFollowUpContainer(rangeObject); + + // now split up the splitObject into itself AND the followUpContainer + this.splitRangeObjectHelper(selectionTree, rangeObject, followUpContainer); // split the current object into itself and the followUpContainer + + // check whether the followupcontainer is still marked for removal + if (followUpContainer.hasClass('preparedForRemoval')) { + // TODO shall we just remove the class or shall we not use the followupcontainer? + followUpContainer.removeClass('preparedForRemoval'); + } + + // now let's find the place, where the followUp is inserted afterwards. normally that's the splitObject itself, but in + // some cases it might be their parent (e.g. inside a list, a

    followUp must be inserted outside the list) + insertAfterObject = this.getInsertAfterObject(rangeObject, followUpContainer); + + // now insert the followUpContainer + jQuery(followUpContainer).insertAfter(insertAfterObject); // attach the followUpContainer right after the insertAfterObject + + // in some cases, we want to remove the "empty" splitObject (e.g. LIs, if enter was hit twice) + if (rangeObject.splitObject.nodeName.toLowerCase() === 'li' && !Aloha.Selection.standardTextLevelSemanticsComparator(rangeObject.splitObject, followUpContainer)) { + jQuery(rangeObject.splitObject).remove(); + } + + rangeObject.startContainer = null; + // first check whether the followUpContainer starts with a
    + // if so, place the cursor right before the
    + var followContents = followUpContainer.contents(); + if (followContents.length > 0 + && followContents.get(0).nodeType == 1 + && followContents.get(0).nodeName.toLowerCase() === 'br') { + rangeObject.startContainer = followUpContainer.get(0); + } + + if (!rangeObject.startContainer) { + // find a possible text node in the followUpContainer and set the selection to it + // if no textnode is available, set the selection to the followup container itself + rangeObject.startContainer = followUpContainer.textNodes(true, true).first().get(0); + } + if (!rangeObject.startContainer) { // if no text node was found, select the parent object of
    + rangeObject.startContainer = followUpContainer.textNodes(false).first().parent().get(0); + } + if (rangeObject.startContainer) { + // the cursor is always at the beginning of the followUp + rangeObject.endContainer = rangeObject.startContainer; + rangeObject.startOffset = 0; + rangeObject.endOffset = 0; + } else { + rangeObject.startContainer = rangeObject.endContainer = followUpContainer.parent().get(0); + rangeObject.startOffset = rangeObject.endOffset = GENTICS.Utils.Dom.getIndexInParent(followUpContainer.get(0)); + } + + // finally update the range object again + rangeObject.update(); + + // now set the selection + rangeObject.select(); + }, + + /** + * method to get the object after which the followUpContainer can be inserted during splitup + * this is a helper method, not needed anywhere else + * @param rangeObject Aloha.Selection.SelectionRange of the current selection + * @param followUpContainer optional jQuery object; if provided the rangeObject will be split and the second part will be insert inside of this object + * @return object after which the followUpContainer can be inserted + */ + getInsertAfterObject: function(rangeObject, followUpContainer) { + var passedSplitObject,i,el; + + for (i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + el = rangeObject.markupEffectiveAtStart[ i ]; + // check if we have already passed the splitObject (some other markup might come before) + if (el === rangeObject.splitObject){ + passedSplitObject = true; + } + // if not passed splitObject, skip this markup + if (!passedSplitObject) { + continue; + } + // once we are passed, check if the followUpContainer is allowed to be inserted into the currents el's parent + if (Aloha.Selection.canTag1WrapTag2(jQuery(el).parent()[0].nodeName, followUpContainer[0].nodeName)) { + return el; + } + } + return false; + }, + + /** + * method to get the html code for a fillUpElement. this is needed for empty paragraphs etc., so that they take up their expected height + * @param splitObject split object (dom object) + * @return fillUpElement HTML Code + */ + getFillUpElement: function(splitObject) { + if (jQuery.browser.msie) { + return false; + } else { + return jQuery('
    '); + } + }, + + /** + * removes textNodes from passed array, which only contain contentWhiteSpace (e.g. a \n between two tags) + * @param domArray array of domObjects + * @return void + */ + removeElementContentWhitespaceObj: function(domArray) { + var correction = 0, + removeLater = [], + i, + el, removeIndex; + + for (i = 0; i < domArray.length; i++) { + el = domArray[i]; + if (el.isElementContentWhitespace) { + removeLater[removeLater.length] = i; + } + } + + for (i = 0; i < removeLater.length; i++) { + removeIndex = removeLater[i]; + domArray.splice(removeIndex - correction, 1); + correction++; + } + }, + + /** + * recursive method to parallelly walk through two dom subtrees, leave elements before startContainer in first subtree and move rest to other + * @param selectionTree tree to iterate over as contained in rangeObject. must be passed separately to allow recursion in the selection tree, but not in the rangeObject + * @param rangeObject Aloha.Selection.SelectionRange of the current selection + * @param followUpContainer optional jQuery object; if provided the rangeObject will be split and the second part will be insert inside of this object + * @param inBetweenMarkup jQuery object to be inserted between the two split parts. will be either a
    (if no followUpContainer is passed) OR e.g. a table, which must be inserted between the splitobject AND the follow up + * @return void + */ + splitRangeObjectHelper: function(selectionTree, rangeObject, followUpContainer, inBetweenMarkup) { + if (!followUpContainer) { + Aloha.Log.warn(this, 'no followUpContainer, no inBetweenMarkup, nothing to do...'); + } + + var fillUpElement = this.getFillUpElement(rangeObject.splitObject), + splitObject = jQuery(rangeObject.splitObject), + startMoving = false, + el, i, completeText, jqObj, mirrorLevel, parent, treeLength; + + if (selectionTree.length > 0) { + mirrorLevel = followUpContainer.contents(); + + // if length of mirrorLevel and selectionTree are not equal, the mirrorLevel must be corrected. this happens, when the mirrorLevel contains whitespace textNodes + if (mirrorLevel.length !== selectionTree.length) { + this.removeElementContentWhitespaceObj(mirrorLevel); + } + + for (i = 0, treeLength = selectionTree.length; i < treeLength; i++) { + el = selectionTree[i]; + // remove all objects in the mirrorLevel, which are BEFORE the cursor + // OR if the cursor is at the last position of the last Textnode (causing an empty followUpContainer to be appended) + if ( + (el.selection === 'none' && startMoving === false) || + (el.domobj && el.domobj.nodeType === 3 && el === selectionTree[ (selectionTree.length-1) ] && el.startOffset === el.domobj.data.length) + ) { + // iteration is before cursor, leave this part inside the splitObject, remove from followUpContainer + // however if the object to remove is the last existing textNode within the followUpContainer, insert a BR instead + // otherwise the followUpContainer is invalid and takes up no vertical space + + if (followUpContainer.textNodes().length > 1 || (el.domobj.nodeType === 1 && el.children.length === 0)) { + // note: the second part of the if (el.domobj.nodeType === 1 && el.children.length === 0) covers a very special condition, + // where an empty tag is located right before the cursor when pressing enter. In this case the empty tag would not be + // removed correctly otherwise + mirrorLevel.eq(i).remove(); + } else if (GENTICS.Utils.Dom.isSplitObject(followUpContainer[0])) { + if (fillUpElement) { + followUpContainer.html(fillUpElement); // for your zoological german knowhow: ephemera = Eintagsfliege + } else { + followUpContainer.empty(); + } + } else { + followUpContainer.empty(); + followUpContainer.addClass('preparedForRemoval'); + } + continue; + } else { + // split objects, which are AT the cursor Position or directly above + if (el.selection !== 'none') { // before cursor, leave this part inside the splitObject + // TODO better check for selection == 'partial' here? + if (el.domobj && el.domobj.nodeType === 3 && el.startOffset !== undefined) { + completeText = el.domobj.data; + if (el.startOffset > 0) {// first check, if there will be some text left in the splitObject + el.domobj.data = completeText.substr(0, el.startOffset); + } else if (selectionTree.length > 1) { // if not, check if the splitObject contains more than one node, because then it can be removed. this happens, when ENTER is pressed inside of a textnode, but not at the borders + jQuery(el.domobj).remove(); + } else { // if the "empty" textnode is the last node left in the splitObject, replace it with a ephemera break + // if the parent is a blocklevel element, we insert the fillup element + parent = jQuery(el.domobj).parent(); + if (GENTICS.Utils.Dom.isSplitObject(parent[0])) { + if (fillUpElement) { + parent.html(fillUpElement); + } else { + parent.empty(); + } + } else { + // if the parent is no blocklevel element and would be empty now, we completely remove it + parent.remove(); + } + } + if (completeText.length - el.startOffset > 0) { + // first check if there is text left to put in the followUpContainer's textnode. this happens, when ENTER is pressed inside of a textnode, but not at the borders + mirrorLevel[i].data = completeText.substr(el.startOffset, completeText.length); + } else if (mirrorLevel.length > 1) { + // if not, check if the followUpContainer contains more than one node, because if yes, the "empty" textnode can be removed + mirrorLevel.eq( (i) ).remove(); + } else if (GENTICS.Utils.Dom.isBlockLevelElement(followUpContainer[0])) { + // if the "empty" textnode is the last node left in the followUpContainer (which is a blocklevel element), replace it with a ephemera break + if (fillUpElement) { + followUpContainer.html(fillUpElement); + } else { + followUpContainer.empty(); + } + } else { + // if the "empty" textnode is the last node left in a non-blocklevel element, mark it for removal + followUpContainer.empty(); + followUpContainer.addClass('preparedForRemoval'); + } + } + startMoving = true; + if (el.children.length > 0) { + this.splitRangeObjectHelper(el.children, rangeObject, mirrorLevel.eq(i), inBetweenMarkup); + } + } else { + + // remove all objects in the origin, which are AFTER the cursor + if (el.selection === 'none' && startMoving === true) { + // iteration is after cursor, remove from splitObject and leave this part inside the followUpContainer + jqObj = jQuery(el.domobj).remove(); + } + } + } + } + } else { + Aloha.Log.error(this, 'can not split splitObject due to an empty selection tree'); + } + + // and finally cleanup: remove all fillUps > 1 + splitObject.find('br.aloha-ephemera:gt(0)').remove(); // remove all elements greater than (gt) 0, that also means: leave one + followUpContainer.find('br.aloha-ephemera:gt(0)').remove(); // remove all elements greater than (gt) 0, that also means: leave one + + // remove objects prepared for removal + splitObject.find('.preparedForRemoval').remove(); + followUpContainer.find('.preparedForRemoval').remove(); + + // if splitObject / followUp are empty, place a fillUp inside + if (splitObject.contents().length === 0 && GENTICS.Utils.Dom.isSplitObject(splitObject[0]) && fillUpElement) { + splitObject.html(fillUpElement); + } + + if (followUpContainer.contents().length === 0 && GENTICS.Utils.Dom.isSplitObject(followUpContainer[0]) && fillUpElement) { + followUpContainer.html(fillUpElement); + } + }, + + /** + * returns a jQuery object fitting the passed splitObject as follow up object + * examples, + * - when passed a p it will return an empty p (clone of the passed p) + * - when passed an h1, it will return either an h1 (clone of the passed one) or a new p (if the collapsed selection was at the end) + * @param rangeObject Aloha.RangeObject + * @return void + */ + getSplitFollowUpContainer: function(rangeObject) { + var + tagName = rangeObject.splitObject.nodeName.toLowerCase(), + returnObj, inside, lastObj; + + switch(tagName) { + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + // get the last textnode in the splitobject, but don't consider aloha-cleanme elements + lastObj = jQuery(rangeObject.splitObject).textNodes(':not(.aloha-cleanme)').last()[0]; + // special case: when enter is hit at the end of a heading, the followUp should be a

    + if (lastObj && rangeObject.startContainer === lastObj && rangeObject.startOffset === lastObj.length) { + returnObj = jQuery('

    '); + inside = jQuery(rangeObject.splitObject).clone().contents(); + returnObj.append(inside); + return returnObj; + } + break; + + case 'li': + // TODO check whether the li is the last one + // special case: if enter is hit twice inside a list, the next item should be a

    (and inserted outside the list) + if (rangeObject.startContainer.nodeName.toLowerCase() === 'br' && jQuery(rangeObject.startContainer).hasClass('aloha-ephemera')) { + returnObj = jQuery('

    '); + inside = jQuery(rangeObject.splitObject).clone().contents(); + returnObj.append(inside); + return returnObj; + } + // when the li is the last one and empty, we also just return a

    + if (!rangeObject.splitObject.nextSibling && jQuery.trim(jQuery(rangeObject.splitObject).text()).length === 0) { + returnObj = jQuery('

    '); + return returnObj; + } + } + + return jQuery(rangeObject.splitObject).clone(); + }, + + /** + * Transform the given domobj into an object with the given new nodeName. + * Preserves the content and all attributes. If a range object is given, also the range will be preserved + * @param domobj dom object to transform + * @param nodeName new node name + * @param range range object + * @api + * @return new object as jQuery object + */ + transformDomObject: function (domobj, nodeName, range) { + // first create the new element + var + jqOldObj = jQuery(domobj), + jqNewObj = jQuery('<' + nodeName + '>'), + i; + + // TODO what about events? css properties? + + // copy attributes + if (jqOldObj[0].attributes) { + for (i = 0; i < jqOldObj[0].attributes.length; i++) { + jqNewObj.attr(jqOldObj[0].attributes[i].nodeName, jqOldObj[0].attributes[i].nodeValue); + } + } + + // copy inline CSS + if (jqOldObj[0].style && jqOldObj[0].style.cssText) { + jqNewObj[0].style.cssText = jqOldObj[0].style.cssText; + } + + // now move the contents of the old dom object into the new dom object + jqOldObj.contents().appendTo(jqNewObj); + + // finally replace the old object with the new one + jqOldObj.replaceWith(jqNewObj); + + // preserve the range + if (range) { + if (range.startContainer == domobj) { + range.startContainer = jqNewObj.get(0); + } + if (range.endContainer == domobj) { + range.endContainer = jqNewObj.get(0); + } + } + return jqNewObj; + }, + + /** + * String representation + * @return "Aloha.Selection" + */ + toString: function() { + return 'Aloha.Markup'; + } +}); + +Aloha.Markup = new Aloha.Markup(); + +return Aloha.Markup; + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright � 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/observable',['aloha/jquery'], +function(jQuery, undefined) { + + + var + $ = jQuery; + + return { + _eventHandlers: null, + + /** + * Attach a handler to an event + * + * @param {String} eventType A string containing the event name to bind to + * @param {Function} handler A function to execute each time the event is triggered + * @param {Object} scope Optional. Set the scope in which handler is executed + */ + bind: function(eventType, handler, scope) { + this._eventHandlers = this._eventHandlers || {}; + if (!this._eventHandlers[eventType]) { + this._eventHandlers[eventType] = []; + } + this._eventHandlers[eventType].push({ + handler: handler, + scope: (scope ? scope : window) + }); + }, + + /** + * Remove a previously-attached event handler + * + * @param {String} eventType A string containing the event name to unbind + * @param {Function} handler The function that is to be no longer executed. Optional. If not given, unregisters all functions for the given event. + */ + unbind: function(eventType, handler) { + this._eventHandlers = this._eventHandlers || {}; + if (!this._eventHandlers[eventType]) { + return; + } + if (!handler) { + // No handler function given, unbind all event handlers for the eventType + this._eventHandlers[eventType] = []; + } else { + this._eventHandlers[eventType] = $.grep(this._eventHandlers[eventType], function(element) { + if (element.handler === handler) { + return false; + } + return true; + }); + } + }, + + /** + * Execute all handlers attached to the given event type. + * All arguments except the eventType are directly passed to the callback function. + * + * @param (String} eventType A string containing the event name for which the event handlers should be invoked. + */ + trigger: function(eventType) { + this._eventHandlers = this._eventHandlers || {}; + if (!this._eventHandlers[eventType]) { + return; + } + + // preparedArguments contains all arguments except the first one. + var preparedArguments = []; + $.each(arguments, function(i, argument) { + if (i>0) { + preparedArguments.push(argument); + } + }); + + $.each(this._eventHandlers[eventType], function(index, element) { + element.handler.apply(element.scope, preparedArguments); + }); + }, + + /** + * Clears all event handlers. Call this method when cleaning up. + */ + unbindAll: function() { + this._eventHandlers = null; + } + }; +}); +/*! + * This file is part of Aloha Editor + * Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + */ + +/** + * Registry base class. + * TODO: document that it also contains Observable. + * + */ +define('aloha/registry',['aloha/jquery', 'aloha/observable'], +function(jQuery, Observable) { + + + return Class.extend(Observable, { + + _entries: null, + + _constructor: function() { + this._entries = {}; + }, + + /** + * @event register + * @param entry + * @param id + */ + register: function(id, entry) { + this._entries[id] = entry; + this.trigger('register', entry, id); + }, + + /** + * @event unregister + * @param odEntry + * @param id + */ + unregister: function(id) { + var oldEntry = this._entries[id]; + delete this._entries[id]; + this.trigger('unregister', oldEntry, id); + }, + + get: function(id) { + return this._entries[id]; + }, + + has: function(id) { + return (this._entries[id] ? true : false); + }, + + getEntries: function() { + // clone the entries so the user does not accidentally modify our _entries object. + return jQuery.extend({}, this._entries); + } + }); +}); +/*! + * Aloha Editor + * Author & Copyright (c) 2010 Gentics Software GmbH + * aloha-sales@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + */ +define('aloha/contenthandlermanager',['aloha/jquery', 'aloha/registry'], +function( jQuery, Registry ) { + + + /** + * Create an contentHandler from the given definition. Acts as a factory method + * for contentHandler. + * + * @param {Object} definition + */ + return new ( Registry.extend({ + + createHandler: function( definition ) { + + if ( typeof definition.handleContent != 'function' ) { + throw 'ContentHandler has no function handleContent().'; + } + + var AbstractContentHandler = Class.extend({ + handleContent: function( content ) { + // Implement in subclass! + } + }, definition); + + return new AbstractContentHandler(); + }, + + handleContent: function ( content, options ) { + var handler, + handlers = this.getEntries(); + + if ( typeof options.contenthandler === 'undefined') { + options.contenthandler = []; + for ( handler in handlers ) { + if ( handlers.hasOwnProperty(handler) ) { + options.contenthandler.push(handler); + } + } + } + + for ( handler in handlers ) { + if ( handlers.hasOwnProperty(handler) ) { + if (jQuery.inArray( handler, options.contenthandler ) < 0 ) { + continue; + } + + if ( typeof handlers[handler].handleContent === 'function') { + content = handlers[handler].handleContent( content, options ); + } else { + console.error( 'A valid content handler needs the method handleContent.' ); + } + } + } + + return content; + } + }))(); +}); +/*! + * This file is part of Aloha Editor Project http://aloha-editor.org + * Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com + * Contributors http://aloha-editor.org/contribution.php + * Licensed unter the terms of http://www.aloha-editor.org/license.html + * + * Aloha Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * ( at your option ) any later version.* + * + * Aloha Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +define('aloha/editable',[ + 'aloha/core', + 'util/class', + 'aloha/jquery', + 'aloha/pluginmanager', + 'aloha/floatingmenu', + 'aloha/selection', + 'aloha/markup', + 'aloha/contenthandlermanager', + 'aloha/console' +], function( Aloha, Class, jQuery, PluginManager, FloatingMenu, Selection, + Markup, ContentHandlerManager, console ) { + + + var unescape = window.unescape, + GENTICS = window.GENTICS, + + // True, if the next editable activate event should not be handled + ignoreNextActivateEvent = false; + + // default supported and custom content handler settings + // @TODO move to new config when implemented in Aloha + Aloha.defaults.contentHandler = {}; + Aloha.defaults.contentHandler.initEditable = [ 'sanitize' ]; + Aloha.defaults.contentHandler.getContents = [ 'sanitize' ]; + + // The insertHtml contenthandler ( paste ) will, by default, use all + // registered content handlers. + //Aloha.defaults.contentHandler.insertHtml = void 0; + + if ( typeof Aloha.settings.contentHandler === 'undefined' ) { + Aloha.settings.contentHandler = {}; + } + + var defaultContentSerializer = function(editableElement){ + return jQuery(editableElement).html(); + }; + + var contentSerializer = defaultContentSerializer; + + /** + * Editable object + * @namespace Aloha + * @class Editable + * @method + * @constructor + * @param {Object} obj jQuery object reference to the object + */ + Aloha.Editable = Class.extend( { + + _constructor: function( obj ) { + // check wheter the object has an ID otherwise generate and set + // globally unique ID + if ( !obj.attr( 'id' ) ) { + obj.attr( 'id', GENTICS.Utils.guid() ); + } + + // store object reference + this.obj = obj; + this.originalObj = obj; + this.ready = false; + + // delimiters, timer and idle for smartContentChange + // smartContentChange triggers -- tab: '\u0009' - space: '\u0020' - enter: 'Enter' + this.sccDelimiters = [ ':', ';', '.', '!', '?', ',', + unescape( '%u0009' ), unescape( '%u0020' ), 'Enter' ]; + this.sccIdle = 5000; + this.sccDelay = 500; + this.sccTimerIdle = false; + this.sccTimerDelay = false; + + // see keyset http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html + this.keyCodeMap = { + 93 : "Apps", // The Application key + 18 : "Alt", // The Alt ( Menu ) key. + 20 : "CapsLock", // The Caps Lock ( Capital ) key. + 17 : "Control", // The Control ( Ctrl ) key. + 40 : "Down", // The Down Arrow key. + 35 : "End", // The End key. + 13 : "Enter", // The Enter key. + 112 : "F1", // The F1 key. + 113 : "F2", // The F2 key. + 114 : "F3", // The F3 key. + 115 : "F4", // The F4 key. + 116 : "F5", // The F5 key. + 117 : "F6", // The F6 key. + 118 : "F7", // The F7 key. + 119 : "F8", // The F8 key. + 120 : "F9", // The F9 key. + 121 : "F10", // The F10 key. + 122 : "F11", // The F11 key. + 123 : "F12", // The F12 key. + + // Anybody knows the keycode for F13-F24? + 36 : "Home", // The Home key. + 45 : "Insert", // The Insert ( Ins ) key. + 37 : "Left", // The Left Arrow key. + 224 : "Meta", // The Meta key. + 34 : "PageDown", // The Page Down ( Next ) key. + 33 : "PageUp", // The Page Up key. + 19 : "Pause", // The Pause key. + 44 : "PrintScreen", // The Print Screen ( PrintScrn, SnapShot ) key. + 39 : "Right", // The Right Arrow key. + 145 : "Scroll", // The scroll lock key + 16 : "Shift", // The Shift key. + 38 : "Up", // The Up Arrow key. + 91 : "Win", // The left Windows Logo key. + 92 : "Win" // The right Windows Logo key. + }; + + this.placeholderClass = 'aloha-placeholder'; + + Aloha.registerEditable( this ); + + this.init(); + }, + + /** + * Initialize the editable + * @return void + * @hide + */ + init: function() { + var me = this; + + // TODO make editables their own settings. + this.settings = Aloha.settings; + + // smartContentChange settings + // @TODO move to new config when implemented in Aloha + if ( Aloha.settings && Aloha.settings.smartContentChange ) { + if ( Aloha.settings.smartContentChange.delimiters ) { + this.sccDelimiters = Aloha.settings.smartContentChange.delimiters; + } /* else { + this.sccDelimiters = this.sccDelimiters; + } */ + + if ( Aloha.settings.smartContentChange.idle ) { + this.sccIdle = Aloha.settings.smartContentChange.idle; + } /* else { + this.sccIdle = this.sccIdle; + } */ + + if ( Aloha.settings.smartContentChange.delay ) { + this.sccDelay = Aloha.settings.smartContentChange.delay; + } /* else { + this.sccDelay = this.sccDelay; + } */ + } + + // check if Aloha can handle the obj as Editable + if ( !this.check( this.obj ) ) { + //Aloha.log( 'warn', this, 'Aloha cannot handle {' + this.obj[0].nodeName + '}' ); + this.destroy(); + return; + } + + // apply content handler to clean up content + var content = me.obj.html(); + if ( typeof Aloha.settings.contentHandler.initEditable === 'undefined' ) { + Aloha.settings.contentHandler.initEditable = Aloha.defaults.contentHandler.initEditable; + } + content = ContentHandlerManager.handleContent( content, { + contenthandler: Aloha.settings.contentHandler.initEditable + } ); + me.obj.html( content ); + + // only initialize the editable when Aloha is fully ready ( including plugins ) + Aloha.bind( 'aloha-ready', function() { + // initialize the object + me.obj.addClass( 'aloha-editable' ).contentEditable( true ); + + // add focus event to the object to activate + me.obj.mousedown( function( e ) { + // check whether the mousedown was already handled + if ( !Aloha.eventHandled ) { + Aloha.eventHandled = true; + return me.activate( e ); + } + } ); + + me.obj.mouseup( function( e ) { + Aloha.eventHandled = false; + } ); + + me.obj.focus( function( e ) { + return me.activate( e ); + } ); + + // by catching the keydown we can prevent the browser from doing its own thing + // if it does not handle the keyStroke it returns true and therefore all other + // events ( incl. browser's ) continue + me.obj.keydown( function( event ) { + me.keyCode = event.which; + return Markup.preProcessKeyStrokes( event ); + } ); + + // handle keypress + me.obj.keypress( function( event ) { + // triggers a smartContentChange to get the right charcode + // To test try http://www.w3.org/2002/09/tests/keys.html + Aloha.activeEditable.smartContentChange( event ); + } ); + + // handle shortcut keys + me.obj.keyup( function( event ) { + if ( event.keyCode === 27 ) { + Aloha.deactivateEditable(); + return false; + } + } ); + + // register the onSelectionChange Event with the Editable field + me.obj.contentEditableSelectionChange( function( event ) { + Selection.onChange( me.obj, event ); + return me.obj; + } ); + + // mark the editable as unmodified + me.setUnmodified(); + + // we don't do the sanitizing on aloha ready, since some plugins add elements into the content and bind events to it. + // if we sanitize by replacing the html, all events would get lost. TODO: think about a better solution for the sanitizing, without + // destroying the events +// // apply content handler to clean up content +// var content = me.obj.html(); +// if ( typeof Aloha.settings.contentHandler.initEditable === 'undefined' ) { +// Aloha.settings.contentHandler.initEditable = Aloha.defaults.contentHandler.initEditable; +// } +// content = ContentHandlerManager.handleContent( content, { +// contenthandler: Aloha.settings.contentHandler.initEditable +// } ); +// me.obj.html( content ); + + me.snapshotContent = me.getContents(); + + // FF bug: check for empty editable contents ( no
    ; no whitespace ) + if ( jQuery.browser.mozilla ) { + me.initEmptyEditable(); + } + + me.initPlaceholder(); + + me.ready = true; + + // throw a new event when the editable has been created + /** + * @event editableCreated fires after a new editable has been created, eg. via $( '#editme' ).aloha() + * The event is triggered in Aloha's global scope Aloha + * @param {Event} e the event object + * @param {Array} a an array which contains a reference to the currently created editable on its first position + */ + Aloha.trigger( 'aloha-editable-created', [ me ] ); + } ); + }, + + /** + * True, if this editable is active for editing + * @property + * @type boolean + */ + isActive: false, + + /** + * stores the original content to determine if it has been modified + * @hide + */ + originalContent: null, + + /** + * every time a selection is made in the current editable the selection has to + * be saved for further use + * @hide + */ + range: undefined, + + /** + * Check if object can be edited by Aloha Editor + * @return {boolean } editable true if Aloha Editor can handle else false + * @hide + */ + check: function() { + /* TODO check those elements + 'map', 'meter', 'object', 'output', 'progress', 'samp', + 'time', 'area', 'datalist', 'figure', 'kbd', 'keygen', + 'mark', 'math', 'wbr', 'area', + */ + + // Extract El + var me = this, + obj = this.obj, + el = obj.get( 0 ), + nodeName = el.nodeName.toLowerCase(), + + // supported elements + textElements = [ 'a', 'abbr', 'address', 'article', 'aside', + 'b', 'bdo', 'blockquote', 'cite', 'code', 'command', + 'del', 'details', 'dfn', 'div', 'dl', 'em', 'footer', + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'i', + 'ins', 'menu', 'nav', 'p', 'pre', 'q', 'ruby', + 'section', 'small', 'span', 'strong', 'sub', 'sup', + 'var' ], + i, div; + + for ( i = 0; i < textElements.length; i++ ) { + if ( nodeName === textElements[ i ] ) { + return true; + } + } + + // special handled elements + switch ( nodeName ) { + case 'label': + case 'button': + // TODO need some special handling. + break; + case 'textarea': + // Create a div alongside the textarea + div = jQuery( '
    ' ) + .insertAfter( obj ); + + // Resize the div to the textarea and + // Populate the div with the value of the textarea + // Then, hide the textarea + div.height( obj.height() ) + .width( obj.width() ) + .html( obj.val() ); + + obj.hide(); + + // Attach a onsubmit to the form to place the HTML of the + // div back into the textarea + obj.parents( 'form:first' ).submit( function() { + obj.val( me.getContents() ); + } ); + + // Swap textarea reference with the new div + this.obj = div; + + // Supported + return true; + default: + break; + } + + // the following elements are not supported + /* + 'canvas', 'audio', 'br', 'embed', 'fieldset', 'hgroup', 'hr', + 'iframe', 'img', 'input', 'map', 'script', 'select', 'style', + 'svg', 'table', 'ul', 'video', 'ol', 'form', 'noscript', + */ + return false; + }, + + /** + * Init Placeholder + * + * @return void + */ + initPlaceholder: function() { + if ( Aloha.settings.placeholder && this.isEmpty() ) { + this.addPlaceholder(); + } + }, + + /** + * Check if the conteneditable is empty. + * + * @return {Boolean} + */ + isEmpty: function() { + var editableTrimedContent = jQuery.trim( this.getContents() ), + onlyBrTag = ( editableTrimedContent === '
    ' ) ? true : false; + return ( editableTrimedContent.length === 0 || onlyBrTag ); + }, + + /** + * Check if the editable div is not empty. Fixes a FF browser bug + * see issue: https://github.com/alohaeditor/Aloha-Editor/issues/269 + * + * @return {undefined} + */ + initEmptyEditable: function( ) { + var obj = this.obj; + if ( this.empty( this.getContents() ) ) { + jQuery( obj ).prepend( '
    ' ); + } + }, + + /** + * Add placeholder in editable + * + * @return void + */ + addPlaceholder: function() { + var div = jQuery( '
    ' ), + span = jQuery( '' ), + el, + obj = this.obj; + + if ( GENTICS.Utils.Dom.allowsNesting( obj[0], div[0] ) ) { + el = div; + } else { + el = span; + } + + jQuery( obj ).append( el.addClass( this.placeholderClass ) ); + jQuery.each( + Aloha.settings.placeholder, + function( selector, selectorConfig ) { + if ( obj.is( selector ) ) { + el.html( selectorConfig ); + } + } + ); + + // remove browser br + jQuery( 'br', obj ).remove(); + + // delete div, span, el; + }, + + /** + * remove placeholder from contenteditable. If setCursor is true, + * will also set the cursor to the start of the selection. However, + * this will be ASYNCHRONOUS, so if you rely on the fact that + * the placeholder is removed after calling this method, setCursor + * should be false ( or not set ) + * + * @return void + */ + removePlaceholder: function( obj, setCursor ) { + var placeholderClass = this.placeholderClass, + range; + + // // remove browser br + // jQuery( 'br', obj ).remove(); + + // set the cursor // remove placeholder + if ( setCursor === true ) { + range = Selection.getRangeObject(); + if ( !range.select ) { + return; + } + range.startContainer = range.endContainer = obj.get( 0 ); + range.startOffset = range.endOffset = 0; + range.select(); + + window.setTimeout( function() { + jQuery( '.' + placeholderClass, obj ).remove(); + }, 20 ); + + } else { + jQuery( '.' + placeholderClass, obj ).remove(); + } + }, + + /** + * destroy the editable + * @return void + */ + destroy: function() { + // leave the element just to get sure + if ( this === Aloha.getActiveEditable() ) { + this.blur(); + + // also hide the floating menu if the current editable was active + FloatingMenu.hide(); + } + + // special handled elements + switch ( this.originalObj.get( 0 ).nodeName.toLowerCase() ) { + case 'label': + case 'button': + // TODO need some special handling. + break; + case 'textarea': + // restore content to original textarea + this.originalObj.val( this.getContents() ); + this.obj.remove(); + this.originalObj.show(); + break; + default: + break; + } + + // now the editable is not ready any more + this.ready = false; + + // remove the placeholder if needed. + this.removePlaceholder( this.obj ); + + // initialize the object and disable contentEditable + // unbind all events + // TODO should only unbind the specific handlers. + this.obj.removeClass( 'aloha-editable' ) + .contentEditable( false ) + .unbind( 'mousedown click dblclick focus keydown keypress keyup' ); + + /* TODO remove this event, it should implemented as bind and unbind + // register the onSelectionChange Event with the Editable field + this.obj.contentEditableSelectionChange( function( event ) { + Aloha.Selection.onChange( me.obj, event ); + return me.obj; + } ); + */ + + // throw a new event when the editable has been created + /** + * @event editableCreated fires after a new editable has been destroyes, eg. via $( '#editme' ).mahalo() + * The event is triggered in Aloha's global scope Aloha + * @param {Event} e the event object + * @param {Array} a an array which contains a reference to the currently created editable on its first position + */ + Aloha.trigger( 'aloha-editable-destroyed', [ this ] ); + + // finally register the editable with Aloha + Aloha.unregisterEditable( this ); + }, + + /** + * marks the editables current state as unmodified. Use this method to inform the editable + * that it's contents have been saved + * @method + */ + setUnmodified: function() { + this.originalContent = this.getContents(); + }, + + /** + * check if the editable has been modified during the edit process# + * @method + * @return boolean true if the editable has been modified, false otherwise + */ + isModified: function() { + return this.originalContent !== this.getContents(); + }, + + /** + * String representation of the object + * @method + * @return Aloha.Editable + */ + toString: function() { + return 'Aloha.Editable'; + }, + + /** + * check whether the editable has been disabled + */ + isDisabled: function() { + return !this.obj.contentEditable() + || this.obj.contentEditable() === 'false'; + }, + + /** + * disable this editable + * a disabled editable cannot be written on by keyboard + */ + disable: function() { + return this.isDisabled() || this.obj.contentEditable( false ); + }, + + /** + * enable this editable + * reenables a disabled editable to be writteable again + */ + enable: function() { + return this.isDisabled() && this.obj.contentEditable( true ); + }, + + + /** + * activates an Editable for editing + * disables all other active items + * @method + */ + activate: function( e ) { + // get active Editable before setting the new one. + var oldActive = Aloha.getActiveEditable(); + + // We need to ommit this call when this flag is set to true. + // This flag will only be set to true before the removePlaceholder method + // is called since that method invokes a focus event which will again trigger + // this method. We want to avoid double invokation of this method. + if ( ignoreNextActivateEvent ) { + ignoreNextActivateEvent = false; + return; + } + + // handle special case in which a nested editable is focused by a click + // in this case the "focus" event would be triggered on the parent element + // which actually shifts the focus away to it's parent. this if is here to + // prevent this situation + if ( e && e.type === 'focus' && oldActive !== null + && oldActive.obj.parent().get( 0 ) === e.currentTarget ) { + return; + } + + // leave immediately if this is already the active editable + if ( this.isActive || this.isDisabled() ) { + // we don't want parent editables to be triggered as well, so return false + return; + } + + this.obj.addClass( 'aloha-editable-active' ); + + Aloha.activateEditable( this ); + + ignoreNextActivateEvent = true; + this.removePlaceholder ( this.obj, true ); + ignoreNextActivateEvent = false; + + this.isActive = true; + + /** + * @event editableActivated fires after the editable has been activated by clicking on it. + * This event is triggered in Aloha's global scope Aloha + * @param {Event} e the event object + * @param {Array} a an array which contains a reference to last active editable on its first position, as well + * as the currently active editable on it's second position + */ + // trigger a 'general' editableActivated event + Aloha.trigger( 'aloha-editable-activated', { + 'oldActive' : oldActive, + 'editable' : this + } ); + }, + + /** + * handle the blur event + * this must not be attached to the blur event, which will trigger far too often + * eg. when a table within an editable is selected + * @hide + */ + blur: function() { + this.obj.blur(); + this.isActive = false; + this.initPlaceholder(); + this.obj.removeClass( 'aloha-editable-active' ); + + /** + * @event editableDeactivated fires after the editable has been activated by clicking on it. + * This event is triggered in Aloha's global scope Aloha + * @param {Event} e the event object + * @param {Array} a an array which contains a reference to this editable + */ + Aloha.trigger( 'aloha-editable-deactivated', { editable : this } ); + + /** + * @event smartContentChanged + */ + Aloha.activeEditable.smartContentChange( { type : 'blur' }, null ); + }, + + /** + * check if the string is empty + * used for zerowidth check + * @return true if empty or string is null, false otherwise + * @hide + */ + empty: function( str ) { + // br is needed for chrome + return ( null === str ) + || ( jQuery.trim( str ) === '' || str === '
    ' ); + }, + + /** + * Get the contents of this editable as a HTML string + * @method + * @return contents of the editable + */ + getContents: function( asObject ) { + var clonedObj = this.obj.clone( false ); + + // do core cleanup + clonedObj.find( '.aloha-cleanme' ).remove(); + this.removePlaceholder( clonedObj ); + PluginManager.makeClean( clonedObj ); + + return asObject ? clonedObj.contents() : contentSerializer(clonedObj[0]); + }, + + /** + * Get the id of this editable + * @method + * @return id of this editable + */ + getId: function() { + return this.obj.attr( 'id' ); + }, + + /** + * Generates and signals a smartContentChange event. + * + * A smart content change occurs when a special editing action, or a + * combination of interactions are performed by the user during the + * course of editing within an editable. + * The smart content change event would therefore signal to any + * component that is listening to this event, that content has been + * inserted into the editable that may need to be prococessed in a + * special way + * This is used for smart actions within the content/while editing. + * @param {Event} event + * @hide + */ + smartContentChange: function( event ) { + var me = this, + uniChar = null, + re, + match; + + // ignore meta keys like crtl+v or crtl+l and so on + if ( event && ( event.metaKey || event.crtlKey || event.altKey ) ) { + return false; + } + + if ( event && event.originalEvent ) { + // regex to strip unicode + re = new RegExp( "U\\+(\\w{4})" ); + match = re.exec( event.originalEvent.keyIdentifier ); + + // Use keyIdentifier if available + if ( event.originalEvent.keyIdentifier && 1 === 2 ) { + // @fixme: Because of "&& 1 === 2" above, all the below is + // unreachable code + if ( match !== null ) { + uniChar = unescape( '%u' + match[1] ); + } + if ( uniChar === null ) { + uniChar = event.originalEvent.keyIdentifier; + } + + // FF & Opera don't support keyIdentifier + } else { + // Use among browsers reliable which http://api.jquery.com/keypress + uniChar = ( this.keyCodeMap[ this.keyCode ] || + String.fromCharCode( event.which ) || 'unknown' ); + } + } + + // handle "Enter" -- it's not "U+1234" -- when returned via "event.originalEvent.keyIdentifier" + // reference: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html + if ( jQuery.inArray( uniChar, this.sccDelimiters ) >= 0 ) { + clearTimeout( this.sccTimerIdle ); + clearTimeout( this.sccTimerDelay ); + + this.sccTimerDelay = setTimeout( function() { + Aloha.trigger( 'aloha-smart-content-changed', { + 'editable' : me, + 'keyIdentifier' : event.originalEvent.keyIdentifier, + 'keyCode' : event.keyCode, + 'char' : uniChar, + 'triggerType' : 'keypress', // keypress, timer, blur, paste + 'snapshotContent' : me.getSnapshotContent() + } ); + + console.debug( 'Aloha.Editable', + 'smartContentChanged: event type keypress triggered' ); + /* + var r = Aloha.Selection.rangeObject; + if ( r.isCollapsed() + && r.startContainer.nodeType == 3 ) { + + var posDummy = jQuery( '' ); + + GENTICS.Utils.Dom.insertIntoDOM( + posDummy, + r, + this.obj, + null, + false, + false + ); + + console.log( posDummy.offset().top, posDummy.offset().left ); + + GENTICS.Utils.Dom.removeFromDOM( + posDummy, + r, + false + ); + + r.select(); + + } + */ + }, this.sccDelay ); + + } else if ( event && event.type === 'paste' ) { + Aloha.trigger( 'aloha-smart-content-changed', { + 'editable' : me, + 'keyIdentifier' : null, + 'keyCode' : null, + 'char' : null, + 'triggerType' : 'paste', + 'snapshotContent' : me.getSnapshotContent() + } ); + + } else if ( event && event.type === 'blur' ) { + Aloha.trigger( 'aloha-smart-content-changed', { + 'editable' : me, + 'keyIdentifier' : null, + 'keyCode' : null, + 'char' : null, + 'triggerType' : 'blur', + 'snapshotContent' : me.getSnapshotContent() + } ); + + } else if ( uniChar !== null ) { + // in the rare case idle time is lower then delay time + clearTimeout( this.sccTimerDelay ); + clearTimeout( this.sccTimerIdle ); + this.sccTimerIdle = setTimeout( function() { + Aloha.trigger( 'aloha-smart-content-changed', { + 'editable' : me, + 'keyIdentifier' : null, + 'keyCode' : null, + 'char' : null, + 'triggerType' : 'idle', + 'snapshotContent' : me.getSnapshotContent() + } ); + }, this.sccIdle ); + } + }, + + /** + * Get a snapshot of the active editable as a HTML string + * @hide + * @return snapshot of the editable + */ + getSnapshotContent: function() { + var ret = this.snapshotContent; + this.snapshotContent = this.getContents(); + return ret; + } + } ); + + /** + * Sets the serializer function to be used for the contents of all editables. + * + * The default content serializer will just call the jQuery.html() + * function on the editable element (which gets the innerHTML property). + * + * This method is a static class method and will affect the result + * of editable.getContents() for all editables that have been or + * will be constructed. + * + * @param serializerFunction + * A function that accepts a DOM element and returns the serialized + * XHTML of the element contents (excluding the start and end tag of + * the passed element). + */ + Aloha.Editable.setContentSerializer = function( serializerFunction ) { + contentSerializer = serializerFunction; + }; +} ); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/message',['aloha/core', 'util/class', 'aloha/jquery'], +function( Aloha, Class, jQuery ) { + + + var +// Aloha = window.Aloha, +// Class = window.Class, + GENTICS = window.GENTICS; + +/** + * Message Object + * @namespace Aloha + * @class Message + * @constructor + * @param {Object} data object which contains the parts of the message + * title: the title + * text: the message text to be displayed + * type: one of Aloha.Message.Type + * callback: callback function, which will be triggered after the message was confirmed, closed or accepted + */ +Aloha.Message = Class.extend({ + _constructor: function (data) { + this.title = data.title; + this.text = data.text; + this.type = data.type; + this.callback = data.callback; + }, + + + + /** + * Returns a textual representation of the message + * @return textual representation of the message + * @hide + */ + toString: function () { + return this.type + ': ' + this.message; + } +}); + +/** + * Message types enum. Contains all allowed types of messages + * @property + */ +Aloha.Message.Type = { + // reserved for messages + // SUCCESS : 'success', + // INFO : 'info', + // WARN : 'warn', + // CRITICAL : 'critical', + CONFIRM : 'confirm', // confirm dialog, like js confirm() + ALERT : 'alert', // alert dialog like js alert() + WAIT : 'wait' // wait dialog with loading bar. has to be hidden via Aloha.hideMessage() +}; + +/** + * This is the message line + * @hide + */ +Aloha.MessageLine = Class.extend({ + messages: [], + + /** + * Add a new message to the message line + * @param message message to add + * @return void + * @hide + */ + add: function(message) { + var messageline = '', + messagesLength = this.messages.length, + i; + + // dummy implementation to add a message + this.messages[messagesLength] = message; + while(messagesLength > 4) { + this.messages.shift(); + --messagesLength; + } + + for ( i = 0; i < messagesLength; i++) { + messageline += this.messages[i].toString() + '
    '; + } + jQuery('#gtx_aloha_messageline').html(messageline); + } +}); + +/** + * Message Line Object + * @hide + */ +Aloha.MessageLine = new Aloha.MessageLine(); + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/plugin',['aloha/core', 'aloha/jquery', 'util/class', 'aloha/pluginmanager', 'aloha/console'], +function(Aloha, jQuery, Class, PluginManager, console ) { + + + /** + * Abstract Plugin Object + * @namespace Aloha + * @class Plugin + * @constructor + * @param {String} pluginPrefix unique plugin prefix + */ + var Plugin = Class.extend({ + + name: null, + + /** + * contains the plugin's default settings object + * @cfg {Object} default settings for the plugin + */ + defaults: {}, + + /** + * contains the plugin's settings object + * @cfg {Object} settings the plugins settings stored in an object + */ + settings: {}, + + /** + * Names of other plugins which must be loaded in order for this plugin to + * function. + * @cfg {Array} + */ + dependencies: [], + + _constructor: function( name ) { + /** + * Settings of the plugin + */ + if (typeof name !== "string") { + console.error('Cannot initialise unnamed plugin, skipping'); + } else { + this.name = name; + } + }, + + /** + * @return true if dependencies satisfied, false otherwise + */ + checkDependencies: function() { + var + dependenciesSatisfied = true, + that = this; + + jQuery.each(this.dependencies, function() { + + if (!Aloha.isPluginLoaded(this)) { + dependenciesSatisfied = false; + console.error('plugin.' + that.name, 'Required plugin "' + this + '" not found.'); + } + }); + + return dependenciesSatisfied; + }, + + /** + * Init method of the plugin. Called from Aloha Core to initialize this plugin + * @return void + * @hide + */ + init: function() {}, + + /** + * Get the configuration settings for an editable obj. + * Handles both conf arrays or conf objects + *
      + *
    • Array configuration parameters are: + *
      +		 * "list": {
      +		 *		config : [ 'b', 'h1' ],
      +		 *		editables : {
      +		 *			'#title'	: [ ],
      +		 *			'div'		: [ 'b', 'i' ],
      +		 *			'.article'	: [ 'h1' ]
      +		 *		}
      +		 *	}
      +		 * 
      + * + * The hash keys of the editables are css selectors. For a + * + *
      +		 *  
      content
      + *
      + * + * the selectors 'div' and '.article' match and the returned configuration is + * + *
      +		 *  [ 'b', 'i', 'h1']
      +		 * 
      + * + * The '#title' object would return an empty configuration. + * + *
      +		 *  [ ]
      +		 * 
      + * + * All other objects would get the 'config' configuration. If config is not set + * the plugin default configuration is returned. + * + *
      +		 *  [ 'b', 'h1']
      +		 * 
    • + *
    • Object configuration parameters are : + *
      +		 *	"image": {
      +		 *		config : { 'img': { 'max_width': '50px',
      +		 *		'max_height': '50px' }},
      +		 *		editables : {
      +		 *			'#title': {},
      +		 *			'div': {'img': {}},
      +		 *			'.article': {'img': { 'max_width': '150px',
      +		 *			'max_height': '150px' }}
      +		 *		}
      +		 *	}
      +		 * 
      + * The '#title' object would return an empty configuration.
      + * The 'div' object would return the default configuration.
      + * the '.article' would return : + *
      +		 *		{'img': { 'max_width': '150px',
      +		 *		'max_height': '150px' }}
      +		 *  
      + *
    • + * + * @param {jQuery} obj jQuery object of an Editable Object + * @return {Array} config A Array with configuration entries + */ + getEditableConfig: function (obj) { + var configObj = null, + configSpecified = false, + that = this; + + if ( this.settings.editables ) { + // check if the editable's selector matches and if so add its configuration to object configuration + jQuery.each( this.settings.editables, function (selector, selectorConfig) { + if ( obj.is(selector) ) { + configSpecified = true; + if (selectorConfig instanceof Array) { + configObj = []; + configObj = jQuery.merge(configObj, selectorConfig); + } else if (typeof selectorConfig === "object") { + configObj = {}; + for (var k in selectorConfig) { + if ( selectorConfig.hasOwnProperty(k) ) { + if (selectorConfig[k] instanceof Array) { + + } else if (typeof selectorConfig[k] === "object") { + configObj[k] = {}; + configObj[k] = jQuery.extend(true, configObj[k], that.config[k], selectorConfig[k]); + } else { + configObj[k] = selectorConfig[k]; + } + } + } + } else { + configObj = selectorConfig; + } + } + }); + } + + // fall back to default configuration + if ( !configSpecified ) { + if ( typeof this.settings.config === 'undefined' || !this.settings.config ) { + configObj = this.config; + } else { + configObj = this.settings.config; + } + } + + return configObj; + }, + + /** + * Make the given jQuery object (representing an editable) clean for saving + * @param obj jQuery object to make clean + * @return void + */ + makeClean: function ( obj ) {}, + + /** + * Make a system-wide unique id out of a plugin-wide unique id by prefixing it with the plugin prefix + * @param id plugin-wide unique id + * @return system-wide unique id + * @hide + * @deprecated + */ + getUID: function(id) { + console.deprecated ('plugin', 'getUID() is deprecated. Use plugin.name instead.'); + return this.name; + }, + + /** + * Localize the given key for the plugin. + * @param key key to be localized + * @param replacements array of replacement strings + * @return localized string + * @hide + * @deprecated + */ + i18n: function(key, replacements) { + console.deprecated ('plugin', 'i18n() is deprecated. Use plugin.t() instead.'); + return Aloha.i18n(this, key, replacements); + }, + + /** + * Return string representation of the plugin, which is the prefix + * @return name + * @hide + * @deprecated + */ + toString: function() { + return this.name; + }, + + /** + * Log a plugin message to the logger + * @param level log level + * @param message log message + * @return void + * @hide + * @deprecated + */ + log: function (level, message) { + console.deprecated ('plugin', 'log() is deprecated. Use Aloha.console instead.'); + console.log(level, this, message); + } + }); + + /** + * Static method used as factory to create plugins. + * + * @param {String} pluginName name of the plugin + * @param {Object} definition definition of the plugin, should have at least an "init" and "destroy" method. + */ + Plugin.create = function(pluginName, definition) { + + var pluginInstance = new ( Plugin.extend( definition ) )( pluginName ); + pluginInstance.settings = jQuery.extendObjects( true, pluginInstance.defaults, Aloha.settings[pluginName] ); + PluginManager.register( pluginInstance ); + + return pluginInstance; + }; + + return Plugin; +}); + +define('aloha/engine',['aloha/ecma5shims', 'aloha/jquery'], +function($_, jQuery) { + + +var htmlNamespace = "http://www.w3.org/1999/xhtml"; + +var cssStylingFlag = false; + +// This is bad :( +var globalRange = null; + +// Commands are stored in a dictionary where we call their actions and such +var commands = {}; + +/////////////////////////////////////////////////////////////////////////////// +////////////////////////////// Utility functions ////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//@{ + +/** + * Method to count the number of styles in the given style + */ +function getStyleLength(node) { + if (!node) { + return 0; + } else if (!node.style) { + return 0; + } + + // some browsers support .length on styles + if (typeof node.style.length !== 'undefined') { + return node.style.length; + } else { + // others don't, so we will count + var styleLength = 0; + for (var s in node.style) { + if (node.style[s] && node.style[s] !== 0 && node.style[s] !== 'false') { + styleLength++; + } + } + + return styleLength; + } +} + +function toArray(obj) { + if (!obj) { + return null; + } + var array = [], i, l = obj.length; + // iterate backwards ensuring that length is an UInt32 + for (i = l >>> 0; i--;) { + array[i] = obj[i]; + } + return array; +} + +function nextNode(node) { + if (node.hasChildNodes()) { + return node.firstChild; + } + return nextNodeDescendants(node); +} + +function previousNode(node) { + if (node.previousSibling) { + node = node.previousSibling; + while (node.hasChildNodes()) { + node = node.lastChild; + } + return node; + } + if (node.parentNode + && node.parentNode.nodeType == $_.Node.ELEMENT_NODE) { + return node.parentNode; + } + return null; +} + +function nextNodeDescendants(node) { + while (node && !node.nextSibling) { + node = node.parentNode; + } + if (!node) { + return null; + } + return node.nextSibling; +} + +/** + * Returns true if ancestor is an ancestor of descendant, false otherwise. + */ +function isAncestor(ancestor, descendant) { + return ancestor + && descendant + && Boolean($_.compareDocumentPosition(ancestor, descendant) & $_.Node.DOCUMENT_POSITION_CONTAINED_BY); +} + +/** + * Returns true if ancestor is an ancestor of or equal to descendant, false + * otherwise. + */ +function isAncestorContainer(ancestor, descendant) { + return (ancestor || descendant) + && (ancestor == descendant || isAncestor(ancestor, descendant)); +} + +/** + * Returns true if descendant is a descendant of ancestor, false otherwise. + */ +function isDescendant(descendant, ancestor) { + return ancestor + && descendant + && Boolean($_.compareDocumentPosition(ancestor, descendant) & $_.Node.DOCUMENT_POSITION_CONTAINED_BY); +} + +/** + * Returns true if node1 is before node2 in tree order, false otherwise. + */ +function isBefore(node1, node2) { + return Boolean($_.compareDocumentPosition(node1,node2) & $_.Node.DOCUMENT_POSITION_FOLLOWING); +} + +/** + * Returns true if node1 is after node2 in tree order, false otherwise. + */ +function isAfter(node1, node2) { + return Boolean($_.compareDocumentPosition(node1,node2) & $_.Node.DOCUMENT_POSITION_PRECEDING); +} + +function getAncestors(node) { + var ancestors = []; + while (node.parentNode) { + ancestors.unshift(node.parentNode); + node = node.parentNode; + } + return ancestors; +} + +function getDescendants(node) { + var descendants = []; + var stop = nextNodeDescendants(node); + while ((node = nextNode(node)) + && node != stop) { + descendants.push(node); + } + return descendants; +} + +function convertProperty(property) { + // Special-case for now + var map = { + "fontFamily": "font-family", + "fontSize": "font-size", + "fontStyle": "font-style", + "fontWeight": "font-weight", + "textDecoration": "text-decoration" + }; + if (typeof map[property] != "undefined") { + return map[property]; + } + + return property; +} + +// Return the value for the given CSS size, or undefined if there +// is none. +function cssSizeToLegacy(cssVal) { + return { + "xx-small": 1, + "small": 2, + "medium": 3, + "large": 4, + "x-large": 5, + "xx-large": 6, + "xxx-large": 7 + }[cssVal]; +} + +// Return the CSS size given a legacy size. +function legacySizeToCss(legacyVal) { + return { + 1: "xx-small", + 2: "small", + 3: "medium", + 4: "large", + 5: "x-large", + 6: "xx-large", + 7: "xxx-large" + }[legacyVal]; +} + +// Opera 11 puts HTML elements in the null namespace, it seems. +function isHtmlNamespace(ns) { + return ns === null + || !ns + || ns === htmlNamespace; +} + +// "the directionality" from HTML. I don't bother caring about non-HTML +// elements. +// +// "The directionality of an element is either 'ltr' or 'rtl', and is +// determined as per the first appropriate set of steps from the following +// list:" +function getDirectionality(element) { + // "If the element's dir attribute is in the ltr state + // The directionality of the element is 'ltr'." + if (element.dir == "ltr") { + return "ltr"; + } + + // "If the element's dir attribute is in the rtl state + // The directionality of the element is 'rtl'." + if (element.dir == "rtl") { + return "rtl"; + } + + // "If the element's dir attribute is in the auto state + // "If the element is a bdi element and the dir attribute is not in a + // defined state (i.e. it is not present or has an invalid value) + // [lots of complicated stuff] + // + // Skip this, since no browser implements it anyway. + + // "If the element is a root element and the dir attribute is not in a + // defined state (i.e. it is not present or has an invalid value) + // The directionality of the element is 'ltr'." + if (!isHtmlElement(element.parentNode)) { + return "ltr"; + } + + // "If the element has a parent element and the dir attribute is not in a + // defined state (i.e. it is not present or has an invalid value) + // The directionality of the element is the same as the element's + // parent element's directionality." + return getDirectionality(element.parentNode); +} + +//@} + +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////// DOM Range functions ///////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//@{ + +function getNodeIndex(node) { + var ret = 0; + while (node.previousSibling) { + ret++; + node = node.previousSibling; + } + return ret; +} + +// "The length of a Node node is the following, depending on node: +// +// ProcessingInstruction +// DocumentType +// Always 0. +// Text +// Comment +// node's length. +// Any other node +// node's childNodes's length." +function getNodeLength(node) { + switch (node.nodeType) { + case $_.Node.PROCESSING_INSTRUCTION_NODE: + case $_.Node.DOCUMENT_TYPE_NODE: + return 0; + + case $_.Node.TEXT_NODE: + case $_.Node.COMMENT_NODE: + return node.length; + + default: + return node.childNodes.length; + } +} + +/** + * The position of two boundary points relative to one another, as defined by + * DOM Range. + */ +function getPosition(nodeA, offsetA, nodeB, offsetB) { + // "If node A is the same as node B, return equal if offset A equals offset + // B, before if offset A is less than offset B, and after if offset A is + // greater than offset B." + if (nodeA == nodeB) { + if (offsetA == offsetB) { + return "equal"; + } + if (offsetA < offsetB) { + return "before"; + } + if (offsetA > offsetB) { + return "after"; + } + } + + // "If node A is after node B in tree order, compute the position of (node + // B, offset B) relative to (node A, offset A). If it is before, return + // after. If it is after, return before." + if ($_.compareDocumentPosition(nodeB, nodeA) & $_.Node.DOCUMENT_POSITION_FOLLOWING) { + var pos = getPosition(nodeB, offsetB, nodeA, offsetA); + if (pos == "before") { + return "after"; + } + if (pos == "after") { + return "before"; + } + } + + // "If node A is an ancestor of node B:" + if ($_.compareDocumentPosition(nodeB, nodeA) & $_.Node.DOCUMENT_POSITION_CONTAINS) { + // "Let child equal node B." + var child = nodeB; + + // "While child is not a child of node A, set child to its parent." + while (child.parentNode != nodeA) { + child = child.parentNode; + } + + // "If the index of child is less than offset A, return after." + if (getNodeIndex(child) < offsetA) { + return "after"; + } + } + + // "Return before." + return "before"; +} + +/** + * Returns the furthest ancestor of a Node as defined by DOM Range. + */ +function getFurthestAncestor(node) { + var root = node; + while (root.parentNode != null) { + root = root.parentNode; + } + return root; +} + +/** + * "contained" as defined by DOM Range: "A Node node is contained in a range + * range if node's furthest ancestor is the same as range's root, and (node, 0) + * is after range's start, and (node, length of node) is before range's end." + */ +function isContained(node, range) { + var pos1 = getPosition(node, 0, range.startContainer, range.startOffset); + var pos2 = getPosition(node, getNodeLength(node), range.endContainer, range.endOffset); + + return getFurthestAncestor(node) == getFurthestAncestor(range.startContainer) + && pos1 == "after" + && pos2 == "before"; +} + +/** + * Return all nodes contained in range that the provided function returns true + * for, omitting any with an ancestor already being returned. + */ +function getContainedNodes(range, condition) { + if (typeof condition == "undefined") { + condition = function() { return true }; + } + var node = range.startContainer; + if (node.hasChildNodes() + && range.startOffset < node.childNodes.length) { + // A child is contained + node = node.childNodes[range.startOffset]; + } else if (range.startOffset == getNodeLength(node)) { + // No descendant can be contained + node = nextNodeDescendants(node); + } else { + // No children; this node at least can't be contained + node = nextNode(node); + } + + var stop = range.endContainer; + if (stop.hasChildNodes() + && range.endOffset < stop.childNodes.length) { + // The node after the last contained node is a child + stop = stop.childNodes[range.endOffset]; + } else { + // This node and/or some of its children might be contained + stop = nextNodeDescendants(stop); + } + + var nodeList = []; + while (isBefore(node, stop)) { + if (isContained(node, range) + && condition(node)) { + nodeList.push(node); + node = nextNodeDescendants(node); + continue; + } + node = nextNode(node); + } + return nodeList; +} + +/** + * As above, but includes nodes with an ancestor that's already been returned. + */ +function getAllContainedNodes(range, condition) { + if (typeof condition == "undefined") { + condition = function() { return true }; + } + var node = range.startContainer; + if (node.hasChildNodes() + && range.startOffset < node.childNodes.length) { + // A child is contained + node = node.childNodes[range.startOffset]; + } else if (range.startOffset == getNodeLength(node)) { + // No descendant can be contained + node = nextNodeDescendants(node); + } else { + // No children; this node at least can't be contained + node = nextNode(node); + } + + var stop = range.endContainer; + if (stop.hasChildNodes() + && range.endOffset < stop.childNodes.length) { + // The node after the last contained node is a child + stop = stop.childNodes[range.endOffset]; + } else { + // This node and/or some of its children might be contained + stop = nextNodeDescendants(stop); + } + + var nodeList = []; + while (isBefore(node, stop)) { + if (isContained(node, range) + && condition(node)) { + nodeList.push(node); + } + node = nextNode(node); + } + return nodeList; +} + +// Returns either null, or something of the form rgb(x, y, z), or something of +// the form rgb(x, y, z, w) with w != 0. +function normalizeColor(color) { + if (color.toLowerCase() == "currentcolor") { + return null; + } + + var outerSpan = document.createElement("span"); + document.body.appendChild(outerSpan); + outerSpan.style.color = "black"; + + var innerSpan = document.createElement("span"); + outerSpan.appendChild(innerSpan); + innerSpan.style.color = color; + color = $_.getComputedStyle(innerSpan).color; + + if (color == "rgb(0, 0, 0)") { + // Maybe it's really black, maybe it's invalid. + outerSpan.color = "white"; + color = $_.getComputedStyle(innerSpan).color; + if (color != "rgb(0, 0, 0)") { + return null; + } + } + + document.body.removeChild(outerSpan); + + // I rely on the fact that browsers generally provide consistent syntax for + // getComputedStyle(), although it's not standardized. There are only two + // exceptions I found: + if (/^rgba\([0-9]+, [0-9]+, [0-9]+, 1\)$/.test(color)) { + // IE10PP2 seems to do this sometimes. + return color.replace("rgba", "rgb").replace(", 1)", ")"); + } + if (color == "transparent") { + // IE10PP2, Firefox 7.0a2, and Opera 11.50 all return "transparent" if + // the specified value is "transparent". + return "rgba(0, 0, 0, 0)"; + } + return color; +} + +// Returns either null, or something of the form #xxxxxx, or the color itself +// if it's a valid keyword. +function parseSimpleColor(color) { + color = color.toLowerCase(); + if ($_(["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", + "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", + "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", + "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", + "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", + "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", + "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", + "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", + "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", + "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", + "lemonchiffon", "lightblue", "lightcoral", "lightcyan", + "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", + "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", + "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", + "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", + "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", + "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", + "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", + "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", + "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", + "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", + "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", + "wheat", "white", "whitesmoke", "yellow", "yellowgreen"]).indexOf(color) != -1) { + return color; + } + + color = normalizeColor(color); + var matches = /^rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)$/.exec(color); + if (matches) { + return "#" + + parseInt(matches[1]).toString(16).replace(/^.$/, "0$&") + + parseInt(matches[2]).toString(16).replace(/^.$/, "0$&") + + parseInt(matches[3]).toString(16).replace(/^.$/, "0$&"); + } + return null; +} + +//@} + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////// Edit command functions /////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////// +///// Methods of the HTMLDocument interface ///// +///////////////////////////////////////////////// +//@{ + +var executionStackDepth = 0; + +// Helper function for common behavior. +function editCommandMethod(command, prop, range, callback) { + // Set up our global range magic, but only if we're the outermost function + if (executionStackDepth == 0 && typeof range != "undefined") { + globalRange = range; + } else if (executionStackDepth == 0) { + globalRange = null; + globalRange = range; + } + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + // + // We can't throw a real one, but a string will do for our purposes. + if (!(command in commands)) { + throw "NOT_SUPPORTED_ERR"; + } + + // "If command has no action, raise an INVALID_ACCESS_ERR exception." + // "If command has no indeterminacy, raise an INVALID_ACCESS_ERR + // exception." + // "If command has no state, raise an INVALID_ACCESS_ERR exception." + // "If command has no value, raise an INVALID_ACCESS_ERR exception." + if (prop != "enabled" + && !(prop in commands[command])) { + throw "INVALID_ACCESS_ERR"; + } + + executionStackDepth++; + try { + var ret = callback(); + } catch(e) { + executionStackDepth--; + throw e; + } + executionStackDepth--; + return ret; +} + +function myExecCommand(command, showUi, value, range) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + // "If only one argument was provided, let show UI be false." + // + // If range was passed, I can't actually detect how many args were passed + // . . . + if (arguments.length == 1 + || (arguments.length >=4 && typeof showUi == "undefined")) { + showUi = false; + } + + // "If only one or two arguments were provided, let value be the empty + // string." + if (arguments.length <= 2 + || (arguments.length >=4 && typeof value == "undefined")) { + value = ""; + } + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + // + // "If command has no action, raise an INVALID_ACCESS_ERR exception." + return editCommandMethod(command, "action", range, (function(command, showUi, value) { return function() { + // "If command is not enabled, return false." + if (!myQueryCommandEnabled(command)) { + return false; + } + + // "Take the action for command, passing value to the instructions as an + // argument." + commands[command].action(value, range); + + // always fix the range after the command is complete + setActiveRange(range); + + // "Return true." + return true; + }})(command, showUi, value)); +} + +function myQueryCommandEnabled(command, range) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + return editCommandMethod(command, "action", range, (function(command) { return function() { + // "Among commands defined in this specification, those listed in + // Miscellaneous commands are always enabled. The other commands defined + // here are enabled if the active range is not null, and disabled + // otherwise." + return $_( ["copy", "cut", "paste", "selectall", "stylewithcss", "usecss"] ).indexOf(command) != -1 + || range !== null; + }})(command)); +} + +function myQueryCommandIndeterm(command, range) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + // + // "If command has no indeterminacy, raise an INVALID_ACCESS_ERR + // exception." + return editCommandMethod(command, "indeterm", range, (function(command) { return function() { + // "If command is not enabled, return false." + if (!myQueryCommandEnabled(command, range)) { + return false; + } + + // "Return true if command is indeterminate, otherwise false." + return commands[command].indeterm( range ); + }})(command)); +} + +function myQueryCommandState(command, range) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + // + // "If command has no state, raise an INVALID_ACCESS_ERR exception." + return editCommandMethod(command, "state", range, (function(command) { return function() { + // "If command is not enabled, return false." + if (!myQueryCommandEnabled(command, range)) { + return false; + } + + // "If the state override for command is set, return it." + if (typeof getStateOverride(command, range) != "undefined") { + return getStateOverride(command, range); + } + + // "Return true if command's state is true, otherwise false." + return commands[command].state( range ); + }})(command)); +} + +// "When the queryCommandSupported(command) method on the HTMLDocument +// interface is invoked, the user agent must return true if command is +// supported, and false otherwise." +function myQueryCommandSupported(command) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + return command in commands; +} + +function myQueryCommandValue(command, range) { + // "All of these methods must treat their command argument ASCII + // case-insensitively." + command = command.toLowerCase(); + + // "If command is not supported, raise a NOT_SUPPORTED_ERR exception." + // + // "If command has no value, raise an INVALID_ACCESS_ERR exception." + return editCommandMethod(command, "value", range, function() { + // "If command is not enabled, return the empty string." + if (!myQueryCommandEnabled(command, range)) { + return ""; + } + + // "If command is "fontSize" and its value override is set, convert the + // value override to an integer number of pixels and return the legacy + // font size for the result." + if (command == "fontsize" + && getValueOverride("fontsize", range) !== undefined) { + return getLegacyFontSize(getValueOverride("fontsize", range)); + } + + // "If the value override for command is set, return it." + if (typeof getValueOverride(command, range) != "undefined") { + return getValueOverride(command, range); + } + + // "Return command's value." + return commands[command].value(); + }); +} +//@} + +////////////////////////////// +///// Common definitions ///// +////////////////////////////// +//@{ + +// "An HTML element is an Element whose namespace is the HTML namespace." +// +// I allow an extra argument to more easily check whether something is a +// particular HTML element, like isHtmlElement(node, "OL"). It accepts arrays +// too, like isHtmlElement(node, ["OL", "UL"]) to check if it's an ol or ul. +function isHtmlElement(node, tags) { + if (typeof tags == "string") { + tags = [tags]; + } + if (typeof tags == "object") { + tags = $_( tags ).map(function(tag) { return tag.toUpperCase() }); + } + return node + && node.nodeType == $_.Node.ELEMENT_NODE + && isHtmlNamespace(node.namespaceURI) + && (typeof tags == "undefined" || $_( tags ).indexOf(node.tagName) != -1); +} + +// "A prohibited paragraph child name is "address", "article", "aside", +// "blockquote", "caption", "center", "col", "colgroup", "dd", "details", +// "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", +// "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "li", +// "listing", "menu", "nav", "ol", "p", "plaintext", "pre", "section", +// "summary", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "ul", or +// "xmp"." +var prohibitedParagraphChildNames = ["address", "article", "aside", + "blockquote", "caption", "center", "col", "colgroup", "dd", "details", + "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", + "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "li", + "listing", "menu", "nav", "ol", "p", "plaintext", "pre", "section", + "summary", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "ul", + "xmp"]; + +// "A prohibited paragraph child is an HTML element whose local name is a +// prohibited paragraph child name." +function isProhibitedParagraphChild(node) { + return isHtmlElement(node, prohibitedParagraphChildNames); +} + +// "A block node is either an Element whose "display" property does not have +// resolved value "inline" or "inline-block" or "inline-table" or "none", or a +// Document, or a DocumentFragment." +function isBlockNode(node) { + + return node + && ((node.nodeType == $_.Node.ELEMENT_NODE && $_( ["inline", "inline-block", "inline-table", "none"] ).indexOf($_.getComputedStyle(node).display) == -1) + || node.nodeType == $_.Node.DOCUMENT_NODE + || node.nodeType == $_.Node.DOCUMENT_FRAGMENT_NODE); +} + +// "An inline node is a node that is not a block node." +function isInlineNode(node) { + return node && !isBlockNode(node); +} + +// "An editing host is a node that is either an Element with a contenteditable +// attribute set to the true state, or the Element child of a Document whose +// designMode is enabled." +function isEditingHost(node) { + return node + && node.nodeType == $_.Node.ELEMENT_NODE + && (node.contentEditable == "true" + || (node.parentNode + && node.parentNode.nodeType == $_.Node.DOCUMENT_NODE + && node.parentNode.designMode == "on")); +} + +// "Something is editable if it is a node which is not an editing host, does +// not have a contenteditable attribute set to the false state, and whose +// parent is an editing host or editable." +function isEditable(node) { + // This is slightly a lie, because we're excluding non-HTML elements with + // contentEditable attributes. + return node + && !isEditingHost(node) + && (node.nodeType != $_.Node.ELEMENT_NODE || node.contentEditable != "false" || jQuery(node).hasClass('aloha-table-wrapper')) + && (isEditingHost(node.parentNode) || isEditable(node.parentNode)); +} + +// Helper function, not defined in the spec +function hasEditableDescendants(node) { + for (var i = 0; i < node.childNodes.length; i++) { + if (isEditable(node.childNodes[i]) + || hasEditableDescendants(node.childNodes[i])) { + return true; + } + } + return false; +} + +// "The editing host of node is null if node is neither editable nor an editing +// host; node itself, if node is an editing host; or the nearest ancestor of +// node that is an editing host, if node is editable." +function getEditingHostOf(node) { + if (isEditingHost(node)) { + return node; + } else if (isEditable(node)) { + var ancestor = node.parentNode; + while (!isEditingHost(ancestor)) { + ancestor = ancestor.parentNode; + } + return ancestor; + } else { + return null; + } +} + +// "Two nodes are in the same editing host if the editing host of the first is +// non-null and the same as the editing host of the second." +function inSameEditingHost(node1, node2) { + return getEditingHostOf(node1) + && getEditingHostOf(node1) == getEditingHostOf(node2); +} + +// "A collapsed line break is a br that begins a line box which has nothing +// else in it, and therefore has zero height." +function isCollapsedLineBreak(br) { + if (!isHtmlElement(br, "br")) { + return false; + } + + // Add a zwsp after it and see if that changes the height of the nearest + // non-inline parent. Note: this is not actually reliable, because the + // parent might have a fixed height or something. + var ref = br.parentNode; + while ($_.getComputedStyle(ref).display == "inline") { + ref = ref.parentNode; + } + + var refStyle = $_( ref ).hasAttribute("style") ? ref.getAttribute("style") : null; + ref.style.height = "auto"; + ref.style.maxHeight = "none"; + ref.style.minHeight = "0"; + var space = document.createTextNode("\u200b"); + var origHeight = ref.offsetHeight; + if (origHeight == 0) { + throw "isCollapsedLineBreak: original height is zero, bug?"; + } + br.parentNode.insertBefore(space, br.nextSibling); + var finalHeight = ref.offsetHeight; + space.parentNode.removeChild(space); + if (refStyle === null) { + // Without the setAttribute() line, removeAttribute() doesn't work in + // Chrome 14 dev. I have no idea why. + ref.setAttribute("style", ""); + ref.removeAttribute("style"); + } else { + ref.setAttribute("style", refStyle); + } + + // Allow some leeway in case the zwsp didn't create a whole new line, but + // only made an existing line slightly higher. Firefox 6.0a2 shows this + // behavior when the first line is bold. + return origHeight < finalHeight - 5; +} + +// "An extraneous line break is a br that has no visual effect, in that +// removing it from the DOM would not change layout, except that a br that is +// the sole child of an li is not extraneous." +// +// FIXME: This doesn't work in IE, since IE ignores display: none in +// contenteditable. +function isExtraneousLineBreak(br) { + if (!isHtmlElement(br, "br")) { + return false; + } + + if (isHtmlElement(br.parentNode, "li") + && br.parentNode.childNodes.length == 1) { + return false; + } + + // Make the line break disappear and see if that changes the block's + // height. Yes, this is an absurd hack. We have to reset height etc. on + // the reference node because otherwise its height won't change if it's not + // auto. + var ref = br.parentNode; + while ($_.getComputedStyle(ref).display == "inline") { + ref = ref.parentNode; + } + var refStyle = $_( ref ).hasAttribute("style") ? ref.getAttribute("style") : null; + ref.style.height = "auto"; + ref.style.maxHeight = "none"; + ref.style.minHeight = "0"; + var brStyle = $_( br ).hasAttribute("style") ? br.getAttribute("style") : null; + var origHeight = ref.offsetHeight; + if (origHeight == 0) { + throw "isExtraneousLineBreak: original height is zero, bug?"; + } + br.setAttribute("style", "display:none"); + var finalHeight = ref.offsetHeight; + if (refStyle === null) { + // Without the setAttribute() line, removeAttribute() doesn't work in + // Chrome 14 dev. I have no idea why. + ref.setAttribute("style", ""); + ref.removeAttribute("style"); + } else { + ref.setAttribute("style", refStyle); + } + if (brStyle === null) { + br.removeAttribute("style"); + } else { + br.setAttribute("style", brStyle); + } + + return origHeight == finalHeight; +} + +// "A whitespace node is either a Text node whose data is the empty string; or +// a Text node whose data consists only of one or more tabs (0x0009), line +// feeds (0x000A), carriage returns (0x000D), and/or spaces (0x0020), and whose +// parent is an Element whose resolved value for "white-space" is "normal" or +// "nowrap"; or a Text node whose data consists only of one or more tabs +// (0x0009), carriage returns (0x000D), and/or spaces (0x0020), and whose +// parent is an Element whose resolved value for "white-space" is "pre-line"." +function isWhitespaceNode(node) { + return node + && node.nodeType == $_.Node.TEXT_NODE + && (node.data == "" + || ( + /^[\t\n\r ]+$/.test(node.data) + && node.parentNode + && node.parentNode.nodeType == $_.Node.ELEMENT_NODE + && $_( ["normal", "nowrap"] ).indexOf($_.getComputedStyle(node.parentNode).whiteSpace) != -1 + ) || ( + /^[\t\r ]+$/.test(node.data) + && node.parentNode + && node.parentNode.nodeType == $_.Node.ELEMENT_NODE + && $_.getComputedStyle(node.parentNode).whiteSpace == "pre-line" + ) || ( + /^[\t\n\r ]+$/.test(node.data) + && node.parentNode + && node.parentNode.nodeType == $_.Node.DOCUMENT_FRAGMENT_NODE + )); +} + +/** + * Collapse sequences of ignorable whitespace (tab (0x0009), line feed (0x000A), carriage return (0x000D), space (0x0020)) to only one space. + * Preserve the given range if necessary. + * @param node text node + * @param range range + */ +function collapseWhitespace(node, range) { + // "If node is neither editable nor an editing host, abort these steps." + if (!isEditable(node) && !isEditingHost(node)) { + return; + } + + // if the given node is not a text node, return + if (!node || node.nodeType !== $_.Node.TEXT_NODE) { + return; + } + + // if the node is in a pre or pre-wrap node, return + if ($_(["pre", "pre-wrap"]).indexOf($_.getComputedStyle(node.parentNode).whiteSpace) != -1) { + return; + } + + // if the given node does not contain sequences of at least two consecutive ignorable whitespace characters, return + if (!/[\t\n\r ]{2,}/.test(node.data)) { + return; + } + + var newData = ''; + var correctStart = range.startContainer == node; + var correctEnd = range.endContainer == node; + var wsFound = false; + + // iterate through the node data + for (var i = 0; i < node.data.length; ++i) { + if (/[\t\n\r ]/.test(node.data[i])) { + // found a whitespace + if (!wsFound) { + // this is the first whitespace in the current sequence + // add a whitespace to the new data sequence + newData += ' '; + // remember that we found a whitespace + wsFound = true; + } else { + // this is not the first whitespace in the sequence, so omit this character + if (correctStart && newData.length < range.startOffset) { + range.startOffset--; + } + if (correctEnd && newData.length < range.endOffset) { + range.endOffset--; + } + } + } else { + newData += node.data[i]; + wsFound = false; + } + } + + // set the new data + node.data = newData; +} + +// "node is a collapsed whitespace node if the following algorithm returns +// true:" +function isCollapsedWhitespaceNode(node) { + // "If node is not a whitespace node, return false." + if (!isWhitespaceNode(node)) { + return false; + } + + // "If node's data is the empty string, return true." + if (node.data == "") { + return true; + } + + // "Let ancestor be node's parent." + var ancestor = node.parentNode; + + // "If ancestor is null, return true." + if (!ancestor) { + return true; + } + + // "If the "display" property of some ancestor of node has resolved value + // "none", return true." + if ($_( getAncestors(node) ).some(function(ancestor) { + return ancestor.nodeType == $_.Node.ELEMENT_NODE + && $_.getComputedStyle(ancestor).display == "none"; + })) { + return true; + } + + // "While ancestor is not a block node and its parent is not null, set + // ancestor to its parent." + while (!isBlockNode(ancestor) + && ancestor.parentNode) { + ancestor = ancestor.parentNode; + } + + // "Let reference be node." + var reference = node; + + // "While reference is a descendant of ancestor:" + while (reference != ancestor) { + // "Let reference be the node before it in tree order." + reference = previousNode(reference); + + // "If reference is a block node or a br, return true." + if (isBlockNode(reference) + || isHtmlElement(reference, "br")) { + return true; + } + + // "If reference is a Text node that is not a whitespace node, or is an + // img, break from this loop." + if ((reference.nodeType == $_.Node.TEXT_NODE && !isWhitespaceNode(reference)) + || isHtmlElement(reference, "img")) { + break; + } + } + + // "Let reference be node." + reference = node; + + // "While reference is a descendant of ancestor:" + var stop = nextNodeDescendants(ancestor); + while (reference != stop) { + // "Let reference be the node after it in tree order, or null if there + // is no such node." + reference = nextNode(reference); + + // "If reference is a block node or a br, return true." + if (isBlockNode(reference) + || isHtmlElement(reference, "br")) { + return true; + } + + // "If reference is a Text node that is not a whitespace node, or is an + // img, break from this loop." + if ((reference && reference.nodeType == $_.Node.TEXT_NODE && !isWhitespaceNode(reference)) + || isHtmlElement(reference, "img")) { + break; + } + } + + // "Return false." + return false; +} + +// "Something is visible if it is a node that either is a block node, or a Text +// node that is not a collapsed whitespace node, or an img, or a br that is not +// an extraneous line break, or any node with a visible descendant; excluding +// any node with an ancestor container Element whose "display" property has +// resolved value "none"." +function isVisible(node) { + if (!node) { + return false; + } + + if ($_( getAncestors(node).concat(node) ) + .filter(function(node) { return node.nodeType == $_.Node.ELEMENT_NODE }, true) + .some(function(node) { return $_.getComputedStyle(node).display == "none" })) { + return false; + } + + if (isBlockNode(node) + || (node.nodeType == $_.Node.TEXT_NODE && !isCollapsedWhitespaceNode(node)) + || isHtmlElement(node, "img") + || (isHtmlElement(node, "br") && !isExtraneousLineBreak(node))) { + return true; + } + + for (var i = 0; i < node.childNodes.length; i++) { + if (isVisible(node.childNodes[i])) { + return true; + } + } + + return false; +} + +// "Something is invisible if it is a node that is not visible." +function isInvisible(node) { + return node && !isVisible(node); +} + +// "A collapsed block prop is either a collapsed line break that is not an +// extraneous line break, or an Element that is an inline node and whose +// children are all either invisible or collapsed block props and that has at +// least one child that is a collapsed block prop." +function isCollapsedBlockProp(node) { + if (isCollapsedLineBreak(node) + && !isExtraneousLineBreak(node)) { + return true; + } + + if (!isInlineNode(node) + || node.nodeType != $_.Node.ELEMENT_NODE) { + return false; + } + + var hasCollapsedBlockPropChild = false; + for (var i = 0; i < node.childNodes.length; i++) { + if (!isInvisible(node.childNodes[i]) + && !isCollapsedBlockProp(node.childNodes[i])) { + return false; + } + if (isCollapsedBlockProp(node.childNodes[i])) { + hasCollapsedBlockPropChild = true; + } + } + + return hasCollapsedBlockPropChild; +} + +function setActiveRange( range ) { + var rangeObject = new window.GENTICS.Utils.RangeObject(); + + rangeObject.startContainer = range.startContainer; + rangeObject.startOffset = range.startOffset; + rangeObject.endContainer = range.endContainer; + rangeObject.endOffset = range.endOffset; + + rangeObject.select(); +} + +// Please note: This method is deprecated and will be removed. +// Every command should use the value and range parameter. +// +// "The active range is the first range in the Selection given by calling +// getSelection() on the context object, or null if there is no such range." +// +// We cheat and return globalRange if that's defined. We also ensure that the +// active range meets the requirements that selection boundary points are +// supposed to meet, i.e., that the nodes are both Text or Element nodes that +// descend from a Document. +function getActiveRange() { + var ret; + if (globalRange) { + ret = globalRange; + } else if (Aloha.getSelection().rangeCount) { + ret = Aloha.getSelection().getRangeAt(0); + } else { + return null; + } + if ($_( [$_.Node.TEXT_NODE, $_.Node.ELEMENT_NODE] ).indexOf(ret.startContainer.nodeType) == -1 + || $_( [$_.Node.TEXT_NODE, $_.Node.ELEMENT_NODE] ).indexOf(ret.endContainer.nodeType) == -1 + || !ret.startContainer.ownerDocument + || !ret.endContainer.ownerDocument + || !isDescendant(ret.startContainer, ret.startContainer.ownerDocument) + || !isDescendant(ret.endContainer, ret.endContainer.ownerDocument)) { + throw "Invalid active range; test bug?"; + } + return ret; +} + +// "For some commands, each HTMLDocument must have a boolean state override +// and/or a string value override. These do not change the command's state or +// value, but change the way some algorithms behave, as specified in those +// algorithms' definitions. Initially, both must be unset for every command. +// Whenever the number of ranges in the Selection changes to something +// different, and whenever a boundary point of the range at a given index in +// the Selection changes to something different, the state override and value +// override must be unset for every command." +// +// We implement this crudely by using setters and getters. To verify that the +// selection hasn't changed, we copy the active range and just check the +// endpoints match. This isn't really correct, but it's good enough for us. +// Unset state/value overrides are undefined. We put everything in a function +// so no one can access anything except via the provided functions, since +// otherwise callers might mistakenly use outdated overrides (if the selection +// has changed). +var getStateOverride, setStateOverride, unsetStateOverride, + getValueOverride, setValueOverride, unsetValueOverride; +(function() { + var stateOverrides = {}; + var valueOverrides = {}; + var storedRange = null; + + function resetOverrides(range) { + if (!storedRange + || storedRange.startContainer != range.startContainer + || storedRange.endContainer != range.endContainer + || storedRange.startOffset != range.startOffset + || storedRange.endOffset != range.endOffset) { + stateOverrides = {}; + valueOverrides = {}; + storedRange = range.cloneRange(); + } + } + + getStateOverride = function(command, range) { + resetOverrides(range); + return stateOverrides[command]; + }; + + setStateOverride = function(command, newState, range) { + resetOverrides(range); + stateOverrides[command] = newState; + }; + + unsetStateOverride = function(command, range) { + resetOverrides(range); + delete stateOverrides[command]; + } + + getValueOverride = function(command, range) { + resetOverrides(range); + return valueOverrides[command]; + } + + // "The value override for the backColor command must be the same as the + // value override for the hiliteColor command, such that setting one sets + // the other to the same thing and unsetting one unsets the other." + setValueOverride = function(command, newValue, range) { + resetOverrides(range); + valueOverrides[command] = newValue; + if (command == "backcolor") { + valueOverrides.hilitecolor = newValue; + } else if (command == "hilitecolor") { + valueOverrides.backcolor = newValue; + } + } + + unsetValueOverride = function(command, range) { + resetOverrides(range); + delete valueOverrides[command]; + if (command == "backcolor") { + delete valueOverrides.hilitecolor; + } else if (command == "hilitecolor") { + delete valueOverrides.backcolor; + } + } +})(); + +//@} + +///////////////////////////// +///// Common algorithms ///// +///////////////////////////// + +///// Assorted common algorithms ///// +//@{ + +function movePreservingRanges(node, newParent, newIndex, range) { + // For convenience, I allow newIndex to be -1 to mean "insert at the end". + if (newIndex == -1) { + newIndex = newParent.childNodes.length; + } + + // "When the user agent is to move a Node to a new location, preserving + // ranges, it must remove the Node from its original parent (if any), then + // insert it in the new location. In doing so, however, it must ignore the + // regular range mutation rules, and instead follow these rules:" + + // "Let node be the moved Node, old parent and old index be the old parent + // (which may be null) and index, and new parent and new index be the new + // parent and index." + var oldParent = node.parentNode; + var oldIndex = getNodeIndex(node); + + // We only even attempt to preserve the global range object and the ranges + // in the selection, not every range out there (the latter is probably + // impossible). + var ranges = [range]; + for (var i = 0; i < Aloha.getSelection().rangeCount; i++) { + ranges.push(Aloha.getSelection().getRangeAt(i)); + } + var boundaryPoints = []; + $_( ranges ).forEach(function(range) { + boundaryPoints.push([range.startContainer, range.startOffset]); + boundaryPoints.push([range.endContainer, range.endOffset]); + }); + + $_( boundaryPoints ).forEach(function(boundaryPoint) { + // "If a boundary point's node is the same as or a descendant of node, + // leave it unchanged, so it moves to the new location." + // + // No modifications necessary. + + // "If a boundary point's node is new parent and its offset is greater + // than new index, add one to its offset." + if (boundaryPoint[0] == newParent + && boundaryPoint[1] > newIndex) { + boundaryPoint[1]++; + } + + // "If a boundary point's node is old parent and its offset is old index or + // old index + 1, set its node to new parent and add new index − old index + // to its offset." + if (boundaryPoint[0] == oldParent + && (boundaryPoint[1] == oldIndex + || boundaryPoint[1] == oldIndex + 1)) { + boundaryPoint[0] = newParent; + boundaryPoint[1] += newIndex - oldIndex; + } + + // "If a boundary point's node is old parent and its offset is greater than + // old index + 1, subtract one from its offset." + if (boundaryPoint[0] == oldParent + && boundaryPoint[1] > oldIndex + 1) { + boundaryPoint[1]--; + } + }); + + // Now actually move it and preserve the ranges. + if (newParent.childNodes.length == newIndex) { + newParent.appendChild(node); + } else { + newParent.insertBefore(node, newParent.childNodes[newIndex]); + } + + // if we're off actual node boundaries this implies that the move was + // part of a deletion process (backspace). If that's the case we + // attempt to fix this by restoring the range to the first index of + // the node that has been moved + if (boundaryPoints[0][1] > boundaryPoints[0][0].childNodes.length + && boundaryPoints[1][1] > boundaryPoints[1][0].childNodes.length) { + range.setStart(node, 0); + range.setEnd(node, 0); + } else { + range.setStart(boundaryPoints[0][0], boundaryPoints[0][1]); + range.setEnd(boundaryPoints[1][0], boundaryPoints[1][1]); + + Aloha.getSelection().removeAllRanges(); + for (var i = 1; i < ranges.length; i++) { + var newRange = Aloha.createRange(); + newRange.setStart(boundaryPoints[2*i][0], boundaryPoints[2*i][1]); + newRange.setEnd(boundaryPoints[2*i + 1][0], boundaryPoints[2*i + 1][1]); + Aloha.getSelection().addRange(newRange); + } + if (newRange) { + range = newRange; + } + } +} + +function setTagName(element, newName, range) { + // "If element is an HTML element with local name equal to new name, return + // element." + if (isHtmlElement(element, newName.toUpperCase())) { + return element; + } + + // "If element's parent is null, return element." + if (!element.parentNode) { + return element; + } + + // "Let replacement element be the result of calling createElement(new + // name) on the ownerDocument of element." + var replacementElement = element.ownerDocument.createElement(newName); + + // "Insert replacement element into element's parent immediately before + // element." + element.parentNode.insertBefore(replacementElement, element); + + // "Copy all attributes of element to replacement element, in order." + for (var i = 0; i < element.attributes.length; i++) { + if (typeof replacementElement.setAttributeNS === 'function') { + replacementElement.setAttributeNS(element.attributes[i].namespaceURI, element.attributes[i].name, element.attributes[i].value); + } else { + replacementElement.setAttribute(element.attributes[i].name, element.attributes[i].value); + } + } + + // "While element has children, append the first child of element as the + // last child of replacement element, preserving ranges." + while (element.childNodes.length) { + movePreservingRanges(element.firstChild, replacementElement, replacementElement.childNodes.length, range); + } + + // "Remove element from its parent." + element.parentNode.removeChild(element); + + // if the range still uses the old element, we modify it to the new one + if (range.startContainer === element) { + range.setStart(replacementElement, range.startOffset); + } + if (range.endContainer === element) { + range.setEnd(replacementElement, range.endOffset); + } + + // "Return replacement element." + return replacementElement; +} + +function removeExtraneousLineBreaksBefore(node) { + // "Let ref be the previousSibling of node." + var ref = node.previousSibling; + + // "If ref is null, abort these steps." + if (!ref) { + return; + } + + // "While ref has children, set ref to its lastChild." + while (ref.hasChildNodes()) { + ref = ref.lastChild; + } + + // "While ref is invisible but not an extraneous line break, and ref does + // not equal node's parent, set ref to the node before it in tree order." + while (isInvisible(ref) + && !isExtraneousLineBreak(ref) + && ref != node.parentNode) { + ref = previousNode(ref); + } + + // "If ref is an editable extraneous line break, remove it from its + // parent." + if (isEditable(ref) + && isExtraneousLineBreak(ref)) { + ref.parentNode.removeChild(ref); + } +} + +function removeExtraneousLineBreaksAtTheEndOf(node) { + // "Let ref be node." + var ref = node; + + // "While ref has children, set ref to its lastChild." + while (ref.hasChildNodes()) { + ref = ref.lastChild; + } + + // "While ref is invisible but not an extraneous line break, and ref does + // not equal node, set ref to the node before it in tree order." + while (isInvisible(ref) + && !isExtraneousLineBreak(ref) + && ref != node) { + ref = previousNode(ref); + } + + // "If ref is an editable extraneous line break, remove it from its + // parent." + if (isEditable(ref) + && isExtraneousLineBreak(ref)) { + ref.parentNode.removeChild(ref); + } +} + +// "To remove extraneous line breaks from a node, first remove extraneous line +// breaks before it, then remove extraneous line breaks at the end of it." +function removeExtraneousLineBreaksFrom(node) { + removeExtraneousLineBreaksBefore(node); + removeExtraneousLineBreaksAtTheEndOf(node); +} + +//@} +///// Wrapping a list of nodes ///// +//@{ + +function wrap(nodeList, siblingCriteria, newParentInstructions, range) { + // "If not provided, sibling criteria returns false and new parent + // instructions returns null." + if (typeof siblingCriteria == "undefined") { + siblingCriteria = function() { return false }; + } + if (typeof newParentInstructions == "undefined") { + newParentInstructions = function() { return null }; + } + + // "If node list is empty, or the first member of node list is not + // editable, return null and abort these steps." + if (!nodeList.length + || !isEditable(nodeList[0])) { + return null; + } + + // "If node list's last member is an inline node that's not a br, and node + // list's last member's nextSibling is a br, append that br to node list." + if (isInlineNode(nodeList[nodeList.length - 1]) + && !isHtmlElement(nodeList[nodeList.length - 1], "br") + && isHtmlElement(nodeList[nodeList.length - 1].nextSibling, "br")) { + nodeList.push(nodeList[nodeList.length - 1].nextSibling); + } + + // "If the previousSibling of the first member of node list is editable and + // running sibling criteria on it returns true, let new parent be the + // previousSibling of the first member of node list." + var newParent; + if (isEditable(nodeList[0].previousSibling) + && siblingCriteria(nodeList[0].previousSibling)) { + newParent = nodeList[0].previousSibling; + + // "Otherwise, if the nextSibling of the last member of node list is + // editable and running sibling criteria on it returns true, let new parent + // be the nextSibling of the last member of node list." + } else if (isEditable(nodeList[nodeList.length - 1].nextSibling) + && siblingCriteria(nodeList[nodeList.length - 1].nextSibling)) { + newParent = nodeList[nodeList.length - 1].nextSibling; + + // "Otherwise, run new parent instructions, and let new parent be the + // result." + } else { + newParent = newParentInstructions(); + } + + // "If new parent is null, abort these steps and return null." + if (!newParent) { + return null; + } + + // "If new parent's parent is null:" + if (!newParent.parentNode) { + // "Insert new parent into the parent of the first member of node list + // immediately before the first member of node list." + nodeList[0].parentNode.insertBefore(newParent, nodeList[0]); + + // "If any range has a boundary point with node equal to the parent of + // new parent and offset equal to the index of new parent, add one to + // that boundary point's offset." + // + // Try to fix range + var startContainer = range.startContainer, startOffset = range.startOffset, + endContainer = range.endContainer, endOffset = range.endOffset; + if (startContainer == newParent.parentNode + && startOffset >= getNodeIndex(newParent)) { + range.setStart(startContainer, startOffset + 1); + } + if (endContainer == newParent.parentNode + && endOffset >= getNodeIndex(newParent)) { + range.setEnd(endContainer, endOffset + 1); + } + + // Only try to fix the global range. TODO remove globalRange here + if (globalRange && globalRange !== range) { + startContainer = globalRange.startContainer, startOffset = globalRange.startOffset, + endContainer = globalRange.endContainer, endOffset = globalRange.endOffset; + if (startContainer == newParent.parentNode + && startOffset >= getNodeIndex(newParent)) { + globalRange.setStart(startContainer, startOffset + 1); + } + if (endContainer == newParent.parentNode + && endOffset >= getNodeIndex(newParent)) { + globalRange.setEnd(endContainer, endOffset + 1); + } + } + } + + // "Let original parent be the parent of the first member of node list." + var originalParent = nodeList[0].parentNode; + + // "If new parent is before the first member of node list in tree order:" + if (isBefore(newParent, nodeList[0])) { + // "If new parent is not an inline node, but the last child of new + // parent and the first member of node list are both inline nodes, and + // the last child of new parent is not a br, call createElement("br") + // on the ownerDocument of new parent and append the result as the last + // child of new parent." + if (!isInlineNode(newParent) + && isInlineNode(newParent.lastChild) + && isInlineNode(nodeList[0]) + && !isHtmlElement(newParent.lastChild, "BR")) { + newParent.appendChild(newParent.ownerDocument.createElement("br")); + } + + // "For each node in node list, append node as the last child of new + // parent, preserving ranges." + for (var i = 0; i < nodeList.length; i++) { + movePreservingRanges(nodeList[i], newParent, -1, range); + } + + // "Otherwise:" + } else { + // "If new parent is not an inline node, but the first child of new + // parent and the last member of node list are both inline nodes, and + // the last member of node list is not a br, call createElement("br") + // on the ownerDocument of new parent and insert the result as the + // first child of new parent." + if (!isInlineNode(newParent) + && isInlineNode(newParent.firstChild) + && isInlineNode(nodeList[nodeList.length - 1]) + && !isHtmlElement(nodeList[nodeList.length - 1], "BR")) { + newParent.insertBefore(newParent.ownerDocument.createElement("br"), newParent.firstChild); + } + + // "For each node in node list, in reverse order, insert node as the + // first child of new parent, preserving ranges." + for (var i = nodeList.length - 1; i >= 0; i--) { + movePreservingRanges(nodeList[i], newParent, 0, range); + } + } + + // "If original parent is editable and has no children, remove it from its + // parent." + if (isEditable(originalParent) && !originalParent.hasChildNodes()) { + originalParent.parentNode.removeChild(originalParent); + } + + // "If new parent's nextSibling is editable and running sibling criteria on + // it returns true:" + if (isEditable(newParent.nextSibling) + && siblingCriteria(newParent.nextSibling)) { + // "If new parent is not an inline node, but new parent's last child + // and new parent's nextSibling's first child are both inline nodes, + // and new parent's last child is not a br, call createElement("br") on + // the ownerDocument of new parent and append the result as the last + // child of new parent." + if (!isInlineNode(newParent) + && isInlineNode(newParent.lastChild) + && isInlineNode(newParent.nextSibling.firstChild) + && !isHtmlElement(newParent.lastChild, "BR")) { + newParent.appendChild(newParent.ownerDocument.createElement("br")); + } + + // "While new parent's nextSibling has children, append its first child + // as the last child of new parent, preserving ranges." + while (newParent.nextSibling.hasChildNodes()) { + movePreservingRanges(newParent.nextSibling.firstChild, newParent, -1, range); + } + + // "Remove new parent's nextSibling from its parent." + newParent.parentNode.removeChild(newParent.nextSibling); + } + + // "Remove extraneous line breaks from new parent." + removeExtraneousLineBreaksFrom(newParent); + + // "Return new parent." + return newParent; +} + + +//@} +///// Allowed children ///// +//@{ + +// "A name of an element with inline contents is "a", "abbr", "b", "bdi", +// "bdo", "cite", "code", "dfn", "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", +// "kbd", "mark", "p", "pre", "q", "rp", "rt", "ruby", "s", "samp", "small", +// "span", "strong", "sub", "sup", "u", "var", "acronym", "listing", "strike", +// "xmp", "big", "blink", "font", "marquee", "nobr", or "tt"." +var namesOfElementsWithInlineContents = ["a", "abbr", "b", "bdi", "bdo", + "cite", "code", "dfn", "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", + "kbd", "mark", "p", "pre", "q", "rp", "rt", "ruby", "s", "samp", "small", + "span", "strong", "sub", "sup", "u", "var", "acronym", "listing", "strike", + "xmp", "big", "blink", "font", "marquee", "nobr", "tt"]; + +// "An element with inline contents is an HTML element whose local name is a +// name of an element with inline contents." +function isElementWithInlineContents(node) { + return isHtmlElement(node, namesOfElementsWithInlineContents); +} + +function isAllowedChild(child, parent_) { + // "If parent is "colgroup", "table", "tbody", "tfoot", "thead", "tr", or + // an HTML element with local name equal to one of those, and child is a + // Text node whose data does not consist solely of space characters, return + // false." + if (($_( ["colgroup", "table", "tbody", "tfoot", "thead", "tr"] ).indexOf(parent_) != -1 + || isHtmlElement(parent_, ["colgroup", "table", "tbody", "tfoot", "thead", "tr"])) + && typeof child == "object" + && child.nodeType == $_.Node.TEXT_NODE + && !/^[ \t\n\f\r]*$/.test(child.data)) { + return false; + } + + // "If parent is "script", "style", "plaintext", or "xmp", or an HTML + // element with local name equal to one of those, and child is not a Text + // node, return false." + if (($_( ["script", "style", "plaintext", "xmp"] ).indexOf(parent_) != -1 + || isHtmlElement(parent_, ["script", "style", "plaintext", "xmp"])) + && (typeof child != "object" || child.nodeType != $_.Node.TEXT_NODE)) { + return false; + } + + // "If child is a Document, DocumentFragment, or DocumentType, return + // false." + if (typeof child == "object" + && (child.nodeType == $_.Node.DOCUMENT_NODE + || child.nodeType == $_.Node.DOCUMENT_FRAGMENT_NODE + || child.nodeType == $_.Node.DOCUMENT_TYPE_NODE)) { + return false; + } + + // "If child is an HTML element, set child to the local name of child." + if (isHtmlElement(child)) { + child = child.tagName.toLowerCase(); + } + + // "If child is not a string, return true." + if (typeof child != "string") { + return true; + } + + // "If parent is an HTML element:" + if (isHtmlElement(parent_)) { + // "If child is "a", and parent or some ancestor of parent is an a, + // return false." + // + // "If child is a prohibited paragraph child name and parent or some + // ancestor of parent is an element with inline contents, return + // false." + // + // "If child is "h1", "h2", "h3", "h4", "h5", or "h6", and parent or + // some ancestor of parent is an HTML element with local name "h1", + // "h2", "h3", "h4", "h5", or "h6", return false." + var ancestor = parent_; + while (ancestor) { + if (child == "a" && isHtmlElement(ancestor, "a")) { + return false; + } + if ($_( prohibitedParagraphChildNames ).indexOf(child) != -1 + && isElementWithInlineContents(ancestor)) { + return false; + } + if (/^h[1-6]$/.test(child) + && isHtmlElement(ancestor) + && /^H[1-6]$/.test(ancestor.tagName)) { + return false; + } + ancestor = ancestor.parentNode; + } + + // "Let parent be the local name of parent." + parent_ = parent_.tagName.toLowerCase(); + } + + // "If parent is an Element or DocumentFragment, return true." + if (typeof parent_ == "object" + && (parent_.nodeType == $_.Node.ELEMENT_NODE + || parent_.nodeType == $_.Node.DOCUMENT_FRAGMENT_NODE)) { + return true; + } + + // "If parent is not a string, return false." + if (typeof parent_ != "string") { + return false; + } + + // "If parent is on the left-hand side of an entry on the following list, + // then return true if child is listed on the right-hand side of that + // entry, and false otherwise." + switch (parent_) { + case "colgroup": + return child == "col"; + case "table": + return $_( ["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"] ).indexOf(child) != -1; + case "tbody": + case "thead": + case "tfoot": + return $_( ["td", "th", "tr"] ).indexOf(child) != -1; + case "tr": + return $_( ["td", "th"] ).indexOf(child) != -1; + case "dl": + return $_( ["dt", "dd"] ).indexOf(child) != -1; + case "dir": + case "ol": + case "ul": + return $_( ["dir", "li", "ol", "ul"] ).indexOf(child) != -1; + case "hgroup": + return /^h[1-6]$/.test(child); + } + + // "If child is "body", "caption", "col", "colgroup", "frame", "frameset", + // "head", "html", "tbody", "td", "tfoot", "th", "thead", or "tr", return + // false." + if ($_( ["body", "caption", "col", "colgroup", "frame", "frameset", "head", + "html", "tbody", "td", "tfoot", "th", "thead", "tr"] ).indexOf(child) != -1) { + return false; + } + + // "If child is "dd" or "dt" and parent is not "dl", return false." + if ($_( ["dd", "dt"] ).indexOf(child) != -1 + && parent_ != "dl") { + return false; + } + + // "If child is "li" and parent is not "ol" or "ul", return false." + if (child == "li" + && parent_ != "ol" + && parent_ != "ul") { + return false; + } + + // "If parent is on the left-hand side of an entry on the following list + // and child is listed on the right-hand side of that entry, return false." + var table = [ + [["a"], ["a"]], + [["dd", "dt"], ["dd", "dt"]], + [["h1", "h2", "h3", "h4", "h5", "h6"], ["h1", "h2", "h3", "h4", "h5", "h6"]], + [["li"], ["li"]], + [["nobr"], ["nobr"]], + [namesOfElementsWithInlineContents, prohibitedParagraphChildNames], + [["td", "th"], ["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"]] + ]; + for (var i = 0; i < table.length; i++) { + if ($_( table[i][0] ).indexOf(parent_) != -1 + && $_( table[i][1] ).indexOf(child) != -1) { + return false; + } + } + + // "Return true." + return true; +} + + +//@} + +////////////////////////////////////// +///// Inline formatting commands ///// +////////////////////////////////////// + +///// Inline formatting command definitions ///// +//@{ + +// "A node node is effectively contained in a range range if range is not +// collapsed, and at least one of the following holds:" +function isEffectivelyContained(node, range) { + if (range.collapsed) { + return false; + } + + // "node is contained in range." + if (isContained(node, range)) { + return true; + } + + // "node is range's start node, it is a Text node, and its length is + // different from range's start offset." + if (node == range.startContainer + && node.nodeType == $_.Node.TEXT_NODE + && getNodeLength(node) != range.startOffset) { + return true; + } + + // "node is range's end node, it is a Text node, and range's end offset is + // not 0." + if (node == range.endContainer + && node.nodeType == $_.Node.TEXT_NODE + && range.endOffset != 0) { + return true; + } + + // "node has at least one child; and all its children are effectively + // contained in range; and either range's start node is not a descendant of + // node or is not a Text node or range's start offset is zero; and either + // range's end node is not a descendant of node or is not a Text node or + // range's end offset is its end node's length." + if (node.hasChildNodes() + && $_(node.childNodes).every(function(child) { return isEffectivelyContained(child, range) }) + && (!isDescendant(range.startContainer, node) + || range.startContainer.nodeType != $_.Node.TEXT_NODE + || range.startOffset == 0) + && (!isDescendant(range.endContainer, node) + || range.endContainer.nodeType != $_.Node.TEXT_NODE + || range.endOffset == getNodeLength(range.endContainer))) { + return true; + } + + return false; +} + +// Like get(All)ContainedNodes(), but for effectively contained nodes. +function getEffectivelyContainedNodes(range, condition) { + if (typeof condition == "undefined") { + condition = function() { return true }; + } + var node = range.startContainer; + while (isEffectivelyContained(node.parentNode, range)) { + node = node.parentNode; + } + + var stop = nextNodeDescendants(range.endContainer); + + var nodeList = []; + while (isBefore(node, stop)) { + if (isEffectivelyContained(node, range) + && condition(node)) { + nodeList.push(node); + node = nextNodeDescendants(node); + continue; + } + node = nextNode(node); + } + return nodeList; +} + +function getAllEffectivelyContainedNodes(range, condition) { + if (typeof condition == "undefined") { + condition = function() { return true }; + } + var node = range.startContainer; + while (isEffectivelyContained(node.parentNode, range)) { + node = node.parentNode; + } + + var stop = nextNodeDescendants(range.endContainer); + + var nodeList = []; + while (isBefore(node, stop)) { + if (isEffectivelyContained(node, range) + && condition(node)) { + nodeList.push(node); + } + node = nextNode(node); + } + return nodeList; +} + +// "A modifiable element is a b, em, i, s, span, strong, sub, sup, or u element +// with no attributes except possibly style; or a font element with no +// attributes except possibly style, color, face, and/or size; or an a element +// with no attributes except possibly style and/or href." +function isModifiableElement(node) { + if (!isHtmlElement(node)) { + return false; + } + + if ($_( ["B", "EM", "I", "S", "SPAN", "STRIKE", "STRONG", "SUB", "SUP", "U"] ).indexOf(node.tagName) != -1) { + if (node.attributes.length == 0) { + return true; + } + + if (node.attributes.length == 1 + && $_( node ).hasAttribute("style")) { + return true; + } + } + + if (node.tagName == "FONT" || node.tagName == "A") { + var numAttrs = node.attributes.length; + + if ($_( node ).hasAttribute("style")) { + numAttrs--; + } + + if (node.tagName == "FONT") { + if ($_( node ).hasAttribute("color")) { + numAttrs--; + } + + if ($_( node ).hasAttribute("face")) { + numAttrs--; + } + + if ($_( node ).hasAttribute("size")) { + numAttrs--; + } + } + + if (node.tagName == "A" + && $_( node ).hasAttribute("href")) { + numAttrs--; + } + + if (numAttrs == 0) { + return true; + } + } + + return false; +} + +function isSimpleModifiableElement(node) { + // "A simple modifiable element is an HTML element for which at least one + // of the following holds:" + if (!isHtmlElement(node)) { + return false; + } + + // Only these elements can possibly be a simple modifiable element. + if ($_( ["A", "B", "EM", "FONT", "I", "S", "SPAN", "STRIKE", "STRONG", "SUB", "SUP", "U"] ).indexOf(node.tagName) == -1) { + return false; + } + + // "It is an a, b, em, font, i, s, span, strike, strong, sub, sup, or u + // element with no attributes." + if (node.attributes.length == 0) { + return true; + } + + // If it's got more than one attribute, everything after this fails. + if (node.attributes.length > 1) { + return false; + } + + // "It is an a, b, em, font, i, s, span, strike, strong, sub, sup, or u + // element with exactly one attribute, which is style, which sets no CSS + // properties (including invalid or unrecognized properties)." + // + // Not gonna try for invalid or unrecognized. + if ($_( node ).hasAttribute("style") + && getStyleLength(node) == 0) { + return true; + } + + // "It is an a element with exactly one attribute, which is href." + if (node.tagName == "A" + && $_( node ).hasAttribute("href")) { + return true; + } + + // "It is a font element with exactly one attribute, which is either color, + // face, or size." + if (node.tagName == "FONT" + && ($_( node ).hasAttribute("color") + || $_( node ).hasAttribute("face") + || $_( node ).hasAttribute("size") + )) { + return true; + } + + // "It is a b or strong element with exactly one attribute, which is style, + // and the style attribute sets exactly one CSS property (including invalid + // or unrecognized properties), which is "font-weight"." + if ((node.tagName == "B" || node.tagName == "STRONG") + && $_( node ).hasAttribute("style") + && getStyleLength(node) == 1 + && node.style.fontWeight != "") { + return true; + } + + // "It is an i or em element with exactly one attribute, which is style, + // and the style attribute sets exactly one CSS property (including invalid + // or unrecognized properties), which is "font-style"." + if ((node.tagName == "I" || node.tagName == "EM") + && $_( node ).hasAttribute("style") + && getStyleLength(node) == 1 + && node.style.fontStyle != "") { + return true; + } + + // "It is an a, font, or span element with exactly one attribute, which is + // style, and the style attribute sets exactly one CSS property (including + // invalid or unrecognized properties), and that property is not + // "text-decoration"." + if ((node.tagName == "A" || node.tagName == "FONT" || node.tagName == "SPAN") + && $_( node ).hasAttribute("style") + && getStyleLength(node) == 1 + && node.style.textDecoration == "") { + return true; + } + + // "It is an a, font, s, span, strike, or u element with exactly one + // attribute, which is style, and the style attribute sets exactly one CSS + // property (including invalid or unrecognized properties), which is + // "text-decoration", which is set to "line-through" or "underline" or + // "overline" or "none"." + if ($_( ["A", "FONT", "S", "SPAN", "STRIKE", "U"] ).indexOf(node.tagName) != -1 + && $_( node ).hasAttribute("style") + && getStyleLength(node) == 1 + && (node.style.textDecoration == "line-through" + || node.style.textDecoration == "underline" + || node.style.textDecoration == "overline" + || node.style.textDecoration == "none")) { + return true; + } + + return false; +} + +// "Two quantities are equivalent values for a command if either both are null, +// or both are strings and they're equal and the command does not define any +// equivalent values, or both are strings and the command defines equivalent +// values and they match the definition." +function areEquivalentValues(command, val1, val2) { + if (val1 === null && val2 === null) { + return true; + } + + if (typeof val1 == "string" + && typeof val2 == "string" + && val1 == val2 + && !("equivalentValues" in commands[command])) { + return true; + } + + if (typeof val1 == "string" + && typeof val2 == "string" + && "equivalentValues" in commands[command] + && commands[command].equivalentValues(val1, val2)) { + return true; + } + + return false; +} + +// "Two quantities are loosely equivalent values for a command if either they +// are equivalent values for the command, or if the command is the fontSize +// command; one of the quantities is one of "xx-small", "small", "medium", +// "large", "x-large", "xx-large", or "xxx-large"; and the other quantity is +// the resolved value of "font-size" on a font element whose size attribute has +// the corresponding value set ("1" through "7" respectively)." +function areLooselyEquivalentValues(command, val1, val2) { + if (areEquivalentValues(command, val1, val2)) { + return true; + } + + if (command != "fontsize" + || typeof val1 != "string" + || typeof val2 != "string") { + return false; + } + + // Static variables in JavaScript? + var callee = areLooselyEquivalentValues; + if (callee.sizeMap === undefined) { + callee.sizeMap = {}; + var font = document.createElement("font"); + document.body.appendChild(font); + $_( ["xx-small", "small", "medium", "large", "x-large", "xx-large", + "xxx-large"] ).forEach(function(keyword) { + font.size = cssSizeToLegacy(keyword); + callee.sizeMap[keyword] = $_.getComputedStyle(font).fontSize; + }); + document.body.removeChild(font); + } + + return val1 === callee.sizeMap[val2] + || val2 === callee.sizeMap[val1]; +} + +//@} +///// Assorted inline formatting command algorithms ///// +//@{ + +function getEffectiveCommandValue(node, command) { + // "If neither node nor its parent is an Element, return null." + if (node.nodeType != $_.Node.ELEMENT_NODE + && (!node.parentNode || node.parentNode.nodeType != $_.Node.ELEMENT_NODE)) { + return null; + } + + // "If node is not an Element, return the effective command value of its + // parent for command." + if (node.nodeType != $_.Node.ELEMENT_NODE) { + return getEffectiveCommandValue(node.parentNode, command); + } + + // "If command is "createLink" or "unlink":" + if (command == "createlink" || command == "unlink") { + // "While node is not null, and is not an a element that has an href + // attribute, set node to its parent." + while (node + && (!isHtmlElement(node) + || node.tagName != "A" + || !$_( node ).hasAttribute("href"))) { + node = node.parentNode; + } + + // "If node is null, return null." + if (!node) { + return null; + } + + // "Return the value of node's href attribute." + return node.getAttribute("href"); + } + + // "If command is "backColor" or "hiliteColor":" + if (command == "backcolor" + || command == "hilitecolor") { + // "While the resolved value of "background-color" on node is any + // fully transparent value, and node's parent is an Element, set + // node to its parent." + // + // Another lame hack to avoid flawed APIs. + while (($_.getComputedStyle(node).backgroundColor == "rgba(0, 0, 0, 0)" + || $_.getComputedStyle(node).backgroundColor === "" + || $_.getComputedStyle(node).backgroundColor == "transparent") + && node.parentNode + && node.parentNode.nodeType == $_.Node.ELEMENT_NODE) { + node = node.parentNode; + } + + // "If the resolved value of "background-color" on node is a fully + // transparent value, return "rgb(255, 255, 255)"." + if ($_.getComputedStyle(node).backgroundColor == "rgba(0, 0, 0, 0)" + || $_.getComputedStyle(node).backgroundColor === "" + || $_.getComputedStyle(node).backgroundColor == "transparent") { + return "rgb(255, 255, 255)"; + } + + // "Otherwise, return the resolved value of "background-color" for + // node." + return $_.getComputedStyle(node).backgroundColor; + } + + // "If command is "subscript" or "superscript":" + if (command == "subscript" || command == "superscript") { + // "Let affected by subscript and affected by superscript be two + // boolean variables, both initially false." + var affectedBySubscript = false; + var affectedBySuperscript = false; + + // "While node is an inline node:" + while (isInlineNode(node)) { + var verticalAlign = $_.getComputedStyle(node).verticalAlign; + + // "If node is a sub, set affected by subscript to true." + if (isHtmlElement(node, "sub")) { + affectedBySubscript = true; + // "Otherwise, if node is a sup, set affected by superscript to + // true." + } else if (isHtmlElement(node, "sup")) { + affectedBySuperscript = true; + } + + // "Set node to its parent." + node = node.parentNode; + } + + // "If affected by subscript and affected by superscript are both true, + // return the string "mixed"." + if (affectedBySubscript && affectedBySuperscript) { + return "mixed"; + } + + // "If affected by subscript is true, return "subscript"." + if (affectedBySubscript) { + return "subscript"; + } + + // "If affected by superscript is true, return "superscript"." + if (affectedBySuperscript) { + return "superscript"; + } + + // "Return null." + return null; + } + + // "If command is "strikethrough", and the "text-decoration" property of + // node or any of its ancestors has resolved value containing + // "line-through", return "line-through". Otherwise, return null." + if (command == "strikethrough") { + do { + if ($_.getComputedStyle(node).textDecoration.indexOf("line-through") != -1) { + return "line-through"; + } + node = node.parentNode; + } while (node && node.nodeType == $_.Node.ELEMENT_NODE); + return null; + } + + // "If command is "underline", and the "text-decoration" property of node + // or any of its ancestors has resolved value containing "underline", + // return "underline". Otherwise, return null." + if (command == "underline") { + do { + if ($_.getComputedStyle(node).textDecoration.indexOf("underline") != -1) { + return "underline"; + } + node = node.parentNode; + } while (node && node.nodeType == $_.Node.ELEMENT_NODE); + return null; + } + + if (!("relevantCssProperty" in commands[command])) { + throw "Bug: no relevantCssProperty for " + command + " in getEffectiveCommandValue"; + } + + // "Return the resolved value for node of the relevant CSS property for + // command." + return $_.getComputedStyle(node)[commands[command].relevantCssProperty].toString(); +} + +function getSpecifiedCommandValue(element, command) { + // "If command is "backColor" or "hiliteColor" and element's display + // property does not have resolved value "inline", return null." + if ((command == "backcolor" || command == "hilitecolor") + && $_.getComputedStyle(element).display != "inline") { + return null; + } + + // "If command is "createLink" or "unlink":" + if (command == "createlink" || command == "unlink") { + // "If element is an a element and has an href attribute, return the + // value of that attribute." + if (isHtmlElement(element) + && element.tagName == "A" + && $_( element ).hasAttribute("href")) { + return element.getAttribute("href"); + } + + // "Return null." + return null; + } + + // "If command is "subscript" or "superscript":" + if (command == "subscript" || command == "superscript") { + // "If element is a sup, return "superscript"." + if (isHtmlElement(element, "sup")) { + return "superscript"; + } + + // "If element is a sub, return "subscript"." + if (isHtmlElement(element, "sub")) { + return "subscript"; + } + + // "Return null." + return null; + } + + // "If command is "strikethrough", and element has a style attribute set, + // and that attribute sets "text-decoration":" + if (command == "strikethrough" + && element.style.textDecoration != "") { + // "If element's style attribute sets "text-decoration" to a value + // containing "line-through", return "line-through"." + if (element.style.textDecoration.indexOf("line-through") != -1) { + return "line-through"; + } + + // "Return null." + return null; + } + + // "If command is "strikethrough" and element is a s or strike element, + // return "line-through"." + if (command == "strikethrough" + && isHtmlElement(element, ["S", "STRIKE"])) { + return "line-through"; + } + + // "If command is "underline", and element has a style attribute set, and + // that attribute sets "text-decoration":" + if (command == "underline" + && element.style.textDecoration != "") { + // "If element's style attribute sets "text-decoration" to a value + // containing "underline", return "underline"." + if (element.style.textDecoration.indexOf("underline") != -1) { + return "underline"; + } + + // "Return null." + return null; + } + + // "If command is "underline" and element is a u element, return + // "underline"." + if (command == "underline" + && isHtmlElement(element, "U")) { + return "underline"; + } + + // "Let property be the relevant CSS property for command." + var property = commands[command].relevantCssProperty; + + // "If property is null, return null." + if (property === null) { + return null; + } + + // "If element has a style attribute set, and that attribute has the + // effect of setting property, return the value that it sets property to." + if (element.style[property] != "") { + return element.style[property]; + } + + // "If element is a font element that has an attribute whose effect is + // to create a presentational hint for property, return the value that the + // hint sets property to. (For a size of 7, this will be the non-CSS value + // "xxx-large".)" + if (isHtmlNamespace(element.namespaceURI) + && element.tagName == "FONT") { + if (property == "color" && $_( element ).hasAttribute("color")) { + return element.color; + } + if (property == "fontFamily" && $_( element ).hasAttribute("face")) { + return element.face; + } + if (property == "fontSize" && $_( element ).hasAttribute("size")) { + // This is not even close to correct in general. + var size = parseInt(element.size); + if (size < 1) { + size = 1; + } + if (size > 7) { + size = 7; + } + return { + 1: "xx-small", + 2: "small", + 3: "medium", + 4: "large", + 5: "x-large", + 6: "xx-large", + 7: "xxx-large" + }[size]; + } + } + + // "If element is in the following list, and property is equal to the + // CSS property name listed for it, return the string listed for it." + // + // A list follows, whose meaning is copied here. + if (property == "fontWeight" + && (element.tagName == "B" || element.tagName == "STRONG")) { + return "bold"; + } + if (property == "fontStyle" + && (element.tagName == "I" || element.tagName == "EM")) { + return "italic"; + } + + // "Return null." + return null; +} + +function reorderModifiableDescendants(node, command, newValue, range) { + // "Let candidate equal node." + var candidate = node; + + // "While candidate is a modifiable element, and candidate has exactly one + // child, and that child is also a modifiable element, and candidate is not + // a simple modifiable element or candidate's specified command value for + // command is not equivalent to new value, set candidate to its child." + while (isModifiableElement(candidate) + && candidate.childNodes.length == 1 + && isModifiableElement(candidate.firstChild) + && (!isSimpleModifiableElement(candidate) + || !areEquivalentValues(command, getSpecifiedCommandValue(candidate, command), newValue))) { + candidate = candidate.firstChild; + } + + // "If candidate is node, or is not a simple modifiable element, or its + // specified command value is not equivalent to new value, or its effective + // command value is not loosely equivalent to new value, abort these + // steps." + if (candidate == node + || !isSimpleModifiableElement(candidate) + || !areEquivalentValues(command, getSpecifiedCommandValue(candidate, command), newValue) + || !areLooselyEquivalentValues(command, getEffectiveCommandValue(candidate, command), newValue)) { + return; + } + + // "While candidate has children, insert the first child of candidate into + // candidate's parent immediately before candidate, preserving ranges." + while (candidate.hasChildNodes()) { + movePreservingRanges(candidate.firstChild, candidate.parentNode, getNodeIndex(candidate), range); + } + + // "Insert candidate into node's parent immediately after node." + node.parentNode.insertBefore(candidate, node.nextSibling); + + // "Append the node as the last child of candidate, preserving ranges." + movePreservingRanges(node, candidate, -1, range); +} + +function recordValues(nodeList) { + // "Let values be a list of (node, command, specified command value) + // triples, initially empty." + var values = []; + + // "For each node in node list, for each command in the list "subscript", + // "bold", "fontName", "fontSize", "foreColor", "hiliteColor", "italic", + // "strikethrough", and "underline" in that order:" + $_( nodeList ).forEach(function(node) { + $_( ["subscript", "bold", "fontname", "fontsize", "forecolor", + "hilitecolor", "italic", "strikethrough", "underline"] ).forEach(function(command) { + // "Let ancestor equal node." + var ancestor = node; + + // "If ancestor is not an Element, set it to its parent." + if (ancestor.nodeType != $_.Node.ELEMENT_NODE) { + ancestor = ancestor.parentNode; + } + + // "While ancestor is an Element and its specified command value + // for command is null, set it to its parent." + while (ancestor + && ancestor.nodeType == $_.Node.ELEMENT_NODE + && getSpecifiedCommandValue(ancestor, command) === null) { + ancestor = ancestor.parentNode; + } + + // "If ancestor is an Element, add (node, command, ancestor's + // specified command value for command) to values. Otherwise add + // (node, command, null) to values." + if (ancestor && ancestor.nodeType == $_.Node.ELEMENT_NODE) { + values.push([node, command, getSpecifiedCommandValue(ancestor, command)]); + } else { + values.push([node, command, null]); + } + }); + }); + + // "Return values." + return values; +} + +function restoreValues(values, range) { + // "For each (node, command, value) triple in values:" + $_( values ).forEach(function(triple) { + var node = triple[0]; + var command = triple[1]; + var value = triple[2]; + + // "Let ancestor equal node." + var ancestor = node; + + // "If ancestor is not an Element, set it to its parent." + if (!ancestor || ancestor.nodeType != $_.Node.ELEMENT_NODE) { + ancestor = ancestor.parentNode; + } + + // "While ancestor is an Element and its specified command value for + // command is null, set it to its parent." + while (ancestor + && ancestor.nodeType == $_.Node.ELEMENT_NODE + && getSpecifiedCommandValue(ancestor, command) === null) { + ancestor = ancestor.parentNode; + } + + // "If value is null and ancestor is an Element, push down values on + // node for command, with new value null." + if (value === null + && ancestor + && ancestor.nodeType == $_.Node.ELEMENT_NODE) { + pushDownValues(node, command, null, range); + + // "Otherwise, if ancestor is an Element and its specified command + // value for command is not equivalent to value, or if ancestor is not + // an Element and value is not null, force the value of command to + // value on node." + } else if ((ancestor + && ancestor.nodeType == $_.Node.ELEMENT_NODE + && !areEquivalentValues(command, getSpecifiedCommandValue(ancestor, command), value)) + || ((!ancestor || ancestor.nodeType != $_.Node.ELEMENT_NODE) + && value !== null)) { + forceValue(node, command, value, range); + } + }); +} + + +//@} +///// Clearing an element's value ///// +//@{ + +function clearValue(element, command, range) { + // "If element is not editable, return the empty list." + if (!isEditable(element)) { + return []; + } + + // "If element's specified command value for command is null, return the + // empty list." + if (getSpecifiedCommandValue(element, command) === null) { + return []; + } + + // "If element is a simple modifiable element:" + if (isSimpleModifiableElement(element)) { + // "Let children be the children of element." + var children = Array.prototype.slice.call(toArray(element.childNodes)); + + // "For each child in children, insert child into element's parent + // immediately before element, preserving ranges." + for (var i = 0; i < children.length; i++) { + movePreservingRanges(children[i], element.parentNode, getNodeIndex(element), range); + } + + // "Remove element from its parent." + element.parentNode.removeChild(element); + + // "Return children." + return children; + } + + // "If command is "strikethrough", and element has a style attribute that + // sets "text-decoration" to some value containing "line-through", delete + // "line-through" from the value." + if (command == "strikethrough" + && element.style.textDecoration.indexOf("line-through") != -1) { + if (element.style.textDecoration == "line-through") { + element.style.textDecoration = ""; + } else { + element.style.textDecoration = element.style.textDecoration.replace("line-through", ""); + } + if (element.getAttribute("style") == "") { + element.removeAttribute("style"); + } + } + + // "If command is "underline", and element has a style attribute that sets + // "text-decoration" to some value containing "underline", delete + // "underline" from the value." + if (command == "underline" + && element.style.textDecoration.indexOf("underline") != -1) { + if (element.style.textDecoration == "underline") { + element.style.textDecoration = ""; + } else { + element.style.textDecoration = element.style.textDecoration.replace("underline", ""); + } + if (element.getAttribute("style") == "") { + element.removeAttribute("style"); + } + } + + // "If the relevant CSS property for command is not null, unset the CSS + // property property of element." + if (commands[command].relevantCssProperty !== null) { + element.style[commands[command].relevantCssProperty] = ''; + if (element.getAttribute("style") == "") { + element.removeAttribute("style"); + } + } + + // "If element is a font element:" + if (isHtmlNamespace(element.namespaceURI) && element.tagName == "FONT") { + // "If command is "foreColor", unset element's color attribute, if set." + if (command == "forecolor") { + element.removeAttribute("color"); + } + + // "If command is "fontName", unset element's face attribute, if set." + if (command == "fontname") { + element.removeAttribute("face"); + } + + // "If command is "fontSize", unset element's size attribute, if set." + if (command == "fontsize") { + element.removeAttribute("size"); + } + } + + // "If element is an a element and command is "createLink" or "unlink", + // unset the href property of element." + if (isHtmlElement(element, "A") + && (command == "createlink" || command == "unlink")) { + element.removeAttribute("href"); + } + + // "If element's specified command value for command is null, return the + // empty list." + if (getSpecifiedCommandValue(element, command) === null) { + return []; + } + + // "Set the tag name of element to "span", and return the one-node list + // consisting of the result." + return [setTagName(element, "span", range)]; +} + + +//@} +///// Pushing down values ///// +//@{ + +function pushDownValues(node, command, newValue, range) { + // "If node's parent is not an Element, abort this algorithm." + if (!node.parentNode + || node.parentNode.nodeType != $_.Node.ELEMENT_NODE) { + return; + } + + // "If the effective command value of command is loosely equivalent to new + // value on node, abort this algorithm." + if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) { + return; + } + + // "Let current ancestor be node's parent." + var currentAncestor = node.parentNode; + + // "Let ancestor list be a list of Nodes, initially empty." + var ancestorList = []; + + // "While current ancestor is an editable Element and the effective command + // value of command is not loosely equivalent to new value on it, append + // current ancestor to ancestor list, then set current ancestor to its + // parent." + while (isEditable(currentAncestor) + && currentAncestor.nodeType == $_.Node.ELEMENT_NODE + && !areLooselyEquivalentValues(command, getEffectiveCommandValue(currentAncestor, command), newValue)) { + ancestorList.push(currentAncestor); + currentAncestor = currentAncestor.parentNode; + } + + // "If ancestor list is empty, abort this algorithm." + if (!ancestorList.length) { + return; + } + + // "Let propagated value be the specified command value of command on the + // last member of ancestor list." + var propagatedValue = getSpecifiedCommandValue(ancestorList[ancestorList.length - 1], command); + + // "If propagated value is null and is not equal to new value, abort this + // algorithm." + if (propagatedValue === null && propagatedValue != newValue) { + return; + } + + // "If the effective command value for the parent of the last member of + // ancestor list is not loosely equivalent to new value, and new value is + // not null, abort this algorithm." + if (newValue !== null + && !areLooselyEquivalentValues(command, getEffectiveCommandValue(ancestorList[ancestorList.length - 1].parentNode, command), newValue)) { + return; + } + + // "While ancestor list is not empty:" + while (ancestorList.length) { + // "Let current ancestor be the last member of ancestor list." + // "Remove the last member from ancestor list." + var currentAncestor = ancestorList.pop(); + + // "If the specified command value of current ancestor for command is + // not null, set propagated value to that value." + if (getSpecifiedCommandValue(currentAncestor, command) !== null) { + propagatedValue = getSpecifiedCommandValue(currentAncestor, command); + } + + // "Let children be the children of current ancestor." + var children = Array.prototype.slice.call(toArray(currentAncestor.childNodes)); + + // "If the specified command value of current ancestor for command is + // not null, clear the value of current ancestor." + if (getSpecifiedCommandValue(currentAncestor, command) !== null) { + clearValue(currentAncestor, command, range); + } + + // "For every child in children:" + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + // "If child is node, continue with the next child." + if (child == node) { + continue; + } + + // "If child is an Element whose specified command value for + // command is neither null nor equivalent to propagated value, + // continue with the next child." + if (child.nodeType == $_.Node.ELEMENT_NODE + && getSpecifiedCommandValue(child, command) !== null + && !areEquivalentValues(command, propagatedValue, getSpecifiedCommandValue(child, command))) { + continue; + } + + // "If child is the last member of ancestor list, continue with the + // next child." + if (child == ancestorList[ancestorList.length - 1]) { + continue; + } + + // "Force the value of child, with command as in this algorithm + // and new value equal to propagated value." + forceValue(child, command, propagatedValue, range); + } + } +} + + +//@} +///// Forcing the value of a node ///// +//@{ + +function forceValue(node, command, newValue, range) { + // "If node's parent is null, abort this algorithm." + if (!node.parentNode) { + return; + } + + // "If new value is null, abort this algorithm." + if (newValue === null) { + return; + } + + // "If node is an allowed child of "span":" + if (isAllowedChild(node, "span")) { + // "Reorder modifiable descendants of node's previousSibling." + reorderModifiableDescendants(node.previousSibling, command, newValue, range); + + // "Reorder modifiable descendants of node's nextSibling." + reorderModifiableDescendants(node.nextSibling, command, newValue, range); + + // "Wrap the one-node list consisting of node, with sibling criteria + // returning true for a simple modifiable element whose specified + // command value is equivalent to new value and whose effective command + // value is loosely equivalent to new value and false otherwise, and + // with new parent instructions returning null." + wrap([node], + function(node) { + return isSimpleModifiableElement(node) + && areEquivalentValues(command, getSpecifiedCommandValue(node, command), newValue) + && areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue); + }, + function() { return null }, + range + ); + } + + // "If the effective command value of command is loosely equivalent to new + // value on node, abort this algorithm." + if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) { + return; + } + + // "If node is not an allowed child of "span":" + if (!isAllowedChild(node, "span")) { + // "Let children be all children of node, omitting any that are + // Elements whose specified command value for command is neither null + // nor equivalent to new value." + var children = []; + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].nodeType == $_.Node.ELEMENT_NODE) { + var specifiedValue = getSpecifiedCommandValue(node.childNodes[i], command); + + if (specifiedValue !== null + && !areEquivalentValues(command, newValue, specifiedValue)) { + continue; + } + } + children.push(node.childNodes[i]); + } + + // "Force the value of each Node in children, with command and new + // value as in this invocation of the algorithm." + for (var i = 0; i < children.length; i++) { + forceValue(children[i], command, newValue, range); + } + + // "Abort this algorithm." + return; + } + + // "If the effective command value of command is loosely equivalent to new + // value on node, abort this algorithm." + if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) { + return; + } + + // "Let new parent be null." + var newParent = null; + + // "If the CSS styling flag is false:" + if (!cssStylingFlag) { + // "If command is "bold" and new value is "bold", let new parent be the + // result of calling createElement("b") on the ownerDocument of node." + if (command == "bold" && (newValue == "bold" || newValue == "700")) { + newParent = node.ownerDocument.createElement("b"); + } + + // "If command is "italic" and new value is "italic", let new parent be + // the result of calling createElement("i") on the ownerDocument of + // node." + if (command == "italic" && newValue == "italic") { + newParent = node.ownerDocument.createElement("i"); + } + + // "If command is "strikethrough" and new value is "line-through", let + // new parent be the result of calling createElement("s") on the + // ownerDocument of node." + if (command == "strikethrough" && newValue == "line-through") { + newParent = node.ownerDocument.createElement("s"); + } + + // "If command is "underline" and new value is "underline", let new + // parent be the result of calling createElement("u") on the + // ownerDocument of node." + if (command == "underline" && newValue == "underline") { + newParent = node.ownerDocument.createElement("u"); + } + + // "If command is "foreColor", and new value is fully opaque with red, + // green, and blue components in the range 0 to 255:" + if (command == "forecolor" && parseSimpleColor(newValue)) { + // "Let new parent be the result of calling createElement("span") + // on the ownerDocument of node." + // NOTE: modified this process to create span elements with style attributes + // instead of oldschool font tags with color attributes + newParent = node.ownerDocument.createElement("span"); + + // "If new value is an extended color keyword, set the color + // attribute of new parent to new value." + // + // "Otherwise, set the color attribute of new parent to the result + // of applying the rules for serializing simple color values to new + // value (interpreted as a simple color)." + jQuery(newParent).css('color', parseSimpleColor(newValue)); + } + + // "If command is "fontName", let new parent be the result of calling + // createElement("font") on the ownerDocument of node, then set the + // face attribute of new parent to new value." + if (command == "fontname") { + newParent = node.ownerDocument.createElement("font"); + newParent.face = newValue; + } + } + + // "If command is "createLink" or "unlink":" + if (command == "createlink" || command == "unlink") { + // "Let new parent be the result of calling createElement("a") on the + // ownerDocument of node." + newParent = node.ownerDocument.createElement("a"); + + // "Set the href attribute of new parent to new value." + newParent.setAttribute("href", newValue); + + // "Let ancestor be node's parent." + var ancestor = node.parentNode; + + // "While ancestor is not null:" + while (ancestor) { + // "If ancestor is an a, set the tag name of ancestor to "span", + // and let ancestor be the result." + if (isHtmlElement(ancestor, "A")) { + ancestor = setTagName(ancestor, "span", range); + } + + // "Set ancestor to its parent." + ancestor = ancestor.parentNode; + } + } + + // "If command is "fontSize"; and new value is one of "xx-small", "small", + // "medium", "large", "x-large", "xx-large", or "xxx-large"; and either the + // CSS styling flag is false, or new value is "xxx-large": let new parent + // be the result of calling createElement("font") on the ownerDocument of + // node, then set the size attribute of new parent to the number from the + // following table based on new value: [table omitted]" + if (command == "fontsize" + && $_( ["xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"] ).indexOf(newValue) != -1 + && (!cssStylingFlag || newValue == "xxx-large")) { + newParent = node.ownerDocument.createElement("font"); + newParent.size = cssSizeToLegacy(newValue); + } + + // "If command is "subscript" or "superscript" and new value is + // "subscript", let new parent be the result of calling + // createElement("sub") on the ownerDocument of node." + if ((command == "subscript" || command == "superscript") + && newValue == "subscript") { + newParent = node.ownerDocument.createElement("sub"); + } + + // "If command is "subscript" or "superscript" and new value is + // "superscript", let new parent be the result of calling + // createElement("sup") on the ownerDocument of node." + if ((command == "subscript" || command == "superscript") + && newValue == "superscript") { + newParent = node.ownerDocument.createElement("sup"); + } + + // "If new parent is null, let new parent be the result of calling + // createElement("span") on the ownerDocument of node." + if (!newParent) { + newParent = node.ownerDocument.createElement("span"); + } + + // "Insert new parent in node's parent before node." + node.parentNode.insertBefore(newParent, node); + + // "If the effective command value of command for new parent is not loosely + // equivalent to new value, and the relevant CSS property for command is + // not null, set that CSS property of new parent to new value (if the new + // value would be valid)." + var property = commands[command].relevantCssProperty; + if (property !== null + && !areLooselyEquivalentValues(command, getEffectiveCommandValue(newParent, command), newValue)) { + newParent.style[property] = newValue; + } + + // "If command is "strikethrough", and new value is "line-through", and the + // effective command value of "strikethrough" for new parent is not + // "line-through", set the "text-decoration" property of new parent to + // "line-through"." + if (command == "strikethrough" + && newValue == "line-through" + && getEffectiveCommandValue(newParent, "strikethrough") != "line-through") { + newParent.style.textDecoration = "line-through"; + } + + // "If command is "underline", and new value is "underline", and the + // effective command value of "underline" for new parent is not + // "underline", set the "text-decoration" property of new parent to + // "underline"." + if (command == "underline" + && newValue == "underline" + && getEffectiveCommandValue(newParent, "underline") != "underline") { + newParent.style.textDecoration = "underline"; + } + + // "Append node to new parent as its last child, preserving ranges." + movePreservingRanges(node, newParent, newParent.childNodes.length, range); + + // "If node is an Element and the effective command value of command for + // node is not loosely equivalent to new value:" + if (node.nodeType == $_.Node.ELEMENT_NODE + && !areEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) { + // "Insert node into the parent of new parent before new parent, + // preserving ranges." + movePreservingRanges(node, newParent.parentNode, getNodeIndex(newParent), range); + + // "Remove new parent from its parent." + newParent.parentNode.removeChild(newParent); + + // "Let children be all children of node, omitting any that are + // Elements whose specified command value for command is neither null + // nor equivalent to new value." + var children = []; + for (var i = 0; i < node.childNodes.length; i++) { + if (node.childNodes[i].nodeType == $_.Node.ELEMENT_NODE) { + var specifiedValue = getSpecifiedCommandValue(node.childNodes[i], command); + + if (specifiedValue !== null + && !areEquivalentValues(command, newValue, specifiedValue)) { + continue; + } + } + children.push(node.childNodes[i]); + } + + // "Force the value of each Node in children, with command and new + // value as in this invocation of the algorithm." + for (var i = 0; i < children.length; i++) { + forceValue(children[i], command, newValue, range); + } + } +} + + +//@} +///// Setting the selection's value ///// +//@{ + +function setSelectionValue(command, newValue, range) { + + // Use current selected range if no range passed + range = range || getActiveRange(); + + // "If there is no editable text node effectively contained in the active + // range:" + if (!$_( getAllEffectivelyContainedNodes(range) ) + .filter(function(node) { return node.nodeType == $_.Node.TEXT_NODE}, true) + .some(isEditable)) { + // "If command has inline command activated values, set the state + // override to true if new value is among them and false if it's not." + if ("inlineCommandActivatedValues" in commands[command]) { + setStateOverride(command, + $_(commands[command].inlineCommandActivatedValues).indexOf(newValue) != -1, + range); + } + + // "If command is "subscript", unset the state override for + // "superscript"." + if (command == "subscript") { + unsetStateOverride("superscript", range); + } + + // "If command is "superscript", unset the state override for + // "subscript"." + if (command == "superscript") { + unsetStateOverride("subscript", range); + } + + // "If new value is null, unset the value override (if any)." + if (newValue === null) { + unsetValueOverride(command, range); + + // "Otherwise, if command has a value specified, set the value override + // to new value." + } else if ("value" in commands[command]) { + setValueOverride(command, newValue, range); + } + + // "Abort these steps." + return; + } + + // "If the active range's start node is an editable Text node, and its + // start offset is neither zero nor its start node's length, call + // splitText() on the active range's start node, with argument equal to the + // active range's start offset. Then set the active range's start node to + // the result, and its start offset to zero." + if (isEditable(range.startContainer) + && range.startContainer.nodeType == $_.Node.TEXT_NODE + && range.startOffset != 0 + && range.startOffset != getNodeLength(range.startContainer)) { + // Account for browsers not following range mutation rules + var newNode = range.startContainer.splitText(range.startOffset); + var newActiveRange = Aloha.createRange(); + if (range.startContainer == range.endContainer) { + var newEndOffset = range.endOffset - range.startOffset; + newActiveRange.setEnd(newNode, newEndOffset); + range.setEnd(newNode, newEndOffset); + } + newActiveRange.setStart(newNode, 0); + Aloha.getSelection().removeAllRanges(); + Aloha.getSelection().addRange(newActiveRange); + + range.setStart(newNode, 0); + } + + // "If the active range's end node is an editable Text node, and its end + // offset is neither zero nor its end node's length, call splitText() on + // the active range's end node, with argument equal to the active range's + // end offset." + if (isEditable(range.endContainer) + && range.endContainer.nodeType == $_.Node.TEXT_NODE + && range.endOffset != 0 + && range.endOffset != getNodeLength(range.endContainer)) { + // IE seems to mutate the range incorrectly here, so we need correction + // here as well. The active range will be temporarily in orphaned + // nodes, so calling getActiveRange() after splitText() but before + // fixing the range will throw an exception. + // TODO: check if this is still neccessary + var activeRange = range; + var newStart = [activeRange.startContainer, activeRange.startOffset]; + var newEnd = [activeRange.endContainer, activeRange.endOffset]; + activeRange.endContainer.splitText(activeRange.endOffset); + activeRange.setStart(newStart[0], newStart[1]); + activeRange.setEnd(newEnd[0], newEnd[1]); + + Aloha.getSelection().removeAllRanges(); + Aloha.getSelection().addRange(activeRange); + } + + // "Let element list be all editable Elements effectively contained in the + // active range. + // + // "For each element in element list, clear the value of element." + $_( getAllEffectivelyContainedNodes(getActiveRange(), function(node) { + return isEditable(node) && node.nodeType == $_.Node.ELEMENT_NODE; + }) ).forEach(function(element) { + clearValue(element, command, range); + }); + + // "Let node list be all editable nodes effectively contained in the active + // range. + // + // "For each node in node list:" + $_( getAllEffectivelyContainedNodes(range, isEditable) ).forEach(function(node) { + // "Push down values on node." + pushDownValues(node, command, newValue, range); + + // "Force the value of node." + forceValue(node, command, newValue, range); + }); +} + + +//@} +///// The backColor command ///// +//@{ +commands.backcolor = { + // Copy-pasted, same as hiliteColor + action: function(value) { + // Action is further copy-pasted, same as foreColor + + // "If value is not a valid CSS color, prepend "#" to it." + // + // "If value is still not a valid CSS color, or if it is currentColor, + // abort these steps and do nothing." + // + // Cheap hack for testing, no attempt to be comprehensive. + if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) { + value = "#" + value; + } + if (!/^(rgba?|hsla?)\(.*\)$/.test(value) + && !parseSimpleColor(value) + && value.toLowerCase() != "transparent") { + return; + } + + // "Set the selection's value to value." + setSelectionValue("backcolor", value); + }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor", + equivalentValues: function(val1, val2) { + // "Either both strings are valid CSS colors and have the same red, + // green, blue, and alpha components, or neither string is a valid CSS + // color." + return normalizeColor(val1) === normalizeColor(val2); + } +}; + +//@} +///// The bold command ///// +//@{ +commands.bold = { + action: function(value, range) { + // "If queryCommandState("bold") returns true, set the selection's + // value to "normal". Otherwise set the selection's value to "bold"." + if (myQueryCommandState("bold", range)) { + setSelectionValue("bold", "normal", range); + } else { + setSelectionValue("bold", "bold", range); + } + }, + inlineCommandActivatedValues: ["bold", "600", "700", "800", "900"], + relevantCssProperty: "fontWeight", + equivalentValues: function(val1, val2) { + // "Either the two strings are equal, or one is "bold" and the other is + // "700", or one is "normal" and the other is "400"." + return val1 == val2 + || (val1 == "bold" && val2 == "700") + || (val1 == "700" && val2 == "bold") + || (val1 == "normal" && val2 == "400") + || (val1 == "400" && val2 == "normal"); + } +}; + +//@} +///// The createLink command ///// +//@{ +commands.createlink = { + action: function(value) { + // "If value is the empty string, abort these steps and do nothing." + if (value === "") { + return; + } + + // "For each editable a element that has an href attribute and is an + // ancestor of some node effectively contained in the active range, set + // that a element's href attribute to value." + // + // TODO: We don't actually do this in tree order, not that it matters + // unless you're spying with mutation events. + $_( getAllEffectivelyContainedNodes(getActiveRange()) ).forEach(function(node) { + $_( getAncestors(node) ).forEach(function(ancestor) { + if (isEditable(ancestor) + && isHtmlElement(ancestor, "a") + && $_( ancestor ).hasAttribute("href")) { + ancestor.setAttribute("href", value); + } + }); + }); + + // "Set the selection's value to value." + setSelectionValue("createlink", value); + }, standardInlineValueCommand: true +}; + +//@} +///// The fontName command ///// +//@{ +commands.fontname = { + action: function(value) { + // "Set the selection's value to value." + setSelectionValue("fontname", value); + }, standardInlineValueCommand: true, relevantCssProperty: "fontFamily" +}; + +//@} +///// The fontSize command ///// +//@{ + +// Helper function for fontSize's action plus queryOutputHelper. It's just the +// middle of fontSize's action, ripped out into its own function. +function normalizeFontSize(value) { + // "Strip leading and trailing whitespace from value." + // + // Cheap hack, not following the actual algorithm. + value = $_(value).trim(); + + // "If value is a valid floating point number, or would be a valid + // floating point number if a single leading "+" character were + // stripped:" + if (/^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/.test(value)) { + var mode; + + // "If the first character of value is "+", delete the character + // and let mode be "relative-plus"." + if (value[0] == "+") { + value = value.slice(1); + mode = "relative-plus"; + // "Otherwise, if the first character of value is "-", delete the + // character and let mode be "relative-minus"." + } else if (value[0] == "-") { + value = value.slice(1); + mode = "relative-minus"; + // "Otherwise, let mode be "absolute"." + } else { + mode = "absolute"; + } + + // "Apply the rules for parsing non-negative integers to value, and + // let number be the result." + // + // Another cheap hack. + var num = parseInt(value); + + // "If mode is "relative-plus", add three to number." + if (mode == "relative-plus") { + num += 3; + } + + // "If mode is "relative-minus", negate number, then add three to + // it." + if (mode == "relative-minus") { + num = 3 - num; + } + + // "If number is less than one, let number equal 1." + if (num < 1) { + num = 1; + } + + // "If number is greater than seven, let number equal 7." + if (num > 7) { + num = 7; + } + + // "Set value to the string here corresponding to number:" [table + // omitted] + value = { + 1: "xx-small", + 2: "small", + 3: "medium", + 4: "large", + 5: "x-large", + 6: "xx-large", + 7: "xxx-large" + }[num]; + } + + return value; +} + +commands.fontsize = { + action: function(value) { + // "If value is the empty string, abort these steps and do nothing." + if (value === "") { + return; + } + + value = normalizeFontSize(value); + + // "If value is not one of the strings "xx-small", "x-small", "small", + // "medium", "large", "x-large", "xx-large", "xxx-large", and is not a + // valid CSS absolute length, then abort these steps and do nothing." + // + // More cheap hacks to skip valid CSS absolute length checks. + if ($_(["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"]).indexOf(value) == -1 + && !/^[0-9]+(\.[0-9]+)?(cm|mm|in|pt|pc)$/.test(value)) { + return; + } + + // "Set the selection's value to value." + setSelectionValue("fontsize", value); + }, + indeterm: function() { + // "True if among editable Text nodes that are effectively contained in + // the active range, there are two that have distinct effective command + // values. Otherwise false." + return $_( getAllEffectivelyContainedNodes(getActiveRange(), function(node) { + return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE; + }) ).map(function(node) { + return getEffectiveCommandValue(node, "fontsize"); + }, true).filter(function(value, i, arr) { + return $_(arr.slice(0, i)).indexOf(value) == -1; + }).length >= 2; + }, + value: function(range) { + // "Let pixel size be the effective command value of the first editable + // Text node that is effectively contained in the active range, or if + // there is no such node, the effective command value of the active + // range's start node, in either case interpreted as a number of + // pixels." + var node = getAllEffectivelyContainedNodes(range, function(node) { + return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE; + })[0]; + if (node === undefined) { + node = range.startContainer; + } + var pixelSize = getEffectiveCommandValue(node, "fontsize"); + + // "Return the legacy font size for pixel size." + return getLegacyFontSize(pixelSize); + }, relevantCssProperty: "fontSize" +}; + +function getLegacyFontSize(size) { + // For convenience in other places in my code, I handle all sizes, not just + // pixel sizes as the spec says. This means pixel sizes have to be passed + // in suffixed with "px", not as plain numbers. + size = normalizeFontSize(size); + + if ($_(["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"]).indexOf(size) == -1 + && !/^[0-9]+(\.[0-9]+)?(cm|mm|in|pt|pc|px)$/.test(size)) { + // There is no sensible legacy size for things like "2em". + return null; + } + + var font = document.createElement("font"); + document.body.appendChild(font); + if (size == "xxx-large") { + font.size = 7; + } else { + font.style.fontSize = size; + } + var pixelSize = parseInt($_.getComputedStyle(font).fontSize); + document.body.removeChild(font); + + // "Let returned size be 1." + var returnedSize = 1; + + // "While returned size is less than 7:" + while (returnedSize < 7) { + // "Let lower bound be the resolved value of "font-size" in pixels + // of a font element whose size attribute is set to returned size." + var font = document.createElement("font"); + font.size = returnedSize; + document.body.appendChild(font); + var lowerBound = parseInt($_.getComputedStyle(font).fontSize); + + // "Let upper bound be the resolved value of "font-size" in pixels + // of a font element whose size attribute is set to one plus + // returned size." + font.size = 1 + returnedSize; + var upperBound = parseInt($_.getComputedStyle(font).fontSize); + document.body.removeChild(font); + + // "Let average be the average of upper bound and lower bound." + var average = (upperBound + lowerBound)/2; + + // "If pixel size is less than average, return the one-element + // string consisting of the digit returned size." + if (pixelSize < average) { + return String(returnedSize); + } + + // "Add one to returned size." + returnedSize++; + } + + // "Return "7"." + return "7"; +} + +//@} +///// The foreColor command ///// +//@{ +commands.forecolor = { + action: function(value) { + // Copy-pasted, same as backColor and hiliteColor + + // "If value is not a valid CSS color, prepend "#" to it." + // + // "If value is still not a valid CSS color, or if it is currentColor, + // abort these steps and do nothing." + // + // Cheap hack for testing, no attempt to be comprehensive. + if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) { + value = "#" + value; + } + if (!/^(rgba?|hsla?)\(.*\)$/.test(value) + && !parseSimpleColor(value) + && value.toLowerCase() != "transparent") { + return; + } + + // "Set the selection's value to value." + setSelectionValue("forecolor", value); + }, standardInlineValueCommand: true, relevantCssProperty: "color", + equivalentValues: function(val1, val2) { + // "Either both strings are valid CSS colors and have the same red, + // green, blue, and alpha components, or neither string is a valid CSS + // color." + return normalizeColor(val1) === normalizeColor(val2); + } +}; + +//@} +///// The hiliteColor command ///// +//@{ +commands.hilitecolor = { + // Copy-pasted, same as backColor + action: function(value) { + // Action is further copy-pasted, same as foreColor + + // "If value is not a valid CSS color, prepend "#" to it." + // + // "If value is still not a valid CSS color, or if it is currentColor, + // abort these steps and do nothing." + // + // Cheap hack for testing, no attempt to be comprehensive. + if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) { + value = "#" + value; + } + if (!/^(rgba?|hsla?)\(.*\)$/.test(value) + && !parseSimpleColor(value) + && value.toLowerCase() != "transparent") { + return; + } + + // "Set the selection's value to value." + setSelectionValue("hilitecolor", value); + }, indeterm: function() { + // "True if among editable Text nodes that are effectively contained in + // the active range, there are two that have distinct effective command + // values. Otherwise false." + return $_( getAllEffectivelyContainedNodes(getActiveRange(), function(node) { + return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE; + }) ).map(function(node) { + return getEffectiveCommandValue(node, "hilitecolor"); + }, true).filter(function(value, i, arr) { + return $_(arr.slice(0, i)).indexOf(value) == -1; + }).length >= 2; + }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor", + equivalentValues: function(val1, val2) { + // "Either both strings are valid CSS colors and have the same red, + // green, blue, and alpha components, or neither string is a valid CSS + // color." + return normalizeColor(val1) === normalizeColor(val2); + } +}; + +//@} +///// The italic command ///// +//@{ +commands.italic = { + action: function( value, range ) { + // "If queryCommandState("italic") returns true, set the selection's + // value to "normal". Otherwise set the selection's value to "italic"." + if (myQueryCommandState("italic", range)) { + setSelectionValue("italic", "normal", range); + } else { + setSelectionValue("italic", "italic", range); + } + }, inlineCommandActivatedValues: ["italic", "oblique"], + relevantCssProperty: "fontStyle" +}; + +//@} +///// The removeFormat command ///// +//@{ +commands.removeformat = { + action: function() { + // "A removeFormat candidate is an editable HTML element with local + // name "abbr", "acronym", "b", "bdi", "bdo", "big", "blink", "cite", + // "code", "dfn", "em", "font", "i", "ins", "kbd", "mark", "nobr", "q", + // "s", "samp", "small", "span", "strike", "strong", "sub", "sup", + // "tt", "u", or "var"." + function isRemoveFormatCandidate(node) { + return isEditable(node) + && isHtmlElement(node, ["abbr", "acronym", "b", "bdi", "bdo", + "big", "blink", "cite", "code", "dfn", "em", "font", "i", + "ins", "kbd", "mark", "nobr", "q", "s", "samp", "small", + "span", "strike", "strong", "sub", "sup", "tt", "u", "var"]); + } + + // "Let elements to remove be a list of every removeFormat candidate + // effectively contained in the active range." + var elementsToRemove = getAllEffectivelyContainedNodes(getActiveRange(), isRemoveFormatCandidate); + + // "For each element in elements to remove:" + $_( elementsToRemove ).forEach(function(element) { + // "While element has children, insert the first child of element + // into the parent of element immediately before element, + // preserving ranges." + while (element.hasChildNodes()) { + movePreservingRanges(element.firstChild, element.parentNode, getNodeIndex(element), range); + } + + // "Remove element from its parent." + element.parentNode.removeChild(element); + }); + + // "If the active range's start node is an editable Text node, and its + // start offset is neither zero nor its start node's length, call + // splitText() on the active range's start node, with argument equal to + // the active range's start offset. Then set the active range's start + // node to the result, and its start offset to zero." + if (isEditable(getActiveRange().startContainer) + && getActiveRange().startContainer.nodeType == $_.Node.TEXT_NODE + && getActiveRange().startOffset != 0 + && getActiveRange().startOffset != getNodeLength(getActiveRange().startContainer)) { + // Account for browsers not following range mutation rules + if (getActiveRange().startContainer == getActiveRange().endContainer) { + var newEnd = getActiveRange().endOffset - getActiveRange().startOffset; + var newNode = getActiveRange().startContainer.splitText(getActiveRange().startOffset); + getActiveRange().setStart(newNode, 0); + getActiveRange().setEnd(newNode, newEnd); + } else { + getActiveRange().setStart(getActiveRange().startContainer.splitText(getActiveRange().startOffset), 0); + } + } + + // "If the active range's end node is an editable Text node, and its + // end offset is neither zero nor its end node's length, call + // splitText() on the active range's end node, with argument equal to + // the active range's end offset." + if (isEditable(getActiveRange().endContainer) + && getActiveRange().endContainer.nodeType == $_.Node.TEXT_NODE + && getActiveRange().endOffset != 0 + && getActiveRange().endOffset != getNodeLength(getActiveRange().endContainer)) { + // IE seems to mutate the range incorrectly here, so we need + // correction here as well. Have to be careful to set the range to + // something not including the text node so that getActiveRange() + // doesn't throw an exception due to a temporarily detached + // endpoint. + var newStart = [getActiveRange().startContainer, getActiveRange().startOffset]; + var newEnd = [getActiveRange().endContainer, getActiveRange().endOffset]; + getActiveRange().setEnd(document.documentElement, 0); + newEnd[0].splitText(newEnd[1]); + getActiveRange().setStart(newStart[0], newStart[1]); + getActiveRange().setEnd(newEnd[0], newEnd[1]); + } + + // "Let node list consist of all editable nodes effectively contained + // in the active range." + // + // "For each node in node list, while node's parent is a removeFormat + // candidate in the same editing host as node, split the parent of the + // one-node list consisting of node." + $_( getAllEffectivelyContainedNodes(getActiveRange(), isEditable) ).forEach(function(node) { + while (isRemoveFormatCandidate(node.parentNode) + && inSameEditingHost(node.parentNode, node)) { + splitParent([node], range); + } + }); + + // "For each of the entries in the following list, in the given order, + // set the selection's value to null, with command as given." + $_( [ + "subscript", + "bold", + "fontname", + "fontsize", + "forecolor", + "hilitecolor", + "italic", + "strikethrough", + "underline", + ] ).forEach(function(command) { + setSelectionValue(command, null); + }); + } +}; + +//@} +///// The strikethrough command ///// +//@{ +commands.strikethrough = { + action: function() { + // "If queryCommandState("strikethrough") returns true, set the + // selection's value to null. Otherwise set the selection's value to + // "line-through"." + if (myQueryCommandState("strikethrough")) { + setSelectionValue("strikethrough", null); + } else { + setSelectionValue("strikethrough", "line-through"); + } + }, inlineCommandActivatedValues: ["line-through"] +}; + +//@} +///// The subscript command ///// +//@{ +commands.subscript = { + action: function() { + // "Call queryCommandState("subscript"), and let state be the result." + var state = myQueryCommandState("subscript"); + + // "Set the selection's value to null." + setSelectionValue("subscript", null); + + // "If state is false, set the selection's value to "subscript"." + if (!state) { + setSelectionValue("subscript", "subscript"); + } + }, indeterm: function() { + // "True if either among editable Text nodes that are effectively + // contained in the active range, there is at least one with effective + // command value "subscript" and at least one with some other effective + // command value; or if there is some editable Text node effectively + // contained in the active range with effective command value "mixed". + // Otherwise false." + var nodes = getAllEffectivelyContainedNodes(getActiveRange(), function(node) { + return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE; + }); + return ($_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "subscript") == "subscript" }) + && $_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "subscript") != "subscript" })) + || $_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "subscript") == "mixed" }); + }, inlineCommandActivatedValues: ["subscript"] +}; + +//@} +///// The superscript command ///// +//@{ +commands.superscript = { + action: function() { + // "Call queryCommandState("superscript"), and let state be the + // result." + var state = myQueryCommandState("superscript"); + + // "Set the selection's value to null." + setSelectionValue("superscript", null); + + // "If state is false, set the selection's value to "superscript"." + if (!state) { + setSelectionValue("superscript", "superscript"); + } + }, indeterm: function() { + // "True if either among editable Text nodes that are effectively + // contained in the active range, there is at least one with effective + // command value "superscript" and at least one with some other + // effective command value; or if there is some editable Text node + // effectively contained in the active range with effective command + // value "mixed". Otherwise false." + var nodes = getAllEffectivelyContainedNodes(getActiveRange(), + function(node) { + return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE; + }); + return ($_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "superscript") == "superscript" }) + && $_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "superscript") != "superscript" })) + || $_( nodes ).some(function(node) { return getEffectiveCommandValue(node, "superscript") == "mixed" }); + }, inlineCommandActivatedValues: ["superscript"] +}; + +//@} +///// The underline command ///// +//@{ +commands.underline = { + action: function() { + // "If queryCommandState("underline") returns true, set the selection's + // value to null. Otherwise set the selection's value to "underline"." + if (myQueryCommandState("underline")) { + setSelectionValue("underline", null); + } else { + setSelectionValue("underline", "underline"); + } + }, inlineCommandActivatedValues: ["underline"] +}; + +//@} +///// The unlink command ///// +//@{ +commands.unlink = { + action: function() { + // "Let hyperlinks be a list of every a element that has an href + // attribute and is contained in the active range or is an ancestor of + // one of its boundary points." + // + // As usual, take care to ensure it's tree order. The correctness of + // the following is left as an exercise for the reader. + var range = getActiveRange(); + var hyperlinks = []; + for ( + var node = range.startContainer; + node; + node = node.parentNode + ) { + if (isHtmlElement(node, "A") + && $_( node ).hasAttribute("href")) { + hyperlinks.unshift(node); + } + } + for ( + var node = range.startContainer; + node != nextNodeDescendants(range.endContainer); + node = nextNode(node) + ) { + if (isHtmlElement(node, "A") + && $_( node ).hasAttribute("href") + && (isContained(node, range) + || isAncestor(node, range.endContainer) + || node == range.endContainer)) { + hyperlinks.push(node); + } + } + + // "Clear the value of each member of hyperlinks." + for (var i = 0; i < hyperlinks.length; i++) { + clearValue(hyperlinks[i], "unlink", range); + } + }, standardInlineValueCommand: true +}; + +//@} + +///////////////////////////////////// +///// Block formatting commands ///// +///////////////////////////////////// + +///// Block formatting command definitions ///// +//@{ + +// "An indentation element is either a blockquote, or a div that has a style +// attribute that sets "margin" or some subproperty of it." +function isIndentationElement(node) { + if (!isHtmlElement(node)) { + return false; + } + + if (node.tagName == "BLOCKQUOTE") { + return true; + } + + if (node.tagName != "DIV") { + return false; + } + + if (typeof node.style.length !== 'undefined') { + for (var i = 0; i < node.style.length; i++) { + // Approximate check + if (/^(-[a-z]+-)?margin/.test(node.style[i])) { + return true; + } + } + } else { + for (var s in node.style) { + if (/^(-[a-z]+-)?margin/.test(s) && node.style[s] && node.style[s] !== 0) { + return true; + } + } + } + + return false; +} + +// "A simple indentation element is an indentation element that has no +// attributes other than one or more of +// +// * "a style attribute that sets no properties other than "margin", "border", +// "padding", or subproperties of those; +// * "a class attribute; +// * "a dir attribute." +function isSimpleIndentationElement(node) { + if (!isIndentationElement(node)) { + return false; + } + + if (node.tagName != "BLOCKQUOTE" && node.tagName != "DIV") { + return false; + } + + for (var i = 0; i < node.attributes.length; i++) { + if (!isHtmlNamespace(node.attributes[i].namespaceURI) + || $_(["style", "class", "dir"]).indexOf(node.attributes[i].name) == -1) { + return false; + } + } + + if (typeof node.style.length !== 'undefined') { + for (var i = 0; i < node.style.length; i++) { + // This is approximate, but it works well enough for my purposes. + if (!/^(-[a-z]+-)?(margin|border|padding)/.test(node.style[i])) { + return false; + } + } + } else { + for (var s in node.style) { + // This is approximate, but it works well enough for my purposes. + if (!/^(-[a-z]+-)?(margin|border|padding)/.test(s) && node.style[s] && node.style[s] !== 0 && node.style[s] !== 'false') { + return false; + } + } + } + + return true; +} + +// "A non-list single-line container is an HTML element with local name +// "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "listing", "p", "pre", +// or "xmp"." +function isNonListSingleLineContainer(node) { + return isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", + "h6", "listing", "p", "pre", "xmp"]); +} + +// "A single-line container is either a non-list single-line container, or an +// HTML element with local name "li", "dt", or "dd"." +function isSingleLineContainer(node) { + return isNonListSingleLineContainer(node) + || isHtmlElement(node, ["li", "dt", "dd"]); +} + +// "The default single-line container name is "p"." +var defaultSingleLineContainerName = "p"; + + +//@} +///// Assorted block formatting command algorithms ///// +//@{ + +function fixDisallowedAncestors(node, range) { + // "If node is not editable, abort these steps." + if (!isEditable(node)) { + return; + } + + // "If node is not an allowed child of any of its ancestors in the same + // editing host, and is not an HTML element with local name equal to the + // default single-line container name:" + if ($_(getAncestors(node)).every(function(ancestor) { + return !inSameEditingHost(node, ancestor) + || !isAllowedChild(node, ancestor) + }) + && !isHtmlElement(node, defaultSingleLineContainerName)) { + // "If node is a dd or dt, wrap the one-node list consisting of node, + // with sibling criteria returning true for any dl with no attributes + // and false otherwise, and new parent instructions returning the + // result of calling createElement("dl") on the context object. Then + // abort these steps." + if (isHtmlElement(node, ["dd", "dt"])) { + wrap([node], + function(sibling) { return isHtmlElement(sibling, "dl") && !sibling.attributes.length }, + function() { return document.createElement("dl") }, + range + ); + return; + } + + // "If node is not a prohibited paragraph child, abort these steps." + if (!isProhibitedParagraphChild(node)) { + return; + } + + // "Set the tag name of node to the default single-line container name, + // and let node be the result." + node = setTagName(node, defaultSingleLineContainerName, range); + + // "Fix disallowed ancestors of node." + fixDisallowedAncestors(node, range); + + // "Let descendants be all descendants of node." + var descendants = getDescendants(node); + + // "Fix disallowed ancestors of each member of descendants." + for (var i = 0; i < descendants.length; i++) { + fixDisallowedAncestors(descendants[i], range); + } + + // "Abort these steps." + return; + } + + // "Record the values of the one-node list consisting of node, and let + // values be the result." + var values = recordValues([node]); + + // "While node is not an allowed child of its parent, split the parent of + // the one-node list consisting of node." + while (!isAllowedChild(node, node.parentNode)) { + // If the parent contains only this node and possibly empty text nodes, we rather want to unwrap the node, instead of splitting. + // With splitting, we would get empty nodes, like: + // split:

      foo

      ->

      foo

      (bad) + // unwrap:

      foo

      ->

      foo

      (good) + + // First remove empty text nodes that are children of the parent and correct the range if necessary + // we do this to have the node being the only child of its parent, so that we can replace the parent with the node + for (var i = node.parentNode.childNodes.length - 1; i >= 0; --i) { + if (node.parentNode.childNodes[i].nodeType == 3 && node.parentNode.childNodes[i].data.length == 0) { + // we remove the empty text node + node.parentNode.removeChild(node.parentNode.childNodes[i]); + + // if the range points to somewhere behind the removed text node, we reduce the offset + if (range.startContainer == node.parentNode && range.startOffset > i) { + range.startOffset--; + } + if (range.endContainer == node.parentNode && range.endOffset > i) { + range.endOffset--; + } + } + } + + // now that the parent has only the node as child (because we + // removed any existing empty text nodes), we can safely unwrap the + // node, and correct the range if necessary + if (node.parentNode.childNodes.length == 1) { + var correctStart = false; + var correctEnd = false; + if (range.startContainer === node.parentNode) { + correctStart = true; + } + if (range.endContainer === node.parentNode) { + correctEnd = true; + } + jQuery(node).unwrap(); + if (correctStart) { + range.startContainer = node.parentNode; + range.startOffset = range.startOffset + getNodeIndex(node); + } + if (correctEnd) { + range.endContainer = node.parentNode; + range.endOffset = range.endOffset + getNodeIndex(node); + } + } else { + splitParent([node], range); + } + } + + // "Restore the values from values." + restoreValues(values, range); +} + +/** + * This method "normalizes" sublists of the given item (which is supposed to be a LI): + * If sublists are found in the LI element, they are moved directly into the outer list. + * @param item item + * @param range range, which will be modified if necessary + */ +function normalizeSublists(item, range) { + // "If item is not an li or it is not editable or its parent is not + // editable, abort these steps." + if (!isHtmlElement(item, "LI") + || !isEditable(item) + || !isEditable(item.parentNode)) { + return; + } + + // "Let new item be null." + var newItem = null; + + // "While item has an ol or ul child:" + while ($_(item.childNodes).some( function (node) { return isHtmlElement(node, ["OL", "UL"]) })) { + // "Let child be the last child of item." + var child = item.lastChild; + + // "If child is an ol or ul, or new item is null and child is a Text + // node whose data consists of zero of more space characters:" + if (isHtmlElement(child, ["OL", "UL"]) + || (!newItem && child.nodeType == $_.Node.TEXT_NODE && /^[ \t\n\f\r]*$/.test(child.data))) { + // "Set new item to null." + newItem = null; + + // "Insert child into the parent of item immediately following + // item, preserving ranges." + movePreservingRanges(child, item.parentNode, 1 + getNodeIndex(item), range); + + // "Otherwise:" + } else { + // "If new item is null, let new item be the result of calling + // createElement("li") on the ownerDocument of item, then insert + // new item into the parent of item immediately after item." + if (!newItem) { + newItem = item.ownerDocument.createElement("li"); + item.parentNode.insertBefore(newItem, item.nextSibling); + } + + // "Insert child into new item as its first child, preserving + // ranges." + movePreservingRanges(child, newItem, 0, range); + } + } +} + +/** + * This method is the exact opposite of normalizeSublists. + * List nodes directly nested into each other are corrected to be nested in li elements (so that the resulting lists conform the html5 specification) + * @param item list node + * @param range range, which is preserved when modifying the list + */ +function unNormalizeSublists(item, range) { + // "If item is not an ol or ol or it is not editable or its parent is not + // editable, abort these steps." + if (!isHtmlElement(item, ["OL", "UL"]) + || !isEditable(item)) { + return; + } + + var $list = jQuery(item); + $list.children("ol,ul").each(function(index, sublist) { + if (isHtmlElement(sublist.previousSibling, "LI")) { + // move the sublist into the LI + movePreservingRanges(sublist, sublist.previousSibling, sublist.previousSibling.childNodes.length, range); + } + }); +} + +function getSelectionListState() { + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node list be a list of nodes, initially empty." + // + // "For each node contained in new range, append node to node list if the + // last member of node list (if any) is not an ancestor of node; node is + // editable; node is not an indentation element; and node is either an ol + // or ul, or the child of an ol or ul, or an allowed child of "li"." + var nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && !isIndentationElement(node) + && (isHtmlElement(node, ["ol", "ul"]) + || isHtmlElement(node.parentNode, ["ol", "ul"]) + || isAllowedChild(node, "li")); + }); + + // "If node list is empty, return "none"." + if (!nodeList.length) { + return "none"; + } + + // "If every member of node list is either an ol or the child of an ol or + // the child of an li child of an ol, and none is a ul or an ancestor of a + // ul, return "ol"." + if ($_(nodeList).every(function(node) { + return isHtmlElement(node, "ol") + || isHtmlElement(node.parentNode, "ol") + || (isHtmlElement(node.parentNode, "li") && isHtmlElement(node.parentNode.parentNode, "ol")); + }) + && !$_( nodeList ).some(function(node) { return isHtmlElement(node, "ul") || ("querySelector" in node && node.querySelector("ul")) })) { + return "ol"; + } + + // "If every member of node list is either a ul or the child of a ul or the + // child of an li child of a ul, and none is an ol or an ancestor of an ol, + // return "ul"." + if ($_(nodeList).every(function(node) { + return isHtmlElement(node, "ul") + || isHtmlElement(node.parentNode, "ul") + || (isHtmlElement(node.parentNode, "li") && isHtmlElement(node.parentNode.parentNode, "ul")); + }) + && !$_( nodeList ).some(function(node) { return isHtmlElement(node, "ol") || ("querySelector" in node && node.querySelector("ol")) })) { + return "ul"; + } + + var hasOl = $_( nodeList ).some(function(node) { + return isHtmlElement(node, "ol") + || isHtmlElement(node.parentNode, "ol") + || ("querySelector" in node && node.querySelector("ol")) + || (isHtmlElement(node.parentNode, "li") && isHtmlElement(node.parentNode.parentNode, "ol")); + }); + var hasUl = $_( nodeList ).some(function(node) { + return isHtmlElement(node, "ul") + || isHtmlElement(node.parentNode, "ul") + || ("querySelector" in node && node.querySelector("ul")) + || (isHtmlElement(node.parentNode, "li") && isHtmlElement(node.parentNode.parentNode, "ul")); + }); + // "If some member of node list is either an ol or the child or ancestor of + // an ol or the child of an li child of an ol, and some member of node list + // is either a ul or the child or ancestor of a ul or the child of an li + // child of a ul, return "mixed"." + if (hasOl && hasUl) { + return "mixed"; + } + + // "If some member of node list is either an ol or the child or ancestor of + // an ol or the child of an li child of an ol, return "mixed ol"." + if (hasOl) { + return "mixed ol"; + } + + // "If some member of node list is either a ul or the child or ancestor of + // a ul or the child of an li child of a ul, return "mixed ul"." + if (hasUl) { + return "mixed ul"; + } + + // "Return "none"." + return "none"; +} + +function getAlignmentValue(node) { + // "While node is neither null nor an Element, or it is an Element but its + // "display" property has resolved value "inline" or "none", set node to + // its parent." + while ((node && node.nodeType != $_.Node.ELEMENT_NODE) + || (node.nodeType == $_.Node.ELEMENT_NODE + && $_(["inline", "none"]).indexOf($_.getComputedStyle(node).display) != -1)) { + node = node.parentNode; + } + + // "If node is not an Element, return "left"." + if (!node || node.nodeType != $_.Node.ELEMENT_NODE) { + return "left"; + } + + var resolvedValue = $_.getComputedStyle(node).textAlign + // Hack around browser non-standardness + .replace(/^-(moz|webkit)-/, "") + .replace(/^auto$/, "start"); + + // "If node's "text-align" property has resolved value "start", return + // "left" if the directionality of node is "ltr", "right" if it is "rtl"." + if (resolvedValue == "start") { + return getDirectionality(node) == "ltr" ? "left" : "right"; + } + + // "If node's "text-align" property has resolved value "end", return + // "right" if the directionality of node is "ltr", "left" if it is "rtl"." + if (resolvedValue == "end") { + return getDirectionality(node) == "ltr" ? "right" : "left"; + } + + // "If node's "text-align" property has resolved value "center", "justify", + // "left", or "right", return that value." + if ($_(["center", "justify", "left", "right"]).indexOf(resolvedValue) != -1) { + return resolvedValue; + } + + // "Return "left"." + return "left"; +} + +//@} +///// Block-extending a range ///// +//@{ + +// "A boundary point (node, offset) is a block start point if either node's +// parent is null and offset is zero; or node has a child with index offset − +// 1, and that child is either a visible block node or a visible br." +function isBlockStartPoint(node, offset) { + return (!node.parentNode && offset == 0) + || (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && isVisible(node.childNodes[offset - 1]) + && (isBlockNode(node.childNodes[offset - 1]) + || isHtmlElement(node.childNodes[offset - 1], "br"))); +} + +// "A boundary point (node, offset) is a block end point if either node's +// parent is null and offset is node's length; or node has a child with index +// offset, and that child is a visible block node." +function isBlockEndPoint(node, offset) { + return (!node.parentNode && offset == getNodeLength(node)) + || (offset < node.childNodes.length + && isVisible(node.childNodes[offset]) + && isBlockNode(node.childNodes[offset])); +} + +// "A boundary point is a block boundary point if it is either a block start +// point or a block end point." +function isBlockBoundaryPoint(node, offset) { + return isBlockStartPoint(node, offset) + || isBlockEndPoint(node, offset); +} + +function blockExtend(range) { + // "Let start node, start offset, end node, and end offset be the start + // and end nodes and offsets of the range." + var startNode = range.startContainer; + var startOffset = range.startOffset; + var endNode = range.endContainer; + var endOffset = range.endOffset; + + // "If some ancestor container of start node is an li, set start offset to + // the index of the last such li in tree order, and set start node to that + // li's parent." + var liAncestors = $_( getAncestors(startNode).concat(startNode) ) + .filter(function(ancestor) { return isHtmlElement(ancestor, "li") }) + .slice(-1); + if (liAncestors.length) { + startOffset = getNodeIndex(liAncestors[0]); + startNode = liAncestors[0].parentNode; + } + + // "If (start node, start offset) is not a block start point, repeat the + // following steps:" + if (!isBlockStartPoint(startNode, startOffset)) do { + // "If start offset is zero, set it to start node's index, then set + // start node to its parent." + if (startOffset == 0) { + startOffset = getNodeIndex(startNode); + startNode = startNode.parentNode; + + // "Otherwise, subtract one from start offset." + } else { + startOffset--; + } + + // "If (start node, start offset) is a block boundary point, break from + // this loop." + } while (!isBlockBoundaryPoint(startNode, startOffset)); + + // "While start offset is zero and start node's parent is not null, set + // start offset to start node's index, then set start node to its parent." + while (startOffset == 0 + && startNode.parentNode) { + startOffset = getNodeIndex(startNode); + startNode = startNode.parentNode; + } + + // "If some ancestor container of end node is an li, set end offset to one + // plus the index of the last such li in tree order, and set end node to + // that li's parent." + var liAncestors = $_( getAncestors(endNode).concat(endNode) ) + .filter(function(ancestor) { return isHtmlElement(ancestor, "li") }) + .slice(-1); + if (liAncestors.length) { + endOffset = 1 + getNodeIndex(liAncestors[0]); + endNode = liAncestors[0].parentNode; + } + + // "If (end node, end offset) is not a block end point, repeat the + // following steps:" + if (!isBlockEndPoint(endNode, endOffset)) do { + // "If end offset is end node's length, set it to one plus end node's + // index, then set end node to its parent." + if (endOffset == getNodeLength(endNode)) { + endOffset = 1 + getNodeIndex(endNode); + endNode = endNode.parentNode; + + // "Otherwise, add one to end offset. + } else { + endOffset++; + } + + // "If (end node, end offset) is a block boundary point, break from + // this loop." + } while (!isBlockBoundaryPoint(endNode, endOffset)); + + // "While end offset is end node's length and end node's parent is not + // null, set end offset to one plus end node's index, then set end node to + // its parent." + while (endOffset == getNodeLength(endNode) + && endNode.parentNode) { + endOffset = 1 + getNodeIndex(endNode); + endNode = endNode.parentNode; + } + + // "Let new range be a new range whose start and end nodes and offsets + // are start node, start offset, end node, and end offset." + var newRange = Aloha.createRange(); + newRange.setStart(startNode, startOffset); + newRange.setEnd(endNode, endOffset); + + // "Return new range." + return newRange; +} + +function followsLineBreak(node) { + // "Let offset be zero." + var offset = 0; + + // "While (node, offset) is not a block boundary point:" + while (!isBlockBoundaryPoint(node, offset)) { + // "If node has a visible child with index offset minus one, return + // false." + if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && isVisible(node.childNodes[offset - 1])) { + return false; + } + + // "If offset is zero or node has no children, set offset to node's + // index, then set node to its parent." + if (offset == 0 + || !node.hasChildNodes()) { + offset = getNodeIndex(node); + node = node.parentNode; + + // "Otherwise, set node to its child with index offset minus one, then + // set offset to node's length." + } else { + node = node.childNodes[offset - 1]; + offset = getNodeLength(node); + } + } + + // "Return true." + return true; +} + +function precedesLineBreak(node) { + // "Let offset be node's length." + var offset = getNodeLength(node); + + // "While (node, offset) is not a block boundary point:" + while (!isBlockBoundaryPoint(node, offset)) { + // "If node has a visible child with index offset, return false." + if (offset < node.childNodes.length + && isVisible(node.childNodes[offset])) { + return false; + } + + // "If offset is node's length or node has no children, set offset to + // one plus node's index, then set node to its parent." + if (offset == getNodeLength(node) + || !node.hasChildNodes()) { + offset = 1 + getNodeIndex(node); + node = node.parentNode; + + // "Otherwise, set node to its child with index offset and set offset + // to zero." + } else { + node = node.childNodes[offset]; + offset = 0; + } + } + + // "Return true." + return true; +} + +//@} +///// Recording and restoring overrides ///// +//@{ + +function recordCurrentOverrides( range ) { + // "Let overrides be a list of (string, string or boolean) ordered pairs, + // initially empty." + var overrides = []; + + // "If there is a value override for "createLink", add ("createLink", value + // override for "createLink") to overrides." + if (getValueOverride("createlink" ,range) !== undefined) { + overrides.push(["createlink", getValueOverride("createlink", range)]); + } + + // "For each command in the list "bold", "italic", "strikethrough", + // "subscript", "superscript", "underline", in order: if there is a state + // override for command, add (command, command's state override) to + // overrides." + $_( ["bold", "italic", "strikethrough", "subscript", "superscript", + "underline"] ).forEach(function(command) { + if (getStateOverride(command, range) !== undefined) { + overrides.push([command, getStateOverride(command, range)]); + } + }); + + // "For each command in the list "fontName", "fontSize", "foreColor", + // "hiliteColor", in order: if there is a value override for command, add + // (command, command's value override) to overrides." + $_( ["fontname", "fontsize", "forecolor", + "hilitecolor"] ).forEach(function(command) { + if (getValueOverride(command, range) !== undefined) { + overrides.push([command, getValueOverride(command, range)]); + } + }); + + // "Return overrides." + return overrides; +} + +function recordCurrentStatesAndValues(range) { + // "Let overrides be a list of (string, string or boolean) ordered pairs, + // initially empty." + var overrides = []; + + // "Let node be the first editable Text node effectively contained in the + // active range, or null if there is none." + var node = $_( getAllEffectivelyContainedNodes(range) ) + .filter(function(node) { return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE })[0]; + + // "If node is null, return overrides." + if (!node) { + return overrides; + } + + // "Add ("createLink", value for "createLink") to overrides." + overrides.push(["createlink", commands.createlink.value(range)]); + + // "For each command in the list "bold", "italic", "strikethrough", + // "subscript", "superscript", "underline", in order: if node's effective + // command value for command is one of its inline command activated values, + // add (command, true) to overrides, and otherwise add (command, false) to + // overrides." + $_( ["bold", "italic", "strikethrough", "subscript", "superscript", + "underline"] ).forEach(function(command) { + if ($_(commands[command].inlineCommandActivatedValues) + .indexOf(getEffectiveCommandValue(node, command)) != -1) { + overrides.push([command, true]); + } else { + overrides.push([command, false]); + } + }); + + // "For each command in the list "fontName", "foreColor", "hiliteColor", in + // order: add (command, command's value) to overrides." + + $_( ["fontname", "fontsize", "forecolor", "hilitecolor"] ).forEach(function(command) { + overrides.push([command, commands[command].value(range)]); + }); + + // "Add ("fontSize", node's effective command value for "fontSize") to + // overrides." + overrides.push("fontsize", getEffectiveCommandValue(node, "fontsize")); + + // "Return overrides." + return overrides; +} + +function restoreStatesAndValues(overrides, range) { + // "Let node be the first editable Text node effectively contained in the + // active range, or null if there is none." + var node = $_( getAllEffectivelyContainedNodes(range) ) + .filter(function(node) { return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE })[0]; + + // "If node is not null, then for each (command, override) pair in + // overrides, in order:" + if (node) { + for (var i = 0; i < overrides.length; i++) { + var command = overrides[i][0]; + var override = overrides[i][1]; + + // "If override is a boolean, and queryCommandState(command) + // returns something different from override, call + // execCommand(command)." + if (typeof override == "boolean" + && myQueryCommandState(command) != override) { + myExecCommand(command); + + // "Otherwise, if override is a string, and command is not + // "fontSize", and queryCommandValue(command) returns something not + // equivalent to override, call execCommand(command, false, + // override)." + } else if (typeof override == "string" + && command != "fontsize" + && !areEquivalentValues(command, myQueryCommandValue(command), override)) { + myExecCommand(command, false, override); + + // "Otherwise, if override is a string; and command is "fontSize"; + // and either there is a value override for "fontSize" that is not + // equal to override, or there is no value override for "fontSize" + // and node's effective command value for "fontSize" is not loosely + // equivalent to override: call execCommand("fontSize", false, + // override)." + } else if (typeof override == "string" + && command == "fontsize" + && ( + ( + getValueOverride("fontsize", range) !== undefined + && getValueOverride("fontsize", range) !== override + ) || ( + getValueOverride("fontsize", range) === undefined + && !areLooselyEquivalentValues(command, getEffectiveCommandValue(node, "fontsize"), override) + ) + )) { + myExecCommand("fontsize", false, override); + + // "Otherwise, continue this loop from the beginning." + } else { + continue; + } + + // "Set node to the first editable Text node effectively contained + // in the active range, if there is one." + node = $_( getAllEffectivelyContainedNodes(range) ) + .filter(function(node) { return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE })[0] + || node; + } + + // "Otherwise, for each (command, override) pair in overrides, in order:" + } else { + for (var i = 0; i < overrides.length; i++) { + var command = overrides[i][0]; + var override = overrides[i][1]; + + // "If override is a boolean, set the state override for command to + // override." + if (typeof override == "boolean") { + setStateOverride(command, override, range); + } + + // "If override is a string, set the value override for command to + // override." + if (typeof override == "string") { + setValueOverride(command, override, range); + } + } + } +} + +//@} +///// Deleting the contents of a range ///// +//@{ + +function deleteContents() { + // We accept several different calling conventions: + // + // 1) A single argument, which is a range. + // + // 2) Two arguments, the first being a range and the second flags. + // + // 3) Four arguments, the start and end of a range. + // + // 4) Five arguments, the start and end of a range plus flags. + // + // The flags argument is a dictionary that can have up to two keys, + // blockMerging and stripWrappers, whose corresponding values are + // interpreted as boolean. E.g., {stripWrappers: false}. + var range; + var flags = {}; + + if (arguments.length < 3) { + range = arguments[0]; + } else { + range = Aloha.createRange(); + range.setStart(arguments[0], arguments[1]); + range.setEnd(arguments[2], arguments[3]); + } + if (arguments.length == 2) { + flags = arguments[1]; + } + if (arguments.length == 5) { + flags = arguments[4]; + } + + var blockMerging = "blockMerging" in flags ? !!flags.blockMerging : true; + var stripWrappers = "stripWrappers" in flags ? !!flags.stripWrappers : true; + + // "If range is null, abort these steps and do nothing." + if (!range) { + return; + } + + // "Let start node, start offset, end node, and end offset be range's start + // and end nodes and offsets." + var startNode = range.startContainer; + var startOffset = range.startOffset; + var endNode = range.endContainer; + var endOffset = range.endOffset; + + // "While start node has at least one child:" + while (startNode.hasChildNodes()) { + // "If start offset is start node's length, and start node's parent is + // in the same editing host, and start node is an inline node, set + // start offset to one plus the index of start node, then set start + // node to its parent and continue this loop from the beginning." + if (startOffset == getNodeLength(startNode) + && inSameEditingHost(startNode, startNode.parentNode) + && isInlineNode(startNode)) { + startOffset = 1 + getNodeIndex(startNode); + startNode = startNode.parentNode; + continue; + } + + // "If start offset is start node's length, break from this loop." + if (startOffset == getNodeLength(startNode)) { + break; + } + + // "Let reference node be the child of start node with index equal to + // start offset." + var referenceNode = startNode.childNodes[startOffset]; + + // "If reference node is a block node or an Element with no children, + // or is neither an Element nor a Text node, break from this loop." + if (isBlockNode(referenceNode) + || (referenceNode.nodeType == $_.Node.ELEMENT_NODE + && !referenceNode.hasChildNodes()) + || (referenceNode.nodeType != $_.Node.ELEMENT_NODE + && referenceNode.nodeType != $_.Node.TEXT_NODE)) { + break; + } + + // "Set start node to reference node and start offset to 0." + startNode = referenceNode; + startOffset = 0; + } + + // "While end node has at least one child:" + while (endNode.hasChildNodes()) { + // "If end offset is 0, and end node's parent is in the same editing + // host, and end node is an inline node, set end offset to the index of + // end node, then set end node to its parent and continue this loop + // from the beginning." + if (endOffset == 0 + && inSameEditingHost(endNode, endNode.parentNode) + && isInlineNode(endNode)) { + endOffset = getNodeIndex(endNode); + endNode = endNode.parentNode; + continue; + } + + // "If end offset is 0, break from this loop." + if (endOffset == 0) { + break; + } + + // "Let reference node be the child of end node with index equal to end + // offset minus one." + var referenceNode = endNode.childNodes[endOffset - 1]; + + // "If reference node is a block node or an Element with no children, + // or is neither an Element nor a Text node, break from this loop." + if (isBlockNode(referenceNode) + || (referenceNode.nodeType == $_.Node.ELEMENT_NODE + && !referenceNode.hasChildNodes()) + || (referenceNode.nodeType != $_.Node.ELEMENT_NODE + && referenceNode.nodeType != $_.Node.TEXT_NODE)) { + break; + } + + // "Set end node to reference node and end offset to the length of + // reference node." + endNode = referenceNode; + endOffset = getNodeLength(referenceNode); + } + + // "If (end node, end offset) is not after (start node, start offset), set + // range's end to its start and abort these steps." + if (getPosition(endNode, endOffset, startNode, startOffset) !== "after") { + range.setEnd(range.startContainer, range.startOffset); + return; + } + + // "If start node is a Text node and start offset is 0, set start offset to + // the index of start node, then set start node to its parent." + if (startNode.nodeType == $_.Node.TEXT_NODE + && startOffset == 0 + && startNode != endNode) { +// startOffset = getNodeIndex(startNode); +// startNode = startNode.parentNode; + } + + // "If end node is a Text node and end offset is its length, set end offset + // to one plus the index of end node, then set end node to its parent." + if (endNode.nodeType == $_.Node.TEXT_NODE + && endOffset == getNodeLength(endNode) + && startNode != endNode) { + endOffset = 1 + getNodeIndex(endNode); + endNode = endNode.parentNode; + } + + // "Set range's start to (start node, start offset) and its end to (end + // node, end offset)." + range.setStart(startNode, startOffset); + range.setEnd(endNode, endOffset); + + // "Let start block be the start node of range." + var startBlock = range.startContainer; + + // "While start block's parent is in the same editing host and start block + // is an inline node, set start block to its parent." + while (inSameEditingHost(startBlock, startBlock.parentNode) + && isInlineNode(startBlock)) { + startBlock = startBlock.parentNode; + } + + // "If start block is neither a block node nor an editing host, or "span" + // is not an allowed child of start block, or start block is a td or th, + // set start block to null." + if ((!isBlockNode(startBlock) && !isEditingHost(startBlock)) + || !isAllowedChild("span", startBlock) + || isHtmlElement(startBlock, ["td", "th"])) { + startBlock = null; + } + + // "Let end block be the end node of range." + var endBlock = range.endContainer; + + // "While end block's parent is in the same editing host and end block is + // an inline node, set end block to its parent." + while (inSameEditingHost(endBlock, endBlock.parentNode) + && isInlineNode(endBlock)) { + endBlock = endBlock.parentNode; + } + + // "If end block is neither a block node nor an editing host, or "span" is + // not an allowed child of end block, or end block is a td or th, set end + // block to null." + if ((!isBlockNode(endBlock) && !isEditingHost(endBlock)) + || !isAllowedChild("span", endBlock) + || isHtmlElement(endBlock, ["td", "th"])) { + endBlock = null; + } + + // "Record current states and values, and let overrides be the result." + var overrides = recordCurrentStatesAndValues(range); + // "If start node and end node are the same, and start node is an editable + // Text node:" + if (startNode == endNode + && isEditable(startNode) + && startNode.nodeType == $_.Node.TEXT_NODE) { + // "Let parent be the parent of node." + var parent_ = startNode.parentNode; + + // "Call deleteData(start offset, end offset − start offset) on start + // node." + startNode.deleteData(startOffset, endOffset - startOffset); + + // "Canonicalize whitespace at (start node, start offset)." + canonicalizeWhitespace(startNode, startOffset); + + // "Set range's end to its start." + range.setEnd(range.startContainer, range.startOffset); + + // "Restore states and values from overrides." + restoreStatesAndValues(overrides, range); + + // "If parent is editable or an editing host, is not an inline node, + // and has no children, call createElement("br") on the context object + // and append the result as the last child of parent." + // only do this, if the offsetHeight is 0 + if ((isEditable(parent_) || isEditingHost(parent_)) + && !isInlineNode(parent_) + && parent_.offsetHeight === 0) { + parent_.appendChild(createEndBreak()); + } + + // "Abort these steps." + return; + } + + // "If start node is an editable Text node, call deleteData() on it, with + // start offset as the first argument and (length of start node − start + // offset) as the second argument." + if (isEditable(startNode) + && startNode.nodeType == $_.Node.TEXT_NODE) { + startNode.deleteData(startOffset, getNodeLength(startNode) - startOffset); + } + + // "Let node list be a list of nodes, initially empty." + // + // "For each node contained in range, append node to node list if the last + // member of node list (if any) is not an ancestor of node; node is + // editable; and node is not a thead, tbody, tfoot, tr, th, or td." + var nodeList = getContainedNodes(range, + function(node) { + return isEditable(node) + && !isHtmlElement(node, ["thead", "tbody", "tfoot", "tr", "th", "td"]); + } + ); + + // "For each node in node list:" + for (var i = 0; i < nodeList.length; i++) { + var node = nodeList[i]; + + // "Let parent be the parent of node." + var parent_ = node.parentNode; + + // "Remove node from parent." + parent_.removeChild(node); + + // "If strip wrappers is true or parent is not an ancestor container of + // start node, while parent is an editable inline node with length 0, + // let grandparent be the parent of parent, then remove parent from + // grandparent, then set parent to grandparent." + if (stripWrappers + || (!isAncestor(parent_, startNode) && parent_ != startNode)) { + while (isEditable(parent_) + && isInlineNode(parent_) + && getNodeLength(parent_) == 0) { + var grandparent = parent_.parentNode; + grandparent.removeChild(parent_); + parent_ = grandparent; + } + } + + // "If parent is editable or an editing host, is not an inline node, + // and has no children, call createElement("br") on the context object + // and append the result as the last child of parent." + // only do this, if the offsetHeight is 0 + if ((isEditable(parent_) || isEditingHost(parent_)) + && !isInlineNode(parent_) + && !parent_.hasChildNodes() + && parent_.offsetHeight === 0) { + parent_.appendChild(createEndBreak()); + } + } + + // "If end node is an editable Text node, call deleteData(0, end offset) on + // it." + if (isEditable(endNode) + && endNode.nodeType == $_.Node.TEXT_NODE) { + endNode.deleteData(0, endOffset); + } + + // "Canonicalize whitespace at range's start." + canonicalizeWhitespace(range.startContainer, range.startOffset); + + // "Canonicalize whitespace at range's end." + canonicalizeWhitespace(range.endContainer, range.endOffset); + + // "If block merging is false, or start block or end block is null, or + // start block is not in the same editing host as end block, or start block + // and end block are the same:" + if (!blockMerging + || !startBlock + || !endBlock + || !inSameEditingHost(startBlock, endBlock) + || startBlock == endBlock) { + // "Set range's end to its start." + range.setEnd(range.startContainer, range.startOffset); + + // "Restore states and values from overrides." + restoreStatesAndValues(overrides, range); + + // "Abort these steps." + return; + } + + // "If start block has one child, which is a collapsed block prop, remove + // its child from it." + if (startBlock.children.length == 1 + && isCollapsedBlockProp(startBlock.firstChild)) { + startBlock.removeChild(startBlock.firstChild); + } + + // "If end block has one child, which is a collapsed block prop, remove its + // child from it." + if (endBlock.children.length == 1 + && isCollapsedBlockProp(endBlock.firstChild)) { + endBlock.removeChild(endBlock.firstChild); + } + + // "If start block is an ancestor of end block:" + if (isAncestor(startBlock, endBlock)) { + // "Let reference node be end block." + var referenceNode = endBlock; + + // "While reference node is not a child of start block, set reference + // node to its parent." + while (referenceNode.parentNode != startBlock) { + referenceNode = referenceNode.parentNode; + } + + // "Set the start and end of range to (start block, index of reference + // node)." + range.setStart(startBlock, getNodeIndex(referenceNode)); + range.setEnd(startBlock, getNodeIndex(referenceNode)); + + // "If end block has no children:" + if (!endBlock.hasChildNodes()) { + // "While end block is editable and is the only child of its parent + // and is not a child of start block, let parent equal end block, + // then remove end block from parent, then set end block to + // parent." + while (isEditable(endBlock) + && endBlock.parentNode.childNodes.length == 1 + && endBlock.parentNode != startBlock) { + var parent_ = endBlock; + parent_.removeChild(endBlock); + endBlock = parent_; + } + + // "If end block is editable and is not an inline node, and its + // previousSibling and nextSibling are both inline nodes, call + // createElement("br") on the context object and insert it into end + // block's parent immediately after end block." + + if (isEditable(endBlock) + && !isInlineNode(endBlock) + && isInlineNode(endBlock.previousSibling) + && isInlineNode(endBlock.nextSibling)) { + endBlock.parentNode.insertBefore(document.createElement("br"), endBlock.nextSibling); + } + + // "If end block is editable, remove it from its parent." + if (isEditable(endBlock)) { + endBlock.parentNode.removeChild(endBlock); + } + + // "Restore states and values from overrides." + restoreStatesAndValues(overrides, range); + + // "Abort these steps." + return; + } + + // "If end block's firstChild is not an inline node, restore states and + // values from overrides, then abort these steps." + if (!isInlineNode(endBlock.firstChild)) { + restoreStatesAndValues(overrides, range); + return; + } + + // "Let children be a list of nodes, initially empty." + var children = []; + + // "Append the first child of end block to children." + children.push(endBlock.firstChild); + + // "While children's last member is not a br, and children's last + // member's nextSibling is an inline node, append children's last + // member's nextSibling to children." + while (!isHtmlElement(children[children.length - 1], "br") + && isInlineNode(children[children.length - 1].nextSibling)) { + children.push(children[children.length - 1].nextSibling); + } + + // "Record the values of children, and let values be the result." + var values = recordValues(children); + + // "While children's first member's parent is not start block, split + // the parent of children." + while (children[0].parentNode != startBlock) { + splitParent(children, range); + } + + // "If children's first member's previousSibling is an editable br, + // remove that br from its parent." + if (isEditable(children[0].previousSibling) + && isHtmlElement(children[0].previousSibling, "br")) { + children[0].parentNode.removeChild(children[0].previousSibling); + } + + // "Otherwise, if start block is a descendant of end block:" + } else if (isDescendant(startBlock, endBlock)) { + // "Set the start and end of range to (start block, length of start + // block)." + range.setStart(startBlock, getNodeLength(startBlock)); + range.setEnd(startBlock, getNodeLength(startBlock)); + + // "Let reference node be start block." + var referenceNode = startBlock; + + // "While reference node is not a child of end block, set reference + // node to its parent." + while (referenceNode.parentNode != endBlock) { + referenceNode = referenceNode.parentNode; + } + + // "If reference node's nextSibling is an inline node and start block's + // lastChild is a br, remove start block's lastChild from it." + if (isInlineNode(referenceNode.nextSibling) + && isHtmlElement(startBlock.lastChild, "br")) { + startBlock.removeChild(startBlock.lastChild); + } + + // "Let nodes to move be a list of nodes, initially empty." + var nodesToMove = []; + + // "If reference node's nextSibling is neither null nor a br nor a + // block node, append it to nodes to move." + if (referenceNode.nextSibling + && !isHtmlElement(referenceNode.nextSibling, "br") + && !isBlockNode(referenceNode.nextSibling)) { + nodesToMove.push(referenceNode.nextSibling); + } + + // "While nodes to move is nonempty and its last member's nextSibling + // is neither null nor a br nor a block node, append it to nodes to + // move." + if (nodesToMove.length + && nodesToMove[nodesToMove.length - 1].nextSibling + && !isHtmlElement(nodesToMove[nodesToMove.length - 1].nextSibling, "br") + && !isBlockNode(nodesToMove[nodesToMove.length - 1].nextSibling)) { + nodesToMove.push(nodesToMove[nodesToMove.length - 1].nextSibling); + } + + // "Record the values of nodes to move, and let values be the result." + var values = recordValues(nodesToMove); + + // "For each node in nodes to move, append node as the last child of + // start block, preserving ranges." + $_( nodesToMove ).forEach(function(node) { + movePreservingRanges(node, startBlock, -1, range); + }); + + // "If the nextSibling of reference node is a br, remove it from its + // parent." + if (isHtmlElement(referenceNode.nextSibling, "br")) { + referenceNode.parentNode.removeChild(referenceNode.nextSibling); + } + + // "Otherwise:" + } else { + // "Set the start and end of range to (start block, length of start + // block)." + range.setStart(startBlock, getNodeLength(startBlock)); + range.setEnd(startBlock, getNodeLength(startBlock)); + + // "If end block's firstChild is an inline node and start block's + // lastChild is a br, remove start block's lastChild from it." + if (isInlineNode(endBlock.firstChild) + && isHtmlElement(startBlock.lastChild, "br")) { + startBlock.removeChild(startBlock.lastChild); + } + + // "Record the values of end block's children, and let values be the + // result." + var values = recordValues([].slice.call(toArray(endBlock.childNodes))); + + // "While end block has children, append the first child of end block + // to start block, preserving ranges." + while (endBlock.hasChildNodes()) { + movePreservingRanges(endBlock.firstChild, startBlock, -1, range); + } + + // "While end block has no children, let parent be the parent of end + // block, then remove end block from parent, then set end block to + // parent." + while (!endBlock.hasChildNodes()) { + var parent_ = endBlock.parentNode; + parent_.removeChild(endBlock); + endBlock = parent_; + } + } + + // "Restore the values from values." + restoreValues(values, range); + + // "If start block has no children, call createElement("br") on the context + // object and append the result as the last child of start block." + if (!startBlock.hasChildNodes() && startBlock.offsetHeight == 0) { + startBlock.appendChild(createEndBreak()); + } + + // "Restore states and values from overrides." + restoreStatesAndValues(overrides, range); +} + + +//@} +///// Splitting a node list's parent ///// +//@{ + +function splitParent(nodeList, range) { + // "Let original parent be the parent of the first member of node list." + var originalParent = nodeList[0].parentNode; + + // "If original parent is not editable or its parent is null, do nothing + // and abort these steps." + if (!isEditable(originalParent) + || !originalParent.parentNode) { + return; + } + + // "If the first child of original parent is in node list, remove + // extraneous line breaks before original parent." + if ($_(nodeList).indexOf(originalParent.firstChild) != -1) { + removeExtraneousLineBreaksBefore(originalParent); + } + + // "If the first child of original parent is in node list, and original + // parent follows a line break, set follows line break to true. Otherwise, + // set follows line break to false." + var followsLineBreak_ = $_(nodeList).indexOf(originalParent.firstChild) != -1 + && followsLineBreak(originalParent); + + // "If the last child of original parent is in node list, and original + // parent precedes a line break, set precedes line break to true. + // Otherwise, set precedes line break to false." + var precedesLineBreak_ = $_(nodeList).indexOf(originalParent.lastChild) != -1 + && precedesLineBreak(originalParent); + + // "If the first child of original parent is not in node list, but its last + // child is:" + if ($_(nodeList).indexOf(originalParent.firstChild) == -1 + && $_(nodeList).indexOf(originalParent.lastChild) != -1) { + // "For each node in node list, in reverse order, insert node into the + // parent of original parent immediately after original parent, + // preserving ranges." + for (var i = nodeList.length - 1; i >= 0; i--) { + movePreservingRanges(nodeList[i], originalParent.parentNode, 1 + getNodeIndex(originalParent), range); + } + + // "If precedes line break is true, and the last member of node list + // does not precede a line break, call createElement("br") on the + // context object and insert the result immediately after the last + // member of node list." + if (precedesLineBreak_ + && !precedesLineBreak(nodeList[nodeList.length - 1])) { + nodeList[nodeList.length - 1].parentNode.insertBefore(document.createElement("br"), nodeList[nodeList.length - 1].nextSibling); + } + + // "Remove extraneous line breaks at the end of original parent." + removeExtraneousLineBreaksAtTheEndOf(originalParent); + + // "Abort these steps." + return; + } + + // "If the first child of original parent is not in node list:" + if ($_(nodeList).indexOf(originalParent.firstChild) == -1) { + // "Let cloned parent be the result of calling cloneNode(false) on + // original parent." + var clonedParent = originalParent.cloneNode(false); + + // "If original parent has an id attribute, unset it." + originalParent.removeAttribute("id"); + + // "Insert cloned parent into the parent of original parent immediately + // before original parent." + originalParent.parentNode.insertBefore(clonedParent, originalParent); + + // "While the previousSibling of the first member of node list is not + // null, append the first child of original parent as the last child of + // cloned parent, preserving ranges." + while (nodeList[0].previousSibling) { + movePreservingRanges(originalParent.firstChild, clonedParent, clonedParent.childNodes.length, range); + } + } + + // "For each node in node list, insert node into the parent of original + // parent immediately before original parent, preserving ranges." + for (var i = 0; i < nodeList.length; i++) { + movePreservingRanges(nodeList[i], originalParent.parentNode, getNodeIndex(originalParent), range); + } + + // "If follows line break is true, and the first member of node list does + // not follow a line break, call createElement("br") on the context object + // and insert the result immediately before the first member of node list." + if (followsLineBreak_ + && !followsLineBreak(nodeList[0])) { + nodeList[0].parentNode.insertBefore(document.createElement("br"), nodeList[0]); + } + + // "If the last member of node list is an inline node other than a br, and + // the first child of original parent is a br, and original parent is not + // an inline node, remove the first child of original parent from original + // parent." + if (isInlineNode(nodeList[nodeList.length - 1]) + && !isHtmlElement(nodeList[nodeList.length - 1], "br") + && isHtmlElement(originalParent.firstChild, "br") + && !isInlineNode(originalParent)) { + originalParent.removeChild(originalParent.firstChild); + } + + // "If original parent has no children:" + if (!originalParent.hasChildNodes()) { + // if the current range is collapsed and at the end of the originalParent.parentNode + // the offset will not be available anymore after the next step (remove child) + // that's why we need to fix the range to prevent a bogus offset + if (originalParent.parentNode === range.startContainer + && originalParent.parentNode === range.endContainer + && range.startContainer === range.endContainer + && range.startOffset === range.endOffset + && originalParent.parentNode.childNodes.length === range.startOffset) { + range.startOffset = originalParent.parentNode.childNodes.length - 1; + range.endOffset = range.startOffset; + } + + // "Remove original parent from its parent." + originalParent.parentNode.removeChild(originalParent); + + // "If precedes line break is true, and the last member of node list + // does not precede a line break, call createElement("br") on the + // context object and insert the result immediately after the last + // member of node list." + if (precedesLineBreak_ + && !precedesLineBreak(nodeList[nodeList.length - 1])) { + nodeList[nodeList.length - 1].parentNode.insertBefore(document.createElement("br"), nodeList[nodeList.length - 1].nextSibling); + } + + // "Otherwise, remove extraneous line breaks before original parent." + } else { + removeExtraneousLineBreaksBefore(originalParent); + } + + // "If node list's last member's nextSibling is null, but its parent is not + // null, remove extraneous line breaks at the end of node list's last + // member's parent." + if (!nodeList[nodeList.length - 1].nextSibling + && nodeList[nodeList.length - 1].parentNode) { + removeExtraneousLineBreaksAtTheEndOf(nodeList[nodeList.length - 1].parentNode); + } +} + +// "To remove a node node while preserving its descendants, split the parent of +// node's children if it has any. If it has no children, instead remove it from +// its parent." +function removePreservingDescendants(node, range) { + if (node.hasChildNodes()) { + splitParent([].slice.call(toArray(node.childNodes)), range); + } else { + node.parentNode.removeChild(node); + } +} + + +//@} +///// Canonical space sequences ///// +//@{ + +function canonicalSpaceSequence(n, nonBreakingStart, nonBreakingEnd) { + // "If n is zero, return the empty string." + if (n == 0) { + return ""; + } + + // "If n is one and both non-breaking start and non-breaking end are false, + // return a single space (U+0020)." + if (n == 1 && !nonBreakingStart && !nonBreakingEnd) { + return " "; + } + + // "If n is one, return a single non-breaking space (U+00A0)." + if (n == 1) { + return "\xa0"; + } + + // "Let buffer be the empty string." + var buffer = ""; + + // "If non-breaking start is true, let repeated pair be U+00A0 U+0020. + // Otherwise, let it be U+0020 U+00A0." + var repeatedPair; + if (nonBreakingStart) { + repeatedPair = "\xa0 "; + } else { + repeatedPair = " \xa0"; + } + + // "While n is greater than three, append repeated pair to buffer and + // subtract two from n." + while (n > 3) { + buffer += repeatedPair; + n -= 2; + } + + // "If n is three, append a three-element string to buffer depending on + // non-breaking start and non-breaking end:" + if (n == 3) { + buffer += + !nonBreakingStart && !nonBreakingEnd ? " \xa0 " + : nonBreakingStart && !nonBreakingEnd ? "\xa0\xa0 " + : !nonBreakingStart && nonBreakingEnd ? " \xa0\xa0" + : nonBreakingStart && nonBreakingEnd ? "\xa0 \xa0" + : "impossible"; + + // "Otherwise, append a two-element string to buffer depending on + // non-breaking start and non-breaking end:" + } else { + buffer += + !nonBreakingStart && !nonBreakingEnd ? "\xa0 " + : nonBreakingStart && !nonBreakingEnd ? "\xa0 " + : !nonBreakingStart && nonBreakingEnd ? " \xa0" + : nonBreakingStart && nonBreakingEnd ? "\xa0\xa0" + : "impossible"; + } + + // "Return buffer." + return buffer; +} + +function canonicalizeWhitespace(node, offset) { + // "If node is neither editable nor an editing host, abort these steps." + if (!isEditable(node) && !isEditingHost(node)) { + return; + } + + // "Let start node equal node and let start offset equal offset." + var startNode = node; + var startOffset = offset; + + // "Repeat the following steps:" + while (true) { + // "If start node has a child in the same editing host with index start + // offset minus one, set start node to that child, then set start + // offset to start node's length." + if (0 <= startOffset - 1 + && inSameEditingHost(startNode, startNode.childNodes[startOffset - 1])) { + startNode = startNode.childNodes[startOffset - 1]; + startOffset = getNodeLength(startNode); + + // "Otherwise, if start offset is zero and start node does not follow a + // line break and start node's parent is in the same editing host, set + // start offset to start node's index, then set start node to its + // parent." + } else if (startOffset == 0 + && !followsLineBreak(startNode) + && inSameEditingHost(startNode, startNode.parentNode)) { + startOffset = getNodeIndex(startNode); + startNode = startNode.parentNode; + + // "Otherwise, if start node is a Text node and its parent's resolved + // value for "white-space" is neither "pre" nor "pre-wrap" and start + // offset is not zero and the (start offset − 1)st element of start + // node's data is a space (0x0020) or non-breaking space (0x00A0), + // subtract one from start offset." + } else if (startNode.nodeType == $_.Node.TEXT_NODE + && $_(["pre", "pre-wrap"]).indexOf($_.getComputedStyle(startNode.parentNode).whiteSpace) == -1 + && startOffset != 0 + && /[ \xa0]/.test(startNode.data[startOffset - 1])) { + startOffset--; + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // "Let end node equal start node and end offset equal start offset." + var endNode = startNode; + var endOffset = startOffset; + + // "Let length equal zero." + var length = 0; + + // "Let follows space be false." + var followsSpace = false; + + // "Repeat the following steps:" + while (true) { + // "If end node has a child in the same editing host with index end + // offset, set end node to that child, then set end offset to zero." + if (endOffset < endNode.childNodes.length + && inSameEditingHost(endNode, endNode.childNodes[endOffset])) { + endNode = endNode.childNodes[endOffset]; + endOffset = 0; + + // "Otherwise, if end offset is end node's length and end node does not + // precede a line break and end node's parent is in the same editing + // host, set end offset to one plus end node's index, then set end node + // to its parent." + } else if (endOffset == getNodeLength(endNode) + && !precedesLineBreak(endNode) + && inSameEditingHost(endNode, endNode.parentNode)) { + endOffset = 1 + getNodeIndex(endNode); + endNode = endNode.parentNode; + + // "Otherwise, if end node is a Text node and its parent's resolved + // value for "white-space" is neither "pre" nor "pre-wrap" and end + // offset is not end node's length and the end offsetth element of + // end node's data is a space (0x0020) or non-breaking space (0x00A0):" + } else if (endNode.nodeType == $_.Node.TEXT_NODE + && $_(["pre", "pre-wrap"]).indexOf($_.getComputedStyle(endNode.parentNode).whiteSpace) == -1 + && endOffset != getNodeLength(endNode) + && /[ \xa0]/.test(endNode.data[endOffset])) { + // "If follows space is true and the end offsetth element of end + // node's data is a space (0x0020), call deleteData(end offset, 1) + // on end node, then continue this loop from the beginning." + if (followsSpace + && " " == endNode.data[endOffset]) { + endNode.deleteData(endOffset, 1); + continue; + } + + // "Set follows space to true if the end offsetth element of end + // node's data is a space (0x0020), false otherwise." + followsSpace = " " == endNode.data[endOffset]; + + // "Add one to end offset." + endOffset++; + + // "Add one to length." + length++; + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // "Let replacement whitespace be the canonical space sequence of length + // length. non-breaking start is true if start offset is zero and start + // node follows a line break, and false otherwise. non-breaking end is true + // if end offset is end node's length and end node precedes a line break, + // and false otherwise." + var replacementWhitespace = canonicalSpaceSequence(length, + startOffset == 0 && followsLineBreak(startNode), + endOffset == getNodeLength(endNode) && precedesLineBreak(endNode)); + + // "While (start node, start offset) is before (end node, end offset):" + while (getPosition(startNode, startOffset, endNode, endOffset) == "before") { + // "If start node has a child with index start offset, set start node + // to that child, then set start offset to zero." + if (startOffset < startNode.childNodes.length) { + startNode = startNode.childNodes[startOffset]; + startOffset = 0; + + // "Otherwise, if start node is not a Text node or if start offset is + // start node's length, set start offset to one plus start node's + // index, then set start node to its parent." + } else if (startNode.nodeType != $_.Node.TEXT_NODE + || startOffset == getNodeLength(startNode)) { + startOffset = 1 + getNodeIndex(startNode); + startNode = startNode.parentNode; + + // "Otherwise:" + } else { + // "Remove the first element from replacement whitespace, and let + // element be that element." + var element = replacementWhitespace[0]; + replacementWhitespace = replacementWhitespace.slice(1); + + // "If element is not the same as the start offsetth element of + // start node's data:" + if (element != startNode.data[startOffset]) { + // "Call insertData(start offset, element) on start node." + startNode.insertData(startOffset, element); + + // "Call deleteData(start offset + 1, 1) on start node." + startNode.deleteData(startOffset + 1, 1); + } + + // "Add one to start offset." + startOffset++; + } + } +} + + +//@} +///// Indenting and outdenting ///// +//@{ + +function indentNodes(nodeList, range) { + // "If node list is empty, do nothing and abort these steps." + if (!nodeList.length) { + return; + } + + // "Let first node be the first member of node list." + var firstNode = nodeList[0]; + + // "If first node's parent is an ol or ul:" + if (isHtmlElement(firstNode.parentNode, ["OL", "UL"])) { + // "Let tag be the local name of the parent of first node." + var tag = firstNode.parentNode.tagName; + + // "Wrap node list, with sibling criteria returning true for an HTML + // element with local name tag and false otherwise, and new parent + // instructions returning the result of calling createElement(tag) on + // the ownerDocument of first node." + wrap(nodeList, + function(node) { return isHtmlElement(node, tag) }, + function() { return firstNode.ownerDocument.createElement(tag) }, + range + ); + + // "Abort these steps." + return; + } + + // "Wrap node list, with sibling criteria returning true for a simple + // indentation element and false otherwise, and new parent instructions + // returning the result of calling createElement("blockquote") on the + // ownerDocument of first node. Let new parent be the result." + var newParent = wrap(nodeList, + function(node) { return isSimpleIndentationElement(node) }, + function() { return firstNode.ownerDocument.createElement("blockquote") }, + range + ); + + // "Fix disallowed ancestors of new parent." + fixDisallowedAncestors(newParent, range); +} + +function outdentNode(node, range) { + // "If node is not editable, abort these steps." + if (!isEditable(node)) { + return; + } + + // "If node is a simple indentation element, remove node, preserving its + // descendants. Then abort these steps." + if (isSimpleIndentationElement(node)) { + removePreservingDescendants(node, range); + return; + } + + // "If node is an indentation element:" + if (isIndentationElement(node)) { + // "Unset the class and dir attributes of node, if any." + node.removeAttribute("class"); + node.removeAttribute("dir"); + + // "Unset the margin, padding, and border CSS properties of node." + node.style.margin = ""; + node.style.padding = ""; + node.style.border = ""; + if (node.getAttribute("style") == "") { + node.removeAttribute("style"); + } + + // "Set the tag name of node to "div"." + setTagName(node, "div", range); + + // "Abort these steps." + return; + } + + // "Let current ancestor be node's parent." + var currentAncestor = node.parentNode; + + // "Let ancestor list be a list of nodes, initially empty." + var ancestorList = []; + + // "While current ancestor is an editable Element that is neither a simple + // indentation element nor an ol nor a ul, append current ancestor to + // ancestor list and then set current ancestor to its parent." + while (isEditable(currentAncestor) + && currentAncestor.nodeType == $_.Node.ELEMENT_NODE + && !isSimpleIndentationElement(currentAncestor) + && !isHtmlElement(currentAncestor, ["ol", "ul"])) { + ancestorList.push(currentAncestor); + currentAncestor = currentAncestor.parentNode; + } + + // "If current ancestor is not an editable simple indentation element:" + if (!isEditable(currentAncestor) + || !isSimpleIndentationElement(currentAncestor)) { + // "Let current ancestor be node's parent." + currentAncestor = node.parentNode; + + // "Let ancestor list be the empty list." + ancestorList = []; + + // "While current ancestor is an editable Element that is neither an + // indentation element nor an ol nor a ul, append current ancestor to + // ancestor list and then set current ancestor to its parent." + while (isEditable(currentAncestor) + && currentAncestor.nodeType == $_.Node.ELEMENT_NODE + && !isIndentationElement(currentAncestor) + && !isHtmlElement(currentAncestor, ["ol", "ul"])) { + ancestorList.push(currentAncestor); + currentAncestor = currentAncestor.parentNode; + } + } + + // "If node is an ol or ul and current ancestor is not an editable + // indentation element:" + if (isHtmlElement(node, ["OL", "UL"]) + && (!isEditable(currentAncestor) + || !isIndentationElement(currentAncestor))) { + // "Unset the reversed, start, and type attributes of node, if any are + // set." + node.removeAttribute("reversed"); + node.removeAttribute("start"); + node.removeAttribute("type"); + + // "Let children be the children of node." + var children = [].slice.call(toArray(node.childNodes)); + + // "If node has attributes, and its parent is not an ol or ul, set the + // tag name of node to "div"." + if (node.attributes.length + && !isHtmlElement(node.parentNode, ["OL", "UL"])) { + setTagName(node, "div", range); + + // "Otherwise:" + } else { + // "Record the values of node's children, and let values be the + // result." + var values = recordValues([].slice.call(toArray(node.childNodes))); + + // "Remove node, preserving its descendants." + removePreservingDescendants(node, range); + + // "Restore the values from values." + restoreValues(values, range); + } + + // "Fix disallowed ancestors of each member of children." + for (var i = 0; i < children.length; i++) { + fixDisallowedAncestors(children[i], range); + } + + // "Abort these steps." + return; + } + + // "If current ancestor is not an editable indentation element, abort these + // steps." + if (!isEditable(currentAncestor) + || !isIndentationElement(currentAncestor)) { + return; + } + + // "Append current ancestor to ancestor list." + ancestorList.push(currentAncestor); + + // "Let original ancestor be current ancestor." + var originalAncestor = currentAncestor; + + // "While ancestor list is not empty:" + while (ancestorList.length) { + // "Let current ancestor be the last member of ancestor list." + // + // "Remove the last member of ancestor list." + currentAncestor = ancestorList.pop(); + + // "Let target be the child of current ancestor that is equal to either + // node or the last member of ancestor list." + var target = node.parentNode == currentAncestor + ? node + : ancestorList[ancestorList.length - 1]; + + // "If target is an inline node that is not a br, and its nextSibling + // is a br, remove target's nextSibling from its parent." + if (isInlineNode(target) + && !isHtmlElement(target, "BR") + && isHtmlElement(target.nextSibling, "BR")) { + target.parentNode.removeChild(target.nextSibling); + } + + // "Let preceding siblings be the preceding siblings of target, and let + // following siblings be the following siblings of target." + var precedingSiblings = [].slice.call(toArray(currentAncestor.childNodes), 0, getNodeIndex(target)); + var followingSiblings = [].slice.call(toArray(currentAncestor.childNodes), 1 + getNodeIndex(target)); + + // "Indent preceding siblings." + indentNodes(precedingSiblings, range); + + // "Indent following siblings." + indentNodes(followingSiblings, range); + } + + // "Outdent original ancestor." + outdentNode(originalAncestor, range); +} + + +//@} +///// Toggling lists ///// +//@{ + +function toggleLists(tagName, range) { + // "Let mode be "disable" if the selection's list state is tag name, and + // "enable" otherwise." + var mode = getSelectionListState() == tagName ? "disable" : "enable"; + + tagName = tagName.toUpperCase(); + + // "Let other tag name be "ol" if tag name is "ul", and "ul" if tag name is + // "ol"." + var otherTagName = tagName == "OL" ? "UL" : "OL"; + + // "Let items be a list of all lis that are ancestor containers of the + // range's start and/or end node." + // + // It's annoying to get this in tree order using functional stuff without + // doing getDescendants(document), which is slow, so I do it imperatively. + var items = []; + (function(){ + for ( + var ancestorContainer = range.endContainer; + ancestorContainer != range.commonAncestorContainer; + ancestorContainer = ancestorContainer.parentNode + ) { + if (isHtmlElement(ancestorContainer, "li")) { + items.unshift(ancestorContainer); + } + } + for ( + var ancestorContainer = range.startContainer; + ancestorContainer; + ancestorContainer = ancestorContainer.parentNode + ) { + if (isHtmlElement(ancestorContainer, "li")) { + items.unshift(ancestorContainer); + } + } + })(); + + // "For each item in items, normalize sublists of item." + $_( items ).forEach( function( thisArg ) { + normalizeSublists( thisArg, range); + }); + + // "Block-extend the range, and let new range be the result." + var newRange = blockExtend(range); + + // "If mode is "enable", then let lists to convert consist of every + // editable HTML element with local name other tag name that is contained + // in new range, and for every list in lists to convert:" + if (mode == "enable") { + $_( getAllContainedNodes(newRange, function(node) { + return isEditable(node) + && isHtmlElement(node, otherTagName); + }) ).forEach(function(list) { + // "If list's previousSibling or nextSibling is an editable HTML + // element with local name tag name:" + if ((isEditable(list.previousSibling) && isHtmlElement(list.previousSibling, tagName)) + || (isEditable(list.nextSibling) && isHtmlElement(list.nextSibling, tagName))) { + // "Let children be list's children." + var children = [].slice.call(toArray(list.childNodes)); + + // "Record the values of children, and let values be the + // result." + var values = recordValues(children); + + // "Split the parent of children." + splitParent(children, range); + + // "Wrap children, with sibling criteria returning true for an + // HTML element with local name tag name and false otherwise." + wrap(children, + function(node) { return isHtmlElement(node, tagName) }, + function() {return null }, + range + ); + + // "Restore the values from values." + restoreValues(values, range); + + // "Otherwise, set the tag name of list to tag name." + } else { + setTagName(list, tagName, range); + } + }); + } + + // "Let node list be a list of nodes, initially empty." + // + // "For each node node contained in new range, if node is editable; the + // last member of node list (if any) is not an ancestor of node; node + // is not an indentation element; and either node is an ol or ul, or its + // parent is an ol or ul, or it is an allowed child of "li"; then append + // node to node list." + var nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && !isIndentationElement(node) + && (isHtmlElement(node, ["OL", "UL"]) + || isHtmlElement(node.parentNode, ["OL", "UL"]) + || isAllowedChild(node, "li")); + }); + + // "If mode is "enable", remove from node list any ol or ul whose parent is + // not also an ol or ul." + if (mode == "enable") { + nodeList = $_( nodeList ).filter(function(node) { + return !isHtmlElement(node, ["ol", "ul"]) + || isHtmlElement(node.parentNode, ["ol", "ul"]); + }); + } + + // "If mode is "disable", then while node list is not empty:" + if (mode == "disable") { + while (nodeList.length) { + // "Let sublist be an empty list of nodes." + var sublist = []; + + // "Remove the first member from node list and append it to + // sublist." + sublist.push(nodeList.shift()); + + // "If the first member of sublist is an HTML element with local + // name tag name, outdent it and continue this loop from the + // beginning." + if (isHtmlElement(sublist[0], tagName)) { + outdentNode(sublist[0], range); + continue; + } + + // "While node list is not empty, and the first member of node list + // is the nextSibling of the last member of sublist and is not an + // HTML element with local name tag name, remove the first member + // from node list and append it to sublist." + while (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling + && !isHtmlElement(nodeList[0], tagName)) { + sublist.push(nodeList.shift()); + } + + // "Record the values of sublist, and let values be the result." + var values = recordValues(sublist); + + // "Split the parent of sublist." + splitParent(sublist, range); + + // "Fix disallowed ancestors of each member of sublist." + for (var i = 0; i < sublist.length; i++) { + fixDisallowedAncestors(sublist[i], range); + } + + // "Restore the values from values." + restoreValues(values, range); + } + + // "Otherwise, while node list is not empty:" + } else { + while (nodeList.length) { + // "Let sublist be an empty list of nodes." + var sublist = []; + + // "While either sublist is empty, or node list is not empty and + // its first member is the nextSibling of sublist's last member:" + while (!sublist.length + || (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling)) { + // "If node list's first member is a p or div, set the tag name + // of node list's first member to "li", and append the result + // to sublist. Remove the first member from node list." + if (isHtmlElement(nodeList[0], ["p", "div"])) { + sublist.push(setTagName(nodeList[0], "li", range)); + nodeList.shift(); + + // "Otherwise, if the first member of node list is an li or ol + // or ul, remove it from node list and append it to sublist." + } else if (isHtmlElement(nodeList[0], ["li", "ol", "ul"])) { + sublist.push(nodeList.shift()); + + // "Otherwise:" + } else { + // "Let nodes to wrap be a list of nodes, initially empty." + var nodesToWrap = []; + + // "While nodes to wrap is empty, or node list is not empty + // and its first member is the nextSibling of nodes to + // wrap's last member and the first member of node list is + // an inline node and the last member of nodes to wrap is + // an inline node other than a br, remove the first member + // from node list and append it to nodes to wrap." + while (!nodesToWrap.length + || (nodeList.length + && nodeList[0] == nodesToWrap[nodesToWrap.length - 1].nextSibling + && isInlineNode(nodeList[0]) + && isInlineNode(nodesToWrap[nodesToWrap.length - 1]) + && !isHtmlElement(nodesToWrap[nodesToWrap.length - 1], "br"))) { + nodesToWrap.push(nodeList.shift()); + } + + // "Wrap nodes to wrap, with new parent instructions + // returning the result of calling createElement("li") on + // the context object. Append the result to sublist." + sublist.push( + wrap(nodesToWrap, + undefined, + function() { return document.createElement("li") }, + range + ) + ); + } + } + + // "If sublist's first member's parent is an HTML element with + // local name tag name, or if every member of sublist is an ol or + // ul, continue this loop from the beginning." + if (isHtmlElement(sublist[0].parentNode, tagName) + || $_(sublist).every(function(node) { return isHtmlElement(node, ["ol", "ul"]) })) { + continue; + } + + // "If sublist's first member's parent is an HTML element with + // local name other tag name:" + if (isHtmlElement(sublist[0].parentNode, otherTagName)) { + // "Record the values of sublist, and let values be the + // result." + var values = recordValues(sublist); + + // "Split the parent of sublist." + splitParent(sublist, range); + + // "Wrap sublist, with sibling criteria returning true for an + // HTML element with local name tag name and false otherwise, + // and new parent instructions returning the result of calling + // createElement(tag name) on the context object." + wrap(sublist, + function(node) { return isHtmlElement(node, tagName) }, + function() { return document.createElement(tagName) }, + range + ); + + // "Restore the values from values." + restoreValues(values, range); + + // "Continue this loop from the beginning." + continue; + } + + // "Wrap sublist, with sibling criteria returning true for an HTML + // element with local name tag name and false otherwise, and new + // parent instructions being the following:" + // . . . + // "Fix disallowed ancestors of the previous step's result." + fixDisallowedAncestors( + wrap(sublist, + function(node) { return isHtmlElement(node, tagName) }, + function() { + // "If sublist's first member's parent is not an editable + // simple indentation element, or sublist's first member's + // parent's previousSibling is not an editable HTML element + // with local name tag name, call createElement(tag name) + // on the context object and return the result." + if (!isEditable(sublist[0].parentNode) + || !isSimpleIndentationElement(sublist[0].parentNode) + || !isEditable(sublist[0].parentNode.previousSibling) + || !isHtmlElement(sublist[0].parentNode.previousSibling, tagName)) { + return document.createElement(tagName); + } + + // "Let list be sublist's first member's parent's + // previousSibling." + var list = sublist[0].parentNode.previousSibling; + + // "Normalize sublists of list's lastChild." + normalizeSublists(list.lastChild, range); + + // "If list's lastChild is not an editable HTML element + // with local name tag name, call createElement(tag name) + // on the context object, and append the result as the last + // child of list." + if (!isEditable(list.lastChild) + || !isHtmlElement(list.lastChild, tagName)) { + list.appendChild(document.createElement(tagName)); + } + + // "Return the last child of list." + return list.lastChild; + }, + range + ) + , range + ); + } + } +} + + +//@} +///// Justifying the selection ///// +//@{ + +function justifySelection(alignment, range) { + + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(range); + + // "Let element list be a list of all editable Elements contained in new + // range that either has an attribute in the HTML namespace whose local + // name is "align", or has a style attribute that sets "text-align", or is + // a center." + var elementList = getAllContainedNodes(newRange, function(node) { + return node.nodeType == $_.Node.ELEMENT_NODE + && isEditable(node) + // Ignoring namespaces here + && ( + $_( node ).hasAttribute("align") + || node.style.textAlign != "" + || isHtmlElement(node, "center") + ); + }); + + // "For each element in element list:" + for (var i = 0; i < elementList.length; i++) { + var element = elementList[i]; + + // "If element has an attribute in the HTML namespace whose local name + // is "align", remove that attribute." + element.removeAttribute("align"); + + // "Unset the CSS property "text-align" on element, if it's set by a + // style attribute." + element.style.textAlign = ""; + if (element.getAttribute("style") == "") { + element.removeAttribute("style"); + } + + // "If element is a div or span or center with no attributes, remove + // it, preserving its descendants." + if (isHtmlElement(element, ["div", "span", "center"]) + && !element.attributes.length) { + removePreservingDescendants(element, range); + } + + // "If element is a center with one or more attributes, set the tag + // name of element to "div"." + if (isHtmlElement(element, "center") + && element.attributes.length) { + setTagName(element, "div", range); + } + } + + // "Block-extend the active range, and let new range be the result." + newRange = blockExtend(globalRange); + + // "Let node list be a list of nodes, initially empty." + var nodeList = []; + + // "For each node node contained in new range, append node to node list if + // the last member of node list (if any) is not an ancestor of node; node + // is editable; node is an allowed child of "div"; and node's alignment + // value is not alignment." + nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && isAllowedChild(node, "div") + && getAlignmentValue(node) != alignment; + }); + + // "While node list is not empty:" + while (nodeList.length) { + // "Let sublist be a list of nodes, initially empty." + var sublist = []; + + // "Remove the first member of node list and append it to sublist." + sublist.push(nodeList.shift()); + + // "While node list is not empty, and the first member of node list is + // the nextSibling of the last member of sublist, remove the first + // member of node list and append it to sublist." + while (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling) { + sublist.push(nodeList.shift()); + } + + // "Wrap sublist. Sibling criteria returns true for any div that has + // one or both of the following two attributes and no other attributes, + // and false otherwise:" + // + // * "An align attribute whose value is an ASCII case-insensitive + // match for alignment. + // * "A style attribute which sets exactly one CSS property + // (including unrecognized or invalid attributes), which is + // "text-align", which is set to alignment. + // + // "New parent instructions are to call createElement("div") on the + // context object, then set its CSS property "text-align" to alignment + // and return the result." + wrap(sublist, + function(node) { + return isHtmlElement(node, "div") + && $_(node.attributes).every(function(attr) { + return (attr.name == "align" && attr.value.toLowerCase() == alignment) + || (attr.name == "style" && getStyleLength(node) == 1 && node.style.textAlign == alignment); + }); + }, + function() { + var newParent = document.createElement("div"); + newParent.setAttribute("style", "text-align: " + alignment); + return newParent; + }, + range + ); + } +} + + +//@} +///// Create an end break ///// +//@{ +function createEndBreak() { + var endBr = document.createElement("br"); + endBr.setAttribute("class", "aloha-end-br"); + return endBr; +} + + +//@} +///// The delete command ///// +//@{ +commands["delete"] = { + action: function(value, range) { + // "If the active range is not collapsed, delete the contents of the + // active range and abort these steps." + if (!range.collapsed) { + deleteContents(range); + return; + } + + // "Canonicalize whitespace at (active range's start node, active + // range's start offset)." + canonicalizeWhitespace(range.startContainer, range.startOffset); + + // "Let node and offset be the active range's start node and offset." + var node = range.startContainer; + var offset = range.startOffset; + var isBr = false; + var isHr = false; + + // "Repeat the following steps:" + while ( true ) { + // we need to reset isBr and isHr on every interation of the loop + if ( offset > 0 ) { + isBr = isHtmlElement(node.childNodes[offset - 1], "br") || false; + isHr = isHtmlElement(node.childNodes[offset - 1], "hr") || false; + } + + // "If offset is zero and node's previousSibling is an editable + // invisible node, remove node's previousSibling from its parent." + if (offset == 0 + && isEditable(node.previousSibling) + && isInvisible(node.previousSibling)) { + node.parentNode.removeChild(node.previousSibling); + + // "Otherwise, if node has a child with index offset − 1 and that + // child is an editable invisible node, remove that child from + // node, then subtract one from offset." + } else if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && isEditable(node.childNodes[offset - 1]) + && (isInvisible(node.childNodes[offset - 1]) || isBr || isHr )) { + node.removeChild(node.childNodes[offset - 1]); + offset--; + if (isBr || isHr) { + range.setStart(node, offset); + range.setEnd(node, offset); + return; + } + + // "Otherwise, if offset is zero and node is an inline node, or if + // node is an invisible node, set offset to the index of node, then + // set node to its parent." + } else if ((offset == 0 + && isInlineNode(node)) + || isInvisible(node)) { + offset = getNodeIndex(node); + node = node.parentNode; + + // "Otherwise, if node has a child with index offset − 1 and that + // child is an editable a, remove that child from node, preserving + // its descendants. Then abort these steps." + } else if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && isEditable(node.childNodes[offset - 1]) + && isHtmlElement(node.childNodes[offset - 1], "a")) { + removePreservingDescendants(node.childNodes[offset - 1], range); + return; + + // "Otherwise, if node has a child with index offset − 1 and that + // child is not a block node or a br or an img, set node to that + // child, then set offset to the length of node." + } else if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && !isBlockNode(node.childNodes[offset - 1]) + && !isHtmlElement(node.childNodes[offset - 1], ["br", "img"])) { + node = node.childNodes[offset - 1]; + offset = getNodeLength(node); + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // collapse whitespace sequences + collapseWhitespace(node, range); + + // "If node is a Text node and offset is not zero, call collapse(node, + // offset) on the Selection. Then delete the contents of the range with + // start (node, offset − 1) and end (node, offset) and abort these + // steps." + if (node.nodeType == $_.Node.TEXT_NODE + && offset != 0) { + range.setStart(node, offset); + range.setEnd(node, offset); + // fix range start container offset according to old code + // so we can still pass our range and have it modified, but + // also conform with the previous implementation + range.startOffset -= 1; + deleteContents(range); + return; + } + + // "If node is an inline node, abort these steps." + if (isInlineNode(node)) { + return; + } + + // "If node has a child with index offset − 1 and that child is a br or + // hr or img, call collapse(node, offset) on the Selection. Then delete + // the contents of the range with start (node, offset − 1) and end + // (node, offset) and abort these steps." + if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && isHtmlElement(node.childNodes[offset - 1], ["br", "hr", "img"])) { + range.setStart(node, offset); + range.setEnd(node, offset); + deleteContents(range); + return; + } + + // "If node is an li or dt or dd and is the first child of its parent, + // and offset is zero:" + if (isHtmlElement(node, ["li", "dt", "dd"]) + && node == node.parentNode.firstChild + && offset == 0) { + // "Let items be a list of all lis that are ancestors of node." + // + // Remember, must be in tree order. + var items = []; + for (var ancestor = node.parentNode; ancestor; ancestor = ancestor.parentNode) { + if (isHtmlElement(ancestor, "li")) { + items.unshift(ancestor); + } + } + + // "Normalize sublists of each item in items." + for (var i = 0; i < items.length; i++) { + normalizeSublists(items[i], range); + } + + // "Record the values of the one-node list consisting of node, and + // let values be the result." + var values = recordValues([node]); + + // "Split the parent of the one-node list consisting of node." + splitParent([node], range); + + // "Restore the values from values." + restoreValues(values, range); + + // "If node is a dd or dt, and it is not an allowed child of any of + // its ancestors in the same editing host, set the tag name of node + // to the default single-line container name and let node be the + // result." + if (isHtmlElement(node, ["dd", "dt"]) + && $_(getAncestors(node)).every(function(ancestor) { + return !inSameEditingHost(node, ancestor) + || !isAllowedChild(node, ancestor) + })) { + node = setTagName(node, defaultSingleLineContainerName, range); + } + + // "Fix disallowed ancestors of node." + fixDisallowedAncestors(node, range); + + // fix the lists to be html5 conformant + for (var i = 0; i < items.length; i++) { + unNormalizeSublists(items[i].parentNode, range); + } + + // "Abort these steps." + return; + } + + // "Let start node equal node and let start offset equal offset." + var startNode = node; + var startOffset = offset; + + // "Repeat the following steps:" + while (true) { + // "If start offset is zero, set start offset to the index of start + // node and then set start node to its parent." + if (startOffset == 0) { + startOffset = getNodeIndex(startNode); + startNode = startNode.parentNode; + + // "Otherwise, if start node has an editable invisible child with + // index start offset minus one, remove it from start node and + // subtract one from start offset." + } else if (0 <= startOffset - 1 + && startOffset - 1 < startNode.childNodes.length + && isEditable(startNode.childNodes[startOffset - 1]) + && isInvisible(startNode.childNodes[startOffset - 1])) { + startNode.removeChild(startNode.childNodes[startOffset - 1]); + startOffset--; + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // "If offset is zero, and node has an editable ancestor container in + // the same editing host that's an indentation element:" + if (offset == 0 + && $_( getAncestors(node).concat(node) ).filter(function(ancestor) { + return isEditable(ancestor) + && inSameEditingHost(ancestor, node) + && isIndentationElement(ancestor); + }).length) { + // "Block-extend the range whose start and end are both (node, 0), + // and let new range be the result." + var newRange = Aloha.createRange(); + newRange.setStart(node, 0); + newRange.setEnd(node, 0); + newRange = blockExtend(newRange); + + // "Let node list be a list of nodes, initially empty." + // + // "For each node current node contained in new range, append + // current node to node list if the last member of node list (if + // any) is not an ancestor of current node, and current node is + // editable but has no editable descendants." + var nodeList = getContainedNodes(newRange, function(currentNode) { + return isEditable(currentNode) + && !hasEditableDescendants(currentNode); + }); + + // "Outdent each node in node list." + for (var i = 0; i < nodeList.length; i++) { + outdentNode(nodeList[i], range); + } + + // "Abort these steps." + return; + } + + // "If the child of start node with index start offset is a table, + // abort these steps." + if (isHtmlElement(startNode.childNodes[startOffset], "table")) { + return; + } + + // "If start node has a child with index start offset − 1, and that + // child is a table:" + if (0 <= startOffset - 1 + && startOffset - 1 < startNode.childNodes.length + && isHtmlElement(startNode.childNodes[startOffset - 1], "table")) { + // "Call collapse(start node, start offset − 1) on the context + // object's Selection." + range.setStart(startNode, startOffset - 1); + + // "Call extend(start node, start offset) on the context object's + // Selection." + range.setEnd(startNode, startOffset); + + // "Abort these steps." + return; + } + + // "If offset is zero; and either the child of start node with index + // start offset minus one is an hr, or the child is a br whose + // previousSibling is either a br or not an inline node:" + if (offset == 0 + && (isHtmlElement(startNode.childNodes[startOffset - 1], "hr") + || ( + isHtmlElement(startNode.childNodes[startOffset - 1], "br") + && ( + isHtmlElement(startNode.childNodes[startOffset - 1].previousSibling, "br") + || !isInlineNode(startNode.childNodes[startOffset - 1].previousSibling) + ) + ) + )) { + // "Call collapse(node, offset) on the Selection." + range.setStart(node, offset); + range.setEnd(node, offset); + + // "Delete the contents of the range with start (start node, start + // offset − 1) and end (start node, start offset)." + deleteContents(startNode, startOffset - 1, startNode, startOffset); + + // "Abort these steps." + return; + } + + // "If the child of start node with index start offset is an li or dt + // or dd, and that child's firstChild is an inline node, and start + // offset is not zero:" + if (isHtmlElement(startNode.childNodes[startOffset], ["li", "dt", "dd"]) + && isInlineNode(startNode.childNodes[startOffset].firstChild) + && startOffset != 0) { + // "Let previous item be the child of start node with index start + // offset minus one." + var previousItem = startNode.childNodes[startOffset - 1]; + + // "If previous item's lastChild is an inline node other than a br, + // call createElement("br") on the context object and append the + // result as the last child of previous item." + if (isInlineNode(previousItem.lastChild) + && !isHtmlElement(previousItem.lastChild, "br")) { + previousItem.appendChild(document.createElement("br")); + } + + // "If previous item's lastChild is an inline node, call + // createElement("br") on the context object and append the result + // as the last child of previous item." + if (isInlineNode(previousItem.lastChild)) { + previousItem.appendChild(document.createElement("br")); + } + } + + // "If the child of start node with index start offset is an li or dt + // or dd, and its previousSibling is also an li or dt or dd, set start + // node to its child with index start offset − 1, then set start offset + // to start node's length, then set node to start node's nextSibling, + // then set offset to 0." + if (isHtmlElement(startNode.childNodes[startOffset], ["li", "dt", "dd"]) + && isHtmlElement(startNode.childNodes[startOffset - 1], ["li", "dt", "dd"])) { + startNode = startNode.childNodes[startOffset - 1]; + startOffset = getNodeLength(startNode); + node = startNode.nextSibling; + offset = 0; + + // "Otherwise, while start node has a child with index start offset + // minus one:" + } else { + while (0 <= startOffset - 1 + && startOffset - 1 < startNode.childNodes.length) { + // "If start node's child with index start offset minus one is + // editable and invisible, remove it from start node, then + // subtract one from start offset." + if (isEditable(startNode.childNodes[startOffset - 1]) + && isInvisible(startNode.childNodes[startOffset - 1])) { + startNode.removeChild(startNode.childNodes[startOffset - 1]); + startOffset--; + + // "Otherwise, set start node to its child with index start + // offset minus one, then set start offset to the length of + // start node." + } else { + startNode = startNode.childNodes[startOffset - 1]; + startOffset = getNodeLength(startNode); + } + } + } + + // "Delete the contents of the range with start (start node, start + // offset) and end (node, offset)." + var delRange = Aloha.createRange(); + delRange.setStart(startNode, startOffset); + delRange.setEnd(node, offset); + deleteContents(delRange); + + if (!isAncestorContainer(document.body, range.startContainer)) { + if (delRange.startContainer.hasChildNodes() || delRange.startContainer.nodeType == $_.Node.TEXT_NODE) { + range.setStart(delRange.startContainer, delRange.startOffset); + range.setEnd(delRange.startContainer, delRange.startOffset); + } else { + range.setStart(delRange.startContainer.parentNode, getNodeIndex(delRange.startContainer)); + range.setEnd(delRange.startContainer.parentNode, getNodeIndex(delRange.startContainer)); + } + } + } +}; + +//@} +///// The formatBlock command ///// +//@{ +// "A formattable block name is "address", "dd", "div", "dt", "h1", "h2", "h3", +// "h4", "h5", "h6", "p", or "pre"." +var formattableBlockNames = ["address", "dd", "div", "dt", "h1", "h2", "h3", + "h4", "h5", "h6", "p", "pre"]; + +commands.formatblock = { + action: function(value) { + // "If value begins with a "<" character and ends with a ">" character, + // remove the first and last characters from it." + if (/^<.*>$/.test(value)) { + value = value.slice(1, -1); + } + + // "Let value be converted to ASCII lowercase." + value = value.toLowerCase(); + + // "If value is not a formattable block name, abort these steps and do + // nothing." + if ($_(formattableBlockNames).indexOf(value) == -1) { + return; + } + + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node list be an empty list of nodes." + // + // "For each node node contained in new range, append node to node list + // if it is editable, the last member of original node list (if any) is + // not an ancestor of node, node is either a non-list single-line + // container or an allowed child of "p" or a dd or dt, and node is not + // the ancestor of a prohibited paragraph child." + var nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && (isNonListSingleLineContainer(node) + || isAllowedChild(node, "p") + || isHtmlElement(node, ["dd", "dt"])) + && !$_( getDescendants(node) ).some(isProhibitedParagraphChild); + }); + + // "Record the values of node list, and let values be the result." + var values = recordValues(nodeList); + + // "For each node in node list, while node is the descendant of an + // editable HTML element in the same editing host, whose local name is + // a formattable block name, and which is not the ancestor of a + // prohibited paragraph child, split the parent of the one-node list + // consisting of node." + for (var i = 0; i < nodeList.length; i++) { + var node = nodeList[i]; + while ($_( getAncestors(node) ).some(function(ancestor) { + return isEditable(ancestor) + && inSameEditingHost(ancestor, node) + && isHtmlElement(ancestor, formattableBlockNames) + && !$_( getDescendants(ancestor) ).some(isProhibitedParagraphChild); + })) { + splitParent([node], range); + } + } + + // "Restore the values from values." + restoreValues(values, range); + + // "While node list is not empty:" + while (nodeList.length) { + var sublist; + + // "If the first member of node list is a single-line + // container:" + if (isSingleLineContainer(nodeList[0])) { + // "Let sublist be the children of the first member of node + // list." + sublist = [].slice.call(toArray(nodeList[0].childNodes)); + + // "Record the values of sublist, and let values be the + // result." + var values = recordValues(sublist); + + // "Remove the first member of node list from its parent, + // preserving its descendants." + removePreservingDescendants(nodeList[0], range); + + // "Restore the values from values." + restoreValues(values, range); + + // "Remove the first member from node list." + nodeList.shift(); + + // "Otherwise:" + } else { + // "Let sublist be an empty list of nodes." + sublist = []; + + // "Remove the first member of node list and append it to + // sublist." + sublist.push(nodeList.shift()); + + // "While node list is not empty, and the first member of + // node list is the nextSibling of the last member of + // sublist, and the first member of node list is not a + // single-line container, and the last member of sublist is + // not a br, remove the first member of node list and + // append it to sublist." + while (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling + && !isSingleLineContainer(nodeList[0]) + && !isHtmlElement(sublist[sublist.length - 1], "BR")) { + sublist.push(nodeList.shift()); + } + } + + // "Wrap sublist. If value is "div" or "p", sibling criteria + // returns false; otherwise it returns true for an HTML element + // with local name value and no attributes, and false otherwise. + // New parent instructions return the result of running + // createElement(value) on the context object. Then fix disallowed + // ancestors of the result." + fixDisallowedAncestors( + wrap(sublist, + $_(["div", "p"]).indexOf(value) == - 1 + ? function(node) { return isHtmlElement(node, value) && !node.attributes.length } + : function() { return false }, + function() { return document.createElement(value) }, + range + ), + range + ); + } + }, indeterm: function() { + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node list be all visible editable nodes that are contained in + // new range and have no children." + var nodeList = getAllContainedNodes(newRange, function(node) { + return isVisible(node) + && isEditable(node) + && !node.hasChildNodes(); + }); + + // "If node list is empty, return false." + if (!nodeList.length) { + return false; + } + + // "Let type be null." + var type = null; + + // "For each node in node list:" + for (var i = 0; i < nodeList.length; i++) { + var node = nodeList[i]; + + // "While node's parent is editable and in the same editing host as + // node, and node is not an HTML element whose local name is a + // formattable block name, set node to its parent." + while (isEditable(node.parentNode) + && inSameEditingHost(node, node.parentNode) + && !isHtmlElement(node, formattableBlockNames)) { + node = node.parentNode; + } + + // "Let current type be the empty string." + var currentType = ""; + + // "If node is an editable HTML element whose local name is a + // formattable block name, and node is not the ancestor of a + // prohibited paragraph child, set current type to node's local + // name." + if (isEditable(node) + && isHtmlElement(node, formattableBlockNames) + && !$_( getDescendants(node) ).some(isProhibitedParagraphChild)) { + currentType = node.tagName; + } + + // "If type is null, set type to current type." + if (type === null) { + type = currentType; + + // "Otherwise, if type does not equal current type, return true." + } else if (type != currentType) { + return true; + } + } + + // "Return false." + return false; + }, value: function() { + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node be the first visible editable node that is contained in + // new range and has no children. If there is no such node, return the + // empty string." + var nodes = getAllContainedNodes(newRange, function(node) { + return isVisible(node) + && isEditable(node) + && !node.hasChildNodes(); + }); + if (!nodes.length) { + return ""; + } + var node = nodes[0]; + + // "While node's parent is editable and in the same editing host as + // node, and node is not an HTML element whose local name is a + // formattable block name, set node to its parent." + while (isEditable(node.parentNode) + && inSameEditingHost(node, node.parentNode) + && !isHtmlElement(node, formattableBlockNames)) { + node = node.parentNode; + } + + // "If node is an editable HTML element whose local name is a + // formattable block name, and node is not the ancestor of a prohibited + // paragraph child, return node's local name, converted to ASCII + // lowercase." + if (isEditable(node) + && isHtmlElement(node, formattableBlockNames) + && !$_( getDescendants(node) ).some(isProhibitedParagraphChild)) { + return node.tagName.toLowerCase(); + } + + // "Return the empty string." + return ""; + } +}; + +//@} +///// The forwardDelete command ///// +//@{ +commands.forwarddelete = { + action: function(value, range) { + + // "If the active range is not collapsed, delete the contents of the + // active range and abort these steps." + if (!range.collapsed) { + deleteContents(range); + return; + } + + // "Canonicalize whitespace at (active range's start node, active + // range's start offset)." + canonicalizeWhitespace(range.startContainer, range.startOffset); + + // "Let node and offset be the active range's start node and offset." + var node = range.startContainer; + var offset = range.startOffset; + var isBr = false; + var isHr = false; + + // "Repeat the following steps:" + while (true) { + // check whether the next element is a br or hr + if ( offset < node.childNodes.length ) { + isBr = isHtmlElement(node.childNodes[offset], "br") || false; + isHr = isHtmlElement(node.childNodes[offset], "hr") || false; + } + + // "If offset is the length of node and node's nextSibling is an + // editable invisible node, remove node's nextSibling from its + // parent." + if (offset == getNodeLength(node) + && isEditable(node.nextSibling) + && isInvisible(node.nextSibling)) { + node.parentNode.removeChild(node.nextSibling); + + // "Otherwise, if node has a child with index offset and that child + // is an editable invisible node, remove that child from node." + } else if (offset < node.childNodes.length + && isEditable(node.childNodes[offset]) + && (isInvisible(node.childNodes[offset]) || isBr || isHr )) { + node.removeChild(node.childNodes[offset]); + if (isBr || isHr) { + range.setStart(node, offset); + range.setEnd(node, offset); + return; + } + + // "Otherwise, if node has a child with index offset and that child + // is a collapsed block prop, add one to offset." + } else if (offset < node.childNodes.length + && isCollapsedBlockProp(node.childNodes[offset])) { + offset++; + + // "Otherwise, if offset is the length of node and node is an + // inline node, or if node is invisible, set offset to one plus the + // index of node, then set node to its parent." + } else if ((offset == getNodeLength(node) + && isInlineNode(node)) + || isInvisible(node)) { + offset = 1 + getNodeIndex(node); + node = node.parentNode; + + // "Otherwise, if node has a child with index offset and that child + // is not a block node or a br or an img, set node to that child, + // then set offset to zero." + } else if (offset < node.childNodes.length + && !isBlockNode(node.childNodes[offset]) + && !isHtmlElement(node.childNodes[offset], ["br", "img"])) { + node = node.childNodes[offset]; + offset = 0; + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // collapse whitespace in the node, if it is a text node + collapseWhitespace(node, range); + + // "If node is a Text node and offset is not node's length:" + if (node.nodeType == $_.Node.TEXT_NODE + && offset != getNodeLength(node)) { + // "Call collapse(node, offset) on the Selection." + range.setStart(node, offset); + range.setEnd(node, offset); + + // "Let end offset be offset plus one." + var endOffset = offset + 1; + + // "While end offset is not node's length and the end offsetth + // element of node's data has general category M when interpreted + // as a Unicode code point, add one to end offset." + // + // TODO: Not even going to try handling anything beyond the most + // basic combining marks, since I couldn't find a good list. I + // special-case a few Hebrew diacritics too to test basic coverage + // of non-Latin stuff. + while (endOffset != node.length + && /^[\u0300-\u036f\u0591-\u05bd\u05c1\u05c2]$/.test(node.data[endOffset])) { + endOffset++; + } + + // "Delete the contents of the range with start (node, offset) and + // end (node, end offset)." + deleteContents(node, offset, node, endOffset); + + // "Abort these steps." + return; + } + + // "If node is an inline node, abort these steps." + if (isInlineNode(node)) { + return; + } + + // "If node has a child with index offset and that child is a br or hr + // or img, call collapse(node, offset) on the Selection. Then delete + // the contents of the range with start (node, offset) and end (node, + // offset + 1) and abort these steps." + if (offset < node.childNodes.length + && isHtmlElement(node.childNodes[offset], ["br", "hr", "img"])) { + range.setStart(node, offset); + range.setEnd(node, offset); + deleteContents(node, offset, node, offset + 1); + return; + } + + // "Let end node equal node and let end offset equal offset." + var endNode = node; + var endOffset = offset; + + // "Repeat the following steps:" + while (true) { + // "If end offset is the length of end node, set end offset to one + // plus the index of end node and then set end node to its parent." + if (endOffset == getNodeLength(endNode)) { + endOffset = 1 + getNodeIndex(endNode); + endNode = endNode.parentNode; + + // "Otherwise, if end node has a an editable invisible child with + // index end offset, remove it from end node." + } else if (endOffset < endNode.childNodes.length + && isEditable(endNode.childNodes[endOffset]) + && isInvisible(endNode.childNodes[endOffset])) { + endNode.removeChild(endNode.childNodes[endOffset]); + + // "Otherwise, break from this loop." + } else { + break; + } + } + + // "If the child of end node with index end offset minus one is a + // table, abort these steps." + if (isHtmlElement(endNode.childNodes[endOffset - 1], "table")) { + return; + } + + // "If the child of end node with index end offset is a table:" + if (isHtmlElement(endNode.childNodes[endOffset], "table")) { + // "Call collapse(end node, end offset) on the context object's + // Selection." + range.setStart(endNode, endOffset); + + // "Call extend(end node, end offset + 1) on the context object's + // Selection." + range.setEnd(endNode, endOffset + 1); + + // "Abort these steps." + return; + } + + // "If offset is the length of node, and the child of end node with + // index end offset is an hr or br:" + if (offset == getNodeLength(node) + && isHtmlElement(endNode.childNodes[endOffset], ["br", "hr"])) { + // "Call collapse(node, offset) on the Selection." + range.setStart(node, offset); + range.setEnd(node, offset); + + // "Delete the contents of the range with end (end node, end + // offset) and end (end node, end offset + 1)." + deleteContents(endNode, endOffset, endNode, endOffset + 1); + + // "Abort these steps." + return; + } + + // "While end node has a child with index end offset:" + while (endOffset < endNode.childNodes.length) { + // "If end node's child with index end offset is editable and + // invisible, remove it from end node." + if (isEditable(endNode.childNodes[endOffset]) + && isInvisible(endNode.childNodes[endOffset])) { + endNode.removeChild(endNode.childNodes[endOffset]); + + // "Otherwise, set end node to its child with index end offset and + // set end offset to zero." + } else { + endNode = endNode.childNodes[endOffset]; + endOffset = 0; + } + } + + // "Delete the contents of the range with start (node, offset) and end + // (end node, end offset)." + deleteContents(node, offset, endNode, endOffset); + } +}; + +//@} +///// The indent command ///// +//@{ +commands.indent = { + action: function() { + // "Let items be a list of all lis that are ancestor containers of the + // active range's start and/or end node." + // + // Has to be in tree order, remember! + var items = []; + for (var node = getActiveRange().endContainer; node != getActiveRange().commonAncestorContainer; node = node.parentNode) { + if (isHtmlElement(node, "LI")) { + items.unshift(node); + } + } + for (var node = getActiveRange().startContainer; node != getActiveRange().commonAncestorContainer; node = node.parentNode) { + if (isHtmlElement(node, "LI")) { + items.unshift(node); + } + } + for (var node = getActiveRange().commonAncestorContainer; node; node = node.parentNode) { + if (isHtmlElement(node, "LI")) { + items.unshift(node); + } + } + + // "For each item in items, normalize sublists of item." + for (var i = 0; i < items.length; i++) { + normalizeSublists(items[i, range]); + } + + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node list be a list of nodes, initially empty." + var nodeList = []; + + // "For each node node contained in new range, if node is editable and + // is an allowed child of "div" or "ol" and if the last member of node + // list (if any) is not an ancestor of node, append node to node list." + nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && (isAllowedChild(node, "div") + || isAllowedChild(node, "ol")); + }); + + // "If the first member of node list is an li whose parent is an ol or + // ul, and its previousSibling is an li as well, normalize sublists of + // its previousSibling." + if (nodeList.length + && isHtmlElement(nodeList[0], "LI") + && isHtmlElement(nodeList[0].parentNode, ["OL", "UL"]) + && isHtmlElement(nodeList[0].previousSibling, "LI")) { + normalizeSublists(nodeList[0].previousSibling, range); + } + + // "While node list is not empty:" + while (nodeList.length) { + // "Let sublist be a list of nodes, initially empty." + var sublist = []; + + // "Remove the first member of node list and append it to sublist." + sublist.push(nodeList.shift()); + + // "While the first member of node list is the nextSibling of the + // last member of sublist, remove the first member of node list and + // append it to sublist." + while (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling) { + sublist.push(nodeList.shift()); + } + + // "Indent sublist." + indentNodes(sublist, range); + } + } +}; + +//@} +///// The insertHorizontalRule command ///// +//@{ +commands.inserthorizontalrule = { + action: function(value, range) { + + // "While range's start offset is 0 and its start node's parent is not + // null, set range's start to (parent of start node, index of start + // node)." + while (range.startOffset == 0 + && range.startContainer.parentNode) { + range.setStart(range.startContainer.parentNode, getNodeIndex(range.startContainer)); + } + + // "While range's end offset is the length of its end node, and its end + // node's parent is not null, set range's end to (parent of end node, 1 + // + index of start node)." + while (range.endOffset == getNodeLength(range.endContainer) + && range.endContainer.parentNode) { + range.setEnd(range.endContainer.parentNode, 1 + getNodeIndex(range.endContainer)); + } + + // "Delete the contents of range, with block merging false." + deleteContents(range, {blockMerging: false}); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(getActiveRange().startContainer) + && !isEditingHost(getActiveRange().startContainer)) { + return; + } + + // "If the active range's start node is a Text node and its start + // offset is zero, set the active range's start and end to (parent of + // start node, index of start node)." + if (getActiveRange().startContainer.nodeType == $_.Node.TEXT_NODE + && getActiveRange().startOffset == 0) { + getActiveRange().setStart(getActiveRange().startContainer.parentNode, getNodeIndex(getActiveRange().startContainer)); + getActiveRange().collapse(true); + } + + // "If the active range's start node is a Text node and its start + // offset is the length of its start node, set the active range's start + // and end to (parent of start node, 1 + index of start node)." + if (getActiveRange().startContainer.nodeType == $_.Node.TEXT_NODE + && getActiveRange().startOffset == getNodeLength(getActiveRange().startContainer)) { + getActiveRange().setStart(getActiveRange().startContainer.parentNode, 1 + getNodeIndex(getActiveRange().startContainer)); + getActiveRange().collapse(true); + } + + // "Let hr be the result of calling createElement("hr") on the + // context object." + var hr = document.createElement("hr"); + + // "Run insertNode(hr) on the range." + range.insertNode(hr); + + // "Fix disallowed ancestors of hr." + fixDisallowedAncestors(hr, range); + + // "Run collapse() on the Selection, with first argument equal to the + // parent of hr and the second argument equal to one plus the index of + // hr." + // + // Not everyone actually supports collapse(), so we do it manually + // instead. Also, we need to modify the actual range we're given as + // well, for the sake of autoimplementation.html's range-filling-in. + range.setStart(hr.parentNode, 1 + getNodeIndex(hr)); + range.setEnd(hr.parentNode, 1 + getNodeIndex(hr)); + Aloha.getSelection().removeAllRanges(); + Aloha.getSelection().addRange(range); + } +}; + +//@} +///// The insertHTML command ///// +//@{ +commands.inserthtml = { + action: function(value, range) { + + + // "Delete the contents of the active range." + deleteContents(range); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(range.startContainer) + && !isEditingHost(range.startContainer)) { + return; + } + + // "Let frag be the result of calling createContextualFragment(value) + // on the active range." + var frag = range.createContextualFragment(value); + + // "Let last child be the lastChild of frag." + var lastChild = frag.lastChild; + + // "If last child is null, abort these steps." + if (!lastChild) { + return; + } + + // "Let descendants be all descendants of frag." + var descendants = getDescendants(frag); + + // "If the active range's start node is a block node:" + if (isBlockNode(range.startContainer)) { + // "Let collapsed block props be all editable collapsed block prop + // children of the active range's start node that have index + // greater than or equal to the active range's start offset." + // + // "For each node in collapsed block props, remove node from its + // parent." + $_(range.startContainer.childNodes).filter(function(node, range) { + return isEditable(node) + && isCollapsedBlockProp(node) + && getNodeIndex(node) >= range.startOffset; + }, true).forEach(function(node) { + node.parentNode.removeChild(node); + }); + } + + // "Call insertNode(frag) on the active range." + range.insertNode(frag); + + // "If the active range's start node is a block node with no visible + // children, call createElement("br") on the context object and append + // the result as the last child of the active range's start node." + if (isBlockNode(range.startContainer) + && !$_(range.startContainer.childNodes).some(isVisible)) { + range.startContainer.appendChild(createEndBreak()); + } + + // "Call collapse() on the context object's Selection, with last + // child's parent as the first argument and one plus its index as the + // second." + range.setStart(lastChild.parentNode, 1 + getNodeIndex(lastChild)); + range.setEnd(lastChild.parentNode, 1 + getNodeIndex(lastChild)); + + // "Fix disallowed ancestors of each member of descendants." + for (var i = 0; i < descendants.length; i++) { + fixDisallowedAncestors(descendants[i], range); + } + + setActiveRange( range ); + } +}; + +//@} +///// The insertImage command ///// +//@{ +commands.insertimage = { + action: function(value) { + // "If value is the empty string, abort these steps and do nothing." + if (value === "") { + return; + } + + // "Let range be the active range." + var range = getActiveRange(); + + // "Delete the contents of range, with strip wrappers false." + deleteContents(range, {stripWrappers: false}); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(getActiveRange().startContainer) + && !isEditingHost(getActiveRange().startContainer)) { + return; + } + + // "If range's start node is a block node whose sole child is a br, and + // its start offset is 0, remove its start node's child from it." + if (isBlockNode(range.startContainer) + && range.startContainer.childNodes.length == 1 + && isHtmlElement(range.startContainer.firstChild, "br") + && range.startOffset == 0) { + range.startContainer.removeChild(range.startContainer.firstChild); + } + + // "Let img be the result of calling createElement("img") on the + // context object." + var img = document.createElement("img"); + + // "Run setAttribute("src", value) on img." + img.setAttribute("src", value); + + // "Run insertNode(img) on the range." + range.insertNode(img); + + // "Run collapse() on the Selection, with first argument equal to the + // parent of img and the second argument equal to one plus the index of + // img." + // + // Not everyone actually supports collapse(), so we do it manually + // instead. Also, we need to modify the actual range we're given as + // well, for the sake of autoimplementation.html's range-filling-in. + range.setStart(img.parentNode, 1 + getNodeIndex(img)); + range.setEnd(img.parentNode, 1 + getNodeIndex(img)); + Aloha.getSelection().removeAllRanges(); + Aloha.getSelection().addRange(range); + + // IE adds width and height attributes for some reason, so remove those + // to actually do what the spec says. + img.removeAttribute("width"); + img.removeAttribute("height"); + } +}; + +//@} +///// The insertLineBreak command ///// +//@{ +commands.insertlinebreak = { + action: function(value, range) { + // "Delete the contents of the active range, with strip wrappers false." + deleteContents(range, {stripWrappers: false}); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(range.startContainer) + && !isEditingHost(range.startContainer)) { + return; + } + + // "If the active range's start node is an Element, and "br" is not an + // allowed child of it, abort these steps." + if (range.startContainer.nodeType == $_.Node.ELEMENT_NODE + && !isAllowedChild("br", range.startContainer)) { + return; + } + + // "If the active range's start node is not an Element, and "br" is not + // an allowed child of the active range's start node's parent, abort + // these steps." + if (range.startContainer.nodeType != $_.Node.ELEMENT_NODE + && !isAllowedChild("br", range.startContainer.parentNode)) { + return; + } + + // "If the active range's start node is a Text node and its start + // offset is zero, call collapse() on the context object's Selection, + // with first argument equal to the active range's start node's parent + // and second argument equal to the active range's start node's index." + if (range.startContainer.nodeType == $_.Node.TEXT_NODE + && range.startOffset == 0) { + var newNode = range.startContainer.parentNode; + var newOffset = getNodeIndex(range.startContainer); + Aloha.getSelection().collapse(newNode, newOffset); + range.setStart(newNode, newOffset); + range.setEnd(newNode, newOffset); + } + + // "If the active range's start node is a Text node and its start + // offset is the length of its start node, call collapse() on the + // context object's Selection, with first argument equal to the active + // range's start node's parent and second argument equal to one plus + // the active range's start node's index." + if (range.startContainer.nodeType == $_.Node.TEXT_NODE + && range.startOffset == getNodeLength(range.startContainer)) { + var newNode = range.startContainer.parentNode; + var newOffset = 1 + getNodeIndex(range.startContainer); + Aloha.getSelection().collapse(newNode, newOffset); + range.setStart(newNode, newOffset); + range.setEnd(newNode, newOffset); + } + + // "Let br be the result of calling createElement("br") on the context + // object." + var br = document.createElement("br"); + + // "Call insertNode(br) on the active range." + range.insertNode(br); + + // "Call collapse() on the context object's Selection, with br's parent + // as the first argument and one plus br's index as the second + // argument." + Aloha.getSelection().collapse(br.parentNode, 1 + getNodeIndex(br)); + range.setStart(br.parentNode, 1 + getNodeIndex(br)); + range.setEnd(br.parentNode, 1 + getNodeIndex(br)); + + // "If br is a collapsed line break, call createElement("br") on the + // context object and let extra br be the result, then call + // insertNode(extra br) on the active range." + if (isCollapsedLineBreak(br)) { + range.insertNode(createEndBreak()); + + // Compensate for nonstandard implementations of insertNode + Aloha.getSelection().collapse(br.parentNode, 1 + getNodeIndex(br)); + range.setStart(br.parentNode, 1 + getNodeIndex(br)); + range.setEnd(br.parentNode, 1 + getNodeIndex(br)); + } + } +}; + +//@} +///// The insertOrderedList command ///// +//@{ +commands.insertorderedlist = { + // "Toggle lists with tag name "ol"." + action: function() { toggleLists("ol") }, + // "True if the selection's list state is "mixed" or "mixed ol", false + // otherwise." + indeterm: function() { return /^mixed( ol)?$/.test(getSelectionListState()) }, + // "True if the selection's list state is "ol", false otherwise." + state: function() { return getSelectionListState() == "ol" } +}; + +//@} +///// The insertParagraph command ///// +//@{ +commands.insertparagraph = { + action: function(value, range) { + + // "Delete the contents of the active range." + deleteContents(range); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(range.startContainer) + && !isEditingHost(range.startContainer)) { + return; + } + + // "Let node and offset be the active range's start node and offset." + var node = range.startContainer; + var offset = range.startOffset; + + // "If node is a Text node, and offset is neither 0 nor the length of + // node, call splitText(offset) on node." + if (node.nodeType == $_.Node.TEXT_NODE + && offset != 0 + && offset != getNodeLength(node)) { + node.splitText(offset); + } + + // "If node is a Text node and offset is its length, set offset to one + // plus the index of node, then set node to its parent." + if (node.nodeType == $_.Node.TEXT_NODE + && offset == getNodeLength(node)) { + offset = 1 + getNodeIndex(node); + node = node.parentNode; + } + + // "If node is a Text or Comment node, set offset to the index of node, + // then set node to its parent." + if (node.nodeType == $_.Node.TEXT_NODE + || node.nodeType == $_.Node.COMMENT_NODE) { + offset = getNodeIndex(node); + node = node.parentNode; + } + + // "Call collapse(node, offset) on the context object's Selection." + Aloha.getSelection().collapse(node, offset); + range.setStart(node, offset); + range.setEnd(node, offset); + + // "Let container equal node." + var container = node; + + // "While container is not a single-line container, and container's + // parent is editable and in the same editing host as node, set + // container to its parent." + while (!isSingleLineContainer(container) + && isEditable(container.parentNode) + && inSameEditingHost(node, container.parentNode)) { + container = container.parentNode; + } + + // "If container is not editable or not in the same editing host as + // node or is not a single-line container:" + if (!isEditable(container) + || !inSameEditingHost(container, node) + || !isSingleLineContainer(container)) { + // "Let tag be the default single-line container name." + var tag = defaultSingleLineContainerName; + + // "Block-extend the active range, and let new range be the + // result." + var newRange = blockExtend(range); + + // "Let node list be a list of nodes, initially empty." + // + // "Append to node list the first node in tree order that is + // contained in new range and is an allowed child of "p", if any." + var nodeList = getContainedNodes(newRange, function(node) { return isAllowedChild(node, "p") }) + .slice(0, 1); + + // "If node list is empty:" + if (!nodeList.length) { + // "If tag is not an allowed child of the active range's start + // node, abort these steps." + if (!isAllowedChild(tag, range.startContainer)) { + return; + } + + // "Set container to the result of calling createElement(tag) + // on the context object." + container = document.createElement(tag); + + // "Call insertNode(container) on the active range." + range.insertNode(container); + + // "Call createElement("br") on the context object, and append + // the result as the last child of container." + container.appendChild(createEndBreak()); + + // "Call collapse(container, 0) on the context object's + // Selection." + // TODO: remove selection from command + Aloha.getSelection().collapse(container, 0); + range.setStart(container, 0); + range.setEnd(container, 0); + + // "Abort these steps." + return; + } + + // "While the nextSibling of the last member of node list is not + // null and is an allowed child of "p", append it to node list." + while (nodeList[nodeList.length - 1].nextSibling + && isAllowedChild(nodeList[nodeList.length - 1].nextSibling, "p")) { + nodeList.push(nodeList[nodeList.length - 1].nextSibling); + } + + // "Wrap node list, with sibling criteria returning false and new + // parent instructions returning the result of calling + // createElement(tag) on the context object. Set container to the + // result." + container = wrap(nodeList, + function() { return false }, + function() { return document.createElement(tag) }, + range + ); + } + + // "If container's local name is "address", "listing", or "pre":" + if (container.tagName == "ADDRESS" + || container.tagName == "LISTING" + || container.tagName == "PRE") { + // "Let br be the result of calling createElement("br") on the + // context object." + var br = document.createElement("br"); + + // remember the old height + var oldHeight = container.offsetHeight; + + // "Call insertNode(br) on the active range." + range.insertNode(br); + + // determine the new height + var newHeight = container.offsetHeight; + + // "Call collapse(node, offset + 1) on the context object's + // Selection." + Aloha.getSelection().collapse(node, offset + 1); + range.setStart(node, offset + 1); + range.setEnd(node, offset + 1); + + // "If br is the last descendant of container, let br be the result + // of calling createElement("br") on the context object, then call + // insertNode(br) on the active range." (Fix: only do this, if the container height did not change by inserting a single
      ) + // + // Work around browser bugs: some browsers select the + // newly-inserted node, not per spec. + if (oldHeight == newHeight && !isDescendant(nextNode(br), container)) { + range.insertNode(createEndBreak()); + Aloha.getSelection().collapse(node, offset + 1); + range.setEnd(node, offset + 1); + } + + // "Abort these steps." + return; + } + + // "If container's local name is "li", "dt", or "dd"; and either it has + // no children or it has a single child and that child is a br:" + if ($_(["LI", "DT", "DD"]).indexOf(container.tagName) != -1 + && (!container.hasChildNodes() + || (container.childNodes.length == 1 + && isHtmlElement(container.firstChild, "br")))) { + // "Split the parent of the one-node list consisting of container." + splitParent([container], range); + + // "If container has no children, call createElement("br") on the + // context object and append the result as the last child of + // container." + // only do this, if inserting the br does NOT modify the offset height of the container + if (!container.hasChildNodes()) { + var oldHeight = container.offsetHeight, endBr = createEndBreak(); + container.appendChild(endBr); + if (container.offsetHeight !== oldHeight) { + container.removeChild(endBr); + } + } + + // "If container is a dd or dt, and it is not an allowed child of + // any of its ancestors in the same editing host, set the tag name + // of container to the default single-line container name and let + // container be the result." + if (isHtmlElement(container, ["dd", "dt"]) + && $_( getAncestors(container) ).every(function(ancestor) { + return !inSameEditingHost(container, ancestor) + || !isAllowedChild(container, ancestor) + })) { + container = setTagName(container, defaultSingleLineContainerName, range); + } + + // "Fix disallowed ancestors of container." + fixDisallowedAncestors(container, range); + + // fix invalid nested lists + if (isHtmlElement(container, "li") + && isHtmlElement(container.nextSibling, "li") + && isHtmlElement(container.nextSibling.firstChild, ["ol", "ul"])) { + // we found a li containing only a br followed by a li containing a list as first element: merge the two li's + var listParent = container.nextSibling, length = container.nextSibling.childNodes.length; + for (var i = 0; i < length; i++) { + container.appendChild(listParent.childNodes[i]); + } + listParent.parentNode.removeChild(listParent); + } + + // "Abort these steps." + return; + } + + // "Let new line range be a new range whose start is the same as + // the active range's, and whose end is (container, length of + // container)." + var newLineRange = Aloha.createRange(); + newLineRange.setStart(range.startContainer, range.startOffset); + newLineRange.setEnd(container, getNodeLength(container)); + + // "While new line range's start offset is zero and its start node is + // not container, set its start to (parent of start node, index of + // start node)." + while (newLineRange.startOffset == 0 + && newLineRange.startContainer != container) { + newLineRange.setStart(newLineRange.startContainer.parentNode, getNodeIndex(newLineRange.startContainer)); + } + + // "While new line range's start offset is the length of its start node + // and its start node is not container, set its start to (parent of + // start node, 1 + index of start node)." + while (newLineRange.startOffset == getNodeLength(newLineRange.startContainer) + && newLineRange.startContainer != container) { + newLineRange.setStart(newLineRange.startContainer.parentNode, 1 + getNodeIndex(newLineRange.startContainer)); + } + + // "Let end of line be true if new line range contains either nothing + // or a single br, and false otherwise." + var containedInNewLineRange = getContainedNodes(newLineRange); + var endOfLine = !containedInNewLineRange.length + || (containedInNewLineRange.length == 1 + && isHtmlElement(containedInNewLineRange[0], "br")); + + // "If the local name of container is "h1", "h2", "h3", "h4", "h5", or + // "h6", and end of line is true, let new container name be the default + // single-line container name." + var newContainerName; + if (/^H[1-6]$/.test(container.tagName) + && endOfLine) { + newContainerName = defaultSingleLineContainerName; + + // "Otherwise, if the local name of container is "dt" and end of line + // is true, let new container name be "dd"." + } else if (container.tagName == "DT" + && endOfLine) { + newContainerName = "dd"; + + // "Otherwise, if the local name of container is "dd" and end of line + // is true, let new container name be "dt"." + } else if (container.tagName == "DD" + && endOfLine) { + newContainerName = "dt"; + + // "Otherwise, let new container name be the local name of container." + } else { + newContainerName = container.tagName.toLowerCase(); + } + + // "Let new container be the result of calling createElement(new + // container name) on the context object." + var newContainer = document.createElement(newContainerName); + + // "Copy all attributes of container to new container." + for (var i = 0; i < container.attributes.length; i++) { + if (typeof newContainer.setAttributeNS === 'function') { + newContainer.setAttributeNS(container.attributes[i].namespaceURI, container.attributes[i].name, container.attributes[i].value); + } else { + newContainer.setAttribute(container.attributes[i].name, container.attributes[i].value); + } + } + + // "If new container has an id attribute, unset it." + newContainer.removeAttribute("id"); + + // "Insert new container into the parent of container immediately after + // container." + container.parentNode.insertBefore(newContainer, container.nextSibling); + + // "Let contained nodes be all nodes contained in new line range." + var containedNodes = getAllContainedNodes(newLineRange); + + // "Let frag be the result of calling extractContents() on new line + // range." + var frag = newLineRange.extractContents(); + + // "Unset the id attribute (if any) of each Element descendant of frag + // that is not in contained nodes." + var descendants = getDescendants(frag); + for (var i = 0; i < descendants.length; i++) { + if (descendants[i].nodeType == $_.Node.ELEMENT_NODE + && $_(containedNodes).indexOf(descendants[i]) == -1) { + descendants[i].removeAttribute("id"); + } + } + + var fragChildren = [], fragChild = frag.firstChild; + if (fragChild) { + do { + if (!isWhitespaceNode(fragChild)) { + fragChildren.push(fragChild); + } + } while(fragChild = fragChild.nextSibling); + } + + // if newContainer is a li and frag contains only a list, we add a br in the li (but only if the height would not change) + if (isHtmlElement(newContainer, "li") && fragChildren.length && isHtmlElement(fragChildren[0], ["ul", "ol"])) { + var oldHeight = newContainer.offsetHeight; + var endBr = createEndBreak(); + newContainer.appendChild(endBr); + var newHeight = newContainer.offsetHeight; + if (oldHeight !== newHeight) { + newContainer.removeChild(endBr); + } + } + + // "Call appendChild(frag) on new container." + newContainer.appendChild(frag); + + // "If container has no visible children, call createElement("br") on + // the context object, and append the result as the last child of + // container." + if (container.offsetHeight == 0 && !$_(container.childNodes).some(isVisible)) { + container.appendChild(createEndBreak()); + } + + // "If new container has no visible children, call createElement("br") + // on the context object, and append the result as the last child of + // new container." + if (newContainer.offsetHeight == 0 && !$_(newContainer.childNodes).some(isVisible)) { + newContainer.appendChild(createEndBreak()); + } + + // "Call collapse(new container, 0) on the context object's Selection." + Aloha.getSelection().collapse(newContainer, 0); + range.setStart(newContainer, 0); + range.setEnd(newContainer, 0); + } +}; + +//@} +///// The insertText command ///// +//@{ +commands.inserttext = { + action: function(value, range) { + // "Delete the contents of the active range, with strip wrappers + // false." + deleteContents(range, {stripWrappers: false}); + + // "If the active range's start node is neither editable nor an editing + // host, abort these steps." + if (!isEditable(range.startContainer) + && !isEditingHost(range.startContainer)) { + return; + } + + // "If value's length is greater than one:" + if (value.length > 1) { + // "For each element el in value, take the action for the + // insertText command, with value equal to el." + for (var i = 0; i < value.length; i++) { + commands.inserttext.action( value[i], range ); + } + + // "Abort these steps." + return; + } + + // "If value is the empty string, abort these steps." + if (value == "") { + return; + } + + // "If value is a newline (U+00A0), take the action for the + // insertParagraph command and abort these steps." + if (value == "\n") { + commands.insertparagraph.action( '', range ); + return; + } + + // "Let node and offset be the active range's start node and offset." + var node = range.startContainer; + var offset = range.startOffset; + + // "If node has a child whose index is offset − 1, and that child is a + // Text node, set node to that child, then set offset to node's + // length." + if (0 <= offset - 1 + && offset - 1 < node.childNodes.length + && node.childNodes[offset - 1].nodeType == $_.Node.TEXT_NODE) { + node = node.childNodes[offset - 1]; + offset = getNodeLength(node); + } + + // "If node has a child whose index is offset, and that child is a Text + // node, set node to that child, then set offset to zero." + if (0 <= offset + && offset < node.childNodes.length + && node.childNodes[offset].nodeType == $_.Node.TEXT_NODE) { + node = node.childNodes[offset]; + offset = 0; + } + + // "If value is a space (U+0020), and either node is an Element whose + // resolved value for "white-space" is neither "pre" nor "pre-wrap" or + // node is not an Element but its parent is an Element whose resolved + // value for "white-space" is neither "pre" nor "pre-wrap", set value + // to a non-breaking space (U+00A0)." + var refElement = node.nodeType == $_.Node.ELEMENT_NODE ? node : node.parentNode; + if (value == " " + && refElement.nodeType == $_.Node.ELEMENT_NODE + && $_(["pre", "pre-wrap"]).indexOf($_.getComputedStyle(refElement).whiteSpace) == -1) { + value = "\xa0"; + } + + // "Record current overrides, and let overrides be the result." + var overrides = recordCurrentOverrides( range ); + + // "If node is a Text node:" + if (node.nodeType == $_.Node.TEXT_NODE) { + // "Call insertData(offset, value) on node." + node.insertData(offset, value); + + // "Call collapse(node, offset) on the context object's Selection." + Aloha.getSelection().collapse(node, offset); + range.setStart(node, offset); + + // "Call extend(node, offset + 1) on the context object's + // Selection." + Aloha.getSelection().extend(node, offset + 1); + range.setEnd(node, offset + 1); + + // "Otherwise:" + } else { + // "If node has only one child, which is a collapsed line break, + // remove its child from it." + // + // FIXME: IE incorrectly returns false here instead of true + // sometimes? + if (node.childNodes.length == 1 + && isCollapsedLineBreak(node.firstChild)) { + node.removeChild(node.firstChild); + } + + // "Let text be the result of calling createTextNode(value) on the + // context object." + var text = document.createTextNode(value); + + // "Call insertNode(text) on the active range." + range.insertNode(text); + + // "Call collapse(text, 0) on the context object's Selection." + Aloha.getSelection().collapse(text, 0); + range.setStart(text, 0); + + // "Call extend(text, 1) on the context object's Selection." + Aloha.getSelection().extend(text, 1); + range.setEnd(text, 1); + } + + // "Restore states and values from overrides." + restoreStatesAndValues(overrides); + + // "Canonicalize whitespace at the active range's start." + canonicalizeWhitespace(range.startContainer, range.startOffset); + + // "Canonicalize whitespace at the active range's end." + canonicalizeWhitespace(range.endContainer, range.endOffset); + + // "Call collapseToEnd() on the context object's Selection." + Aloha.getSelection().collapseToEnd(); + range.collapse(false); + } +}; + +//@} +///// The insertUnorderedList command ///// +//@{ +commands.insertunorderedlist = { + // "Toggle lists with tag name "ul"." + action: function() { toggleLists("ul") }, + // "True if the selection's list state is "mixed" or "mixed ul", false + // otherwise." + indeterm: function() { return /^mixed( ul)?$/.test(getSelectionListState()) }, + // "True if the selection's list state is "ul", false otherwise." + state: function() { return getSelectionListState() == "ul" } +}; + +//@} +///// The justifyCenter command ///// +//@{ +commands.justifycenter = { + // "Justify the selection with alignment "center"." + action: function(value, range) { justifySelection("center", range) }, + indeterm: function() { + // "Block-extend the active range. Return true if among visible + // editable nodes that are contained in the result and have no + // children, at least one has alignment value "center" and at least one + // does not. Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return $_( nodes ).some(function(node) { return getAlignmentValue(node) == "center" }) + && $_( nodes ).some(function(node) { return getAlignmentValue(node) != "center" }); + }, state: function() { + // "Block-extend the active range. Return true if there is at least one + // visible editable node that is contained in the result and has no + // children, and all such nodes have alignment value "center". + // Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return nodes.length + && $_( nodes ).every(function(node) { return getAlignmentValue(node) == "center" }); + }, value: function() { + // "Block-extend the active range, and return the alignment value of + // the first visible editable node that is contained in the result and + // has no children. If there is no such node, return "left"." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + if (nodes.length) { + return getAlignmentValue(nodes[0]); + } else { + return "left"; + } + } +}; + +//@} +///// The justifyFull command ///// +//@{ +commands.justifyfull = { + // "Justify the selection with alignment "justify"." + action: function(value, range) { justifySelection("justify", range) }, + indeterm: function() { + // "Block-extend the active range. Return true if among visible + // editable nodes that are contained in the result and have no + // children, at least one has alignment value "justify" and at least + // one does not. Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return $_( nodes ).some(function(node) { return getAlignmentValue(node) == "justify" }) + && $_( nodes ).some(function(node) { return getAlignmentValue(node) != "justify" }); + }, state: function() { + // "Block-extend the active range. Return true if there is at least one + // visible editable node that is contained in the result and has no + // children, and all such nodes have alignment value "justify". + // Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return nodes.length + && $_( nodes ).every(function(node) { return getAlignmentValue(node) == "justify" }); + }, value: function() { + // "Block-extend the active range, and return the alignment value of + // the first visible editable node that is contained in the result and + // has no children. If there is no such node, return "left"." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + if (nodes.length) { + return getAlignmentValue(nodes[0]); + } else { + return "left"; + } + } +}; + +//@} +///// The justifyLeft command ///// +//@{ +commands.justifyleft = { + // "Justify the selection with alignment "left"." + action: function(value, range) { justifySelection("left", range) }, + indeterm: function() { + // "Block-extend the active range. Return true if among visible + // editable nodes that are contained in the result and have no + // children, at least one has alignment value "left" and at least one + // does not. Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return $_( nodes ).some(function(node) { return getAlignmentValue(node) == "left" }) + && $_( nodes ).some(function(node) { return getAlignmentValue(node) != "left" }); + }, state: function() { + // "Block-extend the active range. Return true if there is at least one + // visible editable node that is contained in the result and has no + // children, and all such nodes have alignment value "left". Otherwise + // return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return nodes.length + && $_( nodes ).every(function(node) { return getAlignmentValue(node) == "left" }); + }, value: function() { + // "Block-extend the active range, and return the alignment value of + // the first visible editable node that is contained in the result and + // has no children. If there is no such node, return "left"." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + if (nodes.length) { + return getAlignmentValue(nodes[0]); + } else { + return "left"; + } + } +}; + +//@} +///// The justifyRight command ///// +//@{ +commands.justifyright = { + // "Justify the selection with alignment "right"." + action: function(value, range) { justifySelection("right", range) }, + indeterm: function() { + // "Block-extend the active range. Return true if among visible + // editable nodes that are contained in the result and have no + // children, at least one has alignment value "right" and at least one + // does not. Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return $_( nodes ).some(function(node) { return getAlignmentValue(node) == "right" }) + && $_( nodes ).some(function(node) { return getAlignmentValue(node) != "right" }); + }, state: function() { + // "Block-extend the active range. Return true if there is at least one + // visible editable node that is contained in the result and has no + // children, and all such nodes have alignment value "right". + // Otherwise return false." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + return nodes.length + && $_( nodes ).every(function(node) { return getAlignmentValue(node) == "right" }); + }, value: function() { + // "Block-extend the active range, and return the alignment value of + // the first visible editable node that is contained in the result and + // has no children. If there is no such node, return "left"." + var nodes = getAllContainedNodes(blockExtend(getActiveRange()), function(node) { + return isEditable(node) && isVisible(node) && !node.hasChildNodes(); + }); + if (nodes.length) { + return getAlignmentValue(nodes[0]); + } else { + return "left"; + } + } +}; + +//@} +///// The outdent command ///// +//@{ +commands.outdent = { + action: function() { + // "Let items be a list of all lis that are ancestor containers of the + // range's start and/or end node." + // + // It's annoying to get this in tree order using functional stuff + // without doing getDescendants(document), which is slow, so I do it + // imperatively. + var items = []; + (function(){ + for ( + var ancestorContainer = getActiveRange().endContainer; + ancestorContainer != getActiveRange().commonAncestorContainer; + ancestorContainer = ancestorContainer.parentNode + ) { + if (isHtmlElement(ancestorContainer, "li")) { + items.unshift(ancestorContainer); + } + } + for ( + var ancestorContainer = getActiveRange().startContainer; + ancestorContainer; + ancestorContainer = ancestorContainer.parentNode + ) { + if (isHtmlElement(ancestorContainer, "li")) { + items.unshift(ancestorContainer); + } + } + })(); + + // "For each item in items, normalize sublists of item." + $_( items ).forEach( function( thisArg) { + normalizeSublists( thisArg, range); + }); + + // "Block-extend the active range, and let new range be the result." + var newRange = blockExtend(getActiveRange()); + + // "Let node list be a list of nodes, initially empty." + // + // "For each node node contained in new range, append node to node list + // if the last member of node list (if any) is not an ancestor of node; + // node is editable; and either node has no editable descendants, or is + // an ol or ul, or is an li whose parent is an ol or ul." + var nodeList = getContainedNodes(newRange, function(node) { + return isEditable(node) + && (!$_( getDescendants(node) ).some(isEditable) + || isHtmlElement(node, ["ol", "ul"]) + || (isHtmlElement(node, "li") && isHtmlElement(node.parentNode, ["ol", "ul"]))); + }); + + // "While node list is not empty:" + while (nodeList.length) { + // "While the first member of node list is an ol or ul or is not + // the child of an ol or ul, outdent it and remove it from node + // list." + while (nodeList.length + && (isHtmlElement(nodeList[0], ["OL", "UL"]) + || !isHtmlElement(nodeList[0].parentNode, ["OL", "UL"]))) { + outdentNode(nodeList.shift(), range); + } + + // "If node list is empty, break from these substeps." + if (!nodeList.length) { + break; + } + + // "Let sublist be a list of nodes, initially empty." + var sublist = []; + + // "Remove the first member of node list and append it to sublist." + sublist.push(nodeList.shift()); + + // "While the first member of node list is the nextSibling of the + // last member of sublist, and the first member of node list is not + // an ol or ul, remove the first member of node list and append it + // to sublist." + while (nodeList.length + && nodeList[0] == sublist[sublist.length - 1].nextSibling + && !isHtmlElement(nodeList[0], ["OL", "UL"])) { + sublist.push(nodeList.shift()); + } + + // "Record the values of sublist, and let values be the result." + var values = recordValues(sublist); + + // "Split the parent of sublist, with new parent null." + splitParent(sublist, range); + + // "Fix disallowed ancestors of each member of sublist." + $_( sublist ).forEach(fixDisallowedAncestors); + + // "Restore the values from values." + restoreValues(values, range); + } + } +}; + +//@} + +////////////////////////////////// +///// Miscellaneous commands ///// +////////////////////////////////// + +///// The selectAll command ///// +//@{ +commands.selectall = { + // Note, this ignores the whole globalRange/getActiveRange() thing and + // works with actual selections. Not suitable for autoimplementation.html. + action: function() { + // "Let target be the body element of the context object." + var target = document.body; + + // "If target is null, let target be the context object's + // documentElement." + if (!target) { + target = document.documentElement; + } + + // "If target is null, call getSelection() on the context object, and + // call removeAllRanges() on the result." + if (!target) { + Aloha.getSelection().removeAllRanges(); + + // "Otherwise, call getSelection() on the context object, and call + // selectAllChildren(target) on the result." + } else { + Aloha.getSelection().selectAllChildren(target); + } + } +}; + +//@} +///// The styleWithCSS command ///// +//@{ +commands.stylewithcss = { + action: function(value) { + // "If value is an ASCII case-insensitive match for the string + // "false", set the CSS styling flag to false. Otherwise, set the + // CSS styling flag to true." + cssStylingFlag = String(value).toLowerCase() != "false"; + }, state: function() { return cssStylingFlag } +}; + +//@} +///// The useCSS command ///// +//@{ +commands.usecss = { + action: function(value) { + // "If value is an ASCII case-insensitive match for the string "false", + // set the CSS styling flag to true. Otherwise, set the CSS styling + // flag to false." + cssStylingFlag = String(value).toLowerCase() == "false"; + } +}; +//@} + +// Some final setup +//@{ +(function() { +// Opera 11.50 doesn't implement Object.keys, so I have to make an explicit +// temporary, which means I need an extra closure to not leak the temporaries +// into the global namespace. >:( +var commandNames = []; +for (var command in commands) { + commandNames.push(command); +} +$_( commandNames ).forEach(function(command) { + // "If a command does not have a relevant CSS property specified, it + // defaults to null." + if (!("relevantCssProperty" in commands[command])) { + commands[command].relevantCssProperty = null; + } + + // "If a command has inline command activated values defined but + // nothing else defines when it is indeterminate, it is indeterminate + // if among editable Text nodes effectively contained in the active + // range, there is at least one whose effective command value is one of + // the given values and at least one whose effective command value is + // not one of the given values." + if ("inlineCommandActivatedValues" in commands[command] + && !("indeterm" in commands[command])) { + commands[command].indeterm = function( range ) { + var values = $_( getAllEffectivelyContainedNodes(range, function(node) { + return isEditable(node) + && node.nodeType == $_.Node.TEXT_NODE; + }) ).map(function(node) { return getEffectiveCommandValue(node, command) }); + + var matchingValues = $_( values ).filter(function(value) { + return $_( commands[command].inlineCommandActivatedValues ).indexOf(value) != -1; + }); + + return matchingValues.length >= 1 + && values.length - matchingValues.length >= 1; + }; + } + + // "If a command has inline command activated values defined, its state + // is true if either no editable Text node is effectively contained in + // the active range, and the active range's start node's effective + // command value is one of the given values; or if there is at least + // one editable Text node effectively contained in the active range, + // and all of them have an effective command value equal to one of the + // given values." + if ("inlineCommandActivatedValues" in commands[command]) { + commands[command].state = function(range) { + var nodes = getAllEffectivelyContainedNodes(range, function(node) { + return isEditable(node) + && node.nodeType == $_.Node.TEXT_NODE; + }); + + if (nodes.length == 0) { + return $_( commands[command].inlineCommandActivatedValues ) + .indexOf(getEffectiveCommandValue(range.startContainer, command)) != -1; + return ret; + } else { + return $_( nodes ).every(function(node) { + return $_( commands[command].inlineCommandActivatedValues ) + .indexOf(getEffectiveCommandValue(node, command)) != -1; + }); + } + }; + } + + // "If a command is a standard inline value command, it is + // indeterminate if among editable Text nodes that are effectively + // contained in the active range, there are two that have distinct + // effective command values. Its value is the effective command value + // of the first editable Text node that is effectively contained in the + // active range, or if there is no such node, the effective command + // value of the active range's start node." + if ("standardInlineValueCommand" in commands[command]) { + commands[command].indeterm = function() { + var values = $_(getAllEffectivelyContainedNodes(getActiveRange())) + .filter(function(node) { return isEditable(node) && node.nodeType == $_.Node.TEXT_NODE }, true) + .map(function(node) { return getEffectiveCommandValue(node, command) }); + for (var i = 1; i < values.length; i++) { + if (values[i] != values[i - 1]) { + return true; + } + } + return false; + }; + + commands[command].value = function(range) { + var refNode = getAllEffectivelyContainedNodes(range, function(node) { + return isEditable(node) + && node.nodeType == $_.Node.TEXT_NODE; + })[0]; + + if (typeof refNode == "undefined") { + refNode = range.startContainer; + } + + return getEffectiveCommandValue(refNode, command); + }; + } +}); +})(); +//@} +return { + commands: commands, + execCommand: myExecCommand, + queryCommandIndeterm: myQueryCommandIndeterm, + queryCommandState: myQueryCommandState, + queryCommandValue: myQueryCommandValue, + queryCommandEnabled: myQueryCommandEnabled, + queryCommandSupported: myQueryCommandSupported +} +}); // end define +// vim: foldmarker=@{,@} foldmethod=marker + +/*! +* CommandManager file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with CommandManager program. If not, see . +*/ + +define('aloha/command',[ 'aloha/core', 'aloha/registry', 'aloha/engine', 'util/dom', 'aloha/contenthandlermanager' ], +function( Aloha, Registry, Engine, Dom, ContentHandlerManager ) { + +// Action: What the command does when executed via execCommand(). Every command defined +// in CommandManager specification has an action defined for it in the relevant section. For example, +// the bold command's action generally makes the current selection bold, or removes bold if +// the selection is already bold. An editing toolbar might provide buttons that execute the +// action for a command if clicked, or a script might run an action without user interaction +// to achieve some particular effect. +// +// Indeterminate: A boolean value returned by queryCommandIndeterm(), depending on the +// current state of the document. Generally, a command that has a state defined will be +// indeterminate if the state is true for part but not all of the current selection, and a +// command that has a value defined will be indeterminate if different parts of the +// selection have different values. An editing toolbar might display a button or control +// in a special way if the command is indeterminate, like showing a "bold" button as +// partially depressed, or leaving a font size selector blank instead of showing the font +// size of the current selection. As a rule, a command can only be indeterminate if its +// state is false, supposing it has a state. +// +// State: A boolean value returned by queryCommandState(), depending on the current state +// of the document. The state of a command is true if it is already in effect, in some +// sense specific to the command. Most commands that have a state defined will take opposite +// actions depending on whether the state is true or false, such as making the selection +// bold if the state is false and removing bold if the state is true. Others will just +// have no effect if the state is true, like the justifyCenter command. Still others will +// have the same effect regardless, like the styleWithCss command. An editing toolbar might +// display a button or control differently depending on the state and indeterminacy of the +// command. +// +// Value: A string returned by queryCommandValue(), depending on the current state of the +// document. A command usually has a value instead of a state if the property it modifies +// can take more than two different values, like the foreColor command. If the command is +// indeterminate, its value is generally based on the start of the selection. Otherwise, +// in most cases the value holds true for the entire selection, but see the justifyCenter +// command and its three companions for an exception. An editing toolbar might display the +// value of a command as selected in a drop-down or filled in in a text box, if the command +// isn't indeterminate. +// +// Relevant CSS property: CommandManager is defined for certain inline formatting commands, and +// is used in algorithms specific to those commands. It is an implementation detail, and +// is not exposed to authors. If a command does not have a relevant CSS property +// specified, it defaults to null. + + var CommandManager = { + + execCommand: function( commandId, showUi, value, range ) { + + // Read current selection if not passed + if ( !range ) { + if ( !Aloha.getSelection().getRangeCount() ) { + return; + } + range = Aloha.getSelection().getRangeAt( 0 ); + } + + // For the insertHTML command we provide contenthandler API + if ( commandId == 'insertHTML' ) { + //if (typeof Aloha.settings.contentHandler.insertHtml === 'undefined') { + // use all registered content handler; used for copy & paste atm (or write log message) + // Aloha.settings.contentHandler.insertHtml = Aloha.defaults.contentHandler.insertHtml; + //} + value = ContentHandlerManager.handleContent( value, { + contenthandler: Aloha.settings.contentHandler.insertHtml + }); + } + + Engine.execCommand( commandId, showUi, value, range ); + + // Read range after engine modification + range = Aloha.getSelection().getRangeAt( 0 ); + + // FIX: doCleanup should work with W3C range + var startnode = range.commonAncestorContainer.parentNode; + var rangeObject = new window.GENTICS.Utils.RangeObject(); + rangeObject.startContainer = range.startContainer; + rangeObject.startOffset = range.startOffset; + rangeObject.endContainer = range.endContainer; + rangeObject.endOffset = range.endOffset; + Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode); + rangeObject.select(); + Aloha.trigger('aloha-command-executed', commandId); + }, + + // If command is available and not disabled or the active range is not null + // the command is enabled + queryCommandEnabled: function( commandId, range ) { + + // Take current selection if not passed + if ( !range ) { + if ( !Aloha.getSelection().getRangeCount() ) { + return; + } + range = Aloha.getSelection().getRangeAt(0); + } + return Engine.queryCommandEnabled( commandId, range ); + }, + + // "Return true if command is indeterminate, otherwise false." + queryCommandIndeterm: function( commandId, range ) { + + // Take current selection if not passed + if ( !range ) { + if ( !Aloha.getSelection().getRangeCount() ) { + return; + } + range = Aloha.getSelection().getRangeAt(0); + } + return Engine.queryCommandIndeterm( commandId, range ); + + }, + + queryCommandState: function( commandId, range ) { + + // Take current selection if not passed + if ( !range ) { + if ( !Aloha.getSelection().getRangeCount() ) { + return; + } + range = Aloha.getSelection().getRangeAt(0); + } + return Engine.queryCommandState( commandId, range ); + + }, + + // "When the queryCommandSupported(command) method on the HTMLDocument + // interface is invoked, the user agent must return true if command is + // supported, and false otherwise." + queryCommandSupported: function( commandId ) { + + return Engine.queryCommandSupported( commandId ); + }, + + queryCommandValue: function( commandId, range ) { + + // Take current selection if not passed + if ( !range ) { + if ( !Aloha.getSelection().getRangeCount() ) { + return; + } + range = Aloha.getSelection().getRangeAt(0); + } + + // "Return command's value." + return Engine.queryCommandValue( commandId, range ); + }, + querySupportedCommands: function() { + + var + commands = [], + command; + + for ( command in Engine.commands ) { + commands.push( command ); + } + return commands; + } + }; + + // create an instance + CommandManager = new ( Registry.extend( CommandManager ) )(); + + /** + * Executes a registered command. + * http://aryeh.name/spec/editing/editing.html#methods-of-the-htmldocument-interface + * @method + * @param command name of the command + * @param showUI has no effect for Aloha Editor and is only here because in spec... + * @param value depends on the used command and it impementation + * @range optional a range on which the command will be executed if not specified + * the current selection will be used as range + */ + Aloha.execCommand = CommandManager.execCommand; + + /** + * Check wheater the command in enabled. + * If command is not supported, raise a NOT_SUPPORTED_ERR exception. + * @param command name of the command + * @return true if command is enabled, false otherwise. + */ + Aloha.queryCommandEnabled = CommandManager.queryCommandEnabled; + + /** + * Check if the command has an indetermed state. + * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown + * If command has no indeterminacy, INVALID_ACCESS_ERR exception is thrown + * If command is not enabled, return false. + * @param command name of the command + * @range optional a range on which the command will be executed if not specified + * the current selection will be used as range + * @return true if command is indeterminate, otherwise false. + */ + Aloha.queryCommandIndeterm = CommandManager.queryCommandIndeterm; + + /** + * Returns the state of a given command + * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown + * If command has no state, an INVALID_ACCESS_ERR exception is thrown + * If command is not enabled, return false + * If the state override for command is set, it returns the state + * @param command name of the command + * @return state override or true if command's state is true, otherwise false. + */ + Aloha.queryCommandState = CommandManager.queryCommandState; + + /** + * Check if a given command is supported + * @return true if command is supported, and false otherwise. + */ + Aloha.queryCommandSupported = CommandManager.queryCommandSupported; + + /** + * Returns the Value of a given Command + * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown + * If command is not enabled, returns an empty string + * If command is "fontSize" and its value override is set, an integer + * number of pixels is returned as font size for the result. + * If the value override for command is set, it returns that. + * @return command's value. + */ + Aloha.queryCommandValue = CommandManager.queryCommandValue; + + Aloha.querySupportedCommands = CommandManager.querySupportedCommands; + + return CommandManager; +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +// use specified jQuery or load jQuery + +define('aloha/jquery.patch',[ 'aloha/jquery' ], +function( jQuery ) { + + //PATCH FOR A JQUERY BUG IN 1.6.1 & 1.6.2 + //An additional sanity check was introduced to prevent IE from crashing when cache[id] does not exist + jQuery.data = ( function( jQuery ) { + return function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + //if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + if ( (!id || (pvt && id && (!cache[id] || !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ jQuery.camelCase( name ) ] : thisCache; + }; + })( jQuery ); + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/jquery.aloha',[ 'aloha/core', 'aloha/selection', 'aloha/jquery', 'aloha/console' ], +function( Aloha, Selection, jQuery, console ) { + + + var +// $ = jQuery, +// Aloha = window.Aloha, +// console = window.console, + XMLSerializer = window.XMLSerializer; + + /** + * jQuery between Extension + * + * insert either html code, a dom object OR a jQuery object inside of an existing text node. + * if the chained jQuery object is not a text node, nothing will happen. + * + * @param content HTML Code, DOM object or jQuery object to be inserted + * @param offset character offset from the start where the content should be inserted + */ + jQuery.fn.between = function(content, offset) { + var + offSize, + fullText; + + if (this[0].nodeType !== 3) { + // we are not in a text node, just insert the element at the corresponding position + offSize = this.children().size(); + if (offset > offSize) { + offset = offSize; + } + if (offset <= 0) { + this.prepend(content); + } else { + this.children().eq(offset -1).after(content); + } + } else { + // we are in a text node so we have to split it at the correct position + if (offset <= 0) { + this.before(content); + } else if (offset >= this[0].length) { + this.after(content); + } else { + fullText = this[0].data; + this[0].data = fullText.substring(0, offset); + this.after(fullText.substring(offset, fullText.length)); + this.after(content); + } + } + }; + + /** + * Make the object contenteditable. Care about browser version (name of contenteditable attribute depends on it) + */ + jQuery.fn.contentEditable = function( b ) { + // ie does not understand contenteditable but contentEditable + // contentEditable is not xhtml compatible. + var $el = jQuery(this); + var ce = 'contenteditable'; + + // Check + if (jQuery.browser.msie && parseInt(jQuery.browser.version,10) == 7 ) { + ce = 'contentEditable'; + } + + if (typeof b === 'undefined' ) { + + // For chrome use this specific attribute. The old ce will only + // return 'inherit' for nested elements of a contenteditable. + // The isContentEditable is a w3c standard compliant property which works in IE7,8,FF36+, Chrome 12+ + if (typeof $el[0] === 'undefined' ) { + console.error('The jquery object did not contain any valid elements.'); + return undefined; + } + if (typeof $el[0].isContentEditable === 'undefined') { + console.warn('Could not determine whether the is editable or not. I assume it is.'); + return true; + } else { + return $el[0].isContentEditable; + } + } else if (b === '') { + $el.removeAttr(ce); + } else { + if (b && b !== 'false') { + b = 'true'; + } else { + b = 'false'; + } + $el.attr(ce, b); + } + + return $el; + }; + + /** + * jQuery Aloha Plugin + * + * turn all dom elements to continous text + * @return jQuery object for the matched elements + * @api + */ + jQuery.fn.aloha = function() { + var $this = jQuery( this ); + + Aloha.bind( 'aloha-ready', function() { + $this.each( function() { + // create a new aloha editable object for each passed object + if ( !Aloha.isEditable( this ) ) { + new Aloha.Editable( jQuery( this ) ); + } + }); + }); + + // Chain + return $this; + }; + + /** + * jQuery destroy elements as editable + * + * destroy all mached elements editable capabilities + * @return jQuery object for the matched elements + * @api + */ + jQuery.fn.mahalo = function() { + return this.each(function() { + if (Aloha.isEditable(this)) { + Aloha.getEditableById(jQuery(this).attr('id')).destroy(); + } + }); + }; + + /** + * jQuery Extension + * new Event which is triggered whenever a selection (length >= 0) is made in + * an Aloha Editable element + */ + jQuery.fn.contentEditableSelectionChange = function(callback) { + var that = this; + + // update selection when keys are pressed + this.keyup(function(event){ + var rangeObject = Selection.getRangeObject(); + callback(event); + }); + + // update selection on doubleclick (especially important for the first automatic selection, when the Editable is not active yet, but is at the same time activated as the selection occurs + this.dblclick(function(event) { + callback(event); + }); + + // update selection when text is selected + this.mousedown(function(event){ + // remember that a selection was started + that.selectionStarted = true; + }); + jQuery(document).mouseup(function(event) { + Selection.eventOriginalTarget = that; + if (that.selectionStarted) { + callback(event); + } + Selection.eventOriginalTarget = false; + that.selectionStarted = false; + }); + + return this; + }; + + /** + * Fetch the outerHTML of an Element + * @version 1.0.0 + * @date February 01, 2011 + * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle} + * @author Benjamin Arthur Lupton {@link http://balupton.com} + * @copyright 2011 Benjamin Arthur Lupton {@link http://balupton.com} + * @license MIT License {@link http://creativecommons.org/licenses/MIT/} + * @return {String} outerHtml + */ + jQuery.fn.outerHtml = jQuery.fn.outerHtml || function(){ + var + $el = jQuery(this), + el = $el.get(0); + if (typeof el.outerHTML != 'undefined') { + return el.outerHTML; + } else { + try { + // Gecko-based browsers, Safari, Opera. + return (new XMLSerializer()).serializeToString(el); + } catch (e) { + try { + // Internet Explorer. + return el.xml; + } catch (e) {} + } + } + + }; + + + jQuery.fn.zap = function () { + return this.each(function(){ jQuery(this.childNodes).insertBefore(this); }).remove(); + }; + + jQuery.fn.textNodes = function(excludeBreaks, includeEmptyTextNodes) { + var + ret = [], + doSomething = function(el){ + if ( + (el.nodeType === 3 && jQuery.trim(el.data) && !includeEmptyTextNodes) || + (el.nodeType === 3 && includeEmptyTextNodes) || + (el.nodeName =="BR" && !excludeBreaks)) { + ret.push(el); + } else { + for (var i=0, childLength = el.childNodes.length; i < childLength; ++i) { + doSomething(el.childNodes[i]); + } + } + }; + + doSomething(this[0]); + + return jQuery(ret); + }; + + /** + * extendObjects is like jQuery.extend, but it does not extend arrays + */ + jQuery.extendObjects = jQuery.fn.extendObjects = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + if (jQuery.isArray(copy)) { + // don't extend arrays + target[ name ] = copy; + } else { + target[ name ] = jQuery.extendObjects( deep, clone, copy ); + } + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; + }; + + jQuery.isBoolean = function(b) { + return b === true || b === false; + }, + + jQuery.isNumeric = function(o) { + return ! isNaN (o-0); + } +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +/** + * @todo: - Make the sidebars resizable using drag handles + * - Make overlayPage setting settable from external config + */ + +define('aloha/sidebar',[ + 'aloha/core', + 'aloha/jquery', + 'aloha/selection' + // 'aloha/plugin' // For when we plugify sidebar +], function ( Aloha, jQuery, Selection, Plugin ) { + + + var $ = jQuery; + var undefined = void 0; + // Pseudo-namespace prefix for Sidebar elements + // Rational: + // We use a prefix instead of an enclosing class or id because we need to + // be paranoid of unintended style inheritance in an environment like the + // one in which Aloha-Editor operates in, with its numerous custom plugins. + // eg: .inner or .btn can be used in several plugins, with eaching adding + // to the class styles properties that we don't want. + var ns = 'aloha-sidebar'; + var uid = +( new Date ); + // namespaced classnames + var nsClasses = { + 'bar' : nsClass( 'bar' ), + 'handle' : nsClass( 'handle' ), + 'inner' : nsClass( 'inner' ), + 'panels' : nsClass( 'panels' ), + 'config-btn' : nsClass( 'config-btn' ), + 'handle-icon' : nsClass( 'handle-icon' ), + 'panel-content' : nsClass( 'panel-content' ), + 'panel-content-inner' : nsClass( 'panel-content-inner' ), + 'panel-content-inner-text' : nsClass( 'panel-content-inner-text' ), + 'panel-title' : nsClass( 'panel-title' ), + 'panel-title-arrow' : nsClass( 'panel-title-arrow' ), + 'panel-title-text' : nsClass( 'panel-title-text' ) + }; + + // Extend jQuery easing animations + if ( !jQuery.easing.easeOutExpo ) { + jQuery.extend(jQuery.easing, { + easeOutExpo: function (x, t, b, c, d) { + return (t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b; + }, + easeOutElastic: function (x, t, b, c, d) { + var m=Math,s=1.70158,p=0,a=c; + if(!t)return b; + if((t/=d)==1)return b+c; + if(!p)p=d*.3; + if(a' + + '
      ' + + '' + + '
      ' + + '
      ' + + '
        ' + + '
        ' + + '
      ' + ) ); + // defaults + this.width = 300; + this.opened = false; + this.isOpen = false; + + this.settings = { + // We automatically set this to true when we are in IE, where rotating + // elements using filters causes undesirable rendering ugliness. + // Our solution is to fallback to swapping icon images. + // We set this as a sidebar property so that it can overridden by + // whoever thinks they are smarter than we are. + rotateIcons : !jQuery.browser.msie, + overlayPage : true + }; + + // Initialize after dom is ready + jQuery( function () { + if ( !( ( typeof Aloha.settings.sidebar != 'undefined' ) && + Aloha.settings.sidebar.disabled ) ) { + sidebar.init( opts ); + } + } ); + }; + + // ------------------------------------------------------------------------ + // Sidebar prototype + // All properties to be shared across Sidebar instances can be placed in + // the prototype object + // ------------------------------------------------------------------------ + jQuery.extend(Sidebar.prototype, { + + // Build as much of the sidebar as we can before appending it to DOM to + // minimize reflow. + init: function (opts) { + var that = this; + var panels; + + // Pluck panels list from opts + if (typeof opts == 'object') { + panels = opts.panels; + delete opts.panels; + } + + // Copy any implements, and overrides in opts to this Sidebar instance + jQuery.extend(this, opts); + + if (typeof panels == 'object') { + jQuery.each(panels, function () { + that.addPanel(this, true); + }); + } + + var bar = this.container; + + if (this.position == 'right') { + bar.addClass(nsClass('right')); + } + + // Place the bar into the DOM + bar.hide() + .appendTo(jQuery('body')) + .click(function () {that.barClicked.apply(that, arguments);}) + .find(nsSel('panels')).width(this.width); + + // IE7 needs us to explicitly set the container width, since it is + // unable to determine it on its own + bar.width(this.width); + + this.width = bar.width(); + + jQuery(window).resize(function () { + that.updateHeight(); + }); + + this.updateHeight(); + this.roundCorners(); + this.initToggler(); + + this.container.css(this.position == 'right' ? 'marginRight' : 'marginLeft', -this.width); + + if (this.opened) { + this.open(0); + } + + this.toggleHandleIcon(this.isOpen); + + this.subscribeToEvents(); + + jQuery(window).resize(function () { + that.correctHeight(); + }); + + this.correctHeight(); + }, + + show: function () { + this.container.css( 'display', 'block' ); + //.animate({opacity: 1}, 1000); + return this; + }, + + hide: function () { + this.container.css( 'display','none' ); + // .animate({opacity: 0}, 1000, function () { + // jQuery(this).css('display', 'block') + // }); + return this; + }, + + /** + * Determines the effective elements at the current selection. + * Iterates through all panels and checks whether the panel should be + * activated for any of the effective elements in the selection. + * + * @param {Object} range - The Aloha.RangeObject + */ + checkActivePanels: function( range ) { + var effective = []; + + if ( typeof range != 'undefined' && + typeof range.markupEffectiveAtStart != 'undefined' ) { + var l = range.markupEffectiveAtStart.length; + for ( var i = 0; i < l; ++i ) { + effective.push( jQuery( range.markupEffectiveAtStart[ i ] ) ); + } + } + + var that = this; + + jQuery.each( this.panels, function () { + that.showActivePanel( this, effective ); + } ); + + this.correctHeight(); + }, + + subscribeToEvents: function () { + var that = this; + var $container = this.container; + + Aloha.bind( 'aloha-selection-changed', function( event, range ) { + that.checkActivePanels( range ); + } ); + + $container.mousedown( function( e ) { + e.originalEvent.stopSelectionUpdate = true; + Aloha.eventHandled = true; + //e.stopSelectionUpdate = true; + } ); + + $container.mouseup( function ( e ) { + e.originalEvent.stopSelectionUpdate = true; + Aloha.eventHandled = false; + } ); + + Aloha.bind( 'aloha-editable-deactivated', function ( event, params ) { + that.checkActivePanels(); + } ); + }, + + /** + * Dynamically set appropriate heights for panels. + * The height for each panel is determined by the amount of space that + * is available in the viewport and the number of panels that need to + * share that space. + */ + correctHeight: function () { + var height = this.container.find(nsSel('inner')).height() - (15 * 2); + var panels = []; + + jQuery.each(this.panels, function () { + if (this.isActive) { + panels.push(this); + } + }); + + if (panels.length == 0) { + return; + } + + var remainingHeight = height - ((panels[0].title.outerHeight() + 10) * panels.length); + var panel; + var targetHeight; + var panelInner; + var panelText; + var undone; + var toadd = 0; + var math = Math; // Local reference for quicker lookup + + while (panels.length > 0 && remainingHeight > 0) { + remainingHeight += toadd; + + toadd = 0; + undone = []; + + for (var j = panels.length - 1; j >= 0; --j) { + panel = panels[j]; + panelInner = panel.content.find(nsSel('panel-content-inner')); + + targetHeight = math.min( + panelInner.height('auto').height(), + math.floor(remainingHeight / (j + 1)) + ); + + panelInner.height(targetHeight); + + remainingHeight -= targetHeight; + + panelText = panelInner.find(nsSel('panel-content-inner-text')); + + if (panelText.height() > targetHeight) { + undone.push(panel); + toadd += targetHeight; + panelInner.css({ + 'overflow-x': 'hidden', + 'overflow-y': 'scroll' + }); + } else { + panelInner.css('overflow-y', 'hidden'); + } + + if (panel.expanded) { + panel.expand(); + } + } + + panels = undone; + } + }, + + /** + * Checks whether this panel should be activated (ie: made visible) for + * any of the elements specified in a given list of elements. + * + * We have to add a null object to the list of elements to allow us to + * check whether the panel should be visible when we have no effective + * elements in the current selection + * + * @param {Object} panel - The Panel object we will test + * @param {Array} elements - The effective elements (jQuery), any of + * which may activate the panel + */ + showActivePanel: function (panel, elements) { + elements.push(null); + + var j = elements.length; + var count = 0; + var li = panel.content.parent('li'); + var activeOn = panel.activeOn; + var effective = jQuery(); + + for (var i = 0; i < j; ++i) { + if (activeOn(elements[i])) { + ++count; + if (elements[i]) { + jQuery.merge(effective, elements[i]); + } + } + } + + if (count) { + panel.activate(effective); + } else { + panel.deactivate(); + } + + this.roundCorners(); + }, + + /** + * Sets up the functionality, event listeners, and animation of the + * sidebar handle + */ + initToggler: function () { + var that = this; + var bar = this.container; + var icon = bar.find(nsSel('handle-icon')); + var toggledClass = nsClass('toggled'); + var bounceTimer; + var isRight = (this.position == 'right'); + + if (this.opened) { + this.rotateHandleArrow(isRight ? 0 : 180, 0); + } + + bar.find(nsSel('handle')) + .click(function () { + if (bounceTimer) { + clearInterval(bounceTimer); + } + + icon.stop().css('marginLeft', 4); + + if (that.isOpen) { + jQuery(this).removeClass(toggledClass); + that.close(); + that.isOpen = false; + } else { + jQuery(this).addClass(toggledClass); + that.open(); + that.isOpen = true; + } + }).hover( + function () { + var flag = that.isOpen ? -1 : 1; + + if (bounceTimer) { + clearInterval(bounceTimer); + } + + icon.stop(); + + jQuery(this).stop().animate( + isRight ? {marginLeft: '-=' + (flag * 5)} : {marginRight: '-=' + (flag * 5)}, + 200 + ); + + bounceTimer = setInterval(function () { + flag *= -1; + icon.animate( + isRight ? {left: '-=' + (flag * 4)} : {right: '-=' + (flag * 4)}, + 300 + ); + }, 300); + }, + + function () { + if (bounceTimer) { + clearInterval(bounceTimer); + } + + icon.stop().css(isRight ? 'left' : 'right', 5); + + jQuery(this).stop().animate( + isRight ? {marginLeft: 0} : {marginRight: 0}, + 600, 'easeOutElastic' + ); + } + ); + }, + + /** + * Rounds the top corners of the first visible panel, and the bottom + * corners of the last visible panel elements in the panels ul list + */ + roundCorners: function () { + var bar = this.container; + var lis = bar.find(nsSel('panels>li:not(', 'deactivated)')); + var topClass = nsClass('panel-top'); + var bottomClass = nsClass('panel-bottom'); + + bar.find(nsSel('panel-top,', 'panel-bottom')) + .removeClass(topClass) + .removeClass(bottomClass); + + lis.first().find(nsSel('panel-title')).addClass(topClass); + lis.last().find(nsSel('panel-content')).addClass(bottomClass); + }, + + /** + * Updates the height of the inner div of the sidebar. This is done + * whenever the viewport is resized + */ + updateHeight: function () { + var h = jQuery(window).height(); + this.container.height(h).find(nsSel('inner')).height(h); + }, + + /** + * Delegate all sidebar onclick events to the container. + * Then use handleBarclick method until we bubble up to the first + * significant element that we can interact with + */ + barClicked: function (ev) { + this.handleBarclick(jQuery(ev.target)); + }, + + /** + * We handle all click events on the sidebar from here--dispatching + * calls to which ever methods that should be invoked for the each + * interaction + */ + handleBarclick: function (el) { + if (el.hasClass(nsClass('panel-title'))) { + this.togglePanel(el); + } else if (el.hasClass(nsClass('panel-content'))) { + // Aloha.Log.log('Content clicked'); + } else if (el.hasClass(nsClass('handle'))) { + // Aloha.Log.log('Handle clicked'); + } else if (el.hasClass(nsClass('bar'))) { + // Aloha.Log.log('Sidebar clicked'); + } else { + this.handleBarclick(el.parent()); + } + }, + + getPanelById: function (id) { + return this.panels[id]; + }, + + getPanelByElement: function (el) { + var li = (el[0].tagName == 'LI') ? el : el.parent('li'); + return this.getPanelById(li[0].id); + }, + + togglePanel: function (el) { + this.getPanelByElement(el).toggle(); + }, + + /** + * Animation to rotate the sidebar arrow + * + * @param {Number} angle - The angle two which the arrow should rotate + * (0 or 180) + * @param {Number|String} duration - (Optional) How long the animation + * should play for + */ + rotateHandleIcon: function (angle, duration) { + var arr = this.container.find(nsSel('handle-icon')); + arr.animate({angle: angle}, { + duration : (typeof duration == 'number' || typeof duration == 'string') ? duration : 500, + easing : 'easeOutExpo', + step : function (val, fx) { + arr.css({ + '-o-transform' : 'rotate(' + val + 'deg)', + '-webkit-transform' : 'rotate(' + val + 'deg)', + '-moz-transform' : 'rotate(' + val + 'deg)', + '-ms-transform' : 'rotate(' + val + 'deg)' + // We cannot use Microsoft Internet Explorer filters + // because Microsoft Internet Explore 8 does not support + // Microsoft Internet Explorer filters correctly. It + // breaks the layout + // filter : 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (angle / 90) + ')' + }); + } + }); + }, + + /** + * Sets the handle icon to the "i am opened, click me to close the + * sidebar" state, or vice versa. The direction of the arrow depends + * on whether the sidebar is on the left or right, and whether it is + * in an opened state or not. + * + * Question: + * Given that the arrow icon is by default pointing right, should + * we make it point left? + * + * Answer: + * isRight & isOpen : no + * isRight & isClosed : yes + * isLeft & isOpen : yes + * isLeft & isClosed : no + * + * Truth table: + * isRight | isOpen | XOR + * ---------+--------+----- + * T | T | F + * T | F | T + * F | T | T + * F | F | F + * + * Therefore: + * isPointingLeft = isRight XOR isOpen + * + * @param {Boolean} isOpened - Whether or not the sidebar is in the + * opened state + */ + toggleHandleIcon: function (isOpen) { + var isPointingLeft = (this.position == 'right') ^ isOpen; + + if (this.settings.rotateIcons) { + this.rotateHandleIcon(isPointingLeft ? 180 : 0, 0); + } else { + var icon = this.container.find(nsSel('handle-icon')); + + if (isPointingLeft) { + icon.addClass(nsClass('handle-icon-left')); + } else { + icon.removeClass(nsClass('handle-icon-left')); + } + } + }, + + /** + * Slides the sidebar into view + */ + open: function (duration, callback) { + if (this.isOpen) { + return this; + } + + var isRight = (this.position == 'right'); + var anim = isRight ? {marginRight: 0} : {marginLeft: 0}; + + this.toggleHandleIcon(true); + + this.container.animate( + anim, + (typeof duration == 'number' || typeof duration == 'string') + ? duration : 500, + 'easeOutExpo' + ); + + if (!this.settings.overlayPage) { + jQuery('body').animate( + isRight ? {marginRight: '+=' + this.width} : {marginLeft: '+=' + this.width}, + 500, 'easeOutExpo' + ); + } + + this.isOpen = true; + + jQuery('body').trigger(nsClass('opened'), this); + + return this; + }, + + /** + * Slides that sidebar out of view + */ + close: function (duration, callback) { + if (!this.isOpen) { + return this; + } + + var isRight = (this.position == 'right'); + var anim = isRight ? {marginRight: -this.width} : {marginLeft: -this.width}; + + this.toggleHandleIcon(false); + + this.container.animate( + anim, + (typeof duration == 'number' || typeof duration == 'string') + ? duration : 500, + 'easeOutExpo' + ); + + if (!this.settings.overlayPage) { + jQuery('body').animate( + isRight ? {marginRight: '-=' + this.width} : {marginLeft: '-=' + this.width}, + 500, 'easeOutExpo' + ); + } + + this.isOpen = false; + + return this; + }, + + /** + * Activates the given panel and passes to it the given element as the + * the effective that we want it to think activated it. + * + * @param {Object|String} panel - Panel instance or the id of a panel + * object + * @param {jQuery} element - Element to pass to the panel as effective + * element (the element that activated it) + */ + activatePanel: function (panel, element) { + if (typeof panel == 'string') { + panel = this.getPanelById(panel); + } + + if (panel){ + panel.activate(element); + } + + this.roundCorners(); + + return this; + }, + + /** + * Invokes the expand method for the given panel so that it expands its + * height to display its contents + * + * @param {Object|String} panel - Panel instance or the id of a panel + * object + * @param {Funtion} callback + */ + expandPanel: function (panel, callback) { + if (typeof panel == 'string') { + panel = this.getPanelById(panel); + } + + if (panel){ + panel.expand(callback); + } + + return this; + }, + + /** + * Collapses the panel contents by invoking the given panel's collapse + * method. + * + * @param {Object|String} panel - Panel instance or the id of a panel + * object + * @param {Funtion} callback + */ + collapsePanel: function (panel, callback) { + if (typeof panel == 'string') { + panel = this.getPanelById(panel); + } + + if (panel){ + panel.collapse(callback); + } + + return this; + }, + + /** + * Adds a panel to this sidebar instance. + * We try and build as much of the panel DOM as we can before inserting + * it into the DOM in order to reduce reflow. + * + * @param {Object} panel - either a panel instance or an associative + * array containing settings for the construction + * of a new panel. + * @param {Boolean} deferRounding - (Optional) If true, the rounding-off + * of the top most and bottom most panels + * will not be automatically done. Set + * this to true when adding a lot of panels + * at once. + * @return {Object} - The newly created panel. + */ + addPanel: function (panel, deferRounding) { + if (!(panel instanceof Panel)) { + if (!panel.width) { + panel.width = this.width; + } + panel.sidebar = this; + panel = new Panel(panel); + } + + this.panels[panel.id] = panel; + + this.container.find(nsSel('panels')).append(panel.element); + + if (deferRounding !== true) { + this.roundCorners(); + } + this.checkActivePanels(Selection.getRangeObject()); + return panel; + } + + }); + + // ------------------------------------------------------------------------ + // Panel constructor + // ------------------------------------------------------------------------ + var Panel = function Panel (opts) { + this.id = null; + this.folds = {}; + this.button = null; + this.title = jQuery(renderTemplate(' \ +
      \ + \ + Untitled \ +
      \ + ')); + this.content = jQuery(renderTemplate(' \ +
      \ +
      \ +
      \ +
      \ +
      \ +
      \ + ')); + this.element = null; + this.expanded = false; + this.effectiveElement = null; + this.isActive = true; + + this.init(opts); + }; + + // ------------------------------------------------------------------------ + // Panel prototype + // ------------------------------------------------------------------------ + jQuery.extend(Panel.prototype, { + + init: function (opts) { + this.setTitle(opts.title) + .setContent(opts.content); + + delete opts.title; + delete opts.content; + + jQuery.extend(this, opts); + + if (!this.id) { + this.id = nsClass(++uid); + } + + var li = this.element = + jQuery('
    • ') + .append(this.title, this.content); + + if (this.expanded){ + this.content.height('auto'); + } + + this.toggleTitleIcon(this.expanded); + + this.coerceActiveOn(); + + // Disable text selection on title element + this.title + .attr('unselectable', 'on') + .css('-moz-user-select', 'none') + .each(function() {this.onselectstart = function() {return false;};}); + + if (typeof this.onInit == 'function') { + this.onInit.apply(this); + } + }, + + /** + * @param {Boolean} isExpanded - Whether or not the panel is in an + * expanded state + */ + toggleTitleIcon: function (isExpanded) { + if (this.sidebar.settings.rotateIcons) { + this.rotateTitleIcon(isExpanded ? 90 : 0); + } else { + var icon = this.title.find(nsSel('panel-title-arrow')); + + if (isExpanded) { + icon.addClass(nsClass('panel-title-arrow-down')); + } else { + icon.removeClass(nsClass('panel-title-arrow-down')); + } + } + }, + + /** + * Normalizes the activeOn property into a predicate function + */ + coerceActiveOn: function () { + if (typeof this.activeOn != 'function') { + var activeOn = this.activeOn; + + this.activeOn = (function () { + var typeofActiveOn = typeof activeOn, + fn; + + if (typeofActiveOn == 'boolean') { + fn = function () { + return activeOn; + }; + } else if (typeofActiveOn == 'undefined') { + fn = function () { + return true; + }; + } else if (typeofActiveOn == 'string') { + fn = function (el) { + return el ? el.is(activeOn) : false; + }; + } else { + fn = function () { + return false; + }; + } + + return fn; + })(); + } + }, + + /** + * Activates (displays) this panel + */ + activate: function (effective) { + this.isActive = true; + this.content.parent('li').show().removeClass(nsClass('deactivated')); + this.effectiveElement = effective; + if (typeof this.onActivate == 'function') { + this.onActivate.call(this, effective); + } + }, + + /** + * Hides this panel + */ + deactivate: function () { + this.isActive = false; + this.content.parent('li').hide().addClass(nsClass('deactivated')); + this.effectiveElement = null; + }, + + toggle: function () { + if (this.expanded) { + this.collapse(); + } else { + this.expand(); + } + }, + + /** + * Displays the panel's contents + */ + expand: function (callback) { + var that = this; + var el = this.content; + var old_h = el.height(); + var new_h = el.height('auto').height(); + + el.height(old_h).stop().animate( + {height: new_h}, 500, 'easeOutExpo', + function () { + if (typeof callback == 'function') { + callback.call(that); + } + } + ); + + this.element.removeClass('collapsed'); + this.toggleTitleIcon(true); + + this.expanded = true; + + return this; + }, + + /** + * Hides the panel's contents--leaving only it's header + */ + collapse: function (duration, callback) { + var that = this; + this.element.addClass('collapsed'); + this.content.stop().animate( + {height: 5}, 250, 'easeOutExpo', + function () { + if (typeof callback == 'function') { + callback.call(that); + } + } + ); + + this.toggleTitleIcon(false); + + this.expanded = false; + + return this; + }, + + /** + * May also be called by the Sidebar to update title of panel + * + * @param html - Markup string, DOM object, or jQuery object + */ + setTitle: function (html) { + this.title.find(nsSel('panel-title-text')).html(html); + return this; + }, + + /** + * May also be called by the Sidebar to update content of panel + * + * @param html - Markup string, DOM object, or jQuery object + */ + setContent: function (html) { + // We do this so that empty panels don't appear collapsed + if (!html || html == '') { + html = ' '; + } + + this.content.find(nsSel('panel-content-inner-text')).html(html); + return this; + }, + + rotateTitleIcon: function (angle, duration) { + var arr = this.title.find(nsSel('panel-title-arrow')); + arr.animate({angle: angle}, { + duration : (typeof duration == 'number') ? duration : 500, + easing : 'easeOutExpo', + step : function (val, fx) { + arr.css({ + '-o-transform' : 'rotate(' + val + 'deg)', + '-webkit-transform' : 'rotate(' + val + 'deg)', + '-moz-transform' : 'rotate(' + val + 'deg)', + '-ms-transform' : 'rotate(' + val + 'deg)' + // filter : 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (angle / 90) + ')' + }); + } + }); + }, + + /** + * Walks up the ancestors chain for the given effective element, and + * renders subpanels using the specified renderer function. + * + * @param {jQuery} effective - The effective element, whose lineage we + * want to render + * @param {Function} renderer - (Optional) function that will render + * each element in the parental lineage + * of the effective element + */ + renderEffectiveParents: function (effective, renderer) { + var el = effective.first(); + var content = []; + var path = []; + var activeOn = this.activeOn; + var l; + var pathRev; + + while (el.length > 0 && !el.is('.aloha-editable')) { + + if (activeOn(el)) { + path.push('' + el[0].tagName.toLowerCase() + ''); + l = path.length; + pathRev = []; + while (l--) { + pathRev.push(path[l]); + } + content.push(supplant( + '
      ' + + '
      {path}
      ' + + '
      {content}
      ' + + '
      ', + { + path : pathRev.join(''), + content : (typeof renderer == 'function') ? renderer(el) : '----' + } + )); + } + + el = el.parent(); + } + + this.setContent(content.join('')); + + jQuery('.aloha-sidebar-panel-parent-path').click(function () { + var c = jQuery(this).parent().find('.aloha-sidebar-panel-parent-content'); + + if (c.hasClass('aloha-sidebar-opened')) { + c.hide().removeClass('aloha-sidebar-opened'); + } else { + c.show().addClass('aloha-sidebar-opened'); + } + }); + + this.content.height('auto').find('.aloha-sidebar-panel-content-inner').height('auto'); + } + + }); + + var left = new Sidebar({ + position : 'left', + width : 250 // TODO define in config + }); + + var right = new Sidebar({ + position : 'right', + width : 250 // TODO define in config + }); + + Aloha.Sidebar = { + left : left, + right : right + }; + + return Aloha.Sidebar; + +}); + +/*! + * This file is part of Aloha Editor + * Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + */ +// Start Closure +// Ensure GENTICS Namespace +GENTICS = window.GENTICS || {}; +GENTICS.Utils = GENTICS.Utils || {}; +define('util/position',['aloha/jquery'], +function(jQuery) { + + + var + $ = jQuery, + GENTICS = window.GENTICS, + Class = window.Class, + console = window.console; + +/** + * position utility, which will provide scroll and mouse positions + * please note that the positions provided by this class are not + * realtime - instead they are calculated with a 0.5 second delay + */ +GENTICS.Utils.Position = {}; + +/** + * jquery reference to the window object + */ +GENTICS.Utils.Position.w = jQuery(window); + +/** + * contains the current scroll top and left position, and indicates if the user is currently scrolling + * @api + */ +GENTICS.Utils.Position.Scroll = { + top : 0, + left : 0, + isScrolling : false +}; + +/** + * contains the scroll corrections to apply on special cases (ribbon for example) + * @api + */ +GENTICS.Utils.Position.ScrollCorrection = { + top : 0, + left : 0 +}; + +/** + * contains the current mouse position (x,y) as well as an indicator if the mouse is moving + * @api + */ +GENTICS.Utils.Position.Mouse = { + x : 0, + y : 0, + oldX : 0, + oldY : 0, + isMoving : false, + triggeredMouseStop : true +}; + +/** + * contains all mousestop callbacks + */ +GENTICS.Utils.Position.mouseStopCallbacks = []; + +/** + * contains all mousemove callbacks + */ +GENTICS.Utils.Position.mouseMoveCallbacks = []; + +/** + * updates scroll position and the scrolling status + */ +GENTICS.Utils.Position.update = function () { + // update scroll position + var + st = this.w.scrollTop(), + sl = this.w.scrollLeft(), + i; + + if (this.Scroll.isScrolling) { + if (this.Scroll.top == st && this.Scroll.left == sl) { + // stopped scrolling + this.Scroll.isScrolling = false; + } + } else { + if (this.Scroll.top != st || this.Scroll.left != sl) { + // started scrolling + this.Scroll.isScrolling = true; + } + } + + // update scroll positions + this.Scroll.top = st; + this.Scroll.left = sl; + + // check wether the user has stopped moving the mouse + if (this.Mouse.x == this.Mouse.oldX && this.Mouse.y == this.Mouse.oldY) { + this.Mouse.isMoving = false; + // now check if we've triggered the mousestop event + if (!this.Mouse.triggeredMouseStop) { + this.Mouse.triggeredMouseStop = true; + // iterate callbacks + for (i=0; i. +*/ + +define('aloha/repositorymanager',[ + 'aloha/core', + 'util/class', + 'aloha/jquery', + 'aloha/console' +], function ( Aloha, Class, jQuery, console ) { + + + var undefined = void 0; + + /** + * Repository Manager + * @namespace Aloha + * @class RepositoryManager + * @singleton + */ + Aloha.RepositoryManager = Class.extend( { + + repositories : [], + + /** + * Initialize all registered repositories + * Before we invoke each repositories init method, we merge the global + * repository settings into each repository's custom settings + * + * @todo: Write unit tests to check that global and custom settings are + * applied correctly + * + * @return void + * @hide + */ + init: function () { + var repositories = this.repositories, + i = 0, + j = repositories.length, + repository, + settings; + + if ( Aloha.settings && Aloha.settings.repositories ) { + settings = Aloha.settings.repositories; + } else { + settings = {}; + } + + for ( ; i < j; ++i ) { + repository = repositories[ i ]; + + if ( !repository.settings ) { + repository.settings = {}; + } + + if ( settings[ repository.repositoryId ] ) { + jQuery.extend( + repository.settings, + settings[ repository.repositoryId ] + ); + } + + repository.init(); + } + }, + + /** + * Register a Repository. + * + * @param {Aloha.Repository} repository Repository to register + */ + register: function ( repository ) { + if ( !this.getRepository( repository.repositoryId ) ) { + this.repositories.push( repository ); + } else { + console.warn( this, 'A repository with name { ' + + repository.repositoryId + + ' } already registerd. Ignoring this.' ); + } + }, + + /** + * Returns the repository object identified by repositoryId. + * + * @param {String} repositoryId - the name of the repository + * @return {?Aloha.Repository} a repository or null if name not found + */ + getRepository: function ( repositoryId ) { + var repositories = this.repositories, + i = 0, + j = repositories.length; + + for ( ; i < j; ++i ) { + if ( repositories[ i ].repositoryId == repositoryId ) { + return repositories[ i ]; + } + } + + return null; + }, + + /** + * Searches a all repositories for repositoryObjects matching query and + * repositoryObjectType. + * +
      
      +			var params = {
      +					queryString: 'hello',
      +					objectTypeFilter: ['website'],
      +					filter: null,
      +					inFolderId: null,
      +					orderBy: null,
      +					maxItems: null,
      +					skipCount: null,
      +					renditionFilter: null,
      +					repositoryId: null
      +			};
      +			Aloha.RepositoryManager.query( params, function( items ) {
      +				// do something with the result items
      +				console.log(items);
      +			});
      +		
      + * + * @param {Object } params object with properties + *
        + *
      • queryString : String
        The query string for full text search
      • + *
      • objectTypeFilter : array (optional)
        Object types that will be returned.
      • + *
      • filter : array (optional)
        Attributes that will be returned.
      • + *
      • inFolderId : boolean (optional)
        This is indicates whether or not a candidate object is a child-object of the folder object identified by the given inFolderId (objectId).
      • + *
      • inTreeId : boolean (optional)
        This indicates whether or not a candidate object is a descendant-object of the folder object identified by the given inTreeId (objectId).
      • + *
      • orderBy : array (optional)
        ex. [{lastModificationDate:’DESC’, name:’ASC’}]
      • + *
      • maxItems : Integer (optional)
        number items to return as result
      • + *
      • skipCount : Integer (optional)
        This is tricky in a merged multi repository scenario
      • + *
      • renditionFilter : array (optional)
        Instead of termlist an array of kind or mimetype is expected. If null or array.length == 0 all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310 for renditionFilter
      • + *
      + * @param {Function} callback - defines a callback function( items ) which will be called when all repositories returned their results or after a time out of 5sec. + * "items" is an Array of objects construced with Document/Folder. + * @void + */ + query: function ( params, callback ) { + var that = this, + repo, + // The merged results, collected from repository responses + allitems = [], + // the merge metainfo, collected from repository responses + allmetainfo = { numItems: 0, hasMoreItems: false }, + // The set of repositories towhich we want to delegate work + repositories = [], + // A counting semaphore (working in reverse, ie: 0 means free) + numOpenCallbacks = 0, + // When this timer times-out, whatever has been collected in + // allitems will be returned to the calling client, and + // numOpenCallbacks will be reset to 0 + timer, + i, j, + /** + * Invoked by each repository when it wants to present its + * results to the manager. + * + * Collects the results from each repository, and decrements + * the numOpenCallbacks semaphore to indicate that there is one + * less repository for which we are waiting a reponse. + * + * If a repository invokes this callback after all + * openCallbacks have been closed (ie: numOpenCallbacks == 0), + * then the repository was too late ("missed the ship"), and + * will be ignored. + * + * If numOpenCallbacks decrements to 0 during this call, it + * means that the the manager is ready to report the results + * back to the client through the queryCallback method. + * + * nb: "this" is reference to the calling repository. + * + * @param {Array} items - Results returned by the repository + * @param {Object} metainfo - optional Metainfo returned by the repository + */ + processResults = function ( items, metainfo ) { + if ( numOpenCallbacks == 0 ) { + return; + } + + var j = items ? items.length : 0; + + if ( j ) { + // Add the repositoryId for each item if a negligent + // repository did not do so. + if ( !items[ 0 ].repositoryId ) { + var repoId = this.repositoryId; + for ( var i = 0; i < j; ++i ) { + items[ i ].repositoryId = repoId; + } + } + + jQuery.merge( allitems, items ); + } + + if ( metainfo && allmetainfo ) { + if ( jQuery.isNumeric( metainfo.numItems ) && + jQuery.isNumeric( allmetainfo.numItems ) ) { + allmetainfo.numItems += metainfo.numItems; + } else { + allmetainfo.numItems = undefined; + } + + if ( jQuery.isBoolean( metainfo.hasMoreItems ) && + jQuery.isBoolean( allmetainfo.hasMoreItems ) ) { + allmetainfo.hasMoreItems = allmetainfo.hasMoreItems || metainfo.hasMoreItems; + } else { + allmetainfo.hasMoreItems = undefined; + } + } else { + // at least one repository did not return metainfo, so + // we have no aggregated metainfo at all + allmetainfo = undefined; + } + + // TODO how to return the metainfo here? + if ( --numOpenCallbacks == 0 ) { + that.queryCallback( callback, allitems, allmetainfo, timer ); + } + }; + + // Unless the calling client specifies otherwise, we will wait a + // maximum of 5 seconds for all repositories to be queried and + // respond. 5 seconds is deemed to be the reasonable time to wait + // when querying the repository manager in the context of something + // like autocomplete + var timeout = parseInt( params.timeout, 10 ) || 5000; + timer = setTimeout( function() { + numOpenCallbacks = 0; + that.queryCallback( callback, allitems, allmetainfo, timer ); + }, timeout ); + + // If repositoryId or a list of repository ids, is not specified in + // the params object, then we will query all registered + // repositories + if ( params.repositoryId ) { + repositories.push( this.getRepository( params.repositoryId ) ); + } else { + repositories = this.repositories; + } + + j = repositories.length; + + var repoQueue = []; + + // We need to know how many callbacks we will open before invoking + // the query method on each, so that as soon as the first one does + // callback, the correct number of open callbacks will be available + // to check. + + for ( i = 0; i < j; ++i ) { + repo = repositories[ i ]; + + if ( typeof repo.query == 'function' ) { + ++numOpenCallbacks; + repoQueue.push( repo ); + } + } + + j = repoQueue.length; + + for ( i = 0; i < j; ++i ) { + repo = repoQueue[ i ]; + repo.query( + params, + function () { + processResults.apply( repo, arguments ); + } + ); + } + + // If none of the repositories implemented the query method, then + // don't wait for the timeout, simply report to the client + if ( numOpenCallbacks == 0 ) { + this.queryCallback( callback, allitems, allmetainfo, timer ); + } + }, + + /** + * Passes all the results we have collected to the client through the + * callback it specified + * + * @param {Function} callback - Callback specified by client when + * invoking the query method + * @param {Array} items - Results, collected from all repositories + * @param {Object} metainfo - optional object containing metainfo + * @param {Timer} timer - We need to clear this timer + * @return void + * @hide + */ + queryCallback: function ( callback, items, metainfo, timer ) { + if ( timer ) { + clearTimeout( timer ); + timer = undefined; + } + + // TODO: Implement sorting based on repository specification + // sort items by weight + //items.sort(function (a,b) { + // return (b.weight || 0) - (a.weight || 0); + //}); + + // prepare result data for the JSON Reader + var result = { + items : items, + results : items.length + }; + + if ( metainfo ) { + result.numItems = metainfo.numItems; + result.hasMoreItems = metainfo.hasMoreItems; + } + + callback.call( this, result ); + }, + + /** + * @todo: This method needs to be covered with some unit tests + * + * Returns children items. (see query for an example) + * @param {Object} params - object with properties + *
        + *
      • objectTypeFilter : array (optional)
        Object types that will be returned.
      • + *
      • filter : array (optional)
        Attributes that will be returned.
      • + *
      • inFolderId : boolean (optional)
        This indicates whether or not a candidate object is a child-object of the folder object identified by the given inFolderId (objectId).
      • + *
      • orderBy : array (optional)
        ex. [{lastModificationDate:’DESC’, name:’ASC’}]
      • + *
      • maxItems : Integer (optional)
        number items to return as result
      • + *
      • skipCount : Integer (optional)
        This is tricky in a merged multi repository scenario
      • + *
      • renditionFilter : array (optional)
        Instead of termlist an array of kind or mimetype is expected. If null or array.length == 0 all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310 for renditionFilter
      • + *
      + * @param {Function} callback - defines a callback function( items ) which will be called when all repositories returned their results or after a time out of 5sec. + * "items" is an Array of objects construced with Document/Folder. + * @void + */ + getChildren: function ( params, callback ) { + var that = this, + repo, + // The marged results, collected from repository responses + allitems = [], + // The set of repositories towhich we want to delegate work + repositories = [], + // A counting semaphore (working in reverse, ie: 0 means free) + numOpenCallbacks = 0, + // When this timer times-out, whatever has been collected in + // allitems will be returned to the calling client, and + // numOpenCallbacks will be reset to 0 + timer, + i, j, + processResults = function ( items ) { + if ( numOpenCallbacks == 0 ) { + return; + } + + jQuery.merge( allitems, items ); + + if ( --numOpenCallbacks == 0 ) { + that.getChildrenCallback( callback, allitems, timer ); + } + }; + + // If the inFolderId is the default id of 'aloha', then return all + // registered repositories + if ( params.inFolderId == 'aloha' ) { + var repoFilter = params.repositoryFilter, + hasRepoFilter = ( repoFilter && repoFilter.length ); + + j = this.repositories.length; + + for ( i = 0; i < j; ++i ) { + var repo = this.repositories[ i ]; + if ( !hasRepoFilter || jQuery.inArray( repo.repositoryId, repoFilter ) > -1 ) { + repositories.push( + new Aloha.RepositoryFolder( { + id : repo.repositoryId, + name : repo.repositoryName, + repositoryId : repo.repositoryId, + type : 'repository', + hasMoreItems : true + } ) + ); + } + } + + that.getChildrenCallback( callback, repositories, null ); + + return; + } else { + repositories = this.repositories; + } + + var timeout = parseInt( params.timeout, 10 ) || 5000; + timer = setTimeout( function () { + numOpenCallbacks = 0; + that.getChildrenCallback( callback, allitems, timer ); + }, timeout ); + + j = repositories.length; + + for ( i = 0; i < j; ++i ) { + repo = repositories[ i ]; + + if ( typeof repo.getChildren === 'function' ) { + ++numOpenCallbacks; + + repo.getChildren( + params, + function () { + processResults.apply( repo, arguments ); + } + ); + } + } + + if ( numOpenCallbacks == 0 ) { + this.getChildrenCallback( callback, allitems, timer ); + } + }, + + /** + * Returns results for getChildren to calling client + * + * @return void + * @hide + */ + getChildrenCallback: function ( callback, items, timer ) { + if ( timer ) { + clearTimeout( timer ); + timer = undefined; + } + + callback.call( this, items ); + }, + + /** + * @fixme: Not tested, but the code for this function does not seem to + * compute repository.makeClean will be undefined + * + * @todo: Rewrite this function header comment so that is clearer + * + * Pass an object, which represents an marked repository to corresponding + * repository, so that it can make the content clean (prepare for saving) + * + * @param {jQuery} obj - representing an editable + * @return void + */ + makeClean: function ( obj ) { + // iterate through all registered repositories + var that = this, + repository = {}, + i = 0, + j = that.repositories.length; + + // find all repository tags + obj.find( '[data-gentics-aloha-repository=' + this.prefix + ']' ) + .each( function () { + for ( ; i < j; ++i ) { + repository.makeClean( obj ); + } + console.debug( that, + 'Passing contents of HTML Element with id { ' + + this.attr('id') + ' } for cleaning to repository { ' + + repository.repositoryId + ' }' ); + repository.makeClean( this ); + } ); + }, + + /** + * Markes an object as repository of this type and with this item.id. + * Objects can be any DOM objects as A, SPAN, ABBR, etc. or + * special objects such as aloha-aloha_block elements. + * This method marks the target obj with two private attributes: + * (see http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data) + * * data-gentics-aloha-repository: stores the repositoryId + * * data-gentics-aloha-object-id: stores the object.id + * + * @param {DOMObject} obj - DOM object to mark + * @param {Aloha.Repository.Object} item - the item which is applied to obj, + * if set to null, the data-GENTICS-... attributes are removed + * @return void + */ + markObject: function ( obj, item ) { + if ( !obj ) { + return; + } + + if ( item ) { + var repository = this.getRepository( item.repositoryId ); + + if ( repository ) { + jQuery( obj ).attr( { + 'data-gentics-aloha-repository' : item.repositoryId, + 'data-gentics-aloha-object-id' : item.id + } ); + + repository.markObject( obj, item ); + } else { + console.error( this, + 'Trying to apply a repository { ' + item.name + + ' } to an object, but item has no repositoryId.' ); + } + } else { + // remove the data attributes + jQuery( obj ).removeAttr( 'data-gentics-aloha-repository' ); + jQuery( obj ).removeAttr( 'data-gentics-aloha-object-id' ); + } + }, + + /** + * Get the object for which the given DOM object is marked from the + * repository. + * + * @param {DOMObject} obj - DOM object which probably is marked + * @param {Function} callback - callback function + */ + getObject: function ( obj, callback ) { + var that = this, + $obj = jQuery( obj ), + repository = this.getRepository( $obj.attr( 'data-gentics-aloha-repository' ) ), + itemId = $obj.attr( 'data-gentics-aloha-object-id' ); + + if ( repository && itemId ) { + // initialize the item cache (per repository) if not already done + this.itemCache = this.itemCache || []; + this.itemCache[ repository.repositoryId ] = this.itemCache[ repository.repositoryId ] || []; + + // when the item is cached, we just call the callback method + if ( this.itemCache[ repository.repositoryId ][ itemId ] ) { + callback.call( this, [ this.itemCache[ repository.repositoryId ][ itemId ] ] ); + } else { + // otherwise we get the object from the repository + repository.getObjectById( itemId, function ( items ) { + // make sure the item is in the cache (for subsequent calls) + that.itemCache[ repository.repositoryId ][ itemId ] = items[ 0 ]; + callback.call( this, items ); + } ); + } + } + }, + + /** + * @return {String} name of repository manager object + */ + toString: function () { + return 'repositorymanager'; + } + + } ); + + Aloha.RepositoryManager = new Aloha.RepositoryManager(); + + // We return the constructor, not the instance of Aloha.RepositoryManager + return Aloha.RepositoryManager; +} ); + +/** + * @license RequireJS i18n 0.24.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +/*jslint regexp: false, nomen: false, plusplus: false, strict: false */ +/*global require: false, navigator: false, define: false */ + +/** + * This plugin handles i18n! prefixed modules. It does the following: + * + * 1) A regular module can have a dependency on an i18n bundle, but the regular + * module does not want to specify what locale to load. So it just specifies + * the top-level bundle, like "i18n!nls/colors". + * + * This plugin will load the i18n bundle at nls/colors, see that it is a root/master + * bundle since it does not have a locale in its name. It will then try to find + * the best match locale available in that master bundle, then request all the + * locale pieces for that best match locale. For instance, if the locale is "en-us", + * then the plugin will ask for the "en-us", "en" and "root" bundles to be loaded + * (but only if they are specified on the master bundle). + * + * Once all the bundles for the locale pieces load, then it mixes in all those + * locale pieces into each other, then finally sets the context.defined value + * for the nls/colors bundle to be that mixed in locale. + * + * 2) A regular module specifies a specific locale to load. For instance, + * i18n!nls/fr-fr/colors. In this case, the plugin needs to load the master bundle + * first, at nls/colors, then figure out what the best match locale is for fr-fr, + * since maybe only fr or just root is defined for that locale. Once that best + * fit is found, all of its locale pieces need to have their bundles loaded. + * + * Once all the bundles for the locale pieces load, then it mixes in all those + * locale pieces into each other, then finally sets the context.defined value + * for the nls/fr-fr/colors bundle to be that mixed in locale. + */ +(function () { + //regexp for reconstructing the master bundle name from parts of the regexp match + //nlsRegExp.exec("foo/bar/baz/nls/en-ca/foo") gives: + //["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"] + //nlsRegExp.exec("foo/bar/baz/nls/foo") gives: + //["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""] + //so, if match[5] is blank, it means this is the top bundle definition. + var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/; + + //Helper function to avoid repeating code. Lots of arguments in the + //desire to stay functional and support RequireJS contexts without having + //to know about the RequireJS contexts. + function addPart(locale, master, needed, toLoad, prefix, suffix) { + if (master[locale]) { + needed.push(locale); + if (master[locale] === true || master[locale] === 1) { + toLoad.push(prefix + locale + '/' + suffix); + } + } + } + + function addIfExists(req, locale, toLoad, prefix, suffix) { + var fullName = prefix + locale + '/' + suffix; + if (require._fileExists(req.nameToUrl(fullName, null))) { + toLoad.push(fullName); + } + } + + define('i18n',{ + version: '0.24.0', + /** + * Called when a dependency needs to be loaded. + */ + load: function (name, req, onLoad, config) { + config = config || {}; + + var masterName, + match = nlsRegExp.exec(name), + prefix = match[1], + locale = match[4], + suffix = match[5], + parts = locale.split("-"), + toLoad = [], + value = {}, + i, part, current = ""; + + //If match[5] is blank, it means this is the top bundle definition, + //so it does not have to be handled. Locale-specific requests + //will have a match[4] value but no match[5] + if (match[5]) { + //locale-specific bundle + prefix = match[1]; + masterName = prefix + suffix; + } else { + //Top-level bundle. + masterName = name; + suffix = match[4]; + locale = config.locale || (config.locale = + typeof navigator === "undefined" ? "root" : + (navigator.language || + navigator.userLanguage || "root").toLowerCase()); + parts = locale.split("-"); + } + + if (config.isBuild) { + //Check for existence of all locale possible files and + //require them if exist. + toLoad.push(masterName); + addIfExists(req, "root", toLoad, prefix, suffix); + for (i = 0; (part = parts[i]); i++) { + current += (current ? "-" : "") + part; + addIfExists(req, current, toLoad, prefix, suffix); + } + req(toLoad); + onLoad(); + } else { + //First, fetch the master bundle, it knows what locales are available. + req([masterName], function (master) { + //Figure out the best fit + var needed = []; + + //Always allow for root, then do the rest of the locale parts. + addPart("root", master, needed, toLoad, prefix, suffix); + for (i = 0; (part = parts[i]); i++) { + current += (current ? "-" : "") + part; + addPart(current, master, needed, toLoad, prefix, suffix); + } + + //Load all the parts missing. + req(toLoad, function () { + var i, partBundle; + for (i = needed.length - 1; i > -1 && (part = needed[i]); i--) { + partBundle = master[part]; + if (partBundle === true || partBundle === 1) { + partBundle = req(prefix + part + '/' + suffix); + } + require.mixin(value, partBundle); + } + + // MODIFICATION FROM ALOHA START: add a t() function + value.t = function(key) { + if (this[key]) { + return this[key]; + } else { + return key; + } + } + // END OF ALOHA MODIFICATION + + //All done, notify the loader. + onLoad(value); + }); + }); + } + } + }); +}()); + +define('aloha/nls/i18n',{ + 'root': { + 'plugin.abbr.floatingmenu.tab.abbr': 'Abbreviation', + 'floatingmenu.tab.format': 'Format', + 'floatingmenu.tab.insert': 'Insert', + 'yes': 'Yes', + 'no': 'No', + 'cancel': 'Cancel', + 'repository.no_item_found': 'No item found.', + 'repository.loading': 'Loading', + 'repository.no_items_found_yet': 'No items found yet...' + }, + 'de': true +/* 'eo': true, + 'fi': true, + 'fr': true, + 'it': true, + 'pl': true, + 'ru': true*/ +} ); +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright � 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ext-alohaproxy',[ + 'aloha/jquery', + 'aloha/ext', + 'aloha/repositorymanager', + 'aloha/console', + 'i18n!aloha/nls/i18n' +], function ( jQuery, Ext, RepositoryManager, console ) { + + + Ext.data.AlohaProxy = function () { + // Must define a dummy api with "read" action to satisfy + // Ext.data.Api#prepare *before* calling super + var api = {}; + api[ Ext.data.Api.actions.read ] = true; + Ext.data.AlohaProxy.superclass.constructor.call( this, { api: api } ); + + this.params = { + queryString : null, + objectTypeFilter : null, + filter : null, + inFolderId : null, + orderBy : null, + maxItems : null, + skipCount : null, + renditionFilter : null, + repositoryId : null + }; + }; + + var i18n = Aloha.require( 'i18n!aloha/nls/i18n' ); + + Ext.extend( Ext.data.AlohaProxy, Ext.data.DataProxy, { + + doRequest: function ( action, rs, params, reader, cb, scope, arg ) { + jQuery.extend( this.params, params ); + + try { + RepositoryManager.query( this.params, function ( items ) { + cb.call( scope, reader.readRecords( items ), arg, true ); + } ); + } catch ( ex ) { + console.error( 'Ext.data.AlohaProxy', + 'An error occured while querying repositories.' ); + + this.fireEvent( 'loadexception', this, null, arg, ex ); + this.fireEvent( 'exception', this, 'response', action, arg, null, ex ); + + return false; + } + }, + + setObjectTypeFilter: function ( otFilter ) { + this.params.objectTypeFilter = otFilter; + }, + + getObjectTypeFilter: function () { + return this.params.objectTypeFilter; + }, + + setParams: function ( p ) { + jQuery.extend( this.params, p ); + } + + } ); + +} ); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright � 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ext-alohareader',['aloha/ext'], +function(Ext) { + + +Ext.data.AlohaObjectReader = function(meta, recordType) { + meta = {}; + Ext.applyIf(meta, { + idProperty: 'id', + root: 'items', + totalProperty: 'results', + // TODO implement all defined optional attributes + fields: [ + 'id', + 'url', + 'name', + 'type', + 'weight', + 'path', + 'repositoryId' + ] + }); + Ext.data.JsonReader.superclass.constructor.call(this, meta, meta.fields); +}; + +Ext.extend(Ext.data.AlohaObjectReader, Ext.data.JsonReader, { + // extend of necessary +}); + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ext-alohatreeloader',['aloha/ext', 'aloha/repositorymanager'], +function(Ext, RepositoryManager) { + + +Ext.tree.AlohaTreeLoader = function(config) { + Ext.apply(this, config); + Ext.tree.AlohaTreeLoader.superclass.constructor.call(this); +}; + +Ext.extend( Ext.tree.AlohaTreeLoader, Ext.tree.TreeLoader, { + paramOrder: ['node', 'id'], + nodeParameter: 'id', + directFn : function(node, id, callback) { + var + params = { + inFolderId: node.id, + objectTypeFilter: this.objectTypeFilter, + repositoryId: node.repositoryId + }; + + RepositoryManager.getChildren ( params, function( items ) { + var response = {}; + + response = { + status: true, + scope: this, + argument: {callback: callback, node: node} + }; + + if(typeof callback === 'function'){ + callback(items, response); + } + }); + }, + createNode: function(node) { + if ( node.name ) { + node.text = node.name; + } + if ( node.hasMoreItems ) { + node.leaf = !node.hasMoreItems; + } + if ( node.objectType ) { + node.cls = node.objectType; + } + return Ext.tree.TreeLoader.prototype.createNode.call(this, node); + }, + objectTypeFilter : null, + setObjectTypeFilter : function (otFilter) { + this.objectTypeFilter = otFilter; + }, + getObjectTypeFilter : function () { + return this.objectTypeFilter; + } +}); + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ui',['aloha/core', 'util/class', 'aloha/jquery', 'aloha/floatingmenu', 'aloha/ext', 'aloha/console', 'i18n!aloha/nls/i18n'], +function(Aloha, Class, jQuery, FloatingMenu, Ext, console, i18n) { + + + var +// $ = jQuery, +// Aloha = window.Aloha, +// Ext = window.Ext, +// Class = window.Class; + GENTICS = window.GENTICS; + + // Ensure Namespace + Aloha.ui = Aloha.ui || {}; + + // internationalize ext js message box buttons + Ext.MessageBox.buttonText.yes = i18n.t('yes'); + Ext.MessageBox.buttonText.no = i18n.t('no'); + Ext.MessageBox.buttonText.cancel = i18n.t('cancel'); + + /** + * This is the Gentics Version of the ExtJS Menu. It is necessary to extend the + * Ext.menu.Menu in order to stop propagation of the mousedown event on the DOM + * element of the menu, because a click in the menu shall not deactivate the + * editable. + */ + Ext.ux.GENTICSMenu = Ext.extend(Ext.menu.Menu, { + /** + * overwrite onRender + */ + onRender: function() { + // call the super method + Ext.ux.GENTICSMenu.superclass.onRender.apply(this, arguments); + + // stop propagation of the mousedown event + jQuery(this.el.dom).mousedown(function (e) { + e.stopPropagation(); + }); + } + }); + +/** + * Constructor for an Aloha button. + * @namespace Aloha.ui + * @class Button + * @param {Object} properties Properties of the button: + * - label: Label that is displayed on the button. + * - onclick: Callback function of the button when activated. + * - menu: Array of Aloha.ui.Button elements that are displayed as drop-down menu. + * - iconClass: Icon displayed on the button. + * - icon: URL to an icon that is displayed on the button. + * - toggle: Boolean that indicates if the button is a toggle button. + */ +Aloha.ui.Button = Class.extend({ + _constructor: function(properties) { + this.init(properties); + }, + + /** + * Init method for an Aloha button. + * This method is necessary due to JS specific initalization. + * @namespace Aloha.ui + * @class Button + * @param {Object} properties Properties of the button: + * - label: Label that is displayed on the button. + * - onclick: Callback function of the button when activated. + * - menu: Array of Aloha.ui.Button elements that are displayed as drop-down menu. + * - iconClass: Icon displayed on the button. + * - icon: URL to an icon that is displayed on the button. + * - toggle: Boolean that indicates if the button is a toggle button. + */ + init: function(properties) { + /** + * Label that is displayed on the button + * @hide + */ + this.label = false; + + /** + * Name for the button + */ + this.name = false; + + /** + * CSS class for an icon on the button + * @hide + */ + this.iconClass = false; + + /** + * URL to an icon to display on the button + * @hide + */ + this.icon = false; + + /** + * Callback function when the button is activated. + * The "this" variable refers to the button inside the callback function. + * @hide + */ + this.onclick = false; + + /** + * Array of buttons that are displayed in a drop down menu. + * If a menu is provided and no onclick callback then clicking the button also opens the menu + * @hide + */ + this.menu = null; + + /** + * Indicates if the button is a toggle button + * @hide + */ + this.toggle = false; + + /** + * Property that indicates if the button is in pressed state + * @hide + */ + this.pressed = false; + + /** + * Property that indicates whether the button is currently visible + * @hide + */ + this.visible = true; + + /** + * Property that indicates whether the button is currently enabled + * @hide + */ + this.enabled = true; + + /** + * Tooltip text + * @hide + */ + this.tooltip = false; + + /** + * holds the ext object of the button + * @hide + */ + this.extButton = null; + + /** + * holds the listeners of the button + * @hide + */ + this.listenerQueue = []; + + GENTICS.Utils.applyProperties(this, properties); + + // use icon class as a fallback for name + if (this.name === false) { + this.name = this.iconClass; + } + + /** + * Unique Id of the button + * @hide + */ + this.id = this.generateId(); + }, + + /** + * Generate a unique id for the button + * @return unique id + * @hide + */ + generateId: function () { + Aloha.ui.Button.idCounter = Aloha.ui.Button.idCounter + 1; + return 'aloha-button' + Aloha.ui.Button.idCounter; + }, + + /** + * Set the 'pressed' state of the button if it is a toggle button + * @param {bool} pressed true when the button shall be 'pressed', false if not + */ + setPressed: function(pressed) { + if (this.toggle) { + this.pressed = pressed; + if (typeof this.extButton === 'object' && this.extButton != null && this.extButton.pressed != pressed) { + this.extButton.toggle(this.pressed); + } + } + }, + + /** + * Indicates if the button is currently in "pressed" state. + * This is only relevant if the button is a toggle button. + * If the button is no toggle button this function always returns false. + * @return {bool} True if the button is pressed, false otherwise. + */ + isPressed: function() { + if (this.toggle) { + return this.pressed; + } + return false; + }, + + /** + * Show the button. When this button is added to the FloatingMenu, it is + * necessary to call FloatingMenu.doLayout() after the visibility + * of the button is changed + */ + show: function() { + this.visible = true; + }, + + /** + * Hide the button. When this button is added to the FloatingMenu, it is + * necessary to call FloatingMenu.doLayout() after the visibility + * of the button is changed + */ + hide: function() { + this.visible = false; + }, + + /** + * Check whether the button is visible or not + * @return true when the button is visible, false if not + */ + isVisible: function() { + return this.visible; + }, + + /** + * Enable the button - make it clickable + */ + enable: function() { + this.enabled = true; + if (typeof this.extButton === 'object') { + this.extButton.enable(); + } + }, + + /** + * Disable the button + */ + disable: function() { + this.enabled = false; + if (typeof this.extButton === 'object') { + this.extButton.disable(); + } + }, + + /** + * Check whether the button is currently enabled + * @return true when the button is enabled, false if it is disabled + */ + isEnabled: function() { + return this.enabled; + }, + + /** + * Get the Ext menu from this button + * @return Ext menu + * @hide + */ + getExtMenu: function() { + var menu, i, entry; + if ( this.menu && typeof this.menu === 'object') { + // build the drop down menu + menu = new Ext.ux.GENTICSMenu(); + for (i = 0; i < this.menu.length; ++i) { + entry = this.menu[i]; + menu.addItem(new Ext.menu.Item(entry.getExtMenuConfigProperties())); + } + } + return menu; + }, + + /** + * Get the config properties for this button as menu entry + * @return config properties for this button as menu entry + * @hide + */ + getExtMenuConfigProperties: function() { + var me = this, + submenu = this.getExtMenu(); + + return { + text: this.label, + icon: this.icon, + iconCls: this.iconClass, + handler: function () { + if (typeof me.onclick == 'function') { + me.onclick(); + } + }, + menu: submenu + }; + }, + + /** + * Return an object containing the config properties to generate this button + * @return config properties + * @hide + */ + getExtConfigProperties: function() { + var me = this, + menu = this.getExtMenu(), + + // configuration for the button + buttonConfig = { + text : this.label, + enableToggle: this.toggle, + pressed : this.pressed, + icon: this.icon, + iconCls: this.iconClass, + scale : this.scale||this.size, + width : this.width||undefined, + rowspan : this.rowspan || ((this.size == 'large' || this.size == 'medium') ? 2 : 1), + menu : menu, + handler : function(element, event) { + if (typeof me.onclick === 'function') { + me.onclick.apply(me, [element, event]); + } + if ( me.toggle ) { + me.pressed = !me.pressed; + } + }, + xtype : (menu && typeof this.onclick == 'function') ? 'splitbutton' : 'button', + tooltipType : 'qtip', + tooltip : this.tooltip, + id : this.id, + arrowAlign: this.arrowAlign || (this.size == 'large' || this.size == 'small' ? 'right' : 'bottom') + }; + + return buttonConfig; + } +}); + +/** + * id counter, for generation of unique id's for the buttons + * @hide + */ +Aloha.ui.Button.idCounter = 0; + +/** + * extJS Multi Split Button + * + * Display a Word-like formatting selection button + * Selection images are typically 52*42 in size + * + * Example configuration + * xtype : 'genticsmultisplitbutton', + * items : [{ + * 'name' : 'normal', // the buttons name, used to identify it + * 'title' : 'Basic Text', // the buttons title, which will be displayed + * 'icon' : 'img/icon.jpg', // source for the icon + * 'click' : function() { alert('normal'); } // callback if the button is clicked + * 'wide' : false // wether it's a wide button, which would be dispalyed at the bottom + * }] + * + * you might want to check out the tutorial at + * http://www.extjs.com/learn/Tutorial:Creating_new_UI_controls + * @hide + */ +Ext.ux.MultiSplitButton = Ext.extend(Ext.Component, { + initComponent: function() { + var me = this; + this.on('beforehide', function() { + me.closePanel(); + }); + }, + /** + * add a css class to the wrapper-div autogenerated by extjs + * @hide + */ + autoEl: { + cls: 'aloha-multisplit-wrapper' + }, + + /** + * will contain a reference to the ul dom object + * @hide + */ + ulObj: null, + + /** + * holds a reference to the expand button + * @hide + */ + panelButton: null, + + /** + * hold a reference to the wrapper div + * @hide + */ + wrapper: null, + + /** + * true if the panel is expanded + * @hide + */ + panelOpened: false, + + /** + * get items for the multisplit button according to config + * configuration for a multisplit button has to be stored + * within an array: + * + * Aloha.settings.components.[MULTISPLITBUTTON-NAME] = [ 'item1', 'item2' ]; + * + * An example for that would be: + * + * // settings for phrasing element for the format plugin + * Aloha.settings.components.phrasing = [ 'h1', 'h2', 'h3', 'removeFormat' ]; + * + * if there is no config available, it will just use all items available + * @return button items for this multisplit button + */ + _getItems: function() { + var that = this, + items = [], + i, length; + + if (Aloha.settings.components && + Aloha.settings.components[this.name] && + typeof Aloha.settings.components[this.name] === 'object') { + // iterate over all buttons in our config... + jQuery.each(Aloha.settings.components[this.name], function (idx, button) { + for (i = 0, length = that.items.length; i < length; i++) { + if (that.items[i].name === button) { + // ... and find the appropriate internal button + items.push(that.items[i]); + break; + } + } + }); + return items; + } else { + return this.items; + } + }, + + /** + * render the multisplit button + * @return void + * @hide + */ + onRender: function() { + Ext.ux.MultiSplitButton.superclass.onRender.apply(this, arguments); + // create a reference to this elements dom object + this.wrapper = jQuery(this.el.dom); + + var + me = this, + i, + item, + items, + html = '
        '; + + items = this._getItems(); + + // add a new button to the list for each configured item + for (i=0; i ' + + ''; + } + + // now add the wide buttons at the bottom of the list + for (i=0; i' + + item.text + '' + + ''; + } + + html += '
      '; + + // register on move event, which occurs when the panel was dragged + // this should be done within the constructor, but ist not possible there + // since the extTabPanel will not be initialized at this moment + FloatingMenu.extTabPanel.on('move', function () { + me.closePanel(); + }); + FloatingMenu.extTabPanel.on('tabchange', function () { + me.closePanel(); + }); + + // add onclick event handler + this.ulObj = jQuery(this.el.createChild(html).dom) + .click(function (event) { + me.onClick(event); + }); + + // add the expand button + this.panelButton = jQuery( + this.el.createChild('').dom + ) + .click(function () { + me.togglePanel(); + }); + }, + + /** + * callback if a button has been clicked + * @param event jquery event object + * @return void + * @hide + */ + onClick: function(event) { + // check if the element has a gtxmultisplititem attribute assigned + if (!event.target.attributes.gtxmultisplititem) { + return; + } + var el = jQuery(event.target); + + // collapse the panel + this.closePanel(); + + // wide buttons cannot become the active element + if (!el.hasClass('aloha-multisplit-wide')) { + this.setActiveDOMElement(el); + } + + // invoke the items function + this.items[event.target.attributes.gtxmultisplititem.value].click(); + }, + + /** + * set the active item specified by its name + * @param name the name of the item to be marked as active + * @return void + * @hide + */ + setActiveItem: function(name) { + var button; + + // collapse the panel + this.closePanel(); + + button = jQuery('#' + this.id + ' .aloha-button-' + name); + if (button.length === 1) { + this.setActiveDOMElement(button); + this.activeItem = name; + } else { + this.setActiveDOMElement(null); + this.activeItem = null; + } + }, + + /** + * mark an item as active + * @param el jquery obj for item to be marked as active + * @return void + * @hide + */ + setActiveDOMElement: function(el) { + // when the component (or one of its owners) is currently hidden, we need to set the active item later + var ct = this, top; + while (typeof ct !== 'undefined') { + if (ct.hidden) { + this.activeDOMElement = el; + return; + } + ct = ct.ownerCt; + } + + jQuery(this.ulObj).find('.aloha-multisplit-activeitem').removeClass('aloha-multisplit-activeitem'); + if(el) { + el.parent().addClass('aloha-multisplit-activeitem'); + } + + if ( !el || el.parent().is(':hidden')) { + return; + } + + // reposition multisplit contents to the active item + if ( el && this.ulObj ) { + this.ulObj.css('margin-top', 0); + top = el.position().top; + this.ulObj.css({ + 'margin-top': - top + 6, + 'height': 46 + top - 6 + }); + } + + this.activeDOMElement = undefined; + }, + /** + * toggle the panel display from closed to expanded or vice versa + * @return void + * @hide + */ + togglePanel: function() { + if (this.panelOpened) { + this.closePanel(); + } else { + this.openPanel(); + } + }, + + /** + * expand the button panel + * @return void + * @hide + */ + openPanel: function() { + if (this.panelOpened) { + return; + } + + var o = this.wrapper.offset(); + + // detach the ul element and reattach it onto the body + this.ulObj + .appendTo(jQuery('body')) + .addClass('aloha-multisplit-expanded') + .mousedown(function (e) { + e.stopPropagation(); + }) + .css({ + // relocate the ul + 'top': o.top - 1, + 'left': o.left - 1 + }) + .animate({ + // display expand animation + height: (this.ulObj.prop)?this.ulObj.prop('scrollHeight'):this.ulObj.attr('scrollHeight') + }); + + // TODO change to css + this.panelButton + .removeClass('aloha-multisplit-toggle-open') + .addClass('aloha-multisplit-toggle-close'); + this.panelOpened = true; + }, + + /** + * collapses the panel + * @return void + * @hide + */ + closePanel: function() { + if (!this.panelOpened) { + return; + } + + this.ulObj + .removeClass('aloha-multisplit-expanded') + .appendTo(this.wrapper); + + // TODO change to css + this.panelButton + .addClass('aloha-multisplit-toggle-open') + .removeClass('aloha-multisplit-toggle-close'); + this.panelOpened = false; + }, + + /** + * hides a multisplit item + * @return void + * @hide + */ + hideItem: function(name) { + for (var i = 0; i. +*/ + +define('aloha/ui-attributefield',[ 'aloha/core', 'aloha/jquery', 'aloha/ext', 'i18n!aloha/nls/i18n', 'aloha/ui', + 'aloha/repositorymanager', 'aloha/selection', 'aloha/ext-alohaproxy', + 'aloha/ext-alohareader' +], function ( Aloha, jQuery, Ext, i18n, Ui, RepositoryManager, Selection ) { +// TODO add parameter for UI class after refactoring UI to requirejs + + +var undefined = void 0; + +var extTemplate = function ( tpl ) { + if ( tpl ) { + tpl = '
      ' + + '{[ this.renderRepositoryTemplate(values) ]}' + + '' + tpl + '' + + '
      '; + } else { + tpl = '
      ' + + '{[ this.renderRepositoryTemplate(values) ]}' + + '{name}' + + '
      '; + } + return new Ext.XTemplate( + tpl, + { + hasRepositoryTemplate : function ( values ) { + var rep = RepositoryManager.getRepository( values.repositoryId ); + return rep && rep.hasTemplate(); + }, + renderRepositoryTemplate : function ( values ) { + var rep = RepositoryManager.getRepository( values.repositoryId ); + if ( rep && rep.hasTemplate() ) { + // create extTemplate if template changed + if ( !rep._ExtTPL || rep.template !== rep._ExtTPLcache ) { + rep._ExtTPL = new Ext.XTemplate( rep.template ); + rep._ExtTPLcache = rep.template; + } + return rep._ExtTPL.apply( values ); + } + } + } ); +}; + + +// This will store the last attribute value. We need to keep track of this value +// due to decide whether to update the value on finish editing +var lastAttributeValue; + +Ext.ux.AlohaAttributeField = Ext.extend( Ext.form.ComboBox, { + typeAhead : false, + mode : 'remote', + triggerAction : 'all', + width : 300, + hideTrigger : true, + minChars : 3, + valueField : 'id', + displayField : 'name', + listEmptyText : i18n.t( 'repository.no_item_found' ), + loadingText : i18n.t( 'repository.loading' ) + '...', + enableKeyEvents : true, + store: new Ext.data.Store( { + proxy: new Ext.data.AlohaProxy(), + reader: new Ext.data.AlohaObjectReader() + } ), + clickAttached: false, // remember that the click event has been attached to the innerList, as this is not implemented in the combobox + tpl : extTemplate(), + onSelect : function ( item ) { + this.setItem( item.data ); + if ( typeof this.alohaButton.onSelect == 'function' ) { + this.alohaButton.onSelect.call( this.alohaButton, item.data ); + } + this.collapse(); + }, + finishEditing : function () { + var target = jQuery( this.getTargetObject() ), color; + + // Remove the highlighting and restore original color if was set before + if ( target ) { + if ( color = target.attr( 'data-original-background-color' ) ) { + jQuery( target ).css( 'background-color', color ); + } else { + jQuery( target ).css( 'background-color', '' ); + } + jQuery( target ).removeAttr( 'data-original-background-color' ); + } + + // Check whether the attribute was changed since the last focus event. Return early when the attribute was not changed. + if ( lastAttributeValue === target.attr( this.targetAttribute ) ) { + return; + } + + // when no resource item was selected, remove any marking of the target object + if ( !this.resourceItem ) { + RepositoryManager.markObject( this.targetObject ); + } + + if ( this.getValue() === '' ) { + if ( this.wrap ) { + jQuery( this.wrap.dom.children[ 0 ] ).css( 'color', '#AAA' ); + } + this.setValue( this.placeholder ); + } + }, + listeners: { + // repository object types could have changed + 'beforequery': function ( event ) { + if ( this.noQuery ) { + event.cancel = true; + return; + } + if ( this.store !== null && this.store.proxy !== null ) { + this.store.proxy.setParams( { + objectTypeFilter: this.getObjectTypeFilter(), + queryString: event.query + } ); + } + }, + 'afterrender': function ( obj, event ) { + jQuery( this.wrap.dom.children[ 0 ] ).css( 'color', '#AAA' ); + this.setValue( this.placeholder ); + }, + 'keydown': function ( obj, event ) { + // on ENTER or ESC leave the editing + // just remember here the status and remove cursor on keyup event + // Otherwise cursor moves to content and no more blur event happens!!?? + if ( event.keyCode == 13 || event.keyCode == 27 ) { + if ( this.isExpanded() ) { + this.ALOHAwasExpanded = true; + } else { + this.ALOHAwasExpanded = false; + } + event.preventDefault(); + } + }, + 'keyup': function ( obj, event ) { + if ( ( event.keyCode == 13 || event.keyCode == 27 ) && + !this.ALOHAwasExpanded ) { + // work around stupid behavior when moving focus + setTimeout( function () { + // Set focus to link element and select the object + Selection.getRangeObject().select(); + }, 0 ); + } + + // when a resource item was (initially) set, but the current value + // is different from the reference value, we unset the resource item + if ( this.resourceItem && + this.resourceValue !== this.wrap.dom.children[ 0 ].value ) { + this.resourceItem = null; + this.resourceValue = null; + } + + // update attribute, but only if no resource item was selected + if ( !this.resourceItem ) { + var v = this.wrap.dom.children[ 0 ].value; + this.setAttribute( this.targetAttribute, v ); + } + }, + 'focus': function ( obj, event ) { + // set background color to give visual feedback which link is modified + var target = jQuery( this.getTargetObject() ), + s = target.css( 'background-color' ); + + if ( this.getValue() === this.placeholder ) { + this.setValue( '' ); + jQuery( this.wrap.dom.children[ 0 ] ).css( 'color', 'black' ); + } + if ( target && target.context && target.context.style && + target.context.style[ 'background-color' ] ) { + target.attr( 'data-original-background-color', + target.context.style[ 'background-color' ] ); + } + target.css( 'background-color', '#80B5F2' ); + }, + 'blur': function ( obj, event ) { + this.finishEditing(); + }, + 'hide': function ( obj, event ) { + this.finishEditing(); + }, + 'expand': function ( combo ) { + if ( this.noQuery ) { + this.collapse(); + } + if ( !this.clickAttached ) { + var that = this; + // attach the mousedown event to set the event handled, + // so that the editable will not get deactivated + this.mon( this.innerList, 'mousedown', function ( event ) { + Aloha.eventHandled = true; + }, this ); + // in the mouseup event, the flag will be reset + this.mon( this.innerList, 'mouseup', function ( event ) { + Aloha.eventHandled = false; + }, this ); + this.clickAttached = true; + } + } + }, + setItem: function ( item, displayField ) { + this.resourceItem = item; + + if ( item ) { + displayField = ( displayField ) ? displayField : this.displayField; + // TODO split display field by '.' and get corresponding attribute, because it could be a properties attribute. + var v = item[ displayField ]; + // set the value into the field + this.setValue( v ); + // store the value to be the "reference" value for the currently selected resource item + this.resourceValue = v; + // set the attribute to the target object + this.setAttribute( this.targetAttribute, item[ this.valueField ] ); + // call the repository marker + RepositoryManager.markObject( this.targetObject, item ); + } else { + // unset the reference value, since no resource item is selected + this.resourceValue = null; + } + }, + getItem: function () { + return this.resourceItem; + }, + // Private hack to allow attribute setting by regex + setAttribute: function ( attr, value, regex, reference ) { + var setAttr = true, regxp; + if ( this.targetObject) { + // check if a reference value is submitted to check against with a regex + if ( typeof reference != 'undefined' ) { + regxp = new RegExp( regex ); + if ( !reference.match( regxp ) ) { + setAttr = false; + } + } + + // if no regex was successful or no reference value + // was submitted remove the attribute + if ( setAttr ) { + jQuery( this.targetObject ).attr( attr, value ); + } else { + jQuery( this.targetObject ).removeAttr( attr ); + } + } + }, + setTargetObject : function ( obj, attr ) { + var that = this; + this.targetObject = obj; + this.targetAttribute = attr; + this.setItem( null ); + + if ( obj && attr ) { + lastAttributeValue = jQuery( obj ).attr( attr ); + } + + if ( this.targetObject && this.targetAttribute ) { + this.setValue( jQuery( this.targetObject ).attr( this.targetAttribute ) ); + } else { + this.setValue( '' ); + } + + // check whether a repository item is linked to the object + var that = this; + RepositoryManager.getObject( obj, function ( items ) { + if ( items && items.length > 0 ) { + that.setItem( items[ 0 ] ); + } + } ); + }, + getTargetObject : function () { + return this.targetObject; + }, + setObjectTypeFilter : function ( otFilter ) { + this.objectTypeFilter = otFilter; + }, + getObjectTypeFilter : function () { + return this.objectTypeFilter; + }, + noQuery: true +}); + +/** + * Register the Aloha attribute field + * @hide + */ +Ext.reg( 'alohaattributefield', Ext.ux.AlohaAttributeField ); + +/** + * Aloha Attribute Field Button + * @namespace Aloha.ui + * @class AttributeField + */ +Ui.AttributeField = Ui.Button.extend( { + _constructor: function ( properties ) { + /** + * @cfg Function called when an element is selected + */ + this.onSelect = null; + this.listenerQueue = []; + this.objectTypeFilter = null; + this.tpl = null; + this.displayField = null; + this.valueField = null; + + this.init( properties ); + }, + + /** + * Create a extjs alohaattributefield + * @hide + */ + getExtConfigProperties: function () { + var props = { + alohaButton : this, + xtype : 'alohaattributefield', + rowspan : this.rowspan || undefined, + width : this.width || undefined, + placeholder : this.placeholder || undefined, + id : this.id, + cls : this.cls || undefined + }; + if ( this.valueField ) { + props.valueField = this.valueField; + } + if ( this.displayField ) { + props.displayField = this.displayField; + } + if ( this.minChars ) { + props.minChars = this.minChars; + } + return props; + }, + + /** + * Sets the target Object of which the Attribute should be modified + * @param {jQuery} obj the target object + * @param {String} attr Attribute to be modified ex. "href" of a link + * @void + */ + setTargetObject: function ( obj, attr ) { + if ( this.extButton ) { + this.extButton.setTargetObject( obj, attr ); + } + }, + + /** + * @return {jQuery} object Returns the current target Object + */ + getTargetObject: function () { + return this.extButton ? this.extButton.getTargetObject() : null; + }, + + /** + * Focus to this field + * @void + */ + focus: function () { + if ( this.extButton ) { + this.extButton.focus(); + if ( this.extButton.getValue().length > 0 ) { + this.extButton.selectText( 0, this.extButton.getValue().length ); + } + } + }, + + /** + * Adding a listener to the field + * @param {String} eventname The name of the event. Ex. 'keyup' + * @param {function} handler The function that should be called when the event happens. + * @param {Object} scope The scope object which the event should be attached + */ + addListener: function ( eventName, handler, scope ) { + var listener; + + if ( this.extButton ) { + this.extButton.addListener( eventName, handler, null ); + } else { + // if extButton not yet initialized adding listeners could be a problem + // so all events are collected in a queue and added on initalizing + listener = { + 'eventName' : eventName, + 'handler' : handler, + 'scope' : scope, + 'options' : null + }; + this.listenerQueue.push( listener ); + } + }, + + /** + * Sets an attribute optionally based on a regex on reference + * @param {String} attr The Attribute name which should be set. Ex. "lang" + * @param {String} value The value to set. Ex. "de-AT" + * @param {String} regex The regex when the attribute should be set. The regex is applied to the value of refernece. + * @param {String} reference The value for the regex. + */ + setAttribute: function ( attr, value, regex, reference ) { + if ( this.extButton ) { + this.extButton.setAttribute( attr, value, regex, reference ); + } + }, + + /** + * When at least on objectType is set the value in the Attribute field does a query to all registered repositories. + * @param {Array} objectTypeFilter The array of objectTypeFilter to be searched for. + * @void + */ + setObjectTypeFilter: function ( objectTypeFilter ) { + if ( this.extButton ) { + this.noQuery = false; + this.extButton.setObjectType( objectTypeFilter ); + } else { + if ( !objectTypeFilter ) { + objectTypeFilter = 'all'; + } + this.objectTypeFilter = objectTypeFilter; + } + }, + + /** + * Sets an item to the link tag. + * @param {resourceItem} item + */ + setItem: function ( item , displayField ) { + if ( this.extButton ) { + this.extButton.setItem( item, displayField ); + } + }, + + /** + * Gets current item set. + * @return {resourceItem} item + */ + getItem: function () { + if ( this.extButton ) { + return this.extButton.getItem(); + } + return null; + }, + + /** + * Returns the current value + * @return {String} attributeValue + */ + getValue: function () { + if ( this.extButton ) { + return this.extButton.getValue(); + } + return null; + }, + + /** + * Sets the current value + * @param {String} va attributeValue + */ + setValue: function ( v ) { + if ( this.extButton ) { + this.extButton.setValue( v ); + } + }, + + /** + * Returns the current query value. + * @return {String} queryValue + */ + getQueryValue: function () { + if ( this.extButton ) { + //return this.extButton.getValue(); + return this.extButton.wrap.dom.children[ 0 ].value; + } + return null; + }, + + /** + * Set the display field, which is displayed in the combobox + * @param {String} displayField name of the field to be displayed + * @return display field name on success, null otherwise + */ + setDisplayField: function ( displayField ) { + var result; + if ( this.extButton ) { + result = this.extButton.displayField = displayField; + } else { + result = this.displayField = displayField; + } + return result; + }, + + /** + * Set the row template for autocomplete hints. The default template is: + * {name}
      {url}
      + * @param {String} tpl template to be rendered for each row + * @return template on success or null otherwise + */ + setTemplate: function ( tpl ) { + var result; + if ( this.extButton ) { + result = this.extButton.tpl = extTemplate( tpl ); + } else { + result = this.tpl = extTemplate( tpl ); + } + return result; + } + +} ); + +} ); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +*//* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/ui-browser',['aloha/ext', 'aloha/ui'], +function(Ext, ui) { + + + var +// $ = jQuery, +// GENTICS = window.GENTICS, +// Aloha = window.Aloha, + Class = window.Class; + +/** + * !!!! ATTENTION !!!! + * This is work in progress. This implemenation may change heavily. + * Not yet implemented: + * - configuring and templating the list + * - DnD + * - passing all possible query attributes to the repository + * - query of subtree + * - icon representation + */ +ui.Browser = Class.extend({ + _constructor: function () { + + /** + * @cfg Function called when an element is selected + */ + this.onSelect = null; + + var that = this; + + // define the grid that represents the filelist + this.grid = new Ext.grid.GridPanel( { + region : 'center', + autoScroll : true, + // the datastore can be used by the gridpanel to fetch data from + // repository manager + store : new Ext.data.Store( { + proxy : new Ext.data.AlohaProxy(), + reader : new Ext.data.AlohaObjectReader() + }), + columns : [ { + id : 'name', + header : 'Name', + width : 100, + sortable : true, + dataIndex : 'name' + }, { + header : 'URL', + renderer : function(val) { + return val; + }, + width : 300, + sortable : true, + dataIndex : 'url' + } ], + stripeRows : true, + autoExpandColumn : 'name', + height : 350, + width : 600, + title : 'Objectlist', + stateful : true, + stateId : 'grid', + selModel: new Ext.grid.RowSelectionModel({singleSelect:true}), + listeners : { + 'dblclick' : function(e) { + that.onItemSelect(); + } + } + }); + this.grid.getSelectionModel().on({ + 'selectionchange' : function(sm, n, node){ + var resourceItem = that.grid.getSelectionModel().getSelected(); + if (resourceItem) { + this.win.buttons[1].enable(); + } else { + this.win.buttons[1].disable(); + } + }, + scope:this + }); + + + // define the treepanel + this.tree = new Ext.tree.TreePanel( { + region : 'center', + useArrows : true, + autoScroll : true, + animate : true, + enableDD : true, + containerScroll : true, + border : false, + loader : new Ext.tree.AlohaTreeLoader(), + root : { + nodeType : 'async', + text : 'Aloha Repositories', + draggable : false, + id : 'aloha' + }, + rootVisible : false, + listeners : { + 'beforeload' : function(node) { + this.loader.baseParams = { + node : node.attributes + }; + } + } + }); + this.tree.getSelectionModel().on({ + 'selectionchange' : function(sm, node){ + if (node) { + var resourceItem = node.attributes; + that.grid.store.load({ params: { + inFolderId: resourceItem.id, + objectTypeFilter: that.objectTypeFilter, + repositoryId: resourceItem.repositoryId + }}); + } + }, + scope:this + }); + + // nest the tree within a panel + this.nav = new Ext.Panel( { + title : 'Navigation', + region : 'west', + width : 300, + layout : 'fit', + collapsible : true, + items : [ this.tree ] + }); + + // add the nested tree and grid (filelist) to the window + this.win = new Ext.Window( { + title : 'Resource Selector', + layout : 'border', + width : 800, + height : 300, + closeAction : 'hide', + onEsc: function () { + this.hide(); + }, + defaultButton: this.nav, + plain : true, + initHidden: true, + items : [ this.nav, this.grid ], + buttons : [{ + text : 'Close', + handler : function() { + that.win.hide(); + } + }, { + text : 'Select', + disabled : true, + handler : function() { + that.onItemSelect(); + } + }], + toFront : function(e) { + this.manager = this.manager || Ext.WindowMgr; + this.manager.bringToFront(this); + this.setZIndex(9999999999); // bring really to front (floating menu is not registered as window...) + return this; + } + }); + + this.onItemSelect = function () { + var + sm = this.grid.getSelectionModel(), + sel = (sm) ? sm.getSelected() : null, + resourceItem = (sel) ? sel.data : null; + this.win.hide(); + if ( typeof this.onSelect === 'function' ) { + this.onSelect.call(this, resourceItem); + } + }; + }, + + setObjectTypeFilter: function(otf) { + this.objectTypeFilter = otf; + }, + + getObjectTypeFilter: function() { + return this.objectTypeFilter; + }, + + show: function() { + this.win.show(); // first show, + this.win.toFront(true); + this.win.focus(); + } +}); + +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +define('aloha/repository',[ 'aloha/core', 'util/class', 'aloha/repositorymanager' ], +function( Aloha, Class, RepositoryManager ) { + + +// var +// $ = jQuery, +// GENTICS = window.GENTICS, +// Aloha = window.Aloha, +// Class = window.Class; + +/** + * Abstract Repository Class. Implement that class for your own repository. + * @namespace Aloha.Repository + * @class Repository + * @constructor + * @param {String} repositoryId unique repository identifier + * @param {String} repositoryName (optional) is the displyed name for this Repository instance + */ +var AbstractRepository = Class.extend({ + _constructor: function(repositoryId, repositoryName) { + /** + * @property repositoryId is the unique Id for this Repository instance + */ + this.repositoryId = repositoryId; + + /** + * contains the repository's settings object + * @property settings {Object} the repository's settings stored in an object + */ + this.settings = {}; + + /** + * @property repositoryName is the name for this Repository instance + */ + this.repositoryName = (repositoryName) ? repositoryName : repositoryId; + + RepositoryManager.register(this); + }, + + /** + * Init method of the repository. Called from Aloha Core to initialize this repository + * @return void + * @hide + */ + init: function() {}, + + /** + * Searches a repository for object items matching queryString if none found returns null. + * The returned object items must be an array of Aloha.Repository.Object + * +
      
      +	// simple delicious implementation
      +	Aloha.Repositories.myRepository.query = function (params, callback) {
      +
      +		// make local var of this to use in ajax function
      +		var that = this;
      +
      +		// handle each word as tag
      +		var tags = p.queryString.split(' ');
      +
      +		// if we have a query and no tag matching return
      +		if ( p.queryString && tags.length == 0 ) {
      +			callback.call( that, []);
      +			return;
      +		}
      +
      +		// no handling of objectTypeFilter, filter, inFolderId, etc...
      +		// in real implementation you should handle all parameters
      +
      +		jQuery.ajax({ type: "GET",
      +			dataType: "jsonp",
      +			url: 'http://feeds.delicious.com/v2/json/' + tags.join('+'),
      +			success: function(data) {
      +				var items = [];
      +				// convert data to Aloha objects
      +				for (var i = 0; i < data.length; i++) {
      +					if (typeof data[i] != 'function' ) {
      +						items.push(new Aloha.Repository.Document ({
      +							id: data[i].u,
      +							name: data[i].d,
      +							repositoryId: that.repositoryId,
      +							type: 'website',
      +							url: data[i].u
      +						}));
      +					}
      +				}
      +				callback.call( that, items);
      +			}
      +		});
      +	};
      +	
      + * + * @param {object} params object with properties + *
        + *
      • queryString : String
        The query string for full text search
      • + *
      • objectTypeFilter : array (optional)
        Object types that will be returned.
      • + *
      • filter : array (optional)
        Attributes that will be returned.
      • + *
      • inFolderId : boolean (optional)
        This is indicates whether or not a candidate object is a child-object of the folder object identified by the given inFolderId (objectId).
      • + *
      • inTreeId : boolean (optional)
        This indicates whether or not a candidate object is a descendant-object of the folder object identified by the given inTreeId (objectId).
      • + *
      • orderBy : array (optional)
        ex. [{lastModificationDate:’DESC’, name:’ASC’}]
      • + *
      • maxItems : Integer (optional)
        number items to return as result
      • + *
      • skipCount : Integer (optional)
        This is tricky in a merged multi repository scenario
      • + *
      • renditionFilter : array (optional)
        Instead of termlist an array of kind or mimetype is expected. If null or array.length == 0 all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310 for renditionFilter
      • + *
      + * @param {function} callback this method must be called with all result items
    • + */ + query: null, + /* + query: function( params, callback ) { + if (typeof callback === 'function') { + callback([]); + } + }, + */ + + /** + * Returns all children of a given motherId. + * + * @param {object} params object with properties + *
        + *
      • objectTypeFilter : array (optional)
        Object types that will be returned.
      • + *
      • filter : array (optional)
        Attributes that will be returned.
      • + *
      • inFolderId : boolean (optional)
        This indicates whether or not a candidate object is a child-object of the folder object identified by the given inFolderId (objectId).
      • + *
      • orderBy : array (optional)
        ex. [{lastModificationDate:’DESC’, name:’ASC’}]
      • + *
      • maxItems : Integer (optional)
        number items to return as result
      • + *
      • skipCount : Integer (optional)
        This is tricky in a merged multi repository scenario
      • + *
      • renditionFilter : array (optional)
        Instead of termlist an array of kind or mimetype is expected. If null or array.length == 0 all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310 for renditionFilter
      • + *
      + * @param {function} callback this method must be called with all result items + */ + getChildren: null, + /* + getChildren: function( params, callback ) { + if (typeof callback === 'function') { + callback([]); + } + }, + */ + + /** + * Make the given jQuery object (representing an object marked as object of this type) + * clean. All attributes needed for handling should be removed. + * +
      
      +	Aloha.Repositories.myRepository.makeClean = function (obj) {
      +		obj.removeAttr('data-myRepository-name');
      +	};
      +	
      + * @param {jQuery} obj jQuery object to make clean + * @return void + */ + makeClean: function (obj) {}, + + /** + * This method will be called when a user chooses an item from a repository and wants + * to insert this item in his content. + * Mark or modify an object as needed by that repository for handling, processing or identification. + * Objects can be any DOM object as A, SPAN, ABBR, etc. or + * special objects such as aloha-aloha_block elements. + * (see http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data) + * +
      
      +	Aloha.Repositories.myRepository.markObject = function (obj, resourceItem) {
      +		obj.attr('data-myRepository-name').text(resourceItem.name);
      +	};
      +	
      + * + * + * @param obj jQuery target object to which the repositoryItem will be applied + * @param repositoryItem The selected item. A class constructed from Document or Folder. + * @return void + */ + markObject: function (obj, repositoryItem) {}, + + /** + * Set a template for rendering objects of this repository + * @param {String} template + * @return void + * @method + */ + setTemplate: function (template) { + if (template) { + this.template = template; + } else { + this.template = null; + } + }, + + /** + * Checks whether the repository has a template + * @return {boolean} true when the repository has a template, false if not + * @method + */ + hasTemplate: function () { + return this.template ? true : false; + }, + + /** + * Get the parsed template + * @return {Object} parsed template + * @method + */ + getTemplate: function () { + return this.template; + }, + + /** + * Get the repositoryItem with given id + * @param itemId {String} id of the repository item to fetch + * @param callback {function} callback function + * @return {Aloha.Repository.Object} item with given id + */ + getObjectById: function ( itemId, callback ) { return true; } +}); + + // expose the AbstractRepository + Aloha.AbstractRepository = AbstractRepository; + + return AbstractRepository; +}); + +/*! + * This file is part of Aloha Editor + * Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + */ +define('aloha/repositoryobjects',[ 'aloha/core', 'util/class'], +function( Aloha, Class ) { + + + var +// Aloha = window.Aloha, +// Class = window.Class, + GENTICS = window.GENTICS; + + Aloha.RepositoryObject = function() {}; + + /** + * @namespace Aloha.Repository + * @class Document + * @constructor + * + * Abstract Document suitable for most Objects.

      + * + * Example: + * +
      
      +	 var item = new Aloha.Repository.Document({
      +		id: 1,
      +		repositoryId: 'myrepository',
      +		name: 'Aloha Editor - The HTML5 Editor',
      +		type: 'website',
      +		url:'http://aloha-editor.com',
      +	 });
      +	
      + * + * @param {Object} properties An object with the data. + *
        + *
      • id : String
        Unique identifier
      • + *
      • repositoryId : String
        Unique repository identifier
      • + *
      • name : String
        Name of the object. This name is used to display
      • + *
      • type : String
        The specific object type
      • + *
      • partentId : String (optional)
      • + *
      • mimetype : String (optional)
        MIME type of the Content Stream
      • + *
      • filename : String (optional)
        File name of the Content Stream
      • + *
      • length : String (optional)
        Length of the content stream (in bytes)
      • + *
      • url : String (optional)
        URL of the content stream
      • + *
      • renditions : Array (optional)
        Array of different renditions of this object
      • + *
      • localName : String (optional)
        Name of the object. This name is used internally
      • + *
      • createdBy : String (optional)
        User who created the object
      • + *
      • creationDate : Date (optional)
        DateTime when the object was created
      • + *
      • lastModifiedBy : String (optional)
        User who last modified the object
      • + *
      • lastModificationDate : Date (optional)
        DateTime when the object was last modified
      • + *
      + * + */ + Aloha.RepositoryDocument = Class.extend({ + _constructor: function (properties) { + + var p = properties; + + this.type = 'document'; + + // Basic error checking for MUST attributes + if (!p.id || + !p.name || + !p.repositoryId + ) { + // Aloha.Log.error(this, "No valid Aloha Object. Missing MUST property"); + return; + } + + GENTICS.Utils.applyProperties(this, properties); + + this.baseType = 'document'; + } + // /** + // * Not implemented method to generate this JS API doc correctly. + // */ + // ,empty = function() } + + }); + + + + /** + * @namespace Aloha.Repository + * @class Folder + * @constructor + * Abstract Folder suitable for most strucural Objects.

      + * + * Example: + * +
      
      +	 var item = new Aloha.Repository.Folder({
      +		id: 2,
      +		repositoryId: 'myrepository',
      +		name: 'images',
      +		type: 'directory',
      +		parentId:'/www'
      +	 });
      +	
      + * @param {Object} properties An object with the data. + *
        + *
      • id : String
        Unique identifier
      • + *
      • repositoryId : String
        Unique repository identifier
      • + *
      • name : String
        Name of the object. This name is used to display
      • + *
      • type : String
        The specific object type
      • + *
      • partentId : String (optional)
      • + *
      • localName : String (optional)
        Name of the object. This name is used internally
      • + *
      • createdBy : String (optional)
        User who created the object
      • + *
      • creationDate : Date (optional)
        DateTime when the object was created
      • + *
      • lastModifiedBy : String (optional)
        User who last modified the object
      • + *
      • lastModificationDate : Date (optional)
        DateTime when the object was last modified
      • + *
      + * + */ + Aloha.RepositoryFolder = Class.extend({ + + _constructor: function(properties) { + + var p = properties; + + this.type = 'folder'; + + // Basic error checking for MUST attributes + if (!p.id || + !p.name || + !p.repositoryId + ) { + // Aloha.Log.error(this, "No valid Aloha Object. Missing MUST property"); + return; + } + + GENTICS.Utils.applyProperties(this, properties); + + this.baseType = 'folder'; + + } + // /** + // * Not implemented method to generate this JS API doc correctly. + // */ + // ,empty = function() {}; + + }); +}); + +/*! +* This file is part of Aloha Editor Project http://aloha-editor.org +* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com +* Contributors http://aloha-editor.org/contribution.php +* Licensed unter the terms of http://www.aloha-editor.org/license.html +* +* Aloha Editor is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version.* +* +* Aloha Editor is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ +( function () { + 'use strict' + + // load jQuery with noConflict (true) to remove anyway from global namespace + // a user may add it by its own with var jQuery = $ = Aloha.jQuery; + var + jQuery = window.jQuery.noConflict( true ), + deferredReady, + alohaRequire; + + // Ensure Aloha settings namespace and default + window.Aloha = window.Aloha || {}; + + // reset defaults. Users should use settings. + Aloha.defaults = {}; + + // guarantee the settings namespace even if not set by user + Aloha.settings = Aloha.settings || {}; + + // set jQuery to buildin of not otherwise set + // From here on Aloha.jQuery is always available + Aloha.jQuery = Aloha.settings.jQuery || Aloha.jQuery || jQuery || null; + + // Aloha define, require, preserve original require + Aloha._require = require; + Aloha.define = define; + + // Determins the base path of Aloha Editor which is supposed to be the path of aloha.js (this file) + Aloha.settings.baseUrl = Aloha.settings.baseUrl || getBaseUrl(); + + // aloha base path is defined by a script tag with the data attribute + // data-aloha-plugins and the filename aloha.js + // no jQuery at this stage... + function getBaseUrl () { + var + baseUrl = './', + script, + scripts = document.getElementsByTagName( 'script' ), + i, j = scripts.length, + regexAlohaJs = /\/aloha.js$/, + regexJs = /[^\/]*\.js$/; + + for ( i = 0; i < j && ( script = scripts[ i ] ); ++i ) { + // take aloha.js or first ocurrency of data-aloha-plugins + // and script ends with .js + if ( regexAlohaJs.test( script.src ) ) { + baseUrl = script.src.replace( regexAlohaJs , '' ); + break; + } + if ( baseUrl === './' && script.getAttribute( 'data-aloha-plugins' ) + && regexJs.test(script.src ) ) { + baseUrl = script.src.replace( regexJs , '' ); + } + } + + return baseUrl; + }; + + // prepare the require config object and remember it + Aloha.settings.requireConfig = { + context: 'aloha', + baseUrl: Aloha.settings.baseUrl, + locale: Aloha.settings.locale + }; + + // configure require and expose the Aloha.require function + alohaRequire = require.config( Aloha.settings.requireConfig ); + Aloha.require = function ( callback ) { + // passes the Aloha object to the passed callback function + if ( arguments.length == 1 && typeof callback === 'function' ) { + return alohaRequire( [ 'aloha' ], callback ); + } + return alohaRequire.apply( this, arguments ); + }; + + // create promise for 'aloha-ready' when Aloha is not yet ready + // and fire later when 'aloha-ready' is triggered all other events bind + deferredReady = Aloha.jQuery.Deferred(); + Aloha.bind = function ( type, fn ) { + if ( type == 'aloha-ready' ) { + if ( Aloha.stage != 'alohaReady' ) { + deferredReady.done( fn ); + } else { + fn(); + } + } else { + Aloha.jQuery( Aloha, 'body' ).bind( type, fn ); + } + + return this; + }; + + Aloha.trigger = function ( type, data ) { + if ( type == 'aloha-ready' ) { + // resolve all deferred events on dom ready and delete local var + Aloha.jQuery( deferredReady.resolve ); + } + Aloha.jQuery( Aloha, 'body' ).trigger( type, data ); + return this; + }; + + Aloha.ready = function ( fn ) { + this.bind( 'aloha-ready', fn ); + return this; + }; + + // Async Module Dependency error handling + // Aloha will intercept RequireJS errors in order to facilitate more + // flexible and more graceful degredation where possible + ( function ( origOnError ) { + require.onError = function ( err ) { + var fatalTimeouts = []; + var failedModules = Aloha.jQuery.trim( err.requireModules ) + .split( ' ' ); + + for ( var i = 0; i < failedModules.length; i++ ) { + switch ( err.requireType ) { + case 'timeout': + // We only catch failures which do not rise from Aloha core + // files. If a core file fails to load properly, it is + // always a fatal error. + if ( !/^aloha\/.+/.test( failedModules[ i ] ) ) { + if ( window.console && + typeof window.console.error === 'function' ) { + window.console.error( 'Aloha-Editor Error: ' + + 'The following module failed to load: ' + + failedModules[ i ] ); + } + } else { + fatalTimeouts.push( failedModules[ i ] ); + } + break; + default: + // "timeout" is currently, the only defined + // err.requireType . But in case of any future custom + // err.requireType which we do not handle, we will pass it + // back to the original require.onError function. + origOnError.apply( {}, arguments ); + } + } + + throw 'Aloha-Editor Exception: The following core file' + + ( fatalTimeouts.length ? 's have' : ' has' ) + + ' timed-out while loading: ' + fatalTimeouts.join( ', ' ); + }; + } )( require.onError ); + +} )(); + +// define aloha object +define( 'aloha', [], function () { + return Aloha; +} ); + +//load Aloha dependencies +require( + Aloha.settings.requireConfig, + [ + 'aloha/jquery', + 'aloha/ext', + ], + function () { + // load Aloha core files + require( + Aloha.settings.requireConfig, + [ + 'vendor/jquery.json-2.2.min', + 'vendor/jquery.store', + 'aloha/rangy-core', + 'util/json2', + 'util/class', + 'util/lang', + 'util/range', + 'util/dom', + 'aloha/core', + 'aloha/editable', + 'aloha/console', + 'aloha/markup', + 'aloha/message', + 'aloha/plugin', + 'aloha/selection', + 'aloha/command', + 'aloha/jquery.patch', + 'aloha/jquery.aloha', + 'aloha/sidebar', + 'util/position', + 'aloha/ext-alohaproxy', + 'aloha/ext-alohareader', + 'aloha/ext-alohatreeloader', + 'aloha/ui', + 'aloha/ui-attributefield', + 'aloha/ui-browser', + 'aloha/floatingmenu', + 'aloha/repositorymanager', + 'aloha/repository', + 'aloha/repositoryobjects', + 'aloha/contenthandlermanager' + ], + function () { + // jQuery calls the init method when the dom is ready + Aloha.jQuery( Aloha.init ); + } + ); + } +); diff --git a/vendor/assets/javascripts/locomotive/aloha/lib/aloha.js b/vendor/assets/javascripts/locomotive/aloha/lib/aloha.js new file mode 100644 index 00000000..9e094e43 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/lib/aloha.js @@ -0,0 +1,88671 @@ + +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 0.26.0+ Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +/*jslint strict: false, plusplus: false */ +/*global window: false, navigator: false, document: false, importScripts: false, + jQuery: false, clearInterval: false, setInterval: false, self: false, + setTimeout: false, opera: false */ + +var requirejs, require, define; +(function () { + //Change this version number for each release. + var version = "0.26.0+", + commentRegExp = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, + cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g, + currDirRegExp = /^\.\//, + jsSuffixRegExp = /\.js$/, + ostring = Object.prototype.toString, + ap = Array.prototype, + aps = ap.slice, + apsp = ap.splice, + isBrowser = !!(typeof window !== "undefined" && navigator && document), + isWebWorker = !isBrowser && typeof importScripts !== "undefined", + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is "loading", "loaded", execution, + // then "complete". The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = "_", + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== "undefined" && opera.toString() === "[object Opera]", + reqWaitIdPrefix = "_r@@", + empty = {}, + contexts = {}, + globalDefQueue = [], + interactiveScript = null, + isDone = false, + checkLoadedDepth = 0, + useInteractive = false, + req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script, + src, subPath, mainScript, dataMain, i, scrollIntervalId, setReadyState, ctx, + jQueryCheck, checkLoadedTimeoutId; + + function isFunction(it) { + return ostring.call(it) === "[object Function]"; + } + + function isArray(it) { + return ostring.call(it) === "[object Array]"; + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + * This is not robust in IE for transferring methods that match + * Object.prototype names, but the uses of mixin here seem unlikely to + * trigger a problem related to that. + */ + function mixin(target, source, force) { + for (var prop in source) { + if (!(prop in empty) && (!(prop in target) || force)) { + target[prop] = source[prop]; + } + } + return req; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + if (err) { + e.originalError = err; + } + return e; + } + + /** + * Used to set up package paths from a packagePaths or packages config object. + * @param {Object} pkgs the object to store the new package config + * @param {Array} currentPackages an array of packages to configure + * @param {String} [dir] a prefix dir to use. + */ + function configurePackageDir(pkgs, currentPackages, dir) { + var i, location, pkgObj; + + for (i = 0; (pkgObj = currentPackages[i]); i++) { + pkgObj = typeof pkgObj === "string" ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Add dir to the path, but avoid paths that start with a slash + //or have a colon (indicates a protocol) + if (dir && (!location || (location.indexOf("/") !== 0 && location.indexOf(":") === -1))) { + location = dir + "/" + (location || pkgObj.name); + } + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || "main") + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + } + } + + /** + * jQuery 1.4.3-1.5.x use a readyWait/ready() pairing to hold DOM + * ready callbacks, but jQuery 1.6 supports a holdReady() API instead. + * At some point remove the readyWait/ready() support and just stick + * with using holdReady. + */ + function jQueryHoldReady($, shouldHold) { + if ($.holdReady) { + $.holdReady(shouldHold); + } else if (shouldHold) { + $.readyWait += 1; + } else { + $.ready(true); + } + } + + if (typeof define !== "undefined") { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== "undefined") { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } else { + cfg = requirejs; + requirejs = undefined; + } + } + + //Allow for a require config object + if (typeof require !== "undefined" && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + /** + * Creates a new context for use in require and define calls. + * Handle most of the heavy lifting. Do not want to use an object + * with prototype here to avoid using "this" in require, in case it + * needs to be used in more super secure envs that do not want this. + * Also there should not be that many contexts in the page. Usually just + * one for the default context, but could be extra for multiversion cases + * or if a package needs a special context for a dependency that conflicts + * with the standard context. + */ + function newContext(contextName) { + var context, resume, + config = { + waitSeconds: 7, + baseUrl: s.baseUrl || "./", + paths: {}, + pkgs: {}, + catchError: {} + }, + defQueue = [], + specified = { + "require": true, + "exports": true, + "module": true + }, + urlMap = {}, + defined = {}, + loaded = {}, + waiting = {}, + waitAry = [], + waitIdCounter = 0, + managerCallbacks = {}, + plugins = {}, + pluginsQueue = {}, + resumeDepth = 0, + normalizedWaiting = {}; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; (part = ary[i]); i++) { + if (part === ".") { + ary.splice(i, 1); + i -= 1; + } else if (part === "..") { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var pkgName, pkgConfig; + + //Adjust any relative paths. + if (name && name.charAt(0) === ".") { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (config.pkgs[baseName]) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + baseName = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that "directory" and not name of the baseName's + //module. For instance, baseName of "one/two/three", maps to + //"one/two/three.js", but we want the directory, "one/two" for + //this normalization. + baseName = baseName.split("/"); + baseName = baseName.slice(0, baseName.length - 1); + } + + name = baseName.concat(name.split("/")); + trimDots(name); + + //Some use of packages may use a . path to reference the + //"main" module name, so normalize for that. + pkgConfig = config.pkgs[(pkgName = name[0])]; + name = name.join("/"); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } + } + return name; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap) { + var index = name ? name.indexOf("!") : -1, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + normalizedName, url, pluginModule; + + if (index !== -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + + if (prefix) { + prefix = normalize(prefix, parentName); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + pluginModule = defined[prefix]; + if (pluginModule) { + //Plugin is loaded, use its normalize method, otherwise, + //normalize name as usual. + if (pluginModule.normalize) { + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName); + }); + } else { + normalizedName = normalize(name, parentName); + } + } else { + //Plugin is not loaded yet, so do not normalize + //the name, wait for plugin to load to see if + //it has a normalize method. To avoid possible + //ambiguity with relative names loaded from another + //plugin, use the parent's name as part of this name. + normalizedName = '__$p' + parentName + '@' + (name || ''); + } + } else { + normalizedName = normalize(name, parentName); + } + + url = urlMap[normalizedName]; + if (!url) { + //Calculate url for the module, if it has a name. + if (req.toModuleUrl) { + //Special logic required for a particular engine, + //like Node. + url = req.toModuleUrl(context, normalizedName, parentModuleMap); + } else { + url = context.nameToUrl(normalizedName, null, parentModuleMap); + } + + //Store the URL mapping for later. + urlMap[normalizedName] = url; + } + } + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + url: url, + originalName: originalName, + fullName: prefix ? prefix + "!" + (normalizedName || '') : normalizedName + }; + } + + /** + * Determine if priority loading is done. If so clear the priorityWait + */ + function isPriorityDone() { + var priorityDone = true, + priorityWait = config.priorityWait, + priorityName, i; + if (priorityWait) { + for (i = 0; (priorityName = priorityWait[i]); i++) { + if (!loaded[priorityName]) { + priorityDone = false; + break; + } + } + if (priorityDone) { + delete config.priorityWait; + } + } + return priorityDone; + } + + /** + * Helper function that creates a setExports function for a "module" + * CommonJS dependency. Do this here to avoid creating a closure that + * is part of a loop. + */ + function makeSetExports(moduleObj) { + return function (exports) { + moduleObj.exports = exports; + }; + } + + function makeContextModuleFunc(func, relModuleMap, enableBuildCallback) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + var args = [].concat(aps.call(arguments, 0)), lastArg; + if (enableBuildCallback && + isFunction((lastArg = args[args.length - 1]))) { + lastArg.__requireJsBuild = true; + } + args.push(relModuleMap); + return func.apply(null, args); + }; + } + + /** + * Helper function that creates a require function object to give to + * modules that ask for it as a dependency. It needs to be specific + * per module because of the implication of path mappings that may + * need to be relative to the module name. + */ + function makeRequire(relModuleMap, enableBuildCallback) { + var modRequire = makeContextModuleFunc(context.require, relModuleMap, enableBuildCallback); + + mixin(modRequire, { + nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap), + toUrl: makeContextModuleFunc(context.toUrl, relModuleMap), + defined: makeContextModuleFunc(context.requireDefined, relModuleMap), + specified: makeContextModuleFunc(context.requireSpecified, relModuleMap), + ready: req.ready, + isBrowser: req.isBrowser + }); + //Something used by node. + if (req.paths) { + modRequire.paths = req.paths; + } + return modRequire; + } + + /** + * Used to update the normalized name for plugin-based dependencies + * after a plugin loads, since it can have its own normalization structure. + * @param {String} pluginName the normalized plugin module name. + */ + function updateNormalizedNames(pluginName) { + + var oldFullName, oldModuleMap, moduleMap, fullName, callbacks, + i, j, k, depArray, existingCallbacks, + maps = normalizedWaiting[pluginName]; + + if (maps) { + for (i = 0; (oldModuleMap = maps[i]); i++) { + oldFullName = oldModuleMap.fullName; + moduleMap = makeModuleMap(oldModuleMap.originalName, oldModuleMap.parentMap); + fullName = moduleMap.fullName; + //Callbacks could be undefined if the same plugin!name was + //required twice in a row, so use empty array in that case. + callbacks = managerCallbacks[oldFullName] || []; + existingCallbacks = managerCallbacks[fullName]; + + if (fullName !== oldFullName) { + //Update the specified object, but only if it is already + //in there. In sync environments, it may not be yet. + if (oldFullName in specified) { + delete specified[oldFullName]; + specified[fullName] = true; + } + + //Update managerCallbacks to use the correct normalized name. + //If there are already callbacks for the normalized name, + //just add to them. + if (existingCallbacks) { + managerCallbacks[fullName] = existingCallbacks.concat(callbacks); + } else { + managerCallbacks[fullName] = callbacks; + } + delete managerCallbacks[oldFullName]; + + //In each manager callback, update the normalized name in the depArray. + for (j = 0; j < callbacks.length; j++) { + depArray = callbacks[j].depArray; + for (k = 0; k < depArray.length; k++) { + if (depArray[k] === oldFullName) { + depArray[k] = fullName; + } + } + } + } + } + } + + delete normalizedWaiting[pluginName]; + } + + /* + * Queues a dependency for checking after the loader is out of a + * "paused" state, for example while a script file is being loaded + * in the browser, where it may have many modules defined in it. + * + * depName will be fully qualified, no relative . or .. path. + */ + function queueDependency(dep) { + //Make sure to load any plugin and associate the dependency + //with that plugin. + var prefix = dep.prefix, + fullName = dep.fullName; + + //Do not bother if the depName is already in transit + if (specified[fullName] || fullName in defined) { + return; + } + + if (prefix && !plugins[prefix]) { + //Queue up loading of the dependency, track it + //via context.plugins. Mark it as a plugin so + //that the build system will know to treat it + //special. + plugins[prefix] = undefined; + + //Remember this dep that needs to have normaliztion done + //after the plugin loads. + (normalizedWaiting[prefix] || (normalizedWaiting[prefix] = [])) + .push(dep); + + //Register an action to do once the plugin loads, to update + //all managerCallbacks to use a properly normalized module + //name. + (managerCallbacks[prefix] || + (managerCallbacks[prefix] = [])).push({ + onDep: function (name, value) { + if (name === prefix) { + updateNormalizedNames(prefix); + } + } + }); + + queueDependency(makeModuleMap(prefix)); + } + + context.paused.push(dep); + } + + function execManager(manager) { + var i, ret, waitingCallbacks, err, errFile, errModuleTree, + cb = manager.callback, + fullName = manager.fullName, + args = [], + ary = manager.depArray; + + //Call the callback to define the module, if necessary. + if (cb && isFunction(cb)) { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + if (ary) { + for (i = 0; i < ary.length; i++) { + args.push(manager.deps[ary[i]]); + } + } + + if (config.catchError.define) { + try { + ret = req.execCb(fullName, manager.callback, args, defined[fullName]); + } catch (e) { + err = e; + } + } else { + ret = req.execCb(fullName, manager.callback, args, defined[fullName]); + } + + if (fullName) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (manager.cjsModule && manager.cjsModule.exports !== undefined) { + ret = defined[fullName] = manager.cjsModule.exports; + } else if (ret === undefined && manager.usingExports) { + //exports already set the defined value. + ret = defined[fullName]; + } else { + //Use the return value from the function. + defined[fullName] = ret; + } + } + } else if (fullName) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + ret = defined[fullName] = cb; + } + + //Clean up waiting. Do this before error calls, and before + //calling back waitingCallbacks, so that bookkeeping is correct + //in the event of an error and error is reported in correct order, + //since the waitingCallbacks will likely have errors if the + //onError function does not throw. + if (waiting[manager.waitId]) { + delete waiting[manager.waitId]; + manager.isDone = true; + context.waitCount -= 1; + if (context.waitCount === 0) { + //Clear the wait array used for cycles. + waitAry = []; + } + } + + if (err) { + errFile = (fullName ? makeModuleMap(fullName).url : '') || + err.fileName || err.sourceURL; + errModuleTree = err.moduleTree; + err = makeError('defineerror', 'Error evaluating ' + + 'module "' + fullName + '" at location "' + + errFile + '":\n' + + err + '\nfileName:' + errFile + + '\nlineNumber: ' + (err.lineNumber || err.line), err); + err.moduleName = fullName; + err.moduleTree = errModuleTree; + return req.onError(err); + } + + if (fullName) { + //If anything was waiting for this module to be defined, + //notify them now. + waitingCallbacks = managerCallbacks[fullName]; + if (waitingCallbacks) { + for (i = 0; i < waitingCallbacks.length; i++) { + waitingCallbacks[i].onDep(fullName, ret); + } + delete managerCallbacks[fullName]; + } + } + + return undefined; + } + + function main(inName, depArray, callback, relModuleMap) { + var moduleMap = makeModuleMap(inName, relModuleMap), + name = moduleMap.name, + fullName = moduleMap.fullName, + uniques = {}, + manager = { + //Use a wait ID because some entries are anon + //async require calls. + waitId: name || reqWaitIdPrefix + (waitIdCounter++), + depCount: 0, + depMax: 0, + prefix: moduleMap.prefix, + name: name, + fullName: fullName, + deps: {}, + depArray: depArray, + callback: callback, + onDep: function (depName, value) { + if (!(depName in manager.deps)) { + manager.deps[depName] = value; + manager.depCount += 1; + if (manager.depCount === manager.depMax) { + //All done, execute! + execManager(manager); + } + } + } + }, + i, depArg, depName, cjsMod; + + if (fullName) { + //If module already defined for context, or already loaded, + //then leave. Also leave if jQuery is registering but it does + //not match the desired version number in the config. + if (fullName in defined || loaded[fullName] === true || + (fullName === "jquery" && config.jQuery && + config.jQuery !== callback().fn.jquery)) { + return; + } + + //Set specified/loaded here for modules that are also loaded + //as part of a layer, where onScriptLoad is not fired + //for those cases. Do this after the inline define and + //dependency tracing is done. + specified[fullName] = true; + loaded[fullName] = true; + + //If module is jQuery set up delaying its dom ready listeners. + if (fullName === "jquery" && callback) { + jQueryCheck(callback()); + } + } + + //Add the dependencies to the deps field, and register for callbacks + //on the dependencies. + for (i = 0; i < depArray.length; i++) { + depArg = depArray[i]; + //There could be cases like in IE, where a trailing comma will + //introduce a null dependency, so only treat a real dependency + //value as a dependency. + if (depArg) { + //Split the dependency name into plugin and name parts + depArg = makeModuleMap(depArg, (name ? moduleMap : relModuleMap)); + depName = depArg.fullName; + + //Fix the name in depArray to be just the name, since + //that is how it will be called back later. + depArray[i] = depName; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + manager.deps[depName] = makeRequire(moduleMap); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + manager.deps[depName] = defined[fullName] = {}; + manager.usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + manager.cjsModule = cjsMod = manager.deps[depName] = { + id: name, + uri: name ? context.nameToUrl(name, null, relModuleMap) : undefined, + exports: defined[fullName] + }; + cjsMod.setExports = makeSetExports(cjsMod); + } else if (depName in defined && !(depName in waiting)) { + //Module already defined, no need to wait for it. + manager.deps[depName] = defined[depName]; + } else if (!uniques[depName]) { + + //A dynamic dependency. + manager.depMax += 1; + + queueDependency(depArg); + + //Register to get notification when dependency loads. + (managerCallbacks[depName] || + (managerCallbacks[depName] = [])).push(manager); + + uniques[depName] = true; + } + } + } + + //Do not bother tracking the manager if it is all done. + if (manager.depCount === manager.depMax) { + //All done, execute! + execManager(manager); + } else { + waiting[manager.waitId] = manager; + waitAry.push(manager); + context.waitCount += 1; + } + } + + /** + * Convenience method to call main for a define call that was put on + * hold in the defQueue. + */ + function callDefMain(args) { + main.apply(null, args); + //Mark the module loaded. Must do it here in addition + //to doing it in define in case a script does + //not call define + loaded[args[0]] = true; + } + + /** + * jQuery 1.4.3+ supports ways to hold off calling + * calling jQuery ready callbacks until all scripts are loaded. Be sure + * to track it if the capability exists.. Also, since jQuery 1.4.3 does + * not register as a module, need to do some global inference checking. + * Even if it does register as a module, not guaranteed to be the precise + * name of the global. If a jQuery is tracked for this context, then go + * ahead and register it as a module too, if not already in process. + */ + jQueryCheck = function (jqCandidate) { + if (!context.jQuery) { + var $ = jqCandidate || (typeof jQuery !== "undefined" ? jQuery : null); + + if ($) { + //If a specific version of jQuery is wanted, make sure to only + //use this jQuery if it matches. + if (config.jQuery && $.fn.jquery !== config.jQuery) { + return; + } + + if ("holdReady" in $ || "readyWait" in $) { + context.jQuery = $; + + //Manually create a "jquery" module entry if not one already + //or in process. Note this could trigger an attempt at + //a second jQuery registration, but does no harm since + //the first one wins, and it is the same value anyway. + callDefMain(["jquery", [], function () { + return jQuery; + }]); + + //Ask jQuery to hold DOM ready callbacks. + if (context.scriptCount) { + jQueryHoldReady($, true); + context.jQueryIncremented = true; + } + } + } + } + }; + + function forceExec(manager, traced) { + if (manager.isDone) { + return undefined; + } + + var fullName = manager.fullName, + depArray = manager.depArray, + depName, i; + if (fullName) { + if (traced[fullName]) { + return defined[fullName]; + } + + traced[fullName] = true; + } + + //forceExec all of its dependencies. + for (i = 0; i < depArray.length; i++) { + //Some array members may be null, like if a trailing comma + //IE, so do the explicit [i] access and check if it has a value. + depName = depArray[i]; + if (depName) { + if (!manager.deps[depName] && waiting[depName]) { + manager.onDep(depName, forceExec(waiting[depName], traced)); + } + } + } + + return fullName ? defined[fullName] : undefined; + } + + /** + * Checks if all modules for a context are loaded, and if so, evaluates the + * new ones in right dependency order. + * + * @private + */ + function checkLoaded() { + var waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = "", hasLoadedProp = false, stillLoading = false, prop, + err, manager; + + //If there are items still in the paused queue processing wait. + //This is particularly important in the sync case where each paused + //item is processed right away but there may be more waiting. + if (context.pausedCount > 0) { + return undefined; + } + + //Determine if priority loading is done. If so clear the priority. If + //not, then do not check + if (config.priorityWait) { + if (isPriorityDone()) { + //Call resume, since it could have + //some waiting dependencies to trace. + resume(); + } else { + return undefined; + } + } + + //See if anything is still in flight. + for (prop in loaded) { + if (!(prop in empty)) { + hasLoadedProp = true; + if (!loaded[prop]) { + if (expired) { + noLoads += prop + " "; + } else { + stillLoading = true; + break; + } + } + } + } + + //Check for exit conditions. + if (!hasLoadedProp && !context.waitCount) { + //If the loaded object had no items, then the rest of + //the work below does not need to be done. + return undefined; + } + if (expired && noLoads) { + //If wait time expired, throw error of unloaded modules. + err = makeError("timeout", "Load timeout for modules: " + noLoads); + err.requireType = "timeout"; + err.requireModules = noLoads; + return req.onError(err); + } + if (stillLoading || context.scriptCount) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + return undefined; + } + + //If still have items in the waiting cue, but all modules have + //been loaded, then it means there are some circular dependencies + //that need to be broken. + //However, as a waiting thing is fired, then it can add items to + //the waiting cue, and those items should not be fired yet, so + //make sure to redo the checkLoaded call after breaking a single + //cycle, if nothing else loaded then this logic will pick it up + //again. + if (context.waitCount) { + //Cycle through the waitAry, and call items in sequence. + for (i = 0; (manager = waitAry[i]); i++) { + forceExec(manager, {}); + } + + //Only allow this recursion to a certain depth. Only + //triggered by errors in calling a module in which its + //modules waiting on it cannot finish loading, or some circular + //dependencies that then may add more dependencies. + //The value of 5 is a bit arbitrary. Hopefully just one extra + //pass, or two for the case of circular dependencies generating + //more work that gets resolved in the sync node case. + if (checkLoadedDepth < 5) { + checkLoadedDepth += 1; + checkLoaded(); + } + } + + checkLoadedDepth = 0; + + //Check for DOM ready, and nothing is waiting across contexts. + req.checkReadyState(); + + return undefined; + } + + function callPlugin(pluginName, dep) { + var name = dep.name, + fullName = dep.fullName, + load; + + //Do not bother if plugin is already defined or being loaded. + if (fullName in defined || fullName in loaded) { + return; + } + + if (!plugins[pluginName]) { + plugins[pluginName] = defined[pluginName]; + } + + //Only set loaded to false for tracking if it has not already been set. + if (!loaded[fullName]) { + loaded[fullName] = false; + } + + load = function (ret) { + //Allow the build process to register plugin-loaded dependencies. + if (req.onPluginLoad) { + req.onPluginLoad(context, pluginName, name, ret); + } + + execManager({ + prefix: dep.prefix, + name: dep.name, + fullName: dep.fullName, + callback: function () { + return ret; + } + }); + loaded[fullName] = true; + }; + + //Allow plugins to load other code without having to know the + //context or how to "complete" the load. + load.fromText = function (moduleName, text) { + /*jslint evil: true */ + var hasInteractive = useInteractive; + + //Indicate a the module is in process of loading. + context.loaded[moduleName] = false; + context.scriptCount += 1; + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + req.exec(text); + + if (hasInteractive) { + useInteractive = true; + } + + //Support anonymous modules. + context.completeLoad(moduleName); + }; + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugins[pluginName].load(name, makeRequire(dep.parentMap, true), load, config); + } + + function loadPaused(dep) { + //Renormalize dependency if its name was waiting on a plugin + //to load, which as since loaded. + if (dep.prefix && dep.name && dep.name.indexOf('__$p') === 0 && defined[dep.prefix]) { + dep = makeModuleMap(dep.originalName, dep.parentMap); + } + + var pluginName = dep.prefix, + fullName = dep.fullName, + urlFetched = context.urlFetched; + + //Do not bother if the dependency has already been specified. + if (specified[fullName] || loaded[fullName]) { + return; + } else { + specified[fullName] = true; + } + + if (pluginName) { + //If plugin not loaded, wait for it. + //set up callback list. if no list, then register + //managerCallback for that plugin. + if (defined[pluginName]) { + callPlugin(pluginName, dep); + } else { + if (!pluginsQueue[pluginName]) { + pluginsQueue[pluginName] = []; + (managerCallbacks[pluginName] || + (managerCallbacks[pluginName] = [])).push({ + onDep: function (name, value) { + if (name === pluginName) { + var i, oldModuleMap, ary = pluginsQueue[pluginName]; + + //Now update all queued plugin actions. + for (i = 0; i < ary.length; i++) { + oldModuleMap = ary[i]; + //Update the moduleMap since the + //module name may be normalized + //differently now. + callPlugin(pluginName, + makeModuleMap(oldModuleMap.originalName, oldModuleMap.parentMap)); + } + delete pluginsQueue[pluginName]; + } + } + }); + } + pluginsQueue[pluginName].push(dep); + } + } else { + if (!urlFetched[dep.url]) { + req.load(context, fullName, dep.url); + urlFetched[dep.url] = true; + } + } + } + + /** + * Resumes tracing of dependencies and then checks if everything is loaded. + */ + resume = function () { + var args, i, p; + + resumeDepth += 1; + + if (context.scriptCount <= 0) { + //Synchronous envs will push the number below zero with the + //decrement above, be sure to set it back to zero for good measure. + //require() calls that also do not end up loading scripts could + //push the number negative too. + context.scriptCount = 0; + } + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return req.onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + callDefMain(args); + } + } + + //Skip the resume of paused dependencies + //if current context is in priority wait. + if (!config.priorityWait || isPriorityDone()) { + while (context.paused.length) { + p = context.paused; + context.pausedCount += p.length; + //Reset paused list + context.paused = []; + + for (i = 0; (args = p[i]); i++) { + loadPaused(args); + } + //Move the start time for timeout forward. + context.startTime = (new Date()).getTime(); + context.pausedCount -= p.length; + } + } + + //Only check if loaded when resume depth is 1. It is likely that + //it is only greater than 1 in sync environments where a factory + //function also then calls the callback-style require. In those + //cases, the checkLoaded should not occur until the resume + //depth is back at the top level. + if (resumeDepth === 1) { + checkLoaded(); + } + + resumeDepth -= 1; + + return undefined; + }; + + //Define the context object. Many of these fields are on here + //just to make debugging easier. + context = { + contextName: contextName, + config: config, + defQueue: defQueue, + waiting: waiting, + waitCount: 0, + specified: specified, + loaded: loaded, + urlMap: urlMap, + scriptCount: 0, + urlFetched: {}, + defined: defined, + paused: [], + pausedCount: 0, + plugins: plugins, + managerCallbacks: managerCallbacks, + makeModuleMap: makeModuleMap, + normalize: normalize, + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + var paths, prop, packages, pkgs, packagePaths, requireWait; + + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== "/") { + cfg.baseUrl += "/"; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + paths = config.paths; + packages = config.packages; + pkgs = config.pkgs; + + //Mix in the config values, favoring the new values over + //existing ones in context.config. + mixin(config, cfg, true); + + //Adjust paths if necessary. + if (cfg.paths) { + for (prop in cfg.paths) { + if (!(prop in empty)) { + paths[prop] = cfg.paths[prop]; + } + } + config.paths = paths; + } + + packagePaths = cfg.packagePaths; + if (packagePaths || cfg.packages) { + //Convert packagePaths into a packages config. + if (packagePaths) { + for (prop in packagePaths) { + if (!(prop in empty)) { + configurePackageDir(pkgs, packagePaths[prop], prop); + } + } + } + + //Adjust packages if necessary. + if (cfg.packages) { + configurePackageDir(pkgs, cfg.packages); + } + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If priority loading is in effect, trigger the loads now + if (cfg.priority) { + //Hold on to requireWait value, and reset it after done + requireWait = context.requireWait; + + //Allow tracing some require calls to allow the fetching + //of the priority config. + context.requireWait = false; + //But first, call resume to register any defined modules that may + //be in a data-main built file before the priority config + //call. Also grab any waiting define calls for this context. + context.takeGlobalQueue(); + resume(); + + context.require(cfg.priority); + + //Trigger a resume right away, for the case when + //the script with the priority load is done as part + //of a data-main call. In that case the normal resume + //call will not happen because the scriptCount will be + //at 1, since the script for data-main is being processed. + resume(); + + //Restore previous state. + context.requireWait = requireWait; + config.priorityWait = cfg.priority; + } + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + + //Set up ready callback, if asked. Useful when require is defined as a + //config object before require.js is loaded. + if (cfg.ready) { + req.ready(cfg.ready); + } + }, + + requireDefined: function (moduleName, relModuleMap) { + return makeModuleMap(moduleName, relModuleMap).fullName in defined; + }, + + requireSpecified: function (moduleName, relModuleMap) { + return makeModuleMap(moduleName, relModuleMap).fullName in specified; + }, + + require: function (deps, callback, relModuleMap) { + var moduleName, fullName, moduleMap; + if (typeof deps === "string") { + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + //In this case deps is the moduleName and callback is + //the relModuleMap + if (req.get) { + return req.get(context, deps, callback); + } + + //Just return the module wanted. In this scenario, the + //second arg (if passed) is just the relModuleMap. + moduleName = deps; + relModuleMap = callback; + + //Normalize module name, if it contains . or .. + moduleMap = makeModuleMap(moduleName, relModuleMap); + fullName = moduleMap.fullName; + + if (!(fullName in defined)) { + return req.onError(makeError("notloaded", "Module name '" + + moduleMap.fullName + + "' has not been loaded yet for context: " + + contextName)); + } + return defined[fullName]; + } + + main(null, deps, callback, relModuleMap); + + //If the require call does not trigger anything new to load, + //then resume the dependency processing. + if (!context.requireWait) { + while (!context.scriptCount && context.paused.length) { + //For built layers, there can be some defined + //modules waiting for intake into the context, + //in particular module plugins. Take them. + context.takeGlobalQueue(); + resume(); + } + } + return context.require; + }, + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + takeGlobalQueue: function () { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(context.defQueue, + [context.defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var args; + + context.takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + + if (args[0] === null) { + args[0] = moduleName; + break; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + break; + } else { + //Some other named define call, most likely the result + //of a build layer that included many define calls. + callDefMain(args); + args = null; + } + } + if (args) { + callDefMain(args); + } else { + //A script that does not call define(), so just simulate + //the call for it. Special exception for jQuery dynamic load. + callDefMain([moduleName, [], + moduleName === "jquery" && typeof jQuery !== "undefined" ? + function () { + return jQuery; + } : null]); + } + + //Mark the script as loaded. Note that this can be different from a + //moduleName that maps to a define call. This line is important + //for traditional browser scripts. + loaded[moduleName] = true; + + //If a global jQuery is defined, check for it. Need to do it here + //instead of main() since stock jQuery does not register as + //a module via define. + jQueryCheck(); + + //Doing this scriptCount decrement branching because sync envs + //need to decrement after resume, otherwise it looks like + //loading is complete after the first dependency is fetched. + //For browsers, it works fine to decrement after, but it means + //the checkLoaded setTimeout 50 ms cost is taken. To avoid + //that cost, decrement beforehand. + if (req.isAsync) { + context.scriptCount -= 1; + } + resume(); + if (!req.isAsync) { + context.scriptCount -= 1; + } + }, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt, relModuleMap) { + var index = moduleNamePlusExt.lastIndexOf("."), + ext = null; + + if (index !== -1) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + */ + nameToUrl: function (moduleName, ext, relModuleMap) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + config = context.config; + + //Normalize module name if have a base relative module name to work from. + moduleName = normalize(moduleName, relModuleMap && relModuleMap.fullName); + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash or ends with .js, it is just a plain file. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext ? ext : ""); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split("/"); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i--) { + parentModule = syms.slice(0, i).join("/"); + if (paths[parentModule]) { + syms.splice(0, i, paths[parentModule]); + break; + } else if ((pkg = pkgs[parentModule])) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join("/") + (ext || ".js"); + url = (url.charAt(0) === '/' || url.match(/^\w+:/) ? "" : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + } + }; + + //Make these visible on the context so can be called at the very + //end of the file to bootstrap + context.jQueryCheck = jQueryCheck; + context.resume = resume; + + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback) { + + //Find the right context, use default + var contextName = defContextName, + context, config; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== "string") { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = arguments[2]; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = contexts[contextName] || + (contexts[contextName] = newContext(contextName)); + + if (config) { + context.configure(config); + } + + return context.require(deps, callback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (typeof require === "undefined") { + require = req; + } + + /** + * Global require.toUrl(), to match global require, mostly useful + * for debugging/work in the global space. + */ + req.toUrl = function (moduleNamePlusExt) { + return contexts[defContextName].toUrl(moduleNamePlusExt); + }; + + req.version = version; + req.isArray = isArray; + req.isFunction = isFunction; + req.mixin = mixin; + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + s = req.s = { + contexts: contexts, + //Stores a list of URLs that should not get async script tag treatment. + skipAsync: {}, + isPageLoaded: !isBrowser, + readyCalls: [] + }; + + req.isAsync = req.isBrowser = isBrowser; + if (isBrowser) { + head = s.head = document.getElementsByTagName("head")[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName("base")[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = function (err) { + throw err; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var loaded = context.loaded; + + isDone = false; + + //Only set loaded to false for tracking if it has not already been set. + if (!loaded[moduleName]) { + loaded[moduleName] = false; + } + + context.scriptCount += 1; + req.attach(url, context, moduleName); + + //If tracking a jQuery, then make sure its ready callbacks + //are put on hold to prevent its ready callbacks from + //triggering too soon. + if (context.jQuery && !context.jQueryIncremented) { + jQueryHoldReady(context.jQuery, true); + context.jQueryIncremented = true; + } + }; + + function getInteractiveScript() { + var scripts, i, script; + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + scripts = document.getElementsByTagName('script'); + for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + } + + return null; + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = req.def = function (name, deps, callback) { + var node, context; + + //Allow for anonymous functions + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!req.isArray(deps)) { + callback = deps; + deps = []; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!name && !deps.length && req.isFunction(callback)) { + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, "") + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ["require"] : ["require", "exports", "module"]).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute("data-requiremodule"); + } + context = contexts[node.getAttribute("data-requirecontext")]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + + return undefined; + }; + + define.amd = { + multiversion: true, + plugins: true, + jQuery: true + }; + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a more environment specific call. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + return eval(text); + }; + + /** + * Executes a module callack function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + req.execCb = function (name, callback, args, exports) { + return callback.apply(exports, args); + }; + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + * + * @private + */ + req.onScriptLoad = function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement || currentlyAddingScript, contextName, moduleName, + context; + + if (evt.type === "load" || readyRegExp.test(node.readyState)) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + contextName = node.getAttribute("data-requirecontext"); + moduleName = node.getAttribute("data-requiremodule"); + context = contexts[contextName]; + + contexts[contextName].completeLoad(moduleName); + + //Clean up script binding. Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + node.detachEvent("onreadystatechange", req.onScriptLoad); + } else { + node.removeEventListener("load", req.onScriptLoad, false); + } + } + }; + + /** + * Attaches the script represented by the URL to the current + * environment. Right now only supports browser loading, + * but can be redefined in other environments to do the right thing. + * @param {String} url the url of the script to attach. + * @param {Object} context the context that wants the script. + * @param {moduleName} the name of the module that is associated with the script. + * @param {Function} [callback] optional callback, defaults to require.onScriptLoad + * @param {String} [type] optional type, defaults to text/javascript + */ + req.attach = function (url, context, moduleName, callback, type) { + var node, loaded; + if (isBrowser) { + //In the browser so use a script tag + callback = callback || req.onScriptLoad; + node = context && context.config && context.config.xhtml ? + document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") : + document.createElement("script"); + node.type = type || "text/javascript"; + node.charset = "utf-8"; + //Use async so Gecko does not block on executing the script if something + //like a long-polling comet tag is being run first. Gecko likes + //to evaluate scripts in DOM order, even for dynamic scripts. + //It will fetch them async, but only evaluate the contents in DOM + //order, so a long-polling script tag can delay execution of scripts + //after it. But telling Gecko we expect async gets us the behavior + //we want -- execute it whenever it is finished downloading. Only + //Helps Firefox 3.6+ + //Allow some URLs to not be fetched async. Mostly helps the order! + //plugin + node.async = !s.skipAsync[url]; + + if (context) { + node.setAttribute("data-requirecontext", context.contextName); + } + node.setAttribute("data-requiremodule", moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in "interactive" + //readyState at the time of the define call. + useInteractive = true; + node.attachEvent("onreadystatechange", callback); + } else { + node.addEventListener("load", callback, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + return node; + } else if (isWebWorker) { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + loaded = context.loaded; + loaded[moduleName] = false; + + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } + return null; + }; + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + scripts = document.getElementsByTagName("script"); + + for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) { + //Set the "head" where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + if ((dataMain = script.getAttribute('data-main'))) { + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = dataMain.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + //Set final config. + cfg.baseUrl = subPath; + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = mainScript.replace(jsSuffixRegExp, ''); + } + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + + break; + } + } + } + + //Set baseUrl based on config. + s.baseUrl = cfg.baseUrl; + + //****** START page load functionality **************** + /** + * Sets the page as loaded and triggers check for all modules loaded. + */ + req.pageLoaded = function () { + if (!s.isPageLoaded) { + s.isPageLoaded = true; + if (scrollIntervalId) { + clearInterval(scrollIntervalId); + } + + //Part of a fix for FF < 3.6 where readyState was not set to + //complete so libraries like jQuery that check for readyState + //after page load where not getting initialized correctly. + //Original approach suggested by Andrea Giammarchi: + //http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + //see other setReadyState reference for the rest of the fix. + if (setReadyState) { + document.readyState = "complete"; + } + + req.callReady(); + } + }; + + //See if there is nothing waiting across contexts, and if not, trigger + //callReady. + req.checkReadyState = function () { + var contexts = s.contexts, prop; + for (prop in contexts) { + if (!(prop in empty)) { + if (contexts[prop].waitCount) { + return; + } + } + } + s.isDone = true; + req.callReady(); + }; + + /** + * Internal function that calls back any ready functions. If you are + * integrating RequireJS with another library without require.ready support, + * you can define this method to call your page ready code instead. + */ + req.callReady = function () { + var callbacks = s.readyCalls, i, callback, contexts, context, prop; + + if (s.isPageLoaded && s.isDone) { + if (callbacks.length) { + s.readyCalls = []; + for (i = 0; (callback = callbacks[i]); i++) { + callback(); + } + } + + //If jQuery with DOM ready delayed, release it now. + contexts = s.contexts; + for (prop in contexts) { + if (!(prop in empty)) { + context = contexts[prop]; + if (context.jQueryIncremented) { + jQueryHoldReady(context.jQuery, false); + context.jQueryIncremented = false; + } + } + } + } + }; + + /** + * Registers functions to call when the page is loaded + */ + req.ready = function (callback) { + if (s.isPageLoaded && s.isDone) { + callback(); + } else { + s.readyCalls.push(callback); + } + return req; + }; + + if (isBrowser) { + if (document.addEventListener) { + //Standards. Hooray! Assumption here that if standards based, + //it knows about DOMContentLoaded. + document.addEventListener("DOMContentLoaded", req.pageLoaded, false); + window.addEventListener("load", req.pageLoaded, false); + //Part of FF < 3.6 readystate fix (see setReadyState refs for more info) + if (!document.readyState) { + setReadyState = true; + document.readyState = "loading"; + } + } else if (window.attachEvent) { + window.attachEvent("onload", req.pageLoaded); + + //DOMContentLoaded approximation, as found by Diego Perini: + //http://javascript.nwbox.com/IEContentLoaded/ + if (self === self.top) { + scrollIntervalId = setInterval(function () { + try { + //From this ticket: + //http://bugs.dojotoolkit.org/ticket/11106, + //In IE HTML Application (HTA), such as in a selenium test, + //javascript in the iframe can't see anything outside + //of it, so self===self.top is true, but the iframe is + //not the top window and doScroll will be available + //before document.body is set. Test document.body + //before trying the doScroll trick. + if (document.body) { + document.documentElement.doScroll("left"); + req.pageLoaded(); + } + } catch (e) {} + }, 30); + } + } + + //Check if document already complete, and if so, just trigger page load + //listeners. NOTE: does not work with Firefox before 3.6. To support + //those browsers, manually call require.pageLoaded(). + if (document.readyState === "complete") { + req.pageLoaded(); + } + } + //****** END page load functionality **************** + + //Set up default context. If require was a configuration object, use that as base config. + req(cfg); + + //If modules are built into require.js, then need to make sure dependencies are + //traced. Use a setTimeout in the browser world, to allow all the modules to register + //themselves. In a non-browser env, assume that modules are not built into require.js, + //which seems odd to do on the server. + if (req.isAsync && typeof setTimeout !== "undefined") { + ctx = s.contexts[(cfg.context || defContextName)]; + //Indicate that the script that includes require() is still loading, + //so that require()'d dependencies are not traced until the end of the + //file is parsed (approximated via the setTimeout call). + ctx.requireWait = true; + setTimeout(function () { + ctx.requireWait = false; + + //Any modules included with the require.js file will be in the + //global queue, assign them to this context. + ctx.takeGlobalQueue(); + + //Allow for jQuery to be loaded/already in the page, and if jQuery 1.4.3, + //make sure to hold onto it for readyWait triggering. + ctx.jQueryCheck(); + + if (!ctx.scriptCount) { + ctx.resume(); + } + req.checkReadyState(); + }, 0); + } +}()); +/*! + * jQuery JavaScript Library v1.6.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu May 12 15:04:36 2011 -0400 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.6.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery._Deferred(); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return (new Function( "return " + data ))(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + + if ( indexOf ) { + return indexOf.call( array, elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can be optionally by executed if its a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +// Expose jQuery to the global object +return jQuery; + +})(); + + +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action ]( returned ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + bodyStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
      a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName( "tbody" ).length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName( "link" ).length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + div.detachEvent( "onclick", click ); + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; + + // Figure out if the W3C box model works as expected + div.style.width = div.style.paddingLeft = "1px"; + + // We use our own, invisible, body + body = document.createElement( "body" ); + bodyStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + // Set background to avoid IE crashes when removing (#9028) + background: "none" + }; + for ( i in bodyStyle ) { + body.style[ i ] = bodyStyle[ i ]; + } + body.appendChild( div ); + documentElement.insertBefore( body, documentElement.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
      "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "
      t
      "; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + body.innerHTML = ""; + documentElement.removeChild( body ); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + return support; +})(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([a-z])([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ jQuery.camelCase( name ) ] : thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + defer; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + rinvalidChar = /\:/, + formHook, boolHook; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class") || "") ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", + setClass = elem.className; + + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + return (elem.value || "").replace(rreturn, ""); + } + + return undefined; + } + + var isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Normalize the name if needed + name = notxml && jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) && + (typeof value === "boolean" || value === undefined || value.toLowerCase() === name.toLowerCase()) ) { + + hooks = boolHook; + + // Use formHook for forms and if the name contains certain characters + } else if ( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { + hooks = formHook; + } + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml ) { + return hooks.get( elem, name ); + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + if ( jQuery.support.getSetAttribute ) { + // Use removeAttribute in browsers that support it + elem.removeAttribute( name ); + } else { + jQuery.attr( elem, name, "" ); + elem.removeAttributeNode( elem.getAttributeNode( name ) ); + } + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabIndex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Try to normalize/fix the name + name = notxml && jQuery.propFix[ name ] || name; + + hooks = jQuery.propHooks[ name ]; + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: {} +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + return elem[ jQuery.propFix[ name ] || name ] ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = value; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// Use the value property for back compat +// Use the formHook for button elements in IE6/7 (#1954) +jQuery.attrHooks.value = { + get: function( elem, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.get( elem, name ); + } + return elem.value; + }, + set: function( elem, value, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // propFix is more comprehensive and contains all fixes + jQuery.attrFix = jQuery.propFix; + + // Use this for any attribute on a form in IE6/7 + formHook = jQuery.attrHooks.name = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Check form objects in IE (multiple bugs related) + // Only use nodeValue if the attribute node exists on the form + var ret = elem.getAttributeNode( name ); + if ( ret ) { + ret.nodeValue = value; + return value; + } + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + + + + +var hasOwn = Object.prototype.hasOwnProperty, + rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; + + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } + + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; + } + } + + return event.result; + }, + + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // set the correct event type + event.type = event.data; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent && parent !== document && !parent.parentNode ) { + return; + } + + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( !jQuery.nodeName( this, "form" ) ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( jQuery.nodeName( elem, "select" ) ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); + e.type = fix; + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( arguments.length === 2 || data === false ) { + fn = data; + data = undefined; + } + + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( liveMap[ type ] ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var match, + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + var first = match[2], + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[ selector ]; + + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
      ", "
      " ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + col: [ 2, "", "
      " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + +
      +

      Aloha, Images! (Extended Version :)

      +
      +
      +

      This extended example is intended for developers planning to use the the CropNResize plugin found at https://github.com/alohaeditor/Aloha-Plugin-CropNResize. It displays the whole set of configuration options currently available. Well, just take a look at the code.

      +
      +
      +

      Click the image to start resizing right away, as a resize handle will appear in it's south-east corner.

      +

      +
      +
      +
        +
        + + \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/crop.php b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/crop.php new file mode 100644 index 00000000..350a3595 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/crop.php @@ -0,0 +1,21 @@ + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/cropnresize.jpg b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/cropnresize.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0fad22ff479befbe3efdfd08e74d299e46dc72e GIT binary patch literal 76312 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

        xyq5-sd~L^zpUIkKxpC#? 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/index.html b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/index.html new file mode 100644 index 00000000..c0f18003 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/demo/index.html @@ -0,0 +1,120 @@ + + + + + Aloha, Images! + + + + + + + + + + + +

        + +
        +

        Aloha, Images!

        +
        +
        +

        This example will show you how to use the Image plugin found at https://github.com/alohaeditor/Aloha-Plugin-Image.

        +
        +
        + +

        +

        Click the image to start resizing right away, as a resize handle will appear in it's south-east corner.

        + +

        Note: This is a very simple example, that will not allow subsequent cropping actions, or cropping combined with resizing.

        +
        + + Outside of the editable +

        +
        + + +
        + + + + + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/blank.jpg b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/blank.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f882a38ccbf20bf6b8525f035bfc9b144eec88a9 GIT binary patch literal 685 zcmex=n}?T8Rorq(5U5H7RWHaGkfcn{zeJb(tU7%peF?$_A5WI>V5%^m(Tk>%+AQ2Yb#$OkBnJ zX2W6KNz$2|6E=AXP5LlpqM)E)g_45o`fb~<&zUUvErvlVHL1j@`Ef=0nj4!1r>VPW z*qOIio$WRNdqdK+cI&=9PiFLQdcgYa+ON-(lI%`5F#D|W>jGl z`p+OVNl8gbpT)&G?dat@yUy>O{EdNewzz-MYrAj$H}H!w`PJ+Ue(o{X%KOsNlcoN4 Yzt2hCDb2FKs_SL11r1XM2KoOt0fZOc5dZ)H literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/cropnresize.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/cropnresize.png new file mode 100644 index 0000000000000000000000000000000000000000..ae04f13ac23a73225ebb4676ecc05b5f3452fe17 GIT binary patch literal 1981 zcmV;u2SWIXP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FZT01FZU(%pXi00007bV*G`2ipk^ z4;2*}W4R�%uuL_t(o!|j+$Y#dn?hQF%n?y=Jo$2b$mFOreROe{8xQcCVvLli(_ z#GUjL^H3>^pa_vTQnJWuKt#w0nZlHn1jl(0h)3@B zE3so^r`ztX2MbPFz`a=ft<;(|O+(jpqN}d!5pYpgfLdQ)|4LI+ z(|3Wt0}GaA6>2c?>%a$&<9xf!)wO!Aycq+#y1L!~-nw?}+WUrKaQN_H7nqg48h^=k z-J#g+URh+ST5K(qN}M})jvF^_(9+Vv;NT$r{r%-@*(sJ!)L5^fX&Tjf1fs6%1VQk* zVzKyxR4Vlopagj0+SOe5-DAg&y?gocWi0~Eah$LohvoZ{NOw-rnA!J$v?i*wxi_slC1ZQd?Ww zrIwbKOHEBp9~*`-lSm}cbsgXL4*{PAc1z4Gcis28ySq0Ba=F|irPNpi9Dw|ujTl*t zff0aHK@da$&Io|x0w%8OPMfCrX`oZnw8-^}^>#fuIZ1DCFS~Z_;_>6hWV6}l1+XBo zYE;&ij`iYlrVrbUgw=oR#sSDT_ur7REmF5DA)i zmdz$IX#;qY%jJ%(uCD&FR4VlWF9WHKjg6jsK7ZQtJW8b!K@j+wruo9s`1+k#9E_5M z0)87Ce@7|xLHs%3pY?<^K@bp^9uf1NLcT%p0EUN$85|s>udj~>4<2yw;ziD%Kfn1M zP16`3AI|`pFbpGU^pqyFEK8r6nd!*q^FP;h{kUNmtgWs6qEIMoX5%QKgkeZBnOu@h z7bKBHjC)fl^*f*~7Uwj_ao!f@y#oZmx0F(=72;=g2FCTC>$<}d^QZ)1J&gx2Jw46R z(h_}reE=Lfbcl(GiA{+!G&IDKBS*M$a3^{uAC;+EVpDwRH7#SI1WMqWhyLWTu%o)y}JsbU9O%v)}U0pw3SXg+~ z_k9%^Fbu=ZkdjO$^Ucl8bKAFXzah!v7BCO2m&Lth;Ez>s`HsZQZ#-))yy?QZT#otq z`H$ivHIfI3M1r=qwuq$`V40?w0anD?o~CIVQejkW>+ApCQ)_E0^YinKXu_biwe?YJ zYwP#3+3XM3*4Dn%+1Yt3olY-FhJ7OLx+KiI3;a#iRH{)MZ_#>=;{?DdrBoXD>azgo zMYXV|X`8Mb-Ai`H_k9fGsq=xo61P@?qSUqnz-L4rY)Kg784!W+>(a}LZ zpRZd8i8`3>>FN3D+}zwk7=}-P2f!m>S(vsapgokaLXA=`ih*;Y7hmW!rg-ASi2*6k z_6iF&DoB;>Q&Ur?BtyHv?K*mGTZO74bK$}TOw%NtPILYGb?)E4UvsgxZ3mWR6-1YM z9UUD%16t&J%aSlkWrqn~ox_BPfgMVzdt&g0JvLEg<4Ac{?KEYFuIs1d_igF_5UUpj z@Vqc!y@Cc?4a1Ph$w?+BCpQOAo;(?e^F?{zs{&#kn3Ir^63`03dOfgeFi>+G=XIsj z#}W!EwOpeIs`bwCb^xymOA+wy2{Y=R=UJB3CW)ewi$9XMH45CbZF{N89J*x6hyjxEMX8k)me;mV54*Xx7xn|3Wj*r9nCbi P00000NkvXXu0mjf_b143 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/handle-sw.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/handle-sw.png new file mode 100644 index 0000000000000000000000000000000000000000..7c8b686f23f0771d441b4c57f0bee1551891e093 GIT binary patch literal 728 zcmV;}0w?{6P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipi9 z6E-Gs>Lh>w000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0006rNkl?}f5-gwGc<9qo6b2hm+uscM4-d}v1nK}1f zU;uuVC+r%JDBIW>1jM%Sh++jBgMe5w9#MF}it&hi8B3~q)xm)=h+GL#f`}V~$QBVX zK0mTW%o(2_nF3~v&krk)X;r;c#g;LMbPkh}5PYoRG<1km783-qP7o(yM2wRVTvgR= z7e`@4j7gH*c5xUwL^6X>lH|+AB)Jb_$(SThS{Nbi$RbJdJyqTHa2-ZORML*P9Mh&{iHHahCxIbY7poC*7uY=E6Lwk<&mH7@KH0I}sSCuds^01#*Yg>h zb+MsDSb0oI<_VVAK_jMxh?o|{E3(=UnF3}dGqw-nG%y5PW3p`rnBI}V%fHX4MlxHu(QwdfbE^wc*=Swtq6AZSst)8 zCPT1RoaIDUh*A}sl2^#C;aG|AaM?@5`xjh_@HsYdNvN^CQ@;=~$=PSG5ZeH<8Jl&n zT_M<$>2vm#uTZUt8-hsn93ee6KCh56)Vvp@RrU583aWbN6IC&ST~wC9?Ci5V=nI1V zS@y-*v0)du`2tG^;^P}NRsHh^P5NhjzWA-=0<%zSzoDoN0pJ(DI=}pP0$95M0000< KMNUMnLSTX>aV^yV literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-align-left.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-align-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5436f1760c4fa0879a2ea844a41ba441b88d7634 GIT binary patch literal 6702 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 VA>c`+BryO0002ovPDHLkV1nO`7eN33 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-border.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image-border.png new file mode 100644 index 0000000000000000000000000000000000000000..9a0e100805d473c08cd23149972a7b9e23a5f39b GIT binary patch literal 6233 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image.gif b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/image.gif new file mode 100644 index 0000000000000000000000000000000000000000..d5924f4bb36a73a3cd9245b098dba3fd783bd889 GIT binary patch literal 621 zcmZ?wbhEHb6krfwc*el+;q%vwKSo{`2<NYb zUv>7rrlE7qrhvvBp+{c)UwG^PzNi0}-}zs&Ik0krU;WnL?T`LVzxIFq{r?Tyf-Bbh zHtq~Pedglod;d2)_`mZp(4wHTuYpzsS8w#&bnQ^(dcR$df!v^`onbSt|6g$P|CWdU zm)!n8|K|Uy4ZfA@eK$V%-?%-bdV~M=NB>W~`oI6_{}p%suetaC{}YC)4SrP{{hN1% z&%N>g$n*b8Z~t#ybKKE0(kC*%Z0e@a?CyInK0SN$<^TWx3)w2#=%N)wYWTM35t|6wz7aG{KM?ip$%|T4uj8*hRlYgkNu(-26AFGhB)U~i1 ztgMQzLZb3gE{0ETu(O+bO3HHcnhS;oGzEq7{Slay*x19t6=bvE(RnThQI#n@839g? z0{j*d|Ck>nA7hf>l3Nqu)X3D(7Hq(<;?Sh0Y79CSe`Y%sdrg@gP~`M*!kG!@9UB=K FtO3mL_vrut literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/padding-decrease.gif b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/padding-decrease.gif new file mode 100644 index 0000000000000000000000000000000000000000..ea186d31a61fcb10b496e3e299fcb64fca3195cb GIT binary patch literal 359 zcmZ?wbhEHb6krfwxXQp_nEhnVj!(0e@3aoee*5vyxjXN-AA5N8^83}>PvlqhKYaS3 zW8vBFfBvsof9dGCN6%k>4~@^6wf6Gbz1Nm)IeGK$`_ngn+Z`Tzg_)5l+*KL7asU*>H* z?HHE#{m0)m>o3h+wd>}yPs_HPJbLcYxoc0hAA8ub@a+Hp|DQho`t+7jnyk@HbW+xcJgW$z1h;onr_Z9^6i;o%F;AR#_X8O%)=8sWY`re zT;-}+)a4~4l$%{zRb^QCI(c;T7~JHFHPj^~c=W{tXSi}pvMX^Ji0aCUt1NM0W0u}3 b&9H-kncsyuB*>6)pXY&K59gyEjttfSIX9a3 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/page.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/page.png new file mode 100644 index 0000000000000000000000000000000000000000..03ddd799fa0a3aec561c75d4221f195db65d6eb9 GIT binary patch literal 635 zcmV->0)+jEP);68^d)m`eN0o>(5%D`Q(1;j>g@G;xlf`0VBQ`PFY?6)!N&f?*K}$p; zB!U=NBn{eB8${1}&-2_L*HuZp@ZP1@clS@cHp)4iM1ewzw59vko7eMM{e9z|%NNdX z0V;`?KKSzTCvTm5bc{L^CIKLUxc2X{i{ISz$8Sgf{q)1nXTP{`{s?9mQ$4&hPiKC- zY8q7(Y1Xu5iCf33=O4Vy(+|zQ?rW#gkKB0f%}?+6{G*qT22|DQB-73`YzA{N4W^=s zq0kQYcbtFfz zLz)H<&|z(Y4kvhNU<6pM87k%8&I29)0}z zZ{pH()3$#4|NsBet>+G$|GweG-IJGp0J#jb0g69a7}*(=7<53!gZ#w6R_-vdz(Yr> z|7iOs#SAOO2?rfsyo^{MvD*2^i6qOG)|OXq1q@owGbxBvn6fw}876k$3HMznq|U-q z#vE2#Ey~y~*%+o+DB8v-E-cq2$ReKDK9Nnjv4BIAdnOy3!W<{&c40P2NnSY-X)&%w Sc7|=+cWm?6y~oXw!5RRtg?q37 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/size-increase.gif b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/img/size-increase.gif new file mode 100644 index 0000000000000000000000000000000000000000..e673ee9ffa50d112ffbf31d0cc653571f5ea2226 GIT binary patch literal 345 zcmZ?wbhEHb6krfwxXQp_;+=fq;fICm4^LjW*)Z$LhmU^`pS%~8+|aw`&6X4Io2MUM zwCnDJ2Os|b_`i7j<@o&m(^q~>S$;S&Htp!8N6S~9fAHdS!_u1vF1(++_0#$Tj}Dyw z{_*F(iA&G@|NnpK)^i(9+yyciXbBX5vM{nUC@|=NECKn6fvwD8LV<^lRKIKcCB+OY z<%tI!Uc8K0AMx7x#fdo1gtnGfTb&LuEIhFLqJU6~r_`2xd0e7QO@anz*uy1QDnuFE zB0) { // when value is 2, won't increase + newValue--; + } + obj.css(attr,newValue); + // Chain + return obj; + } + }); + + // Create and register Image Plugin + return Plugin.create('image', { + + languages: ['en', 'fr', 'de', 'ru', 'cz'], + + defaultSettings: { + 'maxWidth': 1600, + 'minWidth': 3, + 'maxHeight': 1200, + 'minHeight': 3, + // This setting will correct manually values that are out of bounds + 'autoCorrectManualInput': true, + // This setting will define a fixed aspect ratio for all resize actions + 'fixedAspectRatio' : false, + // When enabled this setting will order the plugin to automatically resize images to given bounds + 'autoResize': false, + //Image manipulation options - ONLY in default config section + ui: { + oneTab : false, //Place all ui components within one tab + insert : true, + reset : true, + aspectRatioToggle: true, // Toggle button for the aspect ratio + align : true, // Menu elements to show/hide in menu + resize : true, // Resize buttons + meta : true, + margin : true, + crop : true, + resizable : true, // Resizable ui-drag image + handles : 'ne, se, sw, nw' + }, + + /** + * Crop callback is triggered after the user clicked accept to accept his crop + * @param image jquery image object reference + * @param props cropping properties + */ + onCropped: function ($image, props) { + Aloha.Log.info('Default onCropped invoked', $image, props); + }, + + /** + * Reset callback is triggered before the internal reset procedure is applied + * if this function returns true, then the reset has been handled by the callback + * which means that no other reset will be applied + * if false is returned the internal reset procedure will be applied + * @param image jquery image object reference + * @return true if a reset has been applied, false otherwise + */ + onReset: function ($image) { + Aloha.Log.info('Default onReset invoked', $image); + return false; + }, + + /** + * Example callback method which gets called while the resize process is beeing executed. + */ + onResize: function ($image) { + Aloha.Log.info('Default onResize invoked', $image); + }, + + /** + * Resize callback is triggered after the internal resize procedure is applied. + */ + onResized: function ($image) { + Aloha.Log.info('Default onResized invoked', $image); + } + }, + + /** + * Internal callback hook which gets invoked when cropping has been finished + */ + _onCropped: function ($image, props) { + + $('#' + this.imgResizeHeightField.id).val($image.height()); + $('#' + this.imgResizeWidthField.id).val($image.width()); + + + $('body').trigger('aloha-image-cropped', [$image, props]); + + // Call the custom onCropped function + this.onCropped($image, props); + }, + + /** + * Internal callback hook which gets invoked when resetting images + */ + _onReset: function ($image) { + + $('#' + this.imgResizeHeightField.id).val($image.height()); + $('#' + this.imgResizeWidthField.id).val($image.width()); + + // No default behaviour defined besides event triggering + $('body').trigger('aloha-image-reset', $image); + + // Call the custom resize function + return this.onReset($image); + }, + + /** + * Internal callback hook which gets invoked while the image is beeing resized + */ + _onResize: function ($image) { + + $('#' + this.imgResizeHeightField.id).val($image.height()); + $('#' + this.imgResizeWidthField.id).val($image.width()); + + // No default behaviour defined besides event triggering + $('body').trigger('aloha-image-resize', $image); + + // Call the custom resize function + this.onResize($image); + }, + + /** + * Internal callback hook which gets invoked when the current resizing action has stopped + */ + _onResized: function ($image) { + + $('#' + this.imgResizeHeightField.id).val($image.height()); + $('#' + this.imgResizeWidthField.id).val($image.width()); + + $('body').trigger('aloha-image-resized', $image); + + // Call the custom resize function + this.onResized($image); + }, + + /** + * The image that is currently edited + */ + imageObj: null, + + /** + * The Jcrop API reference + * this is needed to be able to destroy the cropping frame later on + * the variable is linked to the api object whilst cropping, or set to null otherwise + * strange, but done as documented http://deepliquid.com/content/Jcrop_API.html + */ + jcAPI: null, + + + /** + * State variable for the aspect ratio toggle feature + */ + keepAspectRatio: false, + + /** + * Variable that will hold the start aspect ratio. This ratio will be used once starResize will be called. + */ + startAspectRatio: false, + + /** + * This will contain an image's original properties to be able to undo previous settings + * + * when an image is clicked for the first time, a new object will be added to the array + * { + * obj : [the image object reference], + * src : [the original src url], + * width : [initial width], + * height : [initial height] + * } + * + * when an image is clicked the second time, the array will be checked for the image object + * referenct, to prevent for double entries + */ + restoreProps: [], + + objectTypeFilter: [], + + /** + * Plugin initialization method + */ + init: function() { + + var that = this; + + var imagePluginUrl = Aloha.getPluginUrl('image'); + + // Extend the default settings with the custom ones (done by default) + this.startAspectRatio = this.settings.fixedAspectRatio; + this.config = this.defaultSettings; + this.settings = jQuery.extend(true, this.defaultSettings, this.settings); + + that.initializeButtons(); + that.bindInteractions(); + that.subscribeEvents(); + + }, + + /** + * Create buttons + */ + initializeButtons: function() { + + var that = this, + tabInsert = i18nCore.t('floatingmenu.tab.insert'), + tabImage = i18n.t('floatingmenu.tab.img'), + tabFormatting = i18n.t('floatingmenu.tab.formatting'), + tabCrop = i18n.t('floatingmenu.tab.crop'), + tabResize = i18n.t('floatingmenu.tab.resize'); + + FloatingMenu.createScope(this.name, 'Aloha.empty'); + + if (this.settings.ui.insert) { + var tabId = this.settings.ui.oneTab ? tabImage : tabInsert; + that._addUIInsertButton(tabId); + } + + if (this.settings.ui.meta) { + var tabId = this.settings.ui.oneTab ? tabImage : tabImage; + that._addUIMetaButtons(tabId); + } + + if (this.settings.ui.reset) { + var tabId = this.settings.ui.reset ? tabImage : tabImage; + that._addUIResetButton(tabId); + } + + if (this.settings.ui.align) { + var tabId = this.settings.ui.oneTab ? tabImage : tabFormatting; + that._addUIAlignButtons(tabId); + } + + if (this.settings.ui.margin) { + var tabId = this.settings.ui.oneTab ? tabImage : tabFormatting; + that._addUIMarginButtons(tabId); + } + + if (this.settings.ui.crop) { + var tabId = this.settings.ui.oneTab ? tabImage : tabCrop; + that._addUICropButtons(tabId); + } + + if (this.settings.ui.resize) { + var tabId = this.settings.ui.oneTab ? tabImage : tabResize; + that._addUIResizeButtons(tabId); + } + + if (this.settings.ui.aspectRatioToggle) { + var tabId = this.settings.ui.oneTab ? tabImage : tabResize; + that.__addUIAspectRatioToggleButton(tabId); + } + + // TODO fix the function and reenable this button + //that._addNaturalSizeButton(); + }, + + + /** + * Adds the aspect ratio toggle button to the floating menu + */ + __addUIAspectRatioToggleButton: function(tabId) { + var that = this; + var toggleButton = new Aloha.ui.Button({ + 'size' : 'small', + 'tooltip' : i18n.t('button.toggle.tooltip'), + 'toggle' : true, + 'iconClass' : 'cnr-ratio', + 'onclick' : function (btn, event) { + that.toggleKeepAspectRatio(); + } + }); + + + // If the setting has been set to a number or false we need to activate the + // toggle button to indicate that the aspect ratio will be preserved. + if (this.settings.fixedAspectRatio != false) { + toggleButton.pressed = true; + this.keepAspectRatio = true; + } + + FloatingMenu.addButton( + that.name, + toggleButton, + tabId, + 20 + ); + + + }, + + + /** + * Adds the reset button to the floating menu for the given tab + */ + _addUIResetButton: function(tabId) { + var that = this; + // Reset button + var resetButton = new Aloha.ui.Button({ + 'size' : 'small', + 'tooltip' : i18n.t('Reset'), + 'toggle' : false, + 'iconClass' : 'cnr-reset', + 'onclick' : function (btn, event) { + that.reset(); + } + }); + + FloatingMenu.addButton( + that.name, + resetButton, + tabId, + 2 + ); + }, + + /** + * Adds the insert button to the floating menu + */ + _addUIInsertButton: function(tabId) { + var that = this; + this.insertImgButton = new Aloha.ui.Button({ + 'name' : 'insertimage', + 'iconClass': 'aloha-button aloha-image-insert', + 'size' : 'small', + 'onclick' : function () { that.insertImg(); }, + 'tooltip' : i18n.t('button.addimg.tooltip'), + 'toggle' : false + }); + + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.insertImgButton, + tabId, + 1 + ); + }, + + /** + * Adds the ui meta fields (search, title) to the floating menu. + */ + _addUIMetaButtons: function(tabId) { + var that = this; + var imgSrcLabel = new Aloha.ui.Button({ + 'label': i18n.t('field.img.src.label'), + 'tooltip': i18n.t('field.img.src.tooltip'), + 'size': 'small' + }); + this.imgSrcField = new Aloha.ui.AttributeField({'name' : 'imgsrc'}); + this.imgSrcField.setObjectTypeFilter( this.objectTypeFilter ); + + // add the title field for images + var imgTitleLabel = new Aloha.ui.Button({ + 'label': i18n.t('field.img.title.label'), + 'tooltip': i18n.t('field.img.title.tooltip'), + 'size': 'small' + }); + + this.imgTitleField = new Aloha.ui.AttributeField(); + this.imgTitleField.setObjectTypeFilter(); + FloatingMenu.addButton( + this.name, + this.imgSrcField, + tabId, + 1 + ); + + }, + + /** + * Adds the ui align buttons to the floating menu + */ + _addUIAlignButtons: function(tabId) { + var that = this; + + var alignLeftButton = new Aloha.ui.Button({ + 'iconClass': 'aloha-img aloha-image-align-left', + 'size': 'small', + 'onclick' : function() { + var el = jQuery(that.findImgMarkup()); + el.add(el.parent()).css('float', 'left'); + }, + 'tooltip': i18n.t('button.img.align.left.tooltip') + }); + + FloatingMenu.addButton( + that.name, + alignLeftButton, + tabId, + 1 + ); + + var alignRightButton = new Aloha.ui.Button({ + 'iconClass': 'aloha-img aloha-image-align-right', + 'size': 'small', + 'onclick' : function() { + var el = jQuery(that.findImgMarkup()); + el.add(el.parent()).css('float', 'right'); + }, + 'tooltip': i18n.t('button.img.align.right.tooltip') + }); + + FloatingMenu.addButton( + that.name, + alignRightButton, + tabId, + 1 + ); + + var alignNoneButton = new Aloha.ui.Button({ + 'iconClass': 'aloha-img aloha-image-align-none', + 'size': 'small', + 'onclick' : function() { + var el = jQuery(that.findImgMarkup()); + el.add(el.parent()).css({ + 'float': 'none', + display: 'inline-block' + }); + }, + 'tooltip': i18n.t('button.img.align.none.tooltip') + }); + + FloatingMenu.addButton( + that.name, + alignNoneButton, + tabId, + 1 + ); + + }, + + /** + * Adds the ui margin buttons to the floating menu + */ + _addUIMarginButtons: function(tabId) { + var that = this; + var incPadding = new Aloha.ui.Button({ + iconClass: 'aloha-img aloha-image-padding-increase', + toggle: false, + size: 'small', + onclick: function() { + jQuery(that.findImgMarkup()).increase('padding'); + }, + tooltip: i18n.t('padding.increase') + }); + FloatingMenu.addButton( + that.name, + incPadding, + tabId, + 2 + ); + + var decPadding = new Aloha.ui.Button({ + iconClass: 'aloha-img aloha-image-padding-decrease', + toggle: false, + size: 'small', + onclick: function() { + jQuery(that.findImgMarkup()).decrease('padding'); + }, + tooltip: i18n.t('padding.decrease') + }); + FloatingMenu.addButton( + that.name, + decPadding, + tabId, + 2 + ); + }, + + /** + * Adds the crop buttons to the floating menu + */ + _addUICropButtons: function (tabId) { + var that = this; + + FloatingMenu.createScope('Aloha.img', ['Aloha.global']); + + this.cropButton = new Aloha.ui.Button({ + 'size' : 'small', + 'tooltip' : i18n.t('Crop'), + 'toggle' : true, + 'iconClass' : 'cnr-crop', + 'onclick' : function (btn, event) { + if (btn.pressed) { + that.crop(); + } else { + that.endCrop(); + } + } + }); + + FloatingMenu.addButton( + this.name, + this.cropButton, + tabId, + 3 + ); + + }, + + /** + * Adds the resize buttons to the floating menu + */ + _addUIResizeButtons: function (tabId) { + var that = this; + + // Manual resize fields + this.imgResizeHeightField = new Aloha.ui.AttributeField(); + this.imgResizeHeightField.maxValue = that.settings.maxHeight; + this.imgResizeHeightField.minValue = that.settings.minHeight; + + this.imgResizeWidthField = new Aloha.ui.AttributeField(); + this.imgResizeWidthField.maxValue = that.settings.maxWidth; + this.imgResizeWidthField.minValue = that.settings.minWidth; + + this.imgResizeWidthField.width = 50; + this.imgResizeHeightField.width = 50; + + var widthLabel = new Aloha.ui.Button({ + 'label': i18n.t('width'), + 'tooltip': i18n.t('width'), + 'size': 'small' + }); + + FloatingMenu.addButton( + this.name, + widthLabel, + tabId, + 30 + ); + + FloatingMenu.addButton( + this.name, + this.imgResizeWidthField, + tabId, + 40 + ); + + + var heightLabel = new Aloha.ui.Button({ + 'label': i18n.t('height'), + 'tooltip': i18n.t('height'), + 'size': 'small' + }); + + FloatingMenu.addButton( + this.name, + heightLabel, + tabId, + 50 + ); + + FloatingMenu.addButton( + this.name, + this.imgResizeHeightField, + tabId, + 60 + ); + + + }, + + /** + * Adds the natural size button to the floating menu + */ + _addNaturalSizeButton: function () { + var that = this; + var naturalSize = new Aloha.ui.Button({ + iconClass: 'aloha-img aloha-image-size-natural', + size: 'small', + toggle: false, + onclick: function() { + var img = new Image(); + img.onload = function() { + var myimage = that.findImgMarkup(); + if (that.settings.ui.resizable) { + that.endResize(); + } + jQuery(myimage).css({ + 'width': img.width + 'px', + 'height': img.height + 'px', + 'max-width': '', + 'max-height': '' + }); + if (that.settings.ui.resizable) { + that.resize(); + } + }; + img.src = that.findImgMarkup().src; + + }, + tooltip: i18n.t('size.natural') + }); + FloatingMenu.addButton( + this.name, + naturalSize, + tabResize, + 2 + ); + }, + + /** + * Bind plugin interactions + */ + bindInteractions: function () { + var that = this; + + if (this.settings.ui.resizable) { + try { + // this will disable mozillas image resizing facilities + document.execCommand( 'enableObjectResizing', false, false ); + } catch (e) { + Aloha.Log.error( e, 'Could not disable enableObjectResizing' ); + // this is just for internet explorer, who will not support disabling enableObjectResizing + } + } + + if (this.settings.ui.meta) { + // update image object when src changes + this.imgSrcField.addListener('keyup', function(obj, event) { + that.srcChange(); + }); + + this.imgSrcField.addListener('blur', function(obj, event) { + // TODO remove image or do something usefull if the user leaves the + // image without defining a valid image src. + var img = jQuery(obj.getTargetObject()); + if ( img.attr('src') === '' ) { + img.remove(); + } // image removal when src field is blank + }); + } + + // Override the default method by using the given one + if (this.settings.onCropped && typeof this.settings.onCropped === "function") { + this.onCropped = this.settings.onCropped; + } + + // Override the default method by using the given one + if (this.settings.onReset && typeof this.settings.onReset === "function") { + this.onReset = this.settings.onReset; + } + + // Override the default method by using the given one + if (this.settings.onResized && typeof this.settings.onResized === "function") { + this.onResized = this.settings.onResized; + } + + // Override the default method by using the given one + if (this.settings.onResize && typeof this.settings.onResize === "function") { + this.onResize = this.settings.onResize; + } + + }, + + /** + * Subscribe to Aloha events and DragAndDropPlugin Event + */ + subscribeEvents: function() { + var that = this; + var config = this.settings; + + jQuery('img').filter(config.globalselector).unbind(); + jQuery('img').filter(config.globalselector).click(function(event) { + that.clickImage(event); + }); + + Aloha.bind('aloha-drop-files-in-editable', function(event, data) { + var img, len = data.filesObjs.length, fileObj, config; + + while (--len >= 0) { + fileObj = data.filesObjs[len]; + if (fileObj.file.type.match(/image\//)) { + config = that.getEditableConfig(data.editable); + // Prepare + img = jQuery(''); + img.css({ + "max-width": that.maxWidth, + "max-height": that.maxHeight + }); + img.attr('id',fileObj.id); + if (typeof fileObj.src === 'undefined') { + img.attr('src', fileObj.data ); + //fileObj.src = fileObj.data ; + } else { + img.attr('src',fileObj.src ); + } + GENTICS.Utils.Dom.insertIntoDOM(img, data.range, jQuery(Aloha.activeEditable.obj)); + } + } + + }); + + /* + * Add the event handler for selection change + */ + Aloha.bind('aloha-selection-changed', function(event, rangeObject, originalEvent) { + var config, foundMarkup; + if (originalEvent && originalEvent.target) { + // Check if the element is currently beeing resized + if (that.settings.ui.resizable && !jQuery(originalEvent.target).hasClass('ui-resizable-handle')) { + that.endResize(); + } + } + + if (Aloha.activeEditable !== null) { + foundMarkup = that.findImgMarkup( rangeObject ); + //var config = that.getEditableConfig(Aloha.activeEditable.obj); + config = that.getEditableConfig(Aloha.activeEditable.obj); + + if (typeof config !== 'undefined' ) { + that.insertImgButton.show(); + } else { + that.insertImgButton.hide(); + return; + } + + // Enable image specific ui components if the element is an image + if (foundMarkup) { + that.insertImgButton.hide(); + FloatingMenu.setScope(that.name); + if (that.settings.ui.meta) { + that.imgSrcField.setTargetObject(foundMarkup, 'src'); + that.imgTitleField.setTargetObject(foundMarkup, 'title'); + } + that.imgSrcField.focus(); + FloatingMenu.activateTabOfButton('imgsrc'); + } else { + if (that.settings.ui.meta) { + that.imgSrcField.setTargetObject(null); + } + } + // TODO this should not be necessary here! + FloatingMenu.doLayout(); + } + + }); + + Aloha.bind('aloha-editable-created', function( event, editable) { + + try { + // this will disable mozillas image resizing facilities + document.execCommand( 'enableObjectResizing', false, false); + } catch (e) { + Aloha.Log.error( e, 'Could not disable enableObjectResizing'); + // this is just for others, who will not support disabling enableObjectResizing + } + + // Inital click on images will be handled here + // editable.obj.find('img').attr('_moz_resizing', false); + // editable.obj.find('img').contentEditable(false); + editable.obj.delegate( 'img', 'mouseup', function (event) { + that.clickImage(event); + event.stopPropagation(); + }); + }); + + that._subscribeToResizeFieldEvents(); + + }, + + /** + * Automatically resize the image to fit into defined bounds. + */ + autoResize: function() { + var that = this; + + var width = that.imageObj.width(); + var height = that.imageObj.height(); + + // Only normalize the field values when the image exeeds the definded bounds + if (width < that.settings.minWidth || width > that.settings.maxWidth || height < that.settings.minHeight || height > that.settings.maxHeight) { + that._setNormalizedFieldValues('width'); + that.setSizeByFieldValue(); + return true; + } else { + return false; + } + }, + + /** + * Toggle the keep aspect ratio functionallity + */ + toggleKeepAspectRatio: function() { + + this.keepAspectRatio = !this.keepAspectRatio; + + this.endResize(); + if (!this.keepAspectRatio) { + this.startAspectRatio = false; + } else { + // If no fixed aspect ratio was given we will calculate a new start + // aspect ratio that will be used for the next starResize action. + if ( typeof this.settings.fixedAspectRatio !== 'number' ) { + var currentRatio = this.imageObj.width() / this.imageObj.height(); + this.startAspectRatio = currentRatio; + } else { + this.startAspectRatio = this.settings.fixedAspectRatio; + } + } + this.startResize(); + }, + + /** + * Bind interaction events that are invoked on the resize fields + */ + _subscribeToResizeFieldEvents: function() { + var that = this; + + /** + * Helper function that will update the fields + */ + function updateField( $field, delta, maxValue, minValue ) { + + if ( typeof minValue === 'undefined' ) { + minValue = 0; + } + + if ( typeof maxValue === 'undefined' ) { + maxValue = 8000; + } + + // If the current value of the field can't be parsed we don't update it + var oldValue = parseInt( $field.val() ); + if ( isNaN(oldValue) ) { + $field.css( 'background-color', 'red' ); + return false; + } + + var newValue = oldValue + delta; + // Exit if the newValue is above the maxValue limit (only if the user tries to increment) + if (delta>=0 && newValue > maxValue) { + + // Auto correct out of bounds values + if (that.settings.autoCorrectManualInput) { + $field.val(maxValue); + return true; + } else { + $field.css('background-color','red'); + return false; + } + // Exit if the newValue is below the minValue (only if the user tries to decrement) + } else if (delta<=0 && newValue= minValue) { + + // Check if we are currently in cropping mode + if(typeof that.jcAPI !== 'undefined' && that.jcAPI != null) { + that.setCropAreaByFieldValue(); + } else { + // 1. Normalize the size + that._setNormalizedFieldValues(fieldName); + // 2. Set the final size to the image + that.setSizeByFieldValue(); + } + } + // 0-9 keys + } else if (e.keyCode <= 57 && e.keyCode >= 48 || e.keyCode <= 105 && e.keyCode >= 96 ) { + if($(this).val() >= minValue) { + + // Check if we are currently in cropping mode + if(typeof that.jcAPI !== 'undefined' && that.jcAPI != null) { + that.setCropAreaByFieldValue(); + } else { + // 1. Normalize the size + that._setNormalizedFieldValues(fieldName); + // 2. Set the final size to the image + that.setSizeByFieldValue(); + } + } + } else { + var delta = 0; + if (e.keyCode == 38 || e.keyCode == 107) { + delta = +1; + } else if (e.keyCode == 40 || e.keyCode == 109) { + delta = -1; + } + // Handle key combinations + if ( e.shiftKey || e.metaKey || e.ctrlKey ) { + delta = delta * 10; + } + + // Only resize when field values are ok + if(updateField($(this), delta, maxValue, minValue)) { + // Check if we are currently in cropping mode + if(typeof that.jcAPI !== 'undefined' && that.jcAPI != null) { + that.setCropAreaByFieldValue(); + } else { + // 1. Normalize the size + that._setNormalizedFieldValues(fieldName); + // 2. Set the final size to the image + that.setSizeByFieldValue(); + } + } + } + + e.preventDefault(); + return false; + }; + + /** + * Handle the mouse wheel event on the field + */ + function handleMouseWheelEventOnField(e, delta) { + var minValue = e.data.minValue; + var maxValue = e.data.maxValue; + var fieldName = e.data.fieldName; + + // Handle key combinations + if ( e.shiftKey || e.metaKey || e.ctrlKey ) { + delta = delta * 10; + } + + // Only resize when field values are ok + if(updateField($(this), delta, maxValue, minValue)) { + + // Check if we are currently in cropping mode + if(typeof that.jcAPI !== 'undefined' && that.jcAPI != null) { + that.setCropAreaByFieldValue(); + } else { + // 1. Normalize the size + that._setNormalizedFieldValues(fieldName); + // 2. Set the final size to the image + that.setSizeByFieldValue(); + } + } + return false; + }; + + /** + * Handle mousewheel,keyup actions on both fields + */ + var $heightField = $('#' + that.imgResizeHeightField.id ); + var heightEventData = {fieldName: 'height', maxValue: that.imgResizeHeightField.maxValue, minValue: that.imgResizeHeightField.minValue }; + $heightField.live('keyup', heightEventData, handleKeyUpEventOnField); + $heightField.live('mousewheel', heightEventData, handleMouseWheelEventOnField); + + var $widthField = $('#' + that.imgResizeWidthField.id ); + var widthEventData = {fieldName: 'width', maxValue: that.imgResizeWidthField.maxValue , minValue: that.imgResizeWidthField.minValue }; + $widthField.live('keyup',widthEventData , handleKeyUpEventOnField); + $widthField.live('mousewheel', widthEventData, handleMouseWheelEventOnField); + + }, + + + /** + * This helper function will keep the aspect ratio for the field with the given name. + */ + _setNormalizedFieldValues: function(primaryFieldName) { + + var that = this; + var widthField = jQuery("#" + that.imgResizeWidthField.id); + var heightField = jQuery("#" + that.imgResizeHeightField.id); + var width = widthField.val(); + var height = heightField.val(); + + var size = that._normalizeSize(width, height, primaryFieldName); + + widthField.val(size.width); + heightField.val(size.height); + + }, + + /** + * Manually set the given size for the current image + */ + setSize: function(width, height) { + + var that = this; + this.imageObj.width(width); + this.imageObj.height(height); + var $wrapper = this.imageObj.closest('.Aloha_Image_Resize'); + $wrapper.height(height); + $wrapper.width(width); + + this._onResize(this.imageObj); + this._onResized(this.imageObj); + }, + + /** + * This method will handle the mouseUp event on images (eg. within editables). + * It will if enabled activate the resizing action. + */ + clickImage: function( e ) { + + var that = this; + that.imageObj = jQuery(e.target); + var currentImage = that.imageObj; + + FloatingMenu.setScope(that.name); + + var editable = currentImage.closest('.aloha-editable'); + + // Disabling the content editable. This will disable the resizeHandles in internet explorer + jQuery(editable).contentEditable(false); + + //Store the current props of the image + this.restoreProps.push({ + obj : e.srcElement, + src : that.imageObj.attr('src'), + width : that.imageObj.width(), + height : that.imageObj.height() + }); + + // Update the resize input fields with the new width and height + $('#' + that.imgResizeHeightField.id).val(that.imageObj.height()); + $('#' + that.imgResizeWidthField.id).val(that.imageObj.width()); + + + if (this.settings.ui.resizable) { + this.startResize(); + } + + + if (this.settings.autoResize) { + this.autoResize(); + } + + }, + + /** + * This method extracts determins if the range selection contains an image + */ + findImgMarkup: function ( range ) { + + var that = this; + var config = this.config; + var result, targetObj; + + if ( typeof range === 'undefined' ) { + range = Aloha.Selection.getRangeObject(); + } + + targetObj = jQuery(range.startContainer); + + try { + if ( Aloha.activeEditable ) { + if (( typeof range.startContainer !== 'undefined' + && typeof range.startContainer.childNodes !== 'undefined' + && typeof range.startOffset !== 'undefined' + && typeof range.startContainer.childNodes[range.startOffset] !== 'undefined' + && range.startContainer.childNodes[range.startOffset].nodeName.toLowerCase() === 'img' + && range.startOffset+1 === range.endOffset) || + (targetObj.hasClass('Aloha_Image_Resize'))) + { + result = targetObj.find('img')[0]; + if (! result.css) { + result.css = ''; + } + + if (! result.title) { + result.title = ''; + } + + if (! result.src) { + result.src = ''; + } + return result; + } + else { + return null; + } + } + } catch (e) { + Aloha.Log.debug(e, "Error finding img markup."); + } + return null; + + }, + + + /** + * This helper function will calculate the new width and height while keeping + * the aspect ratio when the keepAspectRatio flat is set to true. The primarySize + * can be 'width' or 'height'. The function will first try to normalize the oposite size. + */ + _normalizeSize: function(width, height, primarySize) { + + var that = this; + // Convert string values to numbers + width = parseInt(width); + height = parseInt(height); + + /** + * Inner function that calculates the new height by examining the width + */ + function handleHeight(callHandleWidth) { + + // Check whether the value is within bounds + if (height > that.settings.maxHeight) { + + // Throw a notification event + var eventProps = { 'org': height, 'new': that.settings.maxHeight}; + $('body').trigger('aloha-image-resize-outofbounds', ["height", "max", eventProps]); + height = that.settings.maxHeight; + + } else if (height < that.settings.minHeight) { + + // Throw a notification event + var eventProps = { 'org': height, 'new': that.settings.minHeight}; + $('body').trigger('aloha-image-resize-outofbounds', ["height", "min", eventProps]); + height = that.settings.minHeight; + } + + if (that.keepAspectRatio) { + width = height * aspectRatio; + + // We don't want to invoke handleWidth again. This would mess up our previously calculated width + if (callHandleWidth) { + handleWidth(false); + } + } + + + } + + /** + * Inner function that calculates the new width by examining the width + */ + function handleWidth(callHandleHeight) { + + // Check whether the value is within bounds + if (width > that.settings.maxWidth) { + + // Throw a notification event + var eventProps = { 'org': width, 'new': that.settings.maxWidth}; + $('body').trigger('aloha-image-resize-outofbounds', ["width", "max", eventProps]); + + width = that.settings.maxWidth; + } else if (width < that.settings.minWidth) { + + // Throw a notification event + var eventProps = { 'org': width, 'new': that.settings.minWidth}; + $('body').trigger('aloha-image-resize-outofbounds', ["width", "min", eventProps]); + + width = that.settings.minWidth; + } + + // Calculate the new height + if (that.keepAspectRatio) { + height = width / aspectRatio; + + // We don't want to invoke handleHeight again. This would mess up our previously calculated height + if (callHandleHeight) { + handleHeight(false); + } + + } + + } + + // Load the aspect ratio and use the 4:3 ratio as default value. + var aspectRatio = 1.33333; + if (typeof that.startAspectRatio === 'number') { + aspectRatio = that.startAspectRatio; + } + + // Determin which size should be handled + if (primarySize == 'width') { + handleWidth(true); + } + + if (primarySize == 'height') { + handleHeight(true); + } + + // Floor the values return them + return {'width': Math.floor(width), 'height': Math.floor(height)}; + }, + + + /** + * Helper function that will set the new image size using the field values + */ + setSizeByFieldValue: function() { + var that = this; + var width = $('#' + that.imgResizeWidthField.id ).val(); + var height = $('#' + that.imgResizeHeightField.id ).val(); + that.setSize(width, height); + }, + + /** + * Helper function that will set the new crop area width and height using the field values + */ + setCropAreaByFieldValue: function() { + var that = this; + var currentCropArea = that.jcAPI.tellSelect(); + + var width = $('#' + that.imgResizeWidthField.id ).val(); + width = parseInt(width); + var height = $('#' + that.imgResizeHeightField.id ).val(); + height = parseInt(height); + + var selection = [currentCropArea['x'], currentCropArea['y'], currentCropArea['x'] + width,currentCropArea['y'] + height]; + that.jcAPI.setSelect(selection); + }, + + /** + * This method will insert a new image dom element into the dom tree + */ + insertImg: function() { + var range = Aloha.Selection.getRangeObject(), + config = this.getEditableConfig(Aloha.activeEditable.obj), + imagePluginUrl = Aloha.getPluginUrl('image'), + imagestyle, imagetag, newImg; + + if ( range.isCollapsed() ) { + // TODO I would suggest to call the srcChange method. So all image src + // changes are on one single point. + imagestyle = "max-width: " + config.maxWidth + "; max-height: " + config.maxHeight; + imagetag = ''; + newImg = jQuery(imagetag); + // add the click selection handler + //newImg.click( Aloha.Image.clickImage ); - Using delegate now + GENTICS.Utils.Dom.insertIntoDOM(newImg, range, jQuery(Aloha.activeEditable.obj)); + + } else { + Aloha.Log.error('img cannot markup a selection'); + // TODO the desired behavior could be me the selected content is + // replaced by an image. + // TODO it should be editor's choice, with an NON-Ext Dialog instead of alert + + } + }, + + srcChange: function () { + // TODO the src changed. I suggest : + // 1. set an loading image (I suggest set src base64 enc) to show the user + // we are trying to load an image + // 2. start a request to get the image + // 3a. the image is ok change the src + // 3b. the image is not availbable show an error. + this.imageObj.attr('src', this.imgSrcField.getQueryValue() ); // (the img tag) +// jQuery(img).attr('src', this.imgSrcField.getQueryValue() ); // (the query value in the inputfield) +// this.imgSrcField.getItem(); // (optinal a selected resource item) + // TODO additionally implement an srcChange Handler to let implementer + // customize + }, + + /** + * Code imported from CropnResize Plugin + * + */ + initCropButtons: function() { + var that = this, + btns, + oldLeft = 0, + oldTop = 0; + + jQuery('body').append( + '
        \ + \ + \ +
        ' + ); + + btns = jQuery('#aloha-CropNResize-btns') + + btns.find('.cnr-crop-apply').click(function () { + that.acceptCrop(); + }); + + btns.find('.cnr-crop-cancel').click(function () { + that.endCrop(); + }); + + this.interval = setInterval(function () { + var jt = jQuery('.jcrop-tracker:first'), + off = jt.offset(), + jtt = off.top, + jtl = off.left, + jth = jt.height(), + jtw = jt.width(); + + if (jth && jtw) { + btns.fadeIn('slow'); + } + + // move the icons to the bottom right side + jtt = parseInt(jtt + jth + 3, 10); + jtl = parseInt(jtl + jtw - 55, 10); + + // comparison to old values hinders flickering bug in FF + if (oldLeft != jtl || oldTop != jtt) { + btns.offset({top: jtt, left: jtl}); + } + + oldLeft = jtl; + oldTop = jtt; + }, 10); + }, + + /** + * Destroy crop confirm and cancel buttons + */ + destroyCropButtons: function () { + jQuery('#aloha-CropNResize-btns').remove(); + clearInterval(this.interval); + }, + + /** + * Helper function that will disable selectability of elements + */ + _disableSelection: function (el) { + el.find('*').attr('unselectable', 'on') + .css({ + '-moz-user-select':'none', + '-webkit-user-select':'none', + 'user-select':'none' + }); + /* + .each(function() { + this.onselectstart = function () { return false; }; + }); + */ + + }, + + /** + * Initiate a crop action + */ + crop: function () { + var that = this; + var config = this.config; + + this.initCropButtons(); + if (this.settings.ui.resizable) { + this.endResize(); + } + + this.jcAPI = jQuery.Jcrop(this.imageObj, { + onSelect : function () { + that._onCropSelect(); + // ugly hack to keep scope :( + setTimeout(function () { + FloatingMenu.setScope(that.name); + }, 10); + } + }); + + that._disableSelection($('.jcrop-holder')); + that._disableSelection($('#imageContainer')); + that._disableSelection($('#aloha-CropNResize-btns')); + $('body').trigger('aloha-image-crop-start', [this.imageObj]); + }, + + /** + * Internal on crop select method + */ + _onCropSelect: function() { + var that = this; + + // Update the width and height field using the intiial active crop area values + if(typeof that.jcAPI !== 'undefined' && that.jcAPI != null) { + var currentCropArea = that.jcAPI.tellSelect(); + var widthField = jQuery("#" + that.imgResizeWidthField.id).val(currentCropArea['w']); + var heightField = jQuery("#" + that.imgResizeHeightField.id).val(currentCropArea['h']); + } + + }, + + + /** + * Terminates a crop + */ + endCrop: function () { + if ( this.jcAPI ) { + this.jcAPI.destroy(); + this.jcAPI = null; + } + + this.destroyCropButtons(); + this.cropButton.extButton.toggle(false); + + if ( this.settings.ui.resizable ) { + this.startResize(); + } + + if ( this.keepAspectRatio ) { + var currentRatio = this.imageObj.width() / this.imageObj.height(); + this.startAspectRatio = currentRatio; + } + + $('body').trigger('aloha-image-crop-stop', [this.imageObj]); + }, + + /** + * Accept the current cropping area and apply the crop + */ + acceptCrop: function () { + this._onCropped ( this.imageObj, this.jcAPI.tellSelect() ); + this.endCrop (); + }, + + /** + * This method will activate the jquery-ui resize functionality for the current image + */ + startResize: function () { + var that = this; + var currentImageObj = this.imageObj; + + currentImageObj = this.imageObj.css({ + height : this.imageObj.height(), + width : this.imageObj.width(), + position : 'relative', + 'max-height': '', + 'max-width' : '' + }); + + currentImageObj.resizable({ + + maxHeight : that.settings.maxHeight, + minHeight : that.settings.minHeight, + maxWidth : that.settings.maxWidth, + minWidth : that.settings.minWidth, + aspectRatio : that.startAspectRatio, + handles: that.settings.handles, + grid : that.settings.grid, + resize: function(event, ui) { + that._onResize(that.imageObj); + }, + stop : function (event, ui) { + that._onResized(that.imageObj); + + // Workaround to finish cropping + if (this.enableCrop) { + setTimeout(function () { + FloatingMenu.setScope(that.name); + that.done(event); + }, 10); + } + } + + }); + + currentImageObj.css('display', 'inline-block'); + + // this will prevent the user from resizing an image + // using IE's resize handles + // however I could not manage to hide them completely + jQuery('.ui-wrapper') + .attr('contentEditable', false) + .addClass('aloha-image-box-active Aloha_Image_Resize aloha') + .css({ + position: 'relative', + display: 'inline-block', + 'float': that.imageObj.css('float') + }) + .bind('resizestart', function (e) { + e.preventDefault(); + }) + .bind('mouseup', function (e) { + e.originalEvent.stopSelectionUpdate = true; + }); + }, + + /** + * This method will end resizing and toggle buttons accordingly and remove all markup that has been added for cropping + */ + endResize: function () { + // Find the nearest contenteditable and reenable it since resizing is finished + if (this.imageObj) { + var editable = this.imageObj.closest('.aloha-editable'); + jQuery(editable).contentEditable(true); + } + + if (this.imageObj) { + this.imageObj + .resizable('destroy') + .css({ + top : 0, + left : 0 + }); + } + }, + + /** + * Reset the image to it's original properties + */ + reset: function() { + if (this.settings.ui.crop) { + this.endCrop(); + } + + if (this.settings.ui.resizable) { + this.endResize(); + } + + if (this._onReset(this.imageObj)) { + // the external reset procedure has already performed a reset, so there is no need to apply an internal reset + return; + } + + for (var i=0;i + + + + Aloha, Images! + + + + + + + + + + + +
        +
        + +
        +
        + + \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jcrop.gif b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jcrop.gif new file mode 100644 index 0000000000000000000000000000000000000000..72ea7ccb5321d5384d70437cfaac73011237901e GIT binary patch literal 329 zcmZ?wbhEHb9b#5NV>2k zBC~b@b~P=nNfWAe-b%_i6tS^-1y(h@EsB~1TqDA_h@fkxG$bHgvj}VxE1JLgr!*!^ ILUxTc0Q$^Q5C8xG literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css new file mode 100644 index 00000000..b9622ec4 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.css @@ -0,0 +1,35 @@ +/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */ +.jcrop-holder { text-align: left; } + +.jcrop-vline, .jcrop-hline +{ + font-size: 0; + position: absolute; + background: white url('jcrop.gif') top left repeat; +} +.jcrop-vline { height: 100%; width: 1px !important; } +.jcrop-hline { width: 100%; height: 1px !important; } +.jcrop-handle { + font-size: 1px; + width: 7px !important; + height: 7px !important; + border: 1px #eee solid; + background-color: #333; + *width: 9px; + *height: 9px; +} + +.jcrop-tracker { width: 100%; height: 100%; } + +.custom .jcrop-vline, +.custom .jcrop-hline +{ + background: yellow; +} +.custom .jcrop-handle +{ + border-color: black; + background-color: #C7BB00; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.min.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.min.js new file mode 100644 index 00000000..9002b978 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/jcrop/jquery.jcrop.min.js @@ -0,0 +1,163 @@ +/** + * Jcrop v.0.9.8 (minimized) + * (c) 2008 Kelly Hallman and DeepLiquid.com + * More information: http://deepliquid.com/content/Jcrop.html + * Released under MIT License - this header must remain with code + */ + + +(function($){$.Jcrop=function(obj,opt) +{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt)) +{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8') +opt.trackDocument=true;} +if(!('keySupport'in opt)) +opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('
        ').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('
        ').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('
        ').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('
        ').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function() +{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos) +{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos) +{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset() +{return[ox,oy];};function moveOffset(offset) +{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundyboundx) +{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}} +else +{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0) +{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;} +else if(yy>boundy) +{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}} +if(xx>x1){if(xx-x1max_x){xx=x1+max_x;} +if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xxmax_x){xx=x1-max_x;} +if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}} +if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;} +if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;} +return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p) +{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2) +{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2xlimit)) +x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit)) +y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;} +if(y1<0){y2-=y1;y1-=y1;} +if(x2<0){x1-=x2;x2-=x2;} +if(y2<0){y1-=y2;y2-=y2;} +if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;} +if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;} +if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;} +if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;} +return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a) +{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function() +{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};} +if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');} +options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type) +{var jq=$('
        ').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi) +{var jq=$('
        ').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord) +{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord) +{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord) +{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;} +return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li) +{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c) +{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y) +{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h) +{$sel.width(w).height(h);};function refresh() +{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible() +{if(awake)return update();};function update() +{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show() +{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release() +{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles() +{if(seehandles) +{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles() +{seehandles=true;if(options.allowResize) +{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles() +{seehandles=false;$hdl_holder.hide();};function animMode(v) +{(animating=v)?disableHandles():enableHandles();};function done() +{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360}) +$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function() +{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc) +{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);} +function toFront() +{$trk.css({zIndex:450});if(trackDoc) +{$(document).mousemove(trackMove).mouseup(trackUp);}} +function toBack() +{$trk.css({zIndex:290});if(trackDoc) +{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}} +function trackMove(e) +{onMove(mouseAbs(e));};function trackUp(e) +{e.preventDefault();e.stopPropagation();if(btndown) +{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};} +return false;};function activateHandlers(move,done) +{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function() +{var $keymgr=$('').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('
        ').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys() +{if(options.keySupport) +{$keymgr.show();$keymgr.focus();}};function onBlur(e) +{$keymgr.hide();};function doNudge(e,x,y) +{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e) +{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode) +{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;} +return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj) +{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e) +{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type) +{if(type!=lastcurs) +{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos) +{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move') +return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f) +{return function(pos){if(!options.aspectRatio)switch(mode) +{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;} +else switch(mode) +{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;} +Coords.setCurrent(pos);Selection.update();};};function createMover(pos) +{var lloc=pos;KeyManager.watchKeys();return function(pos) +{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord) +{switch(ord) +{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord) +{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h) +{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0) +{nw=w;nh=(w/$obj.width())*$obj.height();} +if((nh>h)&&h>0) +{nh=h;nw=(h/$obj.height())*$obj.width();} +xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c) +{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos) +{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1]) +{Selection.enableHandles();Selection.done();} +else +{Selection.release();} +Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e) +{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos) +{Coords.setCurrent(pos);Selection.update();};function newTracker() +{var trk=$('
        ').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a) +{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function() +{return function() +{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart() +{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect) +{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l) +{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt) +{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function') +options.onChange=function(){};if(typeof(options.onSelect)!=='function') +options.onSelect=function(){};};function tellSelect() +{return unscale(Coords.getFixed());};function tellScaled() +{return Coords.getFixed();};function setOptionsNew(opt) +{setOptions(opt);interfaceUpdate();};function disableCrop() +{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop() +{options.disabled=false;interfaceUpdate();};function cancelCrop() +{Selection.done();Tracker.activateHandlers(null,null);};function destroy() +{$div.remove();$origimg.show();};function interfaceUpdate(alt) +{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);} +if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;} +xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options) +{$img.attr('src',options.outerImage);delete(options.outerImage);} +Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options) +{function attachWhenDone(from) +{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function() +{if($(this).data('Jcrop')) +{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);} +else attachWhenDone(this);});return this;};})(jQuery); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/mousewheel/mousewheel.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/mousewheel/mousewheel.js new file mode 100644 index 00000000..acebbc7c --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/mousewheel/mousewheel.js @@ -0,0 +1,60 @@ +/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * + * Version: 3.0.3-pre + * + * Requires: 1.2.2+ + */ + +(function($) { + +var types = ['DOMMouseScroll', 'mousewheel']; + +$.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) + for ( var i=types.length; i; ) + this.addEventListener( types[--i], handler, false ); + else + this.onmousewheel = handler; + }, + + teardown: function() { + if ( this.removeEventListener ) + for ( var i=types.length; i; ) + this.removeEventListener( types[--i], handler, false ); + else + this.onmousewheel = null; + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + + +function handler(event) { + var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true; + + event = $.event.fix(event || window.event); + event.type = "mousewheel"; + + if ( event.wheelDelta ) delta = event.wheelDelta/120; + if ( event.detail ) delta = -event.detail/3; + + // Add event and delta to the front of the arguments + args.unshift(event, delta); + + return $.event.handle.apply(this, args); +} + +})(jQuery); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/jquery-ui-1.8.10.custom.min.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/jquery-ui-1.8.10.custom.min.js new file mode 100644 index 00000000..67e59512 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/jquery-ui-1.8.10.custom.min.js @@ -0,0 +1,97 @@ +/*! + * jQuery UI 1.8.10 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.10",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106, +NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this, +"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position"); +if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f, +"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h, +d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}}); +c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a); +return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent", +true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +;/* + * jQuery UI Resizable 1.8.10 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */ +(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element, +_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('
        ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), +top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= +this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", +nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d
        ');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== +String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); +this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()}; +if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(), +d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset= +this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio: +this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize", +b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height; +f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing"); +this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top= +null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidthb.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+ +this.size.height,k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a
        ');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b, +a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a, +c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize, +originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.10"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize= +b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width", +"height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})}; +if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height- +g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width, +height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d= +e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options, +d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper? +d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height= +a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&& +/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable"); +b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/ +(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery); +; \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..954e22dbd99e8c6dd7091335599abf2d10bf8003 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEr#)R9Ln2z=UU%d=WFXS=@V?HT z#xG*`>Yvsgk=}99w^d^D^d*@m74oMo<%#FcopJf?u00-~YVKV2wzrI*_R6;UORMea zBFVSEnN~eiVA6V&z`E)YLz5Aok^D)In}Yn=OzDpgR5Wv0XfT8pOkmV{sKAJ-PO9#T zZK}IXj&Q-V!U)!LcB_3K0&C*{ literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..64ece5707d91a6edf9fad4bfcce0c4dbcafcf58d GIT binary patch literal 251 zcmVbvPcjKS|RKP(6sDcCAB(_QB%0978a<$Ah$!b|E zwn;|HO0i8cQj@~)s!ajF0S002ovPDHLkV1oEp BYH0uf literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_flat_10_000000_40x100.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..abdc01082bf3534eafecc5819d28c9574d44ea89 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F!3HG1q!d*FsY*{5$B>N1x91EQ4=4yQY-ImG zFPf9b{J;c_6SHRK%WcbN_hZpM=(Ry;4Rxv2@@2Y=$K57eF$X$=!PC{xWt~$(69B)$ BI)4BF literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..9b383f4d2eab09c0f2a739d6b232c32934bc620b GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^j6gJjgAK^akKnour1U*q978O6-yYw{%b*}|_(02F z@qbE9)0CJMo;*v*PWv`Vh2h6EmG8IS-Cm{3U~` zFlmZ}YMcJY=eo?o%*@I?2`NblNeMudl#t?{+tN>ySr~=F{k$>;_x^_y?afmf9pRKH0)6?eSP?3s5hEr>mdKI;Vst E0O;M1& literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000000000000000000000000000000000000..39d5824d6af5456f1e89fc7847ea3599ea5fd815 GIT binary patch literal 3762 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f1273672d253263b7564e9e21d69d7d9d0b337d9 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)pi0l%l7LV~E7mxPQ=F85a&M@g_{ d|GeK{$Y5lo%PMu^>wln`44$rjF6*2UngE4^EGqy2 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_222222_256x240.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..b273ff111d219c9b9a8b96d57683d0075fb7871a GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_228ef1_256x240.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..a641a371afa0fbb08ba599dc7ddf14b9bfc3c84f GIT binary patch literal 4369 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 oBo%DI*Kv;w;*%(i9W@e{{5C=l}o! literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ef8c08_256x240.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..85e63e9f604ce042d59eb06a8428eeb7cb7896c9 GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ffd27a_256x240.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..e117effa3dca24e7978cfc5f8b967f661e81044f GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.cropnresize.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.cropnresize.css new file mode 100644 index 00000000..e68df339 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.cropnresize.css @@ -0,0 +1,33 @@ +/* + * Special adapted version for cropnresize plugin + */ +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } + +/* + * jQuery UI Resizable 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.custom.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.custom.css new file mode 100644 index 00000000..ff42d050 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/image/vendor/ui/ui-lightness/jquery-ui-1.8.10.custom.css @@ -0,0 +1,314 @@ +/* + * jQuery UI CSS Framework 1.8.9 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.aloha .ui-helper-hidden { display: none; } +.aloha .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.aloha .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.aloha .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.aloha .ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } + .ui-helper-clearfix { display:block; } +/* end clearfix */ +.aloha .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.aloha .ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.aloha .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.aloha .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.9 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.aloha .ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.aloha .ui-widget .ui-widget { font-size: 1em; } +.aloha .ui-widget input, .aloha .ui-widget select, .aloha .ui-widget textarea, .aloha .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.aloha .ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.aloha .ui-widget-content a { color: #333333; } +.aloha .ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.aloha .ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.aloha .ui-state-default, .aloha .ui-widget-content .ui-state-default, .aloha .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.aloha .ui-state-default a, .aloha .ui-state-default a:link, .aloha .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.aloha .ui-state-hover, .aloha .ui-widget-content .ui-state-hover, .aloha .ui-widget-header .ui-state-hover, .aloha .ui-state-focus, .aloha .ui-widget-content .ui-state-focus, .aloha .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.aloha .ui-state-hover a, .aloha .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.aloha .ui-state-active, .aloha .ui-widget-content .ui-state-active, .aloha .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.aloha .ui-state-active a, .aloha .ui-state-active a:link, .aloha .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.aloha .ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.aloha .ui-state-highlight, .aloha .ui-widget-content .ui-state-highlight, .aloha .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.aloha .ui-state-highlight a, .aloha .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.aloha .ui-state-error, .aloha .ui-widget-content .ui-state-error, .aloha .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.aloha .ui-state-error a, .aloha .ui-widget-content .ui-state-error a, .aloha .ui-widget-header .ui-state-error a { color: #ffffff; } +.aloha .ui-state-error-text, .aloha .ui-widget-content .ui-state-error-text, .aloha .ui-widget-header .ui-state-error-text { color: #ffffff; } +.aloha .ui-priority-primary, .aloha .ui-widget-content .ui-priority-primary, .aloha .ui-widget-header .ui-priority-primary { font-weight: bold; } +.aloha .ui-priority-secondary, .aloha .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.aloha .ui-state-disabled, .aloha .ui-widget-content .ui-state-disabled, .aloha .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.aloha .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.aloha .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.aloha .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.aloha .ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.aloha .ui-state-hover .ui-icon, .aloha .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.aloha .ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.aloha .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.aloha .ui-state-error .ui-icon, .aloha .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.aloha .ui-icon-carat-1-n { background-position: 0 0; } +.aloha .ui-icon-carat-1-ne { background-position: -16px 0; } +.aloha .ui-icon-carat-1-e { background-position: -32px 0; } +.aloha .ui-icon-carat-1-se { background-position: -48px 0; } +.aloha .ui-icon-carat-1-s { background-position: -64px 0; } +.aloha .ui-icon-carat-1-sw { background-position: -80px 0; } +.aloha .ui-icon-carat-1-w { background-position: -96px 0; } +.aloha .ui-icon-carat-1-nw { background-position: -112px 0; } +.aloha .ui-icon-carat-2-n-s { background-position: -128px 0; } +.aloha .ui-icon-carat-2-e-w { background-position: -144px 0; } +.aloha .ui-icon-triangle-1-n { background-position: 0 -16px; } +.aloha .ui-icon-triangle-1-ne { background-position: -16px -16px; } +.aloha .ui-icon-triangle-1-e { background-position: -32px -16px; } +.aloha .ui-icon-triangle-1-se { background-position: -48px -16px; } +.aloha .ui-icon-triangle-1-s { background-position: -64px -16px; } +.aloha .ui-icon-triangle-1-sw { background-position: -80px -16px; } +.aloha .ui-icon-triangle-1-w { background-position: -96px -16px; } +.aloha .ui-icon-triangle-1-nw { background-position: -112px -16px; } +.aloha .ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.aloha .ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.aloha .ui-icon-arrow-1-n { background-position: 0 -32px; } +.aloha .ui-icon-arrow-1-ne { background-position: -16px -32px; } +.aloha .ui-icon-arrow-1-e { background-position: -32px -32px; } +.aloha .ui-icon-arrow-1-se { background-position: -48px -32px; } +.aloha .ui-icon-arrow-1-s { background-position: -64px -32px; } +.aloha .ui-icon-arrow-1-sw { background-position: -80px -32px; } +.aloha .ui-icon-arrow-1-w { background-position: -96px -32px; } +.aloha .ui-icon-arrow-1-nw { background-position: -112px -32px; } +.aloha .ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.aloha .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.aloha .ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.aloha .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.aloha .ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.aloha .ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.aloha .ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.aloha .ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.aloha .ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.aloha .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.aloha .ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.aloha .ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.aloha .ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.aloha .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.aloha .ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.aloha .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.aloha .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.aloha .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.aloha .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.aloha .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.aloha .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.aloha .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.aloha .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.aloha .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.aloha .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.aloha .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.aloha .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.aloha .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.aloha .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.aloha .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.aloha .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.aloha .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.aloha .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.aloha .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.aloha .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.aloha .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.aloha .ui-icon-arrow-4 { background-position: 0 -80px; } +.aloha .ui-icon-arrow-4-diag { background-position: -16px -80px; } +.aloha .ui-icon-extlink { background-position: -32px -80px; } +.aloha .ui-icon-newwin { background-position: -48px -80px; } +.aloha .ui-icon-refresh { background-position: -64px -80px; } +.aloha .ui-icon-shuffle { background-position: -80px -80px; } +.aloha .ui-icon-transfer-e-w { background-position: -96px -80px; } +.aloha .ui-icon-transferthick-e-w { background-position: -112px -80px; } +.aloha .ui-icon-folder-collapsed { background-position: 0 -96px; } +.aloha .ui-icon-folder-open { background-position: -16px -96px; } +.aloha .ui-icon-document { background-position: -32px -96px; } +.aloha .ui-icon-document-b { background-position: -48px -96px; } +.aloha .ui-icon-note { background-position: -64px -96px; } +.aloha .ui-icon-mail-closed { background-position: -80px -96px; } +.aloha .ui-icon-mail-open { background-position: -96px -96px; } +.aloha .ui-icon-suitcase { background-position: -112px -96px; } +.aloha .ui-icon-comment { background-position: -128px -96px; } +.aloha .ui-icon-person { background-position: -144px -96px; } +.aloha .ui-icon-print { background-position: -160px -96px; } +.aloha .ui-icon-trash { background-position: -176px -96px; } +.aloha .ui-icon-locked { background-position: -192px -96px; } +.aloha .ui-icon-unlocked { background-position: -208px -96px; } +.aloha .ui-icon-bookmark { background-position: -224px -96px; } +.aloha .ui-icon-tag { background-position: -240px -96px; } +.aloha .ui-icon-home { background-position: 0 -112px; } +.aloha .ui-icon-flag { background-position: -16px -112px; } +.aloha .ui-icon-calendar { background-position: -32px -112px; } +.aloha .ui-icon-cart { background-position: -48px -112px; } +.aloha .ui-icon-pencil { background-position: -64px -112px; } +.aloha .ui-icon-clock { background-position: -80px -112px; } +.aloha .ui-icon-disk { background-position: -96px -112px; } +.aloha .ui-icon-calculator { background-position: -112px -112px; } +.aloha .ui-icon-zoomin { background-position: -128px -112px; } +.aloha .ui-icon-zoomout { background-position: -144px -112px; } +.aloha .ui-icon-search { background-position: -160px -112px; } +.aloha .ui-icon-wrench { background-position: -176px -112px; } +.aloha .ui-icon-gear { background-position: -192px -112px; } +.aloha .ui-icon-heart { background-position: -208px -112px; } +.aloha .ui-icon-star { background-position: -224px -112px; } +.aloha .ui-icon-link { background-position: -240px -112px; } +.aloha .ui-icon-cancel { background-position: 0 -128px; } +.aloha .ui-icon-plus { background-position: -16px -128px; } +.aloha .ui-icon-plusthick { background-position: -32px -128px; } +.aloha .ui-icon-minus { background-position: -48px -128px; } +.aloha .ui-icon-minusthick { background-position: -64px -128px; } +.aloha .ui-icon-close { background-position: -80px -128px; } +.aloha .ui-icon-closethick { background-position: -96px -128px; } +.aloha .ui-icon-key { background-position: -112px -128px; } +.aloha .ui-icon-lightbulb { background-position: -128px -128px; } +.aloha .ui-icon-scissors { background-position: -144px -128px; } +.aloha .ui-icon-clipboard { background-position: -160px -128px; } +.aloha .ui-icon-copy { background-position: -176px -128px; } +.aloha .ui-icon-contact { background-position: -192px -128px; } +.aloha .ui-icon-image { background-position: -208px -128px; } +.aloha .ui-icon-video { background-position: -224px -128px; } +.aloha .ui-icon-script { background-position: -240px -128px; } +.aloha .ui-icon-alert { background-position: 0 -144px; } +.aloha .ui-icon-info { background-position: -16px -144px; } +.aloha .ui-icon-notice { background-position: -32px -144px; } +.aloha .ui-icon-help { background-position: -48px -144px; } +.aloha .ui-icon-check { background-position: -64px -144px; } +.aloha .ui-icon-bullet { background-position: -80px -144px; } +.aloha .ui-icon-radio-off { background-position: -96px -144px; } +.aloha .ui-icon-radio-on { background-position: -112px -144px; } +.aloha .ui-icon-pin-w { background-position: -128px -144px; } +.aloha .ui-icon-pin-s { background-position: -144px -144px; } +.aloha .ui-icon-play { background-position: 0 -160px; } +.aloha .ui-icon-pause { background-position: -16px -160px; } +.aloha .ui-icon-seek-next { background-position: -32px -160px; } +.aloha .ui-icon-seek-prev { background-position: -48px -160px; } +.aloha .ui-icon-seek-end { background-position: -64px -160px; } +.aloha .ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.aloha .ui-icon-seek-first { background-position: -80px -160px; } +.aloha .ui-icon-stop { background-position: -96px -160px; } +.aloha .ui-icon-eject { background-position: -112px -160px; } +.aloha .ui-icon-volume-off { background-position: -128px -160px; } +.aloha .ui-icon-volume-on { background-position: -144px -160px; } +.aloha .ui-icon-power { background-position: 0 -176px; } +.aloha .ui-icon-signal-diag { background-position: -16px -176px; } +.aloha .ui-icon-signal { background-position: -32px -176px; } +.aloha .ui-icon-battery-0 { background-position: -48px -176px; } +.aloha .ui-icon-battery-1 { background-position: -64px -176px; } +.aloha .ui-icon-battery-2 { background-position: -80px -176px; } +.aloha .ui-icon-battery-3 { background-position: -96px -176px; } +.aloha .ui-icon-circle-plus { background-position: 0 -192px; } +.aloha .ui-icon-circle-minus { background-position: -16px -192px; } +.aloha .ui-icon-circle-close { background-position: -32px -192px; } +.aloha .ui-icon-circle-triangle-e { background-position: -48px -192px; } +.aloha .ui-icon-circle-triangle-s { background-position: -64px -192px; } +.aloha .ui-icon-circle-triangle-w { background-position: -80px -192px; } +.aloha .ui-icon-circle-triangle-n { background-position: -96px -192px; } +.aloha .ui-icon-circle-arrow-e { background-position: -112px -192px; } +.aloha .ui-icon-circle-arrow-s { background-position: -128px -192px; } +.aloha .ui-icon-circle-arrow-w { background-position: -144px -192px; } +.aloha .ui-icon-circle-arrow-n { background-position: -160px -192px; } +.aloha .ui-icon-circle-zoomin { background-position: -176px -192px; } +.aloha .ui-icon-circle-zoomout { background-position: -192px -192px; } +.aloha .ui-icon-circle-check { background-position: -208px -192px; } +.aloha .ui-icon-circlesmall-plus { background-position: 0 -208px; } +.aloha .ui-icon-circlesmall-minus { background-position: -16px -208px; } +.aloha .ui-icon-circlesmall-close { background-position: -32px -208px; } +.aloha .ui-icon-squaresmall-plus { background-position: -48px -208px; } +.aloha .ui-icon-squaresmall-minus { background-position: -64px -208px; } +.aloha .ui-icon-squaresmall-close { background-position: -80px -208px; } +.aloha .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.aloha .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.aloha .ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.aloha .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.aloha .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.aloha .ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.aloha .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.aloha .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.aloha .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.aloha .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.aloha .ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.aloha .ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.aloha .ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.aloha .ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.aloha .ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } + +/* Overlays */ +.aloha .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.aloha .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Resizable 1.8.9 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.aloha .ui-resizable { position: relative;} +.aloha .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block} +.aloha .ui-resizable-disabled .ui-resizable-handle, .aloha .ui-resizable-autohide .ui-resizable-handle { display: none; } +.aloha .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.aloha .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.aloha .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.aloha .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.aloha .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: -5px; bottom: -5px; background-color: Highlight; border: 1px solid black} +.aloha .ui-resizable-sw { cursor: sw-resize; width: 12px; height: 12px; left: -5px; bottom: -5px; background-color: Highlight; border: 1px solid black} +.aloha .ui-resizable-nw { cursor: nw-resize; width: 12px; height: 12px; left: -5px; top: -5px; background-color: Highlight; border: 1px solid black} +.aloha .ui-resizable-ne { cursor: ne-resize; width: 12px; height: 12px; right: -5px; top: -5px;background-color: Highlight; border: 1px solid black} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/css/link.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/css/link.css new file mode 100644 index 00000000..24ec57f9 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/css/link.css @@ -0,0 +1,55 @@ +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +.aloha-link-pointer { + cursor: pointer; +} + +.aloha-link-text { + cursor: text; +} + +.aloha-link-radioTarget { + width:auto !important; +} + +.aloha-link-title-container { + padding:5px 5px; +} + +.aloha-link-target-container { + padding:5px 5px; +} + +.aloha-link-target-container li{ + padding:0 !important; +} + +.aloha-link-target-container fieldset { + border: 2px groove threedface !important; + padding-bottom: 5px; +} + +.aloha-link-title-container fieldset { + border: 2px groove threedface !important; + padding-bottom: 5px; +} + +.aloha-link-title-container fieldset input[type=text]{ + width:auto !important; + min-width:180px; +} + +.aloha-link-target-container fieldset input[type=text]{ + width:auto !important; + min-width:180px; +} + +.x-form-field.x-form-text.aloha-link-href-field { + color: #333 !important; + padding: 3px; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/background.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/background.png new file mode 100644 index 0000000000000000000000000000000000000000..64ece5707d91a6edf9fad4bfcce0c4dbcafcf58d GIT binary patch literal 251 zcmVbvPcjKS|RKP(6sDcCAB(_QB%0978a<$Ah$!b|E zwn;|HO0i8cQj@~)s!ajF0S002ovPDHLkV1oEp BYH0uf literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/external-link-ltr-icon.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/external-link-ltr-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4b710b03ea97bf485f3f89db4f26115554315abb GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2VGmzZ%#=aj&NtU=qlmzFem6RtIr7}3C~moOa}6aA09^+}!-%zEZk&LYIK=Ev8gf-RPY)D)N$i s&x=&9UP#@0ZXWaI2bCVjx$79&7)-htzDAyXo(OWLr>mdKI;Vst04JwPB>(^b literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.css new file mode 100644 index 00000000..c917b72e --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.css @@ -0,0 +1,91 @@ +body { + font-family: sans-serif; +} + +body { + background-image: url("./background.png"); +} + +#bodyContent { + font-size:0.9em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: sans-serif; + padding-bottom:0.1em; + padding-top:0.5em; +} +h1 { + border-bottom:1px solid #AAAAAA; +} + +h1 { font-size: 188%; } +h2 { font-size: 150%; } +h3 { font-size: 132%; } +h4 { font-size: 116%; } +h5 { font-size: 100%; } +h6 { font-size: 80%; } + +#main { + width: 650px; + margin-top: 40px; + margin-left: auto ; + margin-right: auto ; + padding: 70px; + background-color: white; + border-radius: 1px; + -moz-border-radius: 1px; + box-shadow: 5px 5px rgba(0,0,0,0.3); + -webkit-box-shadow: 5px 5px rgba(0,0,0,0.3); + -moz-box-shadow: 5px 5px rgba(0,0,0,0.3); +} + +a.external { + background: url("./external-link-ltr-icon.png") no-repeat 100% 50%; + padding: 0px 13px 0px 0px; +} + +abbr, acronym +{ + border-bottom: .1em dotted; + cursor: help; +} + + +/* A basic table styling */ +table +{ + padding: 0; + margin: 0; + border-collapse: collapse; + border: 1px solid #333; + color: #000; +} + +table caption +{ + caption-side: bottom; + font-size: 0.8em; + font-style: italic; + text-align: right; + padding: 0.5em 0; +} + +table th, table td +{ + border: 1px solid #666; + padding: 0.5em; + text-align: left; +} + + +#main ul, +#main ol { + margin:0 1.5em 1.5em 1.5em; +} +#main ul li { + list-style-type:disc; +} +#main ol li { + list-style-type:decimal; +} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.html b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.html new file mode 100644 index 00000000..eb1c3fae --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/demo/index.html @@ -0,0 +1,91 @@ + + + + + Aloha, Documents! + + + + + + + +
        +
        +
        +

        Aloha

        + +

        Etymology

        + +

        The word aloha derives from the Proto-Polynesian root *qalofa. It has cognates in other Polynesian languages, such as Samoan alofa and Māori aroha, also meaning "love."

        + +

        Aloha Editor is the word's most advanced browser based Editor made with aloha passion.

        + +

        A folk etymology claims that it derives from a compound of the Hawaiian words alo meaning "presence", "front", "face", or "share"; and ha, meaning "breath of life" or "essence of life." Although alo does indeed mean "presence" etc., the word for breath is spelled with a macron or kahakō over the a (hā) whereas the word aloha does not have a long a.

        + +

        Usage

        + +

        Before contact with the West, the words used for greeting were welina and anoai. Today, "aloha kakahiaka" is the phrase for "good morning." "Aloha ʻauinalā" means "good afternoon" and "aloha ahiahi" means "good evening." "Aloha kākou" is a common form of "welcome to all."

        + +

        In modern Hawaiʻi, numerous businesses have aloha in their names, with more than 3 pages of listings in the Oʻahu phone book alone.

        + +

        Trends

        + +

        Recent trends are popularizing the term elsewhere in the United States. Popular entertainer, Broadway star and Hollywood actress Bette Midler, born in Honolulu, uses the greeting frequently in national appearances. The word was also used frequently in the hit television drama Hawaii Five-O. In the influential 1982 film comedy Fast Times at Ridgemont High, the eccentric teacher Mr. Hand makes use of the greeting. The Aloha Spirit is a major concept in Lilo and Stitch, a very popular Disney series of movies and TV shows, set in Hawaiʻi. The drama series Lost, shot in Hawaiʻi, has a thank you note at the end of the credits saying "We thank the people of Hawaiʻi and their Aloha Spirit". Aloha is a term also used in the Nickelodeon program Rocket Power.

        + +
          +
        • Arguably the most famous historical Hawaiian song, "Aloha ʻOe" was written by the last queen of Hawaii, Liliʻuokalani.
        • + +
        • The term inspired the name of the ALOHA Protocol introduced in the 1970s by the University of Hawaii.
        • + +
        • In Hawaii someone can be said to have or show aloha in the way they treat others; whether family, friend, neighbor or stranger.
        • +
        +
        +
        + +
        + +
        + + + + + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/delicious.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/delicious.js new file mode 100644 index 00000000..048c795c --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/delicious.js @@ -0,0 +1,246 @@ + +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +/** + * Create the Repositories object. Namespace for Repositories + * @hide + */ +if ( !GENTICS.Aloha.Repositories ) GENTICS.Aloha.Repositories = {}; + +/** + * register the plugin with unique name + */ +GENTICS.Aloha.Repositories.delicious = new GENTICS.Aloha.Repository('delicious'); + +/** + * If no username is given, the public respoitory is searched: + * @property + * @cfg + */ +GENTICS.Aloha.Repositories.delicious.settings.username = 'draftkraft'; + +/** + * Defines the value to use for sorting the items. Allowed a values 0-0.75 + * We choose a low default weight 0.35 + * @property + * @default 0.35 + * @cfg + */ +GENTICS.Aloha.Repositories.delicious.settings.weight = 0.35; + + + +/** + * init Delicious repository + */ +GENTICS.Aloha.Repositories.delicious.init = function() { + var that = this; + + // check weight + if ( this.settings.weight + 0.15 > 1 ) { + this.settings.weight = 1 - 0.15; + } + + // default delicious URL. Returns most popular links. + this.deliciousURL = "http://feeds.delicious.com/v2/json/"; + + if ( this.settings.username ) { + + // if a username is set use public user links + this.deliciousURL += this.settings.username + '/'; + + // set the repository name + this.repositoryName = 'deliciuos/' + this.settings.username; + + // when a user is specified get his tags and store it local + this.tags = []; + + jQuery.ajax({ type: "GET", + dataType: "jsonp", + url: 'http://feeds.delicious.com/v2/json/tags/'+that.settings.username, + success: function(data) { + // convert data + for (var tag in data) { + that.tags.push(tag); + } + } + }); + } else { + // set the repository name + this.repositoryName = 'deliciuos/' + popular; + + this.deliciousURL += 'tag/'; + } +}; + + +/** + * Searches a repository for items matching query if objectTypeFilter. + * If none found it returns null. + */ +GENTICS.Aloha.Repositories.delicious.query = function( p, callback) { + var that = this; + + if ( p.objectTypeFilter && jQuery.inArray('website', p.objectTypeFilter) == -1) { + + // return if no website type is requested + callback.call( this, []); + + } else { + + // prepare tags + var tags = []; + if ( this.settings.username ) { + + // search in user tags + var queryTags = p.queryString ? p.queryString.split(' ') : []; + for (var i = 0; i < queryTags.length; i++) { + var queryTag = queryTags[i].trim(); + if ( jQuery.inArray(queryTag, that.tags) == -1 ) { + var newtags = that.tags.filter(function(e, i, a) { + var r = new RegExp(queryTag, 'i'); + return ( e.match(r) ); + }); + if ( newtags.length > 0 ) { + tags.push(newtags[0]); + } + } else { + tags.push(queryTag); + } + } + + } else { + + // handle each word as tag + tags = p.queryString.split(' '); + + } + + // search in tree + var folderTags = p.inFolderId ? p.inFolderId.split('+') : []; + jQuery.extend(tags, folderTags); + + // if we have a query and no tag matching return + if ( p.queryString && tags.length == 0 ) { + callback.call( that, []); + return; + } + + jQuery.ajax({ type: "GET", + dataType: "jsonp", + url: that.deliciousURL + tags.join('+'), + success: function(data) { + var items = []; + // convert data to Aloha objects + for (var i = 0; i < data.length; i++) { + if (typeof data[i] != 'function' ) { + items.push(new GENTICS.Aloha.Repository.Document ({ + id: data[i].u, + name: data[i].d, + repositoryId: that.repositoryId, + type: 'website', + url: data[i].u, + weight: that.settings.weight + (15-1)/100 + })); + } + } + callback.call( that, items); + } + }); + } +}; + +/** + * Returns all tags for username in a tree style way + */ +GENTICS.Aloha.Repositories.delicious.getChildren = function( p, callback) { + var that = this; + + // tags are only available when a username is available + if ( this.settings.username ) { + + // return all tags + var items = []; + if ( p.inFolderId == this.repositoryId ) { + + for (var i = 0; i < this.tags.length; i++) { + if (typeof this.tags[i] != 'function' ) { + items.push(new GENTICS.Aloha.Repository.Folder ({ + id: this.tags[i], + name: this.tags[i], + repositoryId: this.repositoryId, + type: 'tag', + url: 'http://feeds.delicious.com/v2/rss/tags/'+that.settings.username+'/'+this.tags[i] + })); + } + } + callback.call( this, items); + + } else { + jQuery.ajax({ type: "GET", + dataType: "jsonp", + url: 'http://feeds.delicious.com/v2/json/tags/'+that.settings.username+'/'+p.inFolderId, + success: function(data) { + var items = []; + // convert data + for (var tag in data) { + // the id is tag[+tag+...+tag] + var id = (p.inFolderId)?p.inFolderId + '+' + tag:tag; + if (typeof data[tag] != 'function' ) { + items.push(new GENTICS.Aloha.Repository.Folder({ + id: id, + name: tag, + repositoryId: that.repositoryId, + type: 'tag', + url: 'http://feeds.delicious.com/v2/rss/tags/'+that.settings.username+'/'+id, + hasMoreItems: true + })); + } + } + callback.call( that, items); + } + }); + + } + } else { + callback.call( this, []); + } +}; + +/** + * Get the repositoryItem with given id + * @param itemId {String} id of the repository item to fetch + * @param callback {function} callback function + * @return {GENTICS.Aloha.Repository.Object} item with given id + */ +GENTICS.Aloha.Repositories.delicious.getObjectById = function ( itemId, callback ) { + var that = this; + + jQuery.ajax({ + type: 'GET', + dataType: "jsonp", + url: 'http://feeds.delicious.com/v2/json/urlinfo/' + jQuery.md5(itemId), + success: function (data) { + var items = []; + // convert data to Aloha objects + for (var i = 0; i < data.length; i++) { + if (typeof data[i] != 'function' ) { + items.push(new GENTICS.Aloha.Repository.Document ({ + id: itemId, + name: data[i].title, + repositoryId: that.repositoryId, + type: 'website', + url: itemId, + weight: that.settings.weight + (15-1)/100 + })); + } + } + callback.call( that, items); + } + }); +}; diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/linklist.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/linklist.js new file mode 100644 index 00000000..51a04c60 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/linklist.js @@ -0,0 +1,222 @@ +/*! + * Aloha Editor + * Author & Copyright (c) 2011 Gentics Software GmbH + * aloha-sales@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + * + * Aloha Link List Repository + * -------------------------- + * A simple demo repository of links. + */ + +define( +[ 'aloha', 'aloha/jquery' ], +function ( Aloha, jQuery ) { + + + /** + * Internal data as array with following format: + * + * [ + * { name: 'Aloha Editor - The HTML5 Editor', url:'http://aloha-editor.com', type:'website' }, + * { name: 'Aloha Logo', url:'http://www.aloha-editor.com/images/aloha-editor-logo.png', type:'image' } + * ]; + * + * @private + */ + var urlset = [ + { name: 'Aloha Editor - The HTML5 Editor', url: 'http://aloha-editor.com', type: 'website' }, + { name: 'Aloha Editor - Wiki', url: 'http://www.aloha-editor.org/wiki/Main_Page', type: 'website' }, + { name: 'Aloha Editor - GitHub', url: 'http://github.com/alohaeditor/Aloha-Editor', type: 'website' }, + { name: 'Aloha Logo', url: 'http://www.aloha-editor.com/images/aloha-editor-logo.png', type: 'image' } + ]; + + new ( Aloha.AbstractRepository.extend( { + + _constructor: function () { + this._super( 'linklist' ); + }, + + /** + * Internal folder structure + * @hide + */ + folder: [], + + /** + * initalize LinkList, parse all links, build folder structure and add + * additional properties to the items + */ + init: function () { + // Add ECMA262-5 Array method filter if not supported natively. + // But we will be very conservative and add to this single array + // object so that we do not tamper with the native Array prototype + // object + if ( !( 'filter' in Array.prototype ) ) { + urlset.filter = function ( filter, that /*opt*/ ) { + var other = [], + v, + i = 0, + n = this.length; + + for ( ; i < n; i++ ) { + if ( i in this && filter.call( that, v = this[ i ], i, this ) ) { + other.push( v ); + } + } + + return other; + }; + } + + var l = urlset.length; + + // generate folder structure + for ( var i = 0; i < l; ++i ) { + var e = urlset[ i ]; + e.repositoryId = this.repositoryId; + e.id = e.id ? e.id : e.url; + + var u = e.uri = this.parseUri( e.url ), + // add hostname as root folder + path = this.addFolder( '', u.host ), + pathparts = u.path.split( '/' ); + + for ( var j = 0; j < pathparts.length; j++ ) { + if ( pathparts[ j ] && + // It's a file because it has an extension. + // Could improve this one :) + pathparts[ j ].lastIndexOf( '.' ) < 0 ) { + path = this.addFolder( path, pathparts[ j ] ); + } + } + + e.parentId = path; + + urlset[ i ] = new Aloha.RepositoryDocument( e ); + } + + this.repositoryName = 'Linklist'; + }, + + /** + * @param {String} path + * @param {String} name + * @return {String} + */ + addFolder: function ( path, name ) { + var type = path ? 'folder' : 'hostname', + p = path ? path + '/' + name : name; + + if ( name && !this.folder[ p ] ) { + this.folder[ p ] = new Aloha.RepositoryFolder( { + id: p, + name: name || p, + parentId: path, + type: 'host', + repositoryId: this.repositoryId + } ); + } + + return p; + }, + + /** + * Searches a repository for object items matching query if + * objectTypeFilter. If none is found it returns null. + * + * @param {Object} p + * @param {Function} callback + */ + query: function ( p, callback ) { + // Not supported; filter, orderBy, maxItems, skipcount, renditionFilter + var r = new RegExp( p.queryString, 'i' ); + + var d = urlset.filter( function ( e, i, a ) { + return ( + ( !p.queryString || e.name.match( r ) || e.url.match( r ) ) && + ( !p.objectTypeFilter || ( !p.objectTypeFilter.length ) || jQuery.inArray( e.type, p.objectTypeFilter ) > -1 ) && + true //( !p.inFolderId || p.inFolderId == e.parentId ) + ); + } ); + + callback.call( this, d ); + }, + + /** + * returns the folder structure as parsed at init + * + * @param {Object} p + * @param {Function} callback + */ + getChildren: function ( p, callback ) { + var d = [], + e; + + for ( e in this.folder ) { + var l = this.folder[ e ].parentId; + if ( typeof this.folder[ e ] != 'function' && ( // extjs prevention + this.folder[ e ].parentId == p.inFolderId || // all subfolders + ( !this.folder[ e ].parentId && p.inFolderId == this.repositoryId ) // the hostname + ) ) { + d.push( this.folder[ e ] ); + } + } + + callback.call( this, d ); + }, + + //parseUri 1.2.2 + //(c) Steven Levithan + //MIT License + //http://blog.stevenlevithan.com/archives/parseuri + parseUri: function(str) { + var o = { + strictMode: false, + key: [ "source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } + }, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + uri = {}, + i = 14; + + while (i--) uri[o.key[i]] = m[i] || ""; + + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + + return uri; + }, + + /** + * Get the repositoryItem with given id + * Callback: {GENTICS.Aloha.Repository.Object} item with given id + * @param itemId {String} id of the repository item to fetch + * @param callback {function} callback function + */ + getObjectById: function ( itemId, callback ) { + var i = 0, + l = urlset.length, + d = []; + + for ( ; i < l; i++ ) { + if ( urlset[ i ].id == itemId ) { + d.push( urlset[ i ] ); + } + } + + callback.call( this, d ); + } + + } ) )(); + +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/slowlinklist.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/slowlinklist.js new file mode 100644 index 00000000..a25e9a20 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/extra/slowlinklist.js @@ -0,0 +1,228 @@ +/*! + * Aloha Editor + * Author & Copyright (c) 2011 Gentics Software GmbH + * aloha-sales@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + * + * Aloha Link List Repository + * -------------------------- + * A simple demo repository of links, which is deliberatly slow, in order to + * simulate lags when querying repositories. + */ + +define( +[ 'aloha', 'aloha/jquery' ], +function ( Aloha, jQuery ) { + 'use strict' + + /** + * Internal data as array with following format: + * + * [ + * { name: 'Aloha Editor - The HTML5 Editor', url:'http://aloha-editor.com', type:'website' }, + * { name: 'Aloha Logo', url:'http://www.aloha-editor.com/images/aloha-editor-logo.png', type:'image' } + * ]; + * + * @private + */ + var urlset = [ + { name: 'Aloha Test', url: '#alohatest', type: 'website' }, + { name: 'Test One', url: '#test1', type: 'website' }, + { name: 'Test Two', url: '#test2', type: 'website' }, + { name: 'Test Three', url: '#test3', type: 'website' }, + { name: 'Test Four', url: '#test4', type: 'image' } + ]; + + new ( Aloha.AbstractRepository.extend( { + + _constructor: function () { + this._super( 'slowlinklist' ); + }, + + /** + * Internal folder structure + * @hide + */ + folder: [], + + /** + * initalize LinkList, parse all links, build folder structure and add + * additional properties to the items + */ + init: function () { + // Add ECMA262-5 Array method filter if not supported natively. + // But we will be very conservative and add to this single array + // object so that we do not tamper with the native Array prototype + // object + if ( !( 'filter' in Array.prototype ) ) { + urlset.filter = function ( filter, that /*opt*/ ) { + var other = [], + v, + i = 0, + n = this.length; + + for ( ; i < n; i++ ) { + if ( i in this && filter.call( that, v = this[ i ], i, this ) ) { + other.push( v ); + } + } + + return other; + }; + } + + var l = urlset.length; + + // generate folder structure + for ( var i = 0; i < l; ++i ) { + var e = urlset[ i ]; + e.repositoryId = this.repositoryId; + e.id = e.id ? e.id : e.url; + + var u = e.uri = this.parseUri( e.url ), + // add hostname as root folder + path = this.addFolder( '', u.host ), + pathparts = u.path.split( '/' ); + + for ( var j = 0; j < pathparts.length; j++ ) { + if ( pathparts[ j ] && + // It's a file because it has an extension. + // Could improve this one :) + pathparts[ j ].lastIndexOf( '.' ) < 0 ) { + path = this.addFolder( path, pathparts[ j ] ); + } + } + + e.parentId = path; + + urlset[ i ] = new Aloha.RepositoryDocument( e ); + } + + this.repositoryName = 'Linklist'; + }, + + /** + * @param {String} path + * @param {String} name + * @return {String} + */ + addFolder: function ( path, name ) { + var type = path ? 'folder' : 'hostname', + p = path ? path + '/' + name : name; + + if ( name && !this.folder[ p ] ) { + this.folder[ p ] = new Aloha.RepositoryFolder( { + id: p, + name: name || p, + parentId: path, + type: 'host', + repositoryId: this.repositoryId + } ); + } + + return p; + }, + + /** + * Searches a repository for object items matching query if + * objectTypeFilter. If none is found it returns null. + * + * @param {Object} p + * @param {Function} callback + */ + query: function ( p, callback ) { + // Not supported; filter, orderBy, maxItems, skipcount, renditionFilter + var r = new RegExp( p.queryString, 'i' ); + + var d = urlset.filter( function ( e, i, a ) { + return ( + ( !p.queryString || e.name.match( r ) || e.url.match( r ) ) && + ( !p.objectTypeFilter || ( !p.objectTypeFilter.length ) || jQuery.inArray( e.type, p.objectTypeFilter ) > -1 ) && + true //( !p.inFolderId || p.inFolderId == e.parentId ) + ); + } ); + + setTimeout( function () { + callback.call( this, d ); + }, 2000 ); + }, + + /** + * returns the folder structure as parsed at init + * + * @param {Object} p + * @param {Function} callback + */ + getChildren: function ( p, callback ) { + var d = [], + e; + + for ( e in this.folder ) { + var l = this.folder[ e ].parentId; + if ( typeof this.folder[ e ] != 'function' && ( // extjs prevention + this.folder[ e ].parentId == p.inFolderId || // all subfolders + ( !this.folder[ e ].parentId && p.inFolderId == this.repositoryId ) // the hostname + ) ) { + d.push( this.folder[ e ] ); + } + } + + setTimeout( function () { + callback.call( this, d ); + }, 2000 ); + }, + + //parseUri 1.2.2 + //(c) Steven Levithan + //MIT License + //http://blog.stevenlevithan.com/archives/parseuri + parseUri: function(str) { + var o = { + strictMode: false, + key: [ "source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } + }, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + uri = {}, + i = 14; + + while (i--) uri[o.key[i]] = m[i] || ""; + + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + + return uri; + }, + + /** + * Get the repositoryItem with given id + * Callback: {GENTICS.Aloha.Repository.Object} item with given id + * @param itemId {String} id of the repository item to fetch + * @param callback {function} callback function + */ + getObjectById: function ( itemId, callback ) { + var i = 0, + l = urlset.length, + d = []; + + for ( ; i < l; i++ ) { + if ( urlset[ i ].id == itemId ) { + d.push( urlset[ i ] ); + } + } + + callback.call( this, d ); + } + + } ) )(); + +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/lib/link-plugin.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/lib/link-plugin.js new file mode 100644 index 00000000..84f40232 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/lib/link-plugin.js @@ -0,0 +1,759 @@ +/*! + * Aloha Editor + * Author & Copyright (c) 2010 Gentics Software GmbH + * aloha-sales@gentics.com + * Licensed unter the terms of http://www.aloha-editor.com/license.html + * + * Aloha Link Plugin + * ----------------- + * This plugin provides an interface to allow the user to insert, edit and + * remove links within an active editable. + * It presents its user interface in the Floating menu, in a Sidebar panel. + * Clicking on any links inside the editable activates the this plugin's + * floating menu scope. + * + * @todo Consider whether it would be better to have the target options in the + * sidebar panel be a selection box rather than radio buttons. + */ + +define( [ + 'aloha', + 'aloha/plugin', + 'aloha/jquery', + 'aloha/floatingmenu', + 'i18n!link/nls/i18n', + 'i18n!aloha/nls/i18n', + 'aloha/console', + 'link/../extra/linklist', + 'link/../extra/slowlinklist', + 'css!link/css/link.css' +], function ( Aloha, Plugin, jQuery, FloatingMenu, i18n, i18nCore, console ) { + + + var GENTICS = window.GENTICS, + pluginNamespace = 'aloha-link', + oldValue = '', + newValue; + + return Plugin.create( 'link', { + /** + * Configure the available languages + */ + languages: [ 'en', 'de', 'fr', 'ru', 'pl' ], + + /** + * Default configuration allows links everywhere + */ + config: [ 'a' ], + + /** + * all links that match the targetregex will get set the target + * e.g. ^(?!.*aloha-editor.com).* matches all href except aloha-editor.com + */ + targetregex: '', + + /** + * this target is set when either targetregex matches or not set + * e.g. _blank opens all links in new window + */ + target: '', + + /** + * all links that match the cssclassregex will get set the css class + * e.g. ^(?!.*aloha-editor.com).* matches all href except aloha-editor.com + */ + cssclassregex: '', + + /** + * this target is set when either cssclassregex matches or not set + */ + cssclass: '', + + /** + * the defined object types to be used for this instance + */ + objectTypeFilter: [], + + /** + * handle change on href change + * called function ( obj, href, item ); + */ + onHrefChange: null, + + /** + * This variable is used to ignore one selection changed event. We need + * to ignore one selectionchanged event when we set our own selection. + */ + ignoreNextSelectionChangedEvent: false, + + /** + * Internal update interval reference to work around an ExtJS bug + */ + hrefUpdateInt: null, + + /** + * Initialize the plugin + */ + init: function () { + var that = this; + + if ( typeof this.settings.targetregex != 'undefined' ) { + this.targetregex = this.settings.targetregex; + } + if ( typeof this.settings.target != 'undefined' ) { + this.target = this.settings.target; + } + if ( typeof this.settings.cssclassregex != 'undefined' ) { + this.cssclassregex = this.settings.cssclassregex; + } + if ( typeof this.settings.cssclass != 'undefined' ) { + this.cssclass = this.settings.cssclass; + } + if ( typeof this.settings.objectTypeFilter != 'undefined' ) { + this.objectTypeFilter = this.settings.objectTypeFilter; + } + if ( typeof this.settings.onHrefChange != 'undefined' ) { + this.onHrefChange = this.settings.onHrefChange; + } + + this.createButtons(); + this.subscribeEvents(); + this.bindInteractions(); + + Aloha.ready( function () { + that.initSidebar( Aloha.Sidebar.right ); + } ); + }, + + nsSel: function () { + var stringBuilder = [], prefix = pluginNamespace; + jQuery.each( arguments, function () { + stringBuilder.push( '.' + ( this == '' ? prefix : prefix + '-' + this ) ); + } ); + return stringBuilder.join( ' ' ).trim(); + }, + + //Creates string with this component's namepsace prefixed the each classname + nsClass: function () { + var stringBuilder = [], prefix = pluginNamespace; + jQuery.each( arguments, function () { + stringBuilder.push( this == '' ? prefix : prefix + '-' + this ); + } ); + return stringBuilder.join( ' ' ).trim(); + }, + + initSidebar: function ( sidebar ) { + var pl = this; + pl.sidebar = sidebar; + sidebar.addPanel( { + + id : pl.nsClass( 'sidebar-panel-target' ), + title : i18n.t( 'floatingmenu.tab.link' ), + content : '', + expanded : true, + activeOn : 'a, link', + + onInit: function () { + var that = this, + content = this.setContent( + '
        ' + i18n.t( 'link.target.legend' ) + '
        • ' + i18n.t( 'link.target.self' ) + '
        • ' + + '
        • ' + i18n.t( 'link.target.blank' ) + '
        • ' + + '
        • ' + i18n.t( 'link.target.parent' ) + '
        • ' + + '
        • ' + i18n.t( 'link.target.top' ) + '
        • ' + + '
        • ' + i18n.t( 'link.target.framename' ) + '
        • ' + + '
        ' + + '
        ' + i18n.t( 'link.title.legend' ) + '
        ' + ).content; + + jQuery( pl.nsSel( 'framename' ) ).live( 'keyup', function () { + jQuery( that.effective ).attr( 'target', jQuery( this ).val().replace( '\"', '"' ).replace( "'", "'" ) ); + } ); + + jQuery( pl.nsSel( 'radioTarget' ) ).live( 'change', function () { + if ( jQuery( this ).val() == 'framename' ) { + jQuery( pl.nsSel( 'framename' ) ).slideDown(); + } else { + jQuery( pl.nsSel( 'framename' ) ).slideUp().val( '' ); + jQuery( that.effective ).attr( 'target', jQuery( this ).val() ); + } + } ); + + jQuery( pl.nsSel( 'linkTitle' ) ).live( 'keyup', function () { + jQuery( that.effective ).attr( 'title', jQuery( this ).val().replace( '\"', '"' ).replace( "'", "'" ) ); + } ); + }, + + onActivate: function ( effective ) { + var that = this; + that.effective = effective; + if ( jQuery( that.effective ).attr( 'target' ) != null ) { + var isFramename = true; + jQuery( pl.nsSel( 'framename' ) ).hide().val( '' ); + jQuery( pl.nsSel( 'radioTarget' ) ).each( function () { + jQuery( this ).removeAttr('checked'); + if ( jQuery( this ).val() === jQuery( that.effective ).attr( 'target' ) ) { + isFramename = false; + jQuery( this ).attr( 'checked', 'checked' ); + } + } ); + if ( isFramename ) { + jQuery( pl.nsSel( 'radioTarget[value="framename"]' ) ).attr( 'checked', 'checked' ); + jQuery( pl.nsSel( 'framename' ) ) + .val( jQuery( that.effective ).attr( 'target' ) ) + .show(); + } + } else { + jQuery( pl.nsSel( 'radioTarget' ) ).first().attr( 'checked', 'checked' ); + jQuery( that.effective ).attr( 'target', jQuery( pl.nsSel( 'radioTarget' ) ).first().val() ); + } + + var that = this; + that.effective = effective; + jQuery( pl.nsSel( 'linkTitle' ) ).val( jQuery( that.effective ).attr( 'title' ) ); + } + + } ); + + sidebar.show(); + }, + + /** + * Subscribe for events + */ + subscribeEvents: function () { + var that = this; + + // add the event handler for creation of editables + Aloha.bind( 'aloha-editable-created', function ( event, editable ) { + // CTRL+L + editable.obj.keydown( function ( e ) { + if ( e.metaKey && e.which == 76 ) { + if ( that.findLinkMarkup() ) { + // open the tab containing the href + FloatingMenu.activateTabOfButton( 'href' ); + that.hrefField.focus(); + } else { + that.insertLink(); + } + // prevent from further handling + // on a MAC Safari cursor would jump to location bar. Use ESC then META+L + return false; + } + } ); + + editable.obj.find( 'a' ).each( function ( i ) { + that.addLinkEventHandlers( this ); + } ); + } ); + + // add the event handler for selection change + Aloha.bind( 'aloha-selection-changed', function ( event, rangeObject ) { + var config, + foundMarkup; + + // Check if we need to ignore this selection changed event for + // now and check whether the selection was placed within a + // editable area. + if ( !that.ignoreNextSelectionChangedEvent && + Aloha.Selection.isSelectionEditable() && + Aloha.activeEditable != null ) { + // show/hide the button according to the configuration + config = that.getEditableConfig( Aloha.activeEditable.obj ); + if ( jQuery.inArray( 'a', config ) != -1 ) { + that.formatLinkButton.show(); + that.insertLinkButton.show(); + } else { + that.formatLinkButton.hide(); + that.insertLinkButton.hide(); + // leave if a is not allowed + return; + } + + foundMarkup = that.findLinkMarkup( rangeObject ); + + if ( foundMarkup ) { + that.insertLinkButton.hide(); + that.formatLinkButton.setPressed( true ); + FloatingMenu.setScope( 'link' ); + + // remember the current tab selected by the user + var currentTab = FloatingMenu.userActivatedTab; + + // switch to the href tab (so that we make sure that the href field gets created) + FloatingMenu.activateTabOfButton( 'href' ); + if ( currentTab ) { + // switch back to the original tab + FloatingMenu.userActivatedTab = currentTab; + } + // now we are ready to set the target object + that.hrefField.setTargetObject( foundMarkup, 'href' ); + + // if the selection-changed event was raised by the first click interaction on this page + // the hrefField component might not be initialized. When the user switches to the link + // tab to edit the link the field would be empty. We check for that situation and add a + // special interval check to set the value once again + if ( jQuery( '#' + that.hrefField.extButton.id ).length == 0 ) { + // there must only be one update interval running at the same time + if ( that.hrefUpdateInt !== null ) { + clearInterval( that.hrefUpdateInt ); + } + + // register a timeout that will set the value as soon as the href field was initialized + that.hrefUpdateInt = setInterval( function () { + if ( jQuery( '#' + that.hrefField.extButton.id ).length > 0 ) { // the object was finally created + that.hrefField.setTargetObject( foundMarkup, 'href' ); + clearInterval( that.hrefUpdateInt ); + } + }, 200 ); + } + } else { + that.formatLinkButton.setPressed( false ); + that.hrefField.setTargetObject( null ); + } + } + + that.ignoreNextSelectionChangedEvent = false; + } ); + }, + + /** + * Add event handlers to the given link object + * @param link object + */ + addLinkEventHandlers: function ( link ) { + var that = this; + + // show pointer on mouse over + jQuery( link ).mouseenter( function ( e ) { + Aloha.Log.debug( that, 'mouse over link.' ); + that.mouseOverLink = link; + that.updateMousePointer(); + } ); + + // in any case on leave show text cursor + jQuery( link ).mouseleave( function ( e ) { + Aloha.Log.debug( that, 'mouse left link.' ); + that.mouseOverLink = null; + that.updateMousePointer(); + } ); + + // follow link on ctrl or meta + click + jQuery( link ).click( function ( e ) { + if ( e.metaKey ) { + // blur current editable. user is waiting for the link to load + Aloha.activeEditable.blur(); + // hack to guarantee a browser history entry + setTimeout( function () { + location.href = e.target; + }, 0 ); + e.stopPropagation(); + + return false; + } + } ); + }, + + /** + * Initialize the buttons + */ + createButtons: function () { + var that = this; + + // format Link Button - this button behaves like + // a formatting button like (bold, italics, etc) + this.formatLinkButton = new Aloha.ui.Button( { + 'name': 'a', + 'iconClass': 'aloha-button aloha-button-a', + 'size': 'small', + 'onclick': function () { that.formatLink(); }, + 'tooltip': i18n.t( 'button.addlink.tooltip' ), + 'toggle': true + } ); + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.formatLinkButton, + i18nCore.t( 'floatingmenu.tab.format' ), + 1 + ); + + // insert Link + // always inserts a new link + this.insertLinkButton = new Aloha.ui.Button( { + 'name': 'insertLink', + 'iconClass': 'aloha-button aloha-button-a', + 'size': 'small', + 'onclick': function () { that.insertLink( false ); }, + 'tooltip': i18n.t( 'button.addlink.tooltip' ), + 'toggle': false + } ); + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.insertLinkButton, + i18nCore.t( 'floatingmenu.tab.insert' ), + 1 + ); + + // add the new scope for links + FloatingMenu.createScope( 'link', 'Aloha.continuoustext' ); + + this.hrefField = new Aloha.ui.AttributeField( { + 'name': 'href', + 'width': 320, + 'valueField': 'url', + 'cls': 'aloha-link-href-field' + } ); + this.hrefField.setTemplate( '{name}
        {url}
        ' ); + this.hrefField.setObjectTypeFilter( this.objectTypeFilter ); + // add the input field for links + FloatingMenu.addButton( + 'link', + this.hrefField, + i18n.t( 'floatingmenu.tab.link' ), + 1 + ); + + this.removeLinkButton = new Aloha.ui.Button( { + // TODO use another icon here + 'name': 'removeLink', + 'iconClass': 'aloha-button aloha-button-a-remove', + 'size': 'small', + 'onclick': function () { that.removeLink(); }, + 'tooltip': i18n.t( 'button.removelink.tooltip' ) + } ); + // add a button for removing the currently set link + FloatingMenu.addButton( + 'link', + this.removeLinkButton, + i18n.t( 'floatingmenu.tab.link' ), + 1 + ); + }, + + /** + * Parse a all editables for links and bind an onclick event + * Add the link short cut to all edtiables + */ + bindInteractions: function () { + var that = this; + + // update link object when src changes + this.hrefField.addListener( 'keyup', function ( obj, event ) { + // Now show all the ui-attributefield elements + that.showComboList(); + + // Handle ESC key press: We do a rough check to see if the user + // has entered a link or searched for something + if ( event.keyCode == 27 ) { + var curval = that.hrefField.getQueryValue(); + if ( curval[ 0 ] == '/' || // local link + curval[ 0 ] == '#' || // inner document link + curval.match( /^.*\.([a-z]){2,4}$/i ) || // local file with extension + curval.match( /^htt.*/i ) // external link + ) { + // could be a link better leave it as it is + } else { + // the user searched for something and aborted + // restore original value + that.hrefField.setValue( that.hrefField.getValue() ); + // or clean the field value + // that.hrefField.setValue(); + that.hideComboList(); + } + } + + that.hrefChange(); + + // Handle the enter key. Terminate the link scope and show the final link. + if ( event.keyCode == 13 ) { + // Update the selection and place the cursor at the end of the link. + var range = Aloha.Selection.getRangeObject(); + + // workaround to keep the found markup otherwise removelink won't work +// var foundMarkup = that.findLinkMarkup( range ); +// console.dir(foundMarkup); +// that.hrefField.setTargetObject(foundMarkup, 'href'); + + // We have to ignore the next 2 onselectionchange events. + // The first one we need to ignore is the one trigger when + // we reposition the selection to right at the end of the + // link. + // Not sure what the next event is yet but we need to + // ignore it as well, ignoring it prevents the value of + // hrefField from being set to the old value. + that.ignoreNextSelectionChangedEvent = true; + range.startContainer = range.endContainer; + range.startOffset = range.endOffset; + range.select(); + that.ignoreNextSelectionChangedEvent = true; + + var hrefValue = jQuery( that.hrefField.extButton.el.dom ).attr( 'value' ); + + if ( hrefValue == 'http://' || hrefValue == '' ) { + that.removeLink( false ); + } + + setTimeout( function () { + FloatingMenu.setScope( 'Aloha.continuoustext' ); + }, 100 ); + + that.preventAutoSuggestionBoxFromExpanding(); + } else { + // Check whether the value in the input field has changed + // because if it has, then the ui-attribute object's store + // needs to be cleared. The reason we need to do this + // clearing is because once the auto-suggeset combo box is + // shown and/or populated, the next enter keypress event + // would be handled as if the user is selecting one of the + // elements in the down down list. + newValue = jQuery( that.hrefField.extButton.el.dom ).attr( 'value' ); + if ( oldValue != newValue ) { + oldValue = newValue; + // Drop local cache of suggestion items + + // Don't use this method because it will update the + // loading message to say that no items were found ... + // that.hrefField.extButton.store.removeAll(); + + // ... instead we will manually delete the store data + // ourselves + var storeData = that.hrefField.extButton.store.data; + storeData.items = []; + storeData.key = []; + storeData.length = 0; + that.hrefField.extButton.store.lastQuery = null; + } + } + } ); + + jQuery( document ) + .keydown( function ( e ) { + Aloha.Log.debug( that, 'Meta key down.' ); + that.metaKey = e.metaKey; + that.updateMousePointer(); + } ).keyup( function ( e ) { + Aloha.Log.debug( that, 'Meta key up.' ); + that.metaKey = e.metaKey; + that.updateMousePointer(); + } ); + }, + + /** + * Updates the mouse pointer + */ + updateMousePointer: function () { + if ( this.metaKey && this.mouseOverLink ) { + Aloha.Log.debug( this, 'set pointer' ); + jQuery( this.mouseOverLink ).removeClass( 'aloha-link-text' ); + jQuery( this.mouseOverLink ).addClass( 'aloha-link-pointer' ); + } else { + jQuery( this.mouseOverLink ).removeClass( 'aloha-link-pointer' ); + jQuery( this.mouseOverLink ).addClass( 'aloha-link-text' ); + } + }, + + /** + * Check whether inside a link tag + * @param {GENTICS.Utils.RangeObject} range range where to insert the + * object (at start or end) + * @return markup + * @hide + */ + findLinkMarkup: function ( range ) { + if ( typeof range == 'undefined' ) { + range = Aloha.Selection.getRangeObject(); + } + if ( Aloha.activeEditable ) { + return range.findMarkup( function () { + return this.nodeName.toLowerCase() == 'a'; + }, Aloha.activeEditable.obj ); + } else { + return null; + } + }, + + /** + * Format the current selection or if collapsed the current word as + * link. If inside a link tag the link is removed. + */ + formatLink: function () { + if ( Aloha.activeEditable ) { + if ( this.findLinkMarkup( Aloha.Selection.getRangeObject() ) ) { + this.removeLink(); + } else { + this.insertLink(); + } + } + }, + + /** + * Insert a new link at the current selection. When the selection is + * collapsed, the link will have a default link text, otherwise the + * selected text will be the link text. + */ + insertLink: function ( extendToWord ) { + var that = this, + range = Aloha.Selection.getRangeObject(), + linkText, + newLink; + + // There are occasions where we do not get a valid range, in such + // cases we should not try and add a link + if ( !( range.startContainer && range.endContainer ) ) { + return; + } + + // do not nest a link inside a link + if ( this.findLinkMarkup( range ) ) { + return; + } + + // activate floating menu tab + FloatingMenu.activateTabOfButton( 'href' ); + + // if selection is collapsed then extend to the word. + if ( range.isCollapsed() && extendToWord !== false ) { + GENTICS.Utils.Dom.extendToWord( range ); + } + if ( range.isCollapsed() ) { + // insert a link with text here + linkText = i18n.t( 'newlink.defaulttext' ); + newLink = jQuery( '' + linkText + '' ); + GENTICS.Utils.Dom.insertIntoDOM( newLink, range, jQuery( Aloha.activeEditable.obj ) ); + range.startContainer = range.endContainer = newLink.contents().get( 0 ); + range.startOffset = 0; + range.endOffset = linkText.length; + } else { + newLink = jQuery( '' ); + GENTICS.Utils.Dom.addMarkup( range, newLink, false ); + } + + Aloha.activeEditable.obj.find( 'a.aloha-new-link' ).each( function ( i ) { + that.addLinkEventHandlers( this ); + jQuery(this).removeClass( 'aloha-new-link' ); + } ); + + range.select(); + + // focus has to become before prefilling the attribute, otherwise + // Chrome and Firefox will not focus the element correctly. + this.hrefField.focus(); + // prefill and select the new href + // We need this guard because there are time when the extButton's + // el element has not yet available + if ( this.hrefField.extButton.el ) { + jQuery( this.hrefField.extButton.el.dom ).attr( 'value', 'http://' ).select(); + } + this.hrefChange(); + }, + + /** + * Remove an a tag and clear the current item from the hrefField + */ + removeLink: function ( terminateLinkScope ) { + var range = Aloha.Selection.getRangeObject(), + foundMarkup = this.findLinkMarkup(); + + // clear the current item from the href field + this.hrefField.setItem(null); + if ( foundMarkup ) { + // remove the link + GENTICS.Utils.Dom.removeFromDOM( foundMarkup, range, true ); + + range.startContainer = range.endContainer; + range.startOffset = range.endOffset; + + // select the (possibly modified) range + range.select(); + + if ( typeof terminateLinkScope == 'undefined' || + terminateLinkScope === true ) { + FloatingMenu.setScope( 'Aloha.continuoustext' ); + } + } + }, + + /** + * Updates the link object depending on the src field + */ + hrefChange: function () { + var that = this; + + // For now hard coded attribute handling with regex. + // Avoid creating the target attribute, if it's unnecessary, so + // that XSS scanners (AntiSamy) don't complain. + if ( this.target != '' ) { + this.hrefField.setAttribute( + 'target', + this.target, + this.targetregex, + this.hrefField.getQueryValue() + ); + } + + this.hrefField.setAttribute( + 'class', + this.cssclass, + this.cssclassregex, + this.hrefField.getQueryValue() + ); + + Aloha.trigger( 'aloha-link-href-change', { + obj: that.hrefField.getTargetObject(), + href: that.hrefField.getQueryValue(), + item: that.hrefField.getItem() + } ); + + if ( typeof this.onHrefChange == 'function' ) { + this.onHrefChange.call( + this, + this.hrefField.getTargetObject(), + this.hrefField.getQueryValue(), + this.hrefField.getItem() + ); + } + }, + + /** + * Prevents the combolist from expanding when + * this.hrefField.extButton.expand method is invoked + */ + preventAutoSuggestionBoxFromExpanding: function () { + this.hrefField.extButton.hasFocus = false; + }, + + /** + * Displays all the ui-attributefield elements + */ + showComboList: function () { + jQuery( '.x-layer x-combo-list,' + + '.x-combo-list-inner,' + + '.x-combo-list' ).show(); + }, + + /** + * Hide all the ui-attributefield elements + */ + hideComboList: function () { + jQuery( '.x-layer x-combo-list,' + + '.x-combo-list-inner,' + + '.x-combo-list' ).hide(); + }, + + /** + * Make the given jQuery object (representing an editable) clean for saving + * Find all links and remove editing objects + * @param obj jQuery object to make clean + * @return void + */ + makeClean: function ( obj ) { + // find all link tags + obj.find( 'a' ).each( function () { + jQuery( this ) + .removeClass( 'aloha-link-pointer' ) + .removeClass( 'aloha-link-text' ); + } ); + } + + } ); + +} ); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/de/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/de/i18n.js new file mode 100644 index 00000000..30a12b84 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/de/i18n.js @@ -0,0 +1,13 @@ +define( { + 'button.addlink.tooltip': 'Verweis einf\u00fcgen', + 'button.removelink.tooltip': 'Verweis entfernen', + 'newlink.defaulttext': 'Neuer Verweis', + 'floatingmenu.tab.link': 'Verweis', + 'link.target.self': '\u00D6ffnet im selben Fenster', + 'link.target.blank': '\u00D6ffnet in neuem Fenster', + 'link.target.parent': 'Parent', + 'link.target.top': 'Top', + 'link.target.framename': 'Framename', + 'link.target.legend': 'Target', + 'link.title.legend': 'Title' +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/fr/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/fr/i18n.js new file mode 100644 index 00000000..86901d7f --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/fr/i18n.js @@ -0,0 +1,6 @@ +define( { + 'button.addlink.tooltip': 'Ins\u00e9rer un lien', + 'button.removelink.tooltip': 'Supprimer le lien', + 'newlink.defaulttext': 'Nouveau lien', + 'floatingmenu.tab.link': 'Lien' +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/i18n.js new file mode 100644 index 00000000..8a2ee0d3 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/i18n.js @@ -0,0 +1,9 @@ +define( { + root: { + 'button.addlink.tooltip': 'Insert Link', 'button.removelink.tooltip': 'Remove Link', 'newlink.defaulttext': 'New Link', 'floatingmenu.tab.link': 'Link', 'link.target.self': 'Self', 'link.target.blank': 'Blank', 'link.target.parent': 'Parent', 'link.target.top': 'Top', 'link.target.framename': 'Framename', 'link.target.legend': 'Target', 'link.title.legend': 'Title' + }, + de: true, + fr: true, + pl: true, + ru: true +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/pl/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/pl/i18n.js new file mode 100644 index 00000000..8fcc277a --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/pl/i18n.js @@ -0,0 +1,6 @@ +define( { + 'button.addlink.tooltip': 'Dodaj link', + 'button.removelink.tooltip': 'Usu\u0144 link', + 'newlink.defaulttext': 'Nowy link', + 'floatingmenu.tab.link': 'Link' +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/ru/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/ru/i18n.js new file mode 100644 index 00000000..36568094 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/link/nls/ru/i18n.js @@ -0,0 +1,6 @@ +define( { + 'button.addlink.tooltip': '\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443', + 'button.removelink.tooltip': '\u0423\u0431\u0440\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443', + 'newlink.defaulttext': '\u041d\u043e\u0432\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430', + 'floatingmenu.tab.link': '\u0421\u0441\u044b\u043b\u043a\u0430' +} ); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/lib/list-plugin.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/lib/list-plugin.js new file mode 100644 index 00000000..139ceaf8 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/lib/list-plugin.js @@ -0,0 +1,849 @@ +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +define( +['aloha', 'aloha/jquery', 'aloha/plugin', 'aloha/floatingmenu', 'i18n!list/nls/i18n', 'i18n!aloha/nls/i18n', 'aloha/engine'], +function(Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore, Engine) { + + + var + GENTICS = window.GENTICS; + + /** + * Register the ListPlugin as Aloha.Plugin + */ + var ListPlugin = Plugin.create('list', { + /** + * Configure the available languages + */ + languages: ['en', 'de', 'fr', 'eo', 'fi', 'ru', 'it'], + + /** + * default button configuration + */ + config: [ 'ul', 'ol' ], + + /** + * List of transformable elements + */ + transformableElements: {'p' : true, 'h1' : true, 'h2' : true, 'h3' : true, 'h4' : true, 'h5' : true, 'h6' : true, 'ul' : true, 'ol' : true}, + + /** + * Initialize the plugin, register the buttons + */ + init: function() { + + var that = this; + +// //register the workaround-handler keypress handler on every editable +// Aloha.bind('aloha-editable-created', function(event, editable) { +// editable.obj.keyup(function(event){ +// deleteWorkaroundHandler(event); +// return true; +// }); +// }); + + // the 'create unordered list' button + this.createUnorderedListButton = new Aloha.ui.Button({ + 'name' : 'ul', + 'iconClass' : 'aloha-button aloha-button-ul', + 'size' : 'small', + 'tooltip' : i18n.t('button.createulist.tooltip'), + 'toggle' : true, + 'onclick' : function (element, event) { + that.transformList(false); + } + }); + // add to floating menu + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.createUnorderedListButton, + i18nCore.t('floatingmenu.tab.format'), + 1 + ); + + // the 'create ordered list' button + this.createOrderedListButton = new Aloha.ui.Button({ + 'name' : 'ol', + 'iconClass' : 'aloha-button aloha-button-ol', + 'size' : 'small', + 'tooltip' : i18n.t('button.createolist.tooltip'), + 'toggle' : true, + 'onclick' : function (element, event) { + that.transformList(true); + } + }); + // add to floating menu + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.createOrderedListButton, + i18nCore.t('floatingmenu.tab.format'), + 1 + ); + + + FloatingMenu.createScope('Aloha.List', 'Aloha.continuoustext'); + // the 'indent list' button + this.indentListButton = new Aloha.ui.Button({ + 'name' : 'indent-list', + 'iconClass' : 'aloha-button aloha-button-indent-list', + 'size' : 'small', + 'tooltip' : i18n.t('button.indentlist.tooltip'), + 'toggle' : false, + 'onclick' : function (element, event) { + that.indentList(); + } + }); + // add to floating menu + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.indentListButton, + i18n.t('floatingmenu.tab.list'), + 1 + ); + + // the 'outdent list' button + this.outdentListButton = new Aloha.ui.Button({ + 'name' : 'outdent-list', + 'iconClass' : 'aloha-button aloha-button-outdent-list', + 'size' : 'small', + 'tooltip' : i18n.t('button.outdentlist.tooltip'), + 'toggle' : false, + 'onclick' : function (element, event) { + that.outdentList(); + } + }); + // add to floating menu + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.outdentListButton, + i18n.t('floatingmenu.tab.list'), + 1 + ); + + // add the event handler for selection change + Aloha.bind('aloha-selection-changed', function ( event, rangeObject ) { + var i, effectiveMarkup; + + // Hide all buttons in the list tab will make the list tab disappear + that.outdentListButton.hide(); + that.indentListButton.hide(); + that.createUnorderedListButton.setPressed(false); + that.createOrderedListButton.setPressed(false); + + for ( i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + effectiveMarkup = rangeObject.markupEffectiveAtStart[ i ]; + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
          '))) { + that.createUnorderedListButton.setPressed(true); + // Show all buttons in the list tab + that.outdentListButton.show(); + that.indentListButton.show(); + break; + } + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
            '))) { + that.createOrderedListButton.setPressed(true); + // Show all buttons in the list tab + that.outdentListButton.show(); + that.indentListButton.show(); + break; + } + } + + if (Aloha.activeEditable) { + that.applyButtonConfig(Aloha.activeEditable.obj); + } + + // TODO this should not be necessary here! + FloatingMenu.doLayout(); + }); + + // add the key handler for Tab + Aloha.Markup.addKeyHandler(9, function(event) { + return that.processTab(event); + }); + }, + + /** + * Applys a configuration specific for an editable + * buttons not available in this configuration are hidden + * @param {jQuery} obj jQuery object of the activated editable + */ + applyButtonConfig: function (obj) { + var config = this.getEditableConfig(obj); + + if (Aloha.Selection.rangeObject.unmodifiableMarkupAtStart[0]) { + // show/hide them according to the config + if (jQuery.inArray('ul', config) != -1 && Aloha.Selection.canTag1WrapTag2(Aloha.Selection.rangeObject.unmodifiableMarkupAtStart[0].nodeName, "ul") != -1) { + this.createUnorderedListButton.show(); + } else { + this.createUnorderedListButton.hide(); + } + + if (jQuery.inArray('ol', config) != -1 && Aloha.Selection.canTag1WrapTag2(Aloha.Selection.rangeObject.unmodifiableMarkupAtStart[0].nodeName, "ol") != -1) { + this.createOrderedListButton.show(); + } else { + this.createOrderedListButton.hide(); + } + + } + }, + + /** + * Process Tab and Shift-Tab pressed in lists + */ + processTab: function (event) { + if (event.keyCode === 9/*tab*/ ) { + if (event.shiftKey) { + return this.outdentList(); + } else { + return this.indentList(); + } + } + return true; + }, + + /** + * For the current selection, get the DOM object, which will be transformed to/from the list + * @return dom object or false + */ + getStartingDomObjectToTransform: function () { + var rangeObject = Aloha.Selection.rangeObject, + i, effectiveMarkup; + + for ( i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + effectiveMarkup = rangeObject.markupEffectiveAtStart[ i ]; + if (this.transformableElements[effectiveMarkup.nodeName.toLowerCase()]) { + return effectiveMarkup; + } + } + + return false; + }, + + /** + * For the current selection, get the nearest list item as dom object + * @return dom object or false + */ + getNearestSelectedListItem: function () { + var rangeObject = Aloha.Selection.rangeObject, + i, effectiveMarkup; + + for ( i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + effectiveMarkup = rangeObject.markupEffectiveAtStart[ i ]; + if (GENTICS.Utils.Dom.isListElement(effectiveMarkup)) { + return effectiveMarkup; + } + } + + return false; + }, + + /** + * Transform the current selection to/from a list + * @param ordered true when transforming to/from an ordered list, false for unordered lists + */ + transformList: function (ordered) { + var domToTransform = this.getStartingDomObjectToTransform(), + lastLi, i, jqNewLi, jqList, selectedSiblings, jqParentList, + newPara, jqToTransform, nodeName; + + // visible is set to true, but the button is not visible + this.outdentListButton.show(); + this.indentListButton.show(); + + if (!domToTransform) { + // wrap a paragraph around the selection + Aloha.Selection.changeMarkupOnSelection(jQuery('

            ')); + domToTransform = this.getStartingDomObjectToTransform(); + + if (!domToTransform) { + if ( Aloha.Selection.rangeObject.startContainer.contentEditable ) { + // create a new list with an empty item + jqList = ordered ? jQuery('
              ') : jQuery('
                '); + jqNewLi = jQuery('
              • '); + jqList.append(jqNewLi); + + var li = jqNewLi.get(0); + var editable = Aloha.getActiveEditable().obj; + //IE7 requires an (empty or non-empty) text node + //inside the li for the selection to work. + li.appendChild(document.createTextNode("")); + /* if ( jQuery.browser.mozilla ) { + li.appendChild(document.createElement("BR")); + }*/ + + editable.append(jqList); + editable.focus(); + + var range = Aloha.createRange(); + var selection = Aloha.getSelection(); + range.setStart( li.firstChild, 0 ); + range.setEnd( li.firstChild, 0 ); + selection.removeAllRanges(); + selection.addRange( range ); + Aloha.Selection.updateSelection(); + + return; + } else { + Aloha.Log.error(this, 'Could not transform selection into a list'); + return; + } + } + } + + // check the dom object + nodeName = domToTransform.nodeName.toLowerCase(); + + if (nodeName == 'ul' && !ordered) { + // first check whether the list is nested into another list + jqList = jQuery(domToTransform); + + jqParentList = jqList.parent(); + if (jqParentList.length > 0 + && GENTICS.Utils.Dom.isListElement(jqParentList.get(0))) { + // when the list is nested into another, our list items will be + // added to the list items of the outer list + + // find the place where to put the children of the inner list + if (jqParentList.get(0).nodeName.toLowerCase() === 'li') { + // inner table is nested in a li (this conforms to the html5 spec) + jqParentList.after(jqList.children()); + jqList.remove(); + } else { + // inner table is nested in the outer list directly (this violates the html5 spec) + jqList.children().unwrap(); + } + } else { + // we are in an unordered list and shall transform it to paragraphs + + // transform all li into p + jqToTransform = jQuery(domToTransform); + jQuery.each(jqToTransform.children('li'), function(index, li) { + newPara = Aloha.Markup.transformDomObject(li, 'p', Aloha.Selection.rangeObject); + // if any lists are in the paragraph, move the to after the paragraph + newPara.after(newPara.children('ol,ul')); + }); + + // unwrap the li (remove the enclosing ul) + jqToTransform.children().unwrap(); + } + } else if (nodeName == 'ul' && ordered) { + // we are in an unordered list and shall transform it to an ordered list + + // transform the ul into an ol + Aloha.Markup.transformDomObject(domToTransform, 'ol', Aloha.Selection.rangeObject); + + // merge adjacent lists + this.mergeAdjacentLists(jQuery(domToTransform)); + } else if (nodeName == 'ol' && !ordered) { + // we are in an ordered list and shall transform it to an unordered list + + // transform the ol into an ul + Aloha.Markup.transformDomObject(domToTransform, 'ul', Aloha.Selection.rangeObject); + + // merge adjacent lists + this.mergeAdjacentLists(jQuery(domToTransform)); + } else if (nodeName == 'ol' && ordered) { + // first check whether the list is nested into another list + jqList = jQuery(domToTransform); + + jqParentList = jqList.parent(); + if (jqParentList.length > 0 + && GENTICS.Utils.Dom.isListElement(jqParentList.get(0))) { + // when the list is nested into another, our list items will be + // added to the list items of the outer list + + // find the place where to put the children of the inner list + if (jqParentList.get(0).nodeName.toLowerCase() === 'li') { + // inner table is nested in a li (this conforms to the html5 spec) + jqParentList.after(jqList.children()); + jqList.remove(); + } else { + // inner table is nested in the outer list directly (this violates the html5 spec) + jqList.children().unwrap(); + } + } else { + // we are in an unordered list and shall transform it to paragraphs + + // transform all li into p + jqToTransform = jQuery(domToTransform); + jQuery.each(jqToTransform.children('li'), function(index, li) { + newPara = Aloha.Markup.transformDomObject(li, 'p', Aloha.Selection.rangeObject); + // if any lists are in the paragraph, move the to after the paragraph + newPara.after(newPara.children('ol,ul')); + }); + + // unwrap the li (remove the enclosing ul) + jqToTransform.children().unwrap(); + } + } else { + // we are in something different from a list and shall transform it into a list + + // get the also selected siblings of the dom object + selectedSiblings = Aloha.Selection.rangeObject.getSelectedSiblings(domToTransform); + + // create a new list + jqList = ordered ? jQuery('
                  ') : jQuery('
                    '); + // add a new list item + jqNewLi = jQuery('
                  • '); + // add the li into the list + jqList.append(jqNewLi); + // append the contents of the old dom element to the li + jQuery(domToTransform).contents().appendTo(jqNewLi); + // replace the old dom element with the new list + jQuery(domToTransform).replaceWith(jqList); + + // update the selection range + if (Aloha.Selection.rangeObject.startContainer == domToTransform) { + Aloha.Selection.rangeObject.startContainer = jqNewLi.get(0); + } + if (Aloha.Selection.rangeObject.endContainer == domToTransform) { + Aloha.Selection.rangeObject.endContainer = jqNewLi.get(0); + } + + var lastAppendedLi = jqNewLi; + + // now also transform all siblings + if (selectedSiblings) { + lastLi = false; + for ( i = 0; i < selectedSiblings.length; ++i) { + if (GENTICS.Utils.Dom.isBlockLevelElement(selectedSiblings[i])) { + if (lastLi) { + lastLi = false; + } + + // transform the block level element + jqNewLi = Aloha.Markup.transformDomObject(selectedSiblings[i], 'li', Aloha.Selection.rangeObject); + jqList.append(jqNewLi); + lastAppendedLi = jqNewLi; + } else { + if (selectedSiblings[i].nodeType == 3 + && jQuery.trim(selectedSiblings[i].data).length === 0) { + continue; + } + if (!lastLi) { + lastLi = jQuery('
                  • '); + jqList.append(lastLi); + lastAppendedLi = lastLi; + } + lastLi.append(selectedSiblings[i]); + } + } + } + + // merge adjacent lists + this.mergeAdjacentLists(jqList); + + //use rangy to change the selection to the contents of + //the last li that was appended to the list + var li = lastAppendedLi.get(0); + if (GENTICS.Utils.Dom.isEmpty(li)) { + var range = Aloha.createRange(); + var selection = Aloha.getSelection(); + //IE7 requires an (empty or non-empty) text node + //inside the li for the selection to work. + li.appendChild(document.createTextNode("")); + range.selectNodeContents( li.lastChild ); + selection.removeAllRanges(); + selection.addRange( range ); + Aloha.Selection.updateSelection(); + } + } + + // refresh the selection + this.refreshSelection(); + }, + + /** + * Indent the selected list items by moving them into a new created, nested list + */ + indentList: function () { + var listItem = this.getNearestSelectedListItem(), + i, jqNewList, selectedSiblings, jqOldList, jqItemBefore; + + if (listItem) { + jqItemBefore = jQuery(listItem).prev('li'); + + // when we are in the first li of a list, there is no indenting + if (jqItemBefore.length === 0) { + // but we handled the TAB keystroke + return false; + } + jqOldList = jQuery(listItem).parent(); + + // get the also selected siblings of the dom object + selectedSiblings = Aloha.Selection.rangeObject.getSelectedSiblings(listItem); + + // create the new list element by cloning the selected list element's parent + jqNewList = jQuery(listItem).parent().clone(false).empty(); + jqNewList.append(listItem); + + // we found a list item before the first selected one, so append the new list to it + jqItemBefore.append(jqNewList); + + // check for multiple selected items + if (selectedSiblings) { + for ( i = 0; i < selectedSiblings.length; ++i) { + jqNewList.append(jQuery(selectedSiblings[i])); + } + } + + // merge adjacent lists + this.mergeAdjacentLists(jqNewList, true); + + // refresh the selection + this.refreshSelection(); + + return false; + } + + return true; + }, + + /** + * Outdent nested list items by moving them into the outer list + */ + outdentList: function () { + var + listItem = this.getNearestSelectedListItem(), + i, jqNewPostList, + jqListItem, jqList, jqParentList, wrappingLi, + selectedSiblings, lastSelected; + + if (listItem) { + // check whether the list is nested into another list + jqListItem = jQuery(listItem); + jqList = jqListItem.parent(); + + // get the parent list + jqParentList = jqList.parents('ul,ol'); + + // check whether the inner list is directly inserted into a li element + wrappingLi = jqList.parent('li'); + + if (jqParentList.length > 0 + && GENTICS.Utils.Dom.isListElement(jqParentList.get(0))) { + // the list is nested into another list + + // get the also selected siblings of the dom object + selectedSiblings = Aloha.Selection.rangeObject.getSelectedSiblings(listItem); + + // check for multiple selected items + if (selectedSiblings && selectedSiblings.length > 0) { + lastSelected = jQuery(selectedSiblings[selectedSiblings.length - 1]); + } else { + lastSelected = jqListItem; + } + + // check whether we found not selected li's after the selection + if (lastSelected.nextAll('li').length > 0) { + jqNewPostList = jqList.clone(false).empty(); + jqNewPostList.append(lastSelected.nextAll()); + lastSelected.append(jqNewPostList); + } + + // now move all selected li's into the higher list + if (wrappingLi.length > 0) { + wrappingLi.after(jqListItem); + } else { + jqList.before(jqListItem); + } + + // check for multiple selected items + if (selectedSiblings && selectedSiblings.length > 0) { + for ( i = selectedSiblings.length - 1; i >= 0; --i) { + jqListItem.after(jQuery(selectedSiblings[i])); + } + } + + // finally check whether there are elements left in the list + if (jqList.contents('li').length === 0) { + // list is completely empty, so remove it + jqList.remove(); + } + + // check whether the wrapping li is empty now + if (wrappingLi.length > 0 && wrappingLi.contents().length === 0) { + wrappingLi.remove(); + } + + // refresh the selection + this.refreshSelection(); + } + + return false; + } + + return true; + }, + + /** + * Refresh the current selection and set to focus to the current editable again + */ + refreshSelection: function () { + Aloha.Selection.rangeObject.update(); + Aloha.Selection.rangeObject.select(); + Aloha.Selection.updateSelection(); + }, + + /** + * Merge adjacent lists (of same type) into the first list + * @param jqList jQuery object of a list + * @param allTypes true if all types of lists may be merged, false if only same types may be merged + */ + mergeAdjacentLists: function (jqList, allTypes) { + // first get the first previous sibling of same type + var firstList = jqList.get(0), jqNextList; + + while ( + firstList.previousSibling + && firstList.previousSibling.nodeType === 1 + && this.isMergable(firstList.previousSibling, firstList, allTypes) + ) { + firstList = firstList.previousSibling; + } + + jqList = jQuery(firstList); + // now merge all adjacent lists into this one + while ( + firstList.nextSibling + && ( + ( + firstList.nextSibling.nodeType === 1 + && this.isMergable(firstList.nextSibling, firstList, allTypes) + ) || ( + firstList.nextSibling.nodeType === 3 + && jQuery.trim(firstList.nextSibling.data).length === 0 + ) + ) + ) { + jqNextList = jQuery(firstList.nextSibling); + if (firstList.nextSibling.nodeType == 1) { + jqNextList.contents().appendTo(jqList); + } + jqNextList.remove(); + } + }, + + /** + * Check whether the given DOM element toCheck is mergeable into the DOM element mergeInto + * @param toCheck DOM element to check + * @param mergeInto DOM element into which toCheck shall be merged + * @param allTypes true if all types of lists may be merged, false if only same types may be merged + */ + isMergable: function (toCheck, mergeInto, allTypes) { + if (allTypes) { + return toCheck.nodeName.toLowerCase() == 'ul' || toCheck.nodeName.toLowerCase() == 'ol'; + } else { + return toCheck.nodeName == mergeInto.nodeName; + } + } + }); + + /** + * + */ + Engine.commands['insertorderedlist'] = { + action: function(value, range) { + ListPlugin.transformList(true); + if (range && Aloha.Selection.rangeObject) { + range.startContainer = Aloha.Selection.rangeObject.startContainer; + range.startOffset = Aloha.Selection.rangeObject.startOffset; + range.endContainer = Aloha.Selection.rangeObject.endContainer; + range.endOffset = Aloha.Selection.rangeObject.endOffset; + } + }, + indeterm: function() { + // TODO + }, + state: function() { + for ( i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + effectiveMarkup = rangeObject.markupEffectiveAtStart[ i ]; + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
                      '))) { + return false; + } + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
                        '))) { + return true; + } + } + + return false; + } + }; + + Engine.commands['insertunorderedlist'] = { + action: function(value, range) { + ListPlugin.transformList(false); + if (range && Aloha.Selection.rangeObject) { + range.startContainer = Aloha.Selection.rangeObject.startContainer; + range.startOffset = Aloha.Selection.rangeObject.startOffset; + range.endContainer = Aloha.Selection.rangeObject.endContainer; + range.endOffset = Aloha.Selection.rangeObject.endOffset; + } + }, + indeterm: function() { + // TODO + }, + state: function() { + for ( i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) { + effectiveMarkup = rangeObject.markupEffectiveAtStart[ i ]; + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
                          '))) { + return true; + } + if (Aloha.Selection.standardTagNameComparator(effectiveMarkup, jQuery('
                            '))) { + return false; + } + } + + return false; + } + }; + + Engine.commands['indent'] = { + action: function(value, range) { + ListPlugin.indentList(); + if (range && Aloha.Selection.rangeObject) { + range.startContainer = Aloha.Selection.rangeObject.startContainer; + range.startOffset = Aloha.Selection.rangeObject.startOffset; + range.endContainer = Aloha.Selection.rangeObject.endContainer; + range.endOffset = Aloha.Selection.rangeObject.endOffset; + } + }, + indeterm: function() { + // TODO + }, + state: function() { + // TODO + return false; + } + }; + + Engine.commands['outdent'] = { + action: function(value, range) { + ListPlugin.outdentList(); + if (range && Aloha.Selection.rangeObject) { + range.startContainer = Aloha.Selection.rangeObject.startContainer; + range.startOffset = Aloha.Selection.rangeObject.startOffset; + range.endContainer = Aloha.Selection.rangeObject.endContainer; + range.endOffset = Aloha.Selection.rangeObject.endOffset; + } + }, + indeterm: function() { + // TODO + }, + state: function() { + // TODO + return false; + } + }; + + /** + * A key handler that should be run as a keyup handler for the + * backspace and del keys. keyup fires after the browser has already + * performed the delete - this handler will perform a cleanup if + * necessary. + * + * Will work around an IE bug which breaks nested lists in the + * following situation, where [] is the selection, if backspace is + * pressed (same goes for the del key if the selection is at the end + * of the li that occurs before the selection): + * + *
                              + *
                            • one
                            • + *
                              • two
                            • + *
                            + *

                            []

                            + * + * The browser behaviour, if one would presses backspace, results in + * the following: + * + *
                              + *
                            • one
                            • + *
                              • two
                              + *
                            + * + * which is invalid HTML since the
                              s are nested directly inside + * each other. + * + * Also, the following situation will cause the kind of invalid HTML + * as above. + *
                                + *
                              • one
                              • + *
                                • two
                              • + *
                              • []three
                              • + *
                              + * + * Also, the following situtation: + *
                                + *
                              • one
                              • + *
                                • two
                                + *

                                []three

                                + *
                              • four
                              • + * + *
                              + * + * And similar situations, some of which are not so easy to reproduce. + * + * @param event a jQuery key event + * @return false if no action needed to be taken, true if cleanup has been performed + */ + function deleteWorkaroundHandler(event) { + if (8/*backspace*/ != event.keyCode && 46/*del*/ != event.keyCode) { + return false; + } + + var rangeObj = Aloha.getSelection().getRangeAt(0); + var startContainer = rangeObj.startContainer; + + //the hack is only relevant if after the deletion has been + //performed we are inside a li of a nested list + var $nestedList = jQuery(startContainer).closest('ul, ol'); + if ( ! $nestedList.length ) { + return false; + } + var $parentList = $nestedList.parent().closest('ul, ol'); + if ( ! $parentList.length ) { + return false; + } + + var ranges = Aloha.getSelection().getAllRanges(); + + var actionPerformed = false; + $parentList.each(function(){ + actionPerformed = actionPerformed || fixListNesting(jQuery(this)); + }); + + if (actionPerformed) { + Aloha.getSelection().setRanges(ranges); + for (var i = 0; i < ranges.length; i++) { + ranges[i].detach(); + } + } + + return actionPerformed; + } + + /** + * If uls or ols are nested directly inside the given list (invalid + * HTML), they will be cleaned up by being appended to the preceding + * li. + */ + function fixListNesting($list) { + var actionPerformed = false; + $list.children('ul, ol').each(function(){ + Aloha.Log.debug("performing list-nesting cleanup"); + if ( ! jQuery(this).prev('li').append(this).length ) { + //if there is no preceding li, create a new one and append to that + jQuery(this).parent().prepend(document.createElement('li')).append(this); + } + actionPerformed = true; + }); + return actionPerformed; + } + + return ListPlugin; +}); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/de/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/de/i18n.js new file mode 100644 index 00000000..5cfa9105 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/de/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"Unsortierte Liste einf\u00fcgen","button.createolist.tooltip":"Sortierte Liste einf\u00fcgen"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/eo/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/eo/i18n.js new file mode 100644 index 00000000..bb4d5282 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/eo/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"Enmeti senordan liston","button.createolist.tooltip":"Enmeti ordan liston"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fi/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fi/i18n.js new file mode 100644 index 00000000..c753847d --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fi/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"Lis\u00e4\u00e4 j\u00e4rjestelem\u00e4t\u00f6n lista","button.createolist.tooltip":"Lis\u00e4\u00e4 j\u00e4rjestelty lista"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fr/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fr/i18n.js new file mode 100644 index 00000000..3794f9b3 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/fr/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"Ins\u00e9rer une liste non ordonn\u00e9e","button.createolist.tooltip":"Ins\u00e9rer liste ordonn\u00e9e"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/i18n.js new file mode 100644 index 00000000..ed651757 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/i18n.js @@ -0,0 +1,9 @@ +define({ + root: {"button.createulist.tooltip":"Insert Unordered List","button.createolist.tooltip":"Insert Ordered List","button.indentlist.tooltip":"Indent List","button.outdentlist.tooltip":"Outdent List","floatingmenu.tab.list":"Lists"} +, "de":true, + "eo":true, + "fi":true, + "fr":true, + "it":true, + "ru":true +}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/it/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/it/i18n.js new file mode 100644 index 00000000..70c30d01 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/it/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"Inserisci una lista","button.createolist.tooltip":"Inserisci una lista numerata"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/ru/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/ru/i18n.js new file mode 100644 index 00000000..108d9c4f --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/nls/ru/i18n.js @@ -0,0 +1 @@ +define({"button.createulist.tooltip":"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0421\u043f\u0438\u0441\u043e\u043a","button.createolist.tooltip":"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0423\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0435\u043d\u043d\u044b\u0439 \u0421\u043f\u0438\u0441\u043e\u043a"}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/package.json b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/package.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/list/package.json @@ -0,0 +1 @@ +{} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/README.md b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/README.md new file mode 100644 index 00000000..0921e15c --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/README.md @@ -0,0 +1,3 @@ +Paste plugin allows to handle some different contents that are pasted into the editable area. + +This plugin is released under the AGPL license. diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/lib/paste-plugin.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/lib/paste-plugin.js new file mode 100644 index 00000000..e092f9ca --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/lib/paste-plugin.js @@ -0,0 +1,221 @@ +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +/** + * Paste Plugin + * ------------ + * The paste plugin intercepts all browser paste events that target aloha- + * editables, and redirects the events into a hidden div. Once pasting is done + * into this div, its contents will be processed by registered content handlers + * before being copied into the active editable, at the current range. + */ + +define( +[ 'aloha/core', 'aloha/plugin', 'aloha/jquery', 'aloha/command', + 'aloha/console' ], +function ( Aloha, Plugin, jQuery, Commands, console ) { + + + var GENTICS = window.GENTICS, + $window = jQuery( window ), + pasteRange = null, + pasteEditable = null; + + // We need to hide the editable div. We'll use clip:rect for chrome and IE, + // and width/height for FF + var $pasteDiv = jQuery( '
                              ' ).contentEditable( true ); + + /** + * Redirects the paste event into the hidden pasteDiv + */ + function redirectPaste () { + // store the current range + pasteRange = Aloha.getSelection().getRangeAt( 0 ); + pasteEditable = Aloha.activeEditable; + + // store the current scroll position + $pasteDiv.css( { + top: $window.scrollTop(), + left: $window.scrollLeft() - 200 + } ); + + // empty the pasteDiv + $pasteDiv.contents().remove(); + + if ( pasteEditable ) { + // TODO test in IE! + pasteEditable.obj.blur(); + } + + GENTICS.Utils.Dom.setCursorInto( $pasteDiv.get( 0 ) ); + + $pasteDiv.focus(); + }; + + /** + * Gets the pasted content and inserts them into the current active + * editable + */ + function getPastedContent () { + var that = this, + pasteDivContents; + + // insert the content into the editable at the current range + if ( pasteRange && pasteEditable ) { + // activate and focus the editable + // @todo test in IE + //pasteEditable.activate(); + pasteEditable.obj.click(); + + pasteDivContents = $pasteDiv.html(); + + // We need to remove an insidious nbsp that IE inserted into our + // paste div, otherwise it will result in an empty paragraph being + // created right before the pasted content, if the pasted content + // is a paragraph + if ( jQuery.browser.msie && + /^ /.test( pasteDivContents ) ) { + pasteDivContents = pasteDivContents.substring( 6 ); + } + + pasteDivContents = jQuery.trim( pasteDivContents ); + + // Detects a situation where we are about to paste into a selection + // that looks like this:

                              [

                              ... + // The nbsp inside the

                              node was placed there to make the empty + // paragraph visible in HTML5 conformant rendering engines, like + // WebKit. Without the white space, such browsers would correctly + // render an empty

                              as invisible. + // Note that we do not "prop up" otherwise empty paragraph nodes + // using a
                              , as WebKit does, because IE does display empty + // paragraphs which are content-editable and so a
                              results in + // 2 lines instead of 1 being shown inside the paragraph. + // If we detect this situation, we remove the white space so that + // when we paste a new paragraph into the paragraph, it is not be + // split, leaving an empty paragraph on top of the pasted content + // + // We use "/^(\s|%A0)$/.test( escape(" instead of + // "/^(\s| )$/.test( escape(" because it seems that IE + // transforms non-breaking spaces into atomic tokens + var startContainer = pasteRange.startContainer; + if ( startContainer.nodeType == 3 && + startContainer.parentNode.nodeName == 'P' && + startContainer.parentNode.childNodes.length == 1 && + /^(\s|%A0)$/.test( escape( startContainer.data ) ) ) { + startContainer.data = ''; + pasteRange.startOffset = 0; + + // In case ...

                              []

                              + if ( pasteRange.endContainer == startContainer ) { + pasteRange.endOffset = 0; + } + } + + if ( Aloha.queryCommandSupported( 'insertHTML' ) ) { + Aloha.execCommand( 'insertHTML', false, pasteDivContents, + pasteRange ); + } else { + console.error( 'Common.Paste', 'Command "insertHTML" not ' + + 'available. Enable the plugin "common/commands".' ); + } + } + + pasteRange = void 0; + pasteEditable = void 0; + + $pasteDiv.contents().remove(); + }; + + // Public Methods + return Plugin.create( 'paste', { + + settings: {}, + + init: function () { + var that = this; + + jQuery( 'body' ).append( $pasteDiv ); + + // subscribe to the event editableCreated to redirect paste events + // into our hidden pasteDiv + // TODO: move to paste command + // http://support.mozilla.com/en-US/kb/Granting%20JavaScript%20access%20to%20the%20clipboard + // https://code.google.com/p/zeroclipboard/ + Aloha.bind( 'aloha-editable-created', function ( event, editable ) { + // browser-dependent events + if ( jQuery.browser.msie ) { + // We will only us the ugly beforepaste hack if we shall + // not access the clipboard + if ( that.settings.noclipboardaccess ) { + editable.obj.bind( 'beforepaste', function ( event ) { + redirectPaste(); + event.stopPropagation(); + } ); + } else { + // uses the execCommand for IE + editable.obj.bind( 'paste', function ( event ) { + redirectPaste(); + + var range = document.selection.createRange(); + range.execCommand( 'paste' ); + + getPastedContent(); + // We manually unset the metaKey property because + // the smartContentChange method will not process + // this event if the metaKey property is set + event.metaKey = void 0; + + Aloha.activeEditable.smartContentChange( event ); + event.stopPropagation(); + + return false; + } ); + } + } else { + editable.obj.bind( 'paste', function ( event ) { + redirectPaste(); + // We need to accomodate a small amount execution + // window to ensure that pasted content has actually + // been inserted + window.setTimeout( function () { + getPastedContent(); + Aloha.activeEditable.smartContentChange( event ); + event.stopPropagation(); + }, 10 ); + } ); + } + } ); + + // bind a handler to the paste event of the pasteDiv to get the + // pasted content (but do this only once, not for every editable) + if ( jQuery.browser.msie && that.settings.noclipboardaccess ) { + $pasteDiv.bind( 'paste', function ( event ) { + window.setTimeout( function () { + getPastedContent(); + Aloha.activeEditable.smartContentChange( event ); + event.stopPropagation(); + }, 10 ); + } ); + } + }, + + /** + * Register the given paste handler + * @deprecated + * @param pasteHandler paste handler to be registered + */ + register: function ( pasteHandler ) { + console.deprecated( 'Plugins.Paste', 'register() for ' + + 'pasteHandler is deprecated. Use the ContentHandler Plugin ' + + 'instead.' ); + } + + } ); + +} ); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/package.json b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/package.json new file mode 100644 index 00000000..aa3b2af1 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/paste/package.json @@ -0,0 +1,8 @@ +{ + "js": [ + "src/paste.js", + "src/wordpastehandler.js", + "src/oembedpastehandler.js", + "src/genericpastehandler.js" + ] +} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/css/table.css b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/css/table.css new file mode 100644 index 00000000..ecc31e8a --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/css/table.css @@ -0,0 +1,160 @@ +/* reset */ +.aloha-table tr.aloha-table-selectcolumn { + line-height: 0.01em; + height: 12px !important; +} +.aloha-table td.aloha-table-selectrow { + width: 25px !important; +} +.aloha-editable div.aloha-table-wrapper, .aloha-table-wrapper div.aloha-table-cell-editable, +.aloha-table-wrapper .aloha-table-leftuppercorner div, .aloha-table-wrapper tr.aloha-table-selectcolumn td, +.aloha-table-wrapper td.aloha-table-selectrow , .aloha-table-wrapper div.aloha-editable-caption { + margin:0; + padding:0; + border:none; + background:none; + outline: 0px solid transparent; +} + +/* editable wrappers in cells */ +div.aloha-table-cell-editable { + height: 100%; + min-height: 100%; + width: 100%; + z-index: 99999; +} + +/* only show controls when in active state */ +tr.aloha-table-selectcolumn td, +td.aloha-table-selectrow { + visibility: hidden; +} +.aloha-editable-active tr.aloha-table-selectcolumn td, +.aloha-editable-active td.aloha-table-selectrow { + visibility: visible; +} + +/* selection and hover */ +.aloha-cell-selected { + background-color: #80B5F2 !important; + color: #FFF; +} +.aloha-table td.aloha-table-selectrow, +.aloha-table tr.aloha-table-selectcolumn td { + background-color: #D0D0D0; +} +.aloha-table td.aloha-table-selectrow:hover, +.aloha-table tr.aloha-table-selectcolumn td:hover { + background-color: #FFE767; +} + + +/* TODO make custom cursors visible in IE */ +.aloha-table tr.aloha-table-selectcolumn td.aloha-table-leftuppercorner, +.aloha-table tr.aloha-table-selectcolumn td.aloha-table-leftuppercorner:hover { + cursor: default; + background-color: transparent; +} +.aloha-table td .aloha-table-cell-editable { + cursor: text !important; +} +.aloha-table tr.aloha-table-selectcolumn td { + cursor: url(../img/down.cur),default; +} +/* :tODO: make custom cursors visible in IE */ +.aloha-table td.aloha-table-selectrow { + cursor: url(../img/left.cur),default; +} + +/* wai indicator */ +.aloha-table-wrapper div.aloha-wai-red { + background-image: url(../img/wai-red.png); +} + +.aloha-table-wrapper div.aloha-wai-green { + background-image: url(../img/wai-green.png); +} + +.aloha-table td.aloha-table-leftuppercorner div { + cursor: pointer !important; +} + +/* create dialog */ +.aloha-table-createdialog { + z-index: 99999; + position: absolute; + background-color: #F0F0F0; + border: 1px solid #cccccc; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; +} +.aloha-table-createdialog table { + padding: 0px; + margin: 0px; +} +.aloha-table-createdialog table td { + margin: 0px; + padding: 0px; + border: 1px solid #AFAFAF; + font-size: 8px; + width: 15px; + height: 15px; +} +.aloha-table-createdialog table td.hover { + background-color: #1c94c4; +} +.aloha-table-createdialog #table-size-info { + text-align: center; + font-size: 0.8em; +} + +.aloha-table-textarea { + width:90%; + height:100px; + margin-left:5px; + margin-right:5px; +} + +.aloha-table-label { + margin-left:5px; +} + + +/* ui buttons */ +button.aloha-button-table { + background-position: -96px 0 !important; +} +button.aloha-button-addColumnLeft { + background-position: -112px 0 !important; +} +button.aloha-button-addColumnRight { + background-position: -128px 0 !important; +} +button.aloha-button-addRowBefore { + background-position: -144px 0 !important; +} +button.aloha-button-addRowAfter { + background-position: -160px 0 !important; +} +button.aloha-button-deleteRows { + background-position: -176px 0 !important; +} +button.aloha-button-deleteColumns { + background-position: -192px 0 !important; +} +button.aloha-button-row-header { + background-position: -352px 0px !important; +} +button.aloha-button-col-header { + background-position: -368px 0px !important; +} +button.aloha-button-table-caption { + background-position: -320px 0px !important; +} +.aloha-button.aloha-button-merge-cells { + background-position: -384px 0px !important; +} +.aloha-button.aloha-button-split-cells { + background-position: -400px 0px !important; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/down.cur b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/down.cur new file mode 100644 index 0000000000000000000000000000000000000000..a15fb191a75286147ad26d590428f03276e01f70 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)L!3HEN&baUbDaPU;cPEB*=VV?2Ic!PZ?k)`f zL2$v|<&%LToCO|{#S9F5he4R}c>anMpdfpRr>`sfEfzK|HNCy8=_i0f=AJH&ArhC5 z_Iq+MDDW_=|NTGzcr%CVitu8tNQF)=he^H+rVK}!?awguoi+a5HtW^?WAoi#9AwqF WEXBO2xk?IX1cRrmpUXO@geCxkK{dw! literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/left.cur b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/left.cur new file mode 100644 index 0000000000000000000000000000000000000000..5df3fd091b7b5b9baa4d68caa88d74b5168954c1 GIT binary patch literal 55 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

                              P001ei>>3ubr*Ow%_ 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 Wp7#7aeUef|%w2I@2b literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-green.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-green.png new file mode 100644 index 0000000000000000000000000000000000000000..d09089db8d77b14fc6692f364cb8a9f06d47c49d GIT binary patch literal 51404 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 Usin2{A1iwRb>17rDGYFaQ7m literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-red.png b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/img/wai-red.png new file mode 100644 index 0000000000000000000000000000000000000000..89589914b94b6269ffd5f65e4310ef91ef3959ec GIT binary patch literal 48696 zcmc$`1#leCm*;6&WXWP?Su9!1+-+IR%*@QJ7TA)-%*@OdGcz+Yvs%n>`u%Ta_iiq3 zcXn;xmgI*( zIsOz^`tp%HzZeC5)Zy&J)Ez&4g1`9ZfcRO)mh|x@j+3yOlc0mKzLUAF%{L`;YvWJM z91P4%3@l8{OsP2=dmlCg|JW$nnmD=YI~acwFtRl;{w8AXVC-t^VCncxP>~I$dM4}B zCkRqI2NhMfw6obRdp{0JbsZ8x)-D~#=hrF?Z8m^P=i3d1#5x9mWPEDc~4`(x|*$@dR8{w=-bql|Ac z(P`rF{b|r!!1CE2SS=<#6<)c>hXrv;Hn>1iM5aHrzZfPJlcS5%AZO<( z@Z7$h${uTn3%cFSNgU1JJ7R-NMXJaPQU)r#YDzO^!JXuNU9MSi^O+25PxC67o<`O_ z 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 literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-cell.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-cell.js new file mode 100644 index 00000000..237b5bea --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-cell.js @@ -0,0 +1,463 @@ +define( +['aloha/jquery', 'table/table-plugin-utils'], +function (jQuery, Utils) { + /** + * Constructs a TableCell. + * + * @param {DomNode} cell + * A td/th which will be represente by this TableCell. + * @param {Table} tableObj + * The Table which contains the cell. The cell will be + * activated/dactivated with the table. + */ + var TableCell = function(originalTd, tableObj) { + if (null == originalTd) { + originalTd = ' '; + } + + //original Td must be a DOM node so that the this.obj.context property is available + //this transformation will properly handle jQuery objects as well as DOM nodes + originalTd = jQuery( originalTd ).get( 0 ); + + this.obj = jQuery(originalTd); + this.tableObj = tableObj; + + tableObj.cells.push(this); + }; + + /** + * Reference to the jQuery-representation of the wrapping table + * + * @see TableCell.table + */ + TableCell.prototype.tableObj = undefined; + + /** + * Reference to the jQuery td-Object of the cell + */ + TableCell.prototype.obj = undefined; + + /** + * The jQuery wrapper of the cell + */ + TableCell.prototype.wrapper = undefined; + + /** + * Flag if the cell has focus + */ + TableCell.prototype.hasFocus = false; + + TableCell.prototype.activate = function () { + // wrap the created div into the contents of the cell + this.obj.wrapInner( '

                              ' ); + + // create the editable wrapper for the cells + var wrapper = this.obj.children( 'div' ).eq( 0 ); + + wrapper.contentEditable( true ); + wrapper.addClass( 'aloha-table-cell-editable' ); + + var that = this; + + // attach events to the editable div-object + wrapper.bind( 'focus', function ( jqEvent ) { + // ugly workaround for ext-js-adapter problem in ext-jquery-adapter-debug.js:1020 + if ( jqEvent.currentTarget ) { + jqEvent.currentTarget.indexOf = function () { + return -1; + }; + } + that._editableFocus( jqEvent ); + } ); + + wrapper.bind( 'mousedown', function ( jqEvent ) { + // ugly workaround for ext-js-adapter problem in ext-jquery-adapter-debug.js:1020 + if ( jqEvent.currentTarget ) { + jqEvent.currentTarget.indexOf = function () { + return -1; + }; + } + + that._editableMouseDown( jqEvent ); + + that._startCellSelection(); + } ); + wrapper.bind( 'blur', function ( jqEvent ) { that._editableBlur( jqEvent ); }); + wrapper.bind( 'keyup', function ( jqEvent ) { that._editableKeyUp( jqEvent ); }); + wrapper.bind( 'keydown', function ( jqEvent ) { that._editableKeyDown( jqEvent ); }); + wrapper.bind( 'mouseover', function ( jqEvent ) { that._selectCellRange(); }); + + // we will treat the wrapper just like an editable + wrapper.contentEditableSelectionChange( function ( event ) { + Aloha.Selection.onChange( wrapper, event ); + return wrapper; + } ); + + this.obj.bind( 'mousedown', function ( jqEvent ) { + setTimeout( function () { + that.wrapper.trigger( 'focus' ); + }, 1 ); + that.tableObj.selection.unselectCells(); + that._startCellSelection(); + jqEvent.stopPropagation(); + } ); + + if ( this.obj.get( 0 ) ) { + this.obj.get( 0 ).onselectstart = function ( jqEvent ) { return false; }; + } + + // set contenteditable wrapper div + this.wrapper = this.obj.children(); + if ( this.wrapper.get( 0 ) ) { + this.wrapper.get( 0 ).onselectstart = function () { + window.event.cancelBubble = true; + }; + // Disabled the dragging of content, since it makes cell selection difficult + this.wrapper.get( 0 ).ondragstart = function () { return false }; + } + + return this; + }; + + /** + * The deactivate method removes the contenteditable helper div within the + * table-data field and wraps the innerHtml to the outerHTML + * + * @return void + */ + TableCell.prototype.deactivate = function() { + var wrapper = this.obj.children('.aloha-table-cell-editable'); + + if (wrapper.length) { + // get the inner html of the contenteditable div + var innerHtml = wrapper.html(); + + // remove the contenteditable div and its attached events + wrapper.remove(); + + // remove the click event of the + this.obj.unbind('click'); + + if (jQuery.trim(this.obj.attr('class')) == '') { + this.obj.removeAttr('class'); + } + + // set the inner html of the contenteditable div as html for the table-data + // field + this.obj.html(innerHtml); + } + } + + /** + * Native toString-method + * + * @return string name of the namespace + */ + TableCell.prototype.toString = function() { + return 'TableCell'; + }; + + /** + * Focus method for the contentediable div within a table data-field. The method + * requires the event-property Cell as a Cell object. If the + * Cell wasn't activated yet it does all relevant actions to activate the cell. + * + * @param e + * the jquery event object + * @return void + */ + TableCell.prototype._editableFocus = function(e) { + // only do activation stuff if the cell don't has the focus + if (!this.hasFocus) { + // set an internal flag to focus the table + this.tableObj.focus(); + + // add an active-class + this.obj.addClass('aloha-table-cell_active'); + + // set the focus flag + this.hasFocus = true; + + // select the whole content in the table-data field + this._selectAll(this.wrapper.get(0)); + + // unset the selection type + this.tableObj.selection.selectionType = 'cell'; + + } + }; + + /** + * Blur event for the contenteditable div within a table-data field. The method + * requires the event-property TableCell as a TableCell object. It + * sets the hasFocus flag of the cell to false and removes the "active" + * css-class. + * + * @param jqEvent + * the jquery event object + * @return void + */ + TableCell.prototype._editableBlur = function(jqEvent){ + + // reset the focus of the cell + this.hasFocus = false; + + // remove "active class" + this.obj.removeClass('aloha-table-cell-active'); + }; + + /** + * Gives the X (column no) for a cell, after adding colspans + */ + TableCell.prototype._virtualX = function(){ + var $rows = this.tableObj.obj.children().children('tr'); + var rowIdx = this.obj.parent().index(); + var colIdx = this.obj.index(); + return Utils.cellIndexToGridColumn($rows, rowIdx, colIdx); + }; + + /** + * Gives the Y (row no) for a cell, after adding colspans + */ + TableCell.prototype._virtualY = function(){ + return this.obj.parent('tr').index(); + }; + + /** + * Starts the cell selection mode + */ + TableCell.prototype._startCellSelection = function(){ + if(!this.tableObj.selection.cellSelectionMode){ + + //unselect currently selected cells + this.tableObj.selection.unselectCells(); + + // activate cell selection mode + this.tableObj.selection.cellSelectionMode = true; + + //bind a global mouseup event handler to stop cell selection + var that = this; + jQuery('body').bind('mouseup.cellselection', function(){ + that._endCellSelection(); + }); + + this.tableObj.selection.baseCellPosition = [this._virtualY(), this._virtualX()]; + } + }; + + /** + * Ends the cell selection mode + */ + TableCell.prototype._endCellSelection = function(){ + if(this.tableObj.selection.cellSelectionMode){ + this.tableObj.selection.cellSelectionMode = false; + this.tableObj.selection.baseCellPosition = null; + this.tableObj.selection.lastSelectionRange = null; + + this.tableObj.selection.selectionType = 'cell'; + + //unbind the global cell selection event + jQuery('body').unbind('mouseup.cellselection'); + } + }; + + TableCell.prototype._getSelectedRect = function () { + var right = this._virtualX(); + var bottom = this._virtualY(); + var topLeft = this.tableObj.selection.baseCellPosition; + var left = topLeft[1]; + if (left > right) { + left = right; + right = topLeft[1]; + } + var top = topLeft[0]; + if (top > bottom) { + top = bottom; + bottom = topLeft[0]; + } + return {"top": top, "right": right, "bottom": bottom, "left": left}; + }; + + /** + * Toggles selection of cell. + * This works only when cell selection mode is active. + */ + TableCell.prototype._selectCellRange = function(){ + if(!this.tableObj.selection.cellSelectionMode) { + return; + } + + var rect = this._getSelectedRect(); + + var table = this.tableObj; + var $rows = table.obj.children().children('tr'); + var grid = Utils.makeGrid($rows); + + table.selection.selectedCells = []; + var selectClass = table.get('classCellSelected'); + Utils.walkGrid(grid, function (cellInfo, j, i) { + if ( Utils.containsDomCell(cellInfo) ) { + if (i >= rect.top && i <= rect.bottom && j >= rect.left && j <= rect.right) { + jQuery( cellInfo.cell ).addClass(selectClass); + table.selection.selectedCells.push(cellInfo.cell); + } else { + jQuery( cellInfo.cell ).removeClass(selectClass); + } + } + }); + + table.selection.notifyCellsSelected(); + }; + + /** + * Selects all inner-contens of an contentEditable-object + * + * @param editableNode dom-representation of the editable node (div-element) + * @return void + */ + TableCell.prototype._selectAll = function(editableNode) { + var e = (editableNode.jquery) ? editableNode.get(0) : editableNode; + + // Not IE + if (!jQuery.browser.msie) { + var s = window.getSelection(); + // WebKit + if ( s.setBaseAndExtent /*&& e> 0 */ ) { + s.setBaseAndExtent( e, 0, e, Math.max( 0, e.innerText.length - 1 ) ); + } + // Firefox and Opera + else { + // workaround for bug # 42885 + if (window.opera + && e.innerHTML.substring(e.innerHTML.length - 4) == '
                              ') { + e.innerHTML = e.innerHTML + ' '; + } + + var r = document.createRange(); + r.selectNodeContents(e); + s.removeAllRanges(); + s.addRange(r); + } + } + // Some older browsers + else if (document.getSelection) { + var s = document.getSelection(); + var r = document.createRange(); + r.selectNodeContents(e); + s.removeAllRanges(); + s.addRange(r); + } + // IE + else if (document.selection) { + var r = document.body.createTextRange(); + r.moveToElementText(e); + r.select(); + } + }; + + /** + * The mouse-down event for the editable-div in the thd-field. Unselect all + * cells when clicking on the editable-div. + * + * @param jqEvent + * the jquery-event object + * @return void + */ + TableCell.prototype._editableMouseDown = function(jqEvent) { + // deselect all highlighted cells registered in the this.tableObj.selection object + this.tableObj.selection.unselectCells(); + + if (this.tableObj.hasFocus) { + jqEvent.stopPropagation(); + } + }; + + /** + * The key-up event for the editable-div in the td-field. Just check if the div + * is empty and insert an   + * + * @param jqEvent + * the jquery-event object + * @return void + */ + TableCell.prototype._editableKeyUp = function( jqEvent ) { + //TODO do we need to check for empty cells and insert a space? + //this._checkForEmptyEvent(jqEvent); + }; + + /** + * The key-down event for the ediable-div in the td-field. Check if the the div + * is empty and insert an  . Furthermore if cells are selected, unselect + * them. + * + * @param jqEvent + * the jquery-event object + * @return void + */ + TableCell.prototype._editableKeyDown = function(jqEvent) { + var KEYCODE_TAB = 9; + + this._checkForEmptyEvent(jqEvent); + + if ( this.obj[0] === this.tableObj.obj.find('tr:last td:last')[0] ) { + // only add a row on a single key-press of tab (so check + // that alt-, shift- or ctrl-key are NOT pressed) + if (KEYCODE_TAB == jqEvent.keyCode && !jqEvent.altKey && !jqEvent.shiftKey && !jqEvent.ctrlKey) { + // add a row after the current row + this.tableObj.addRow(this.obj.parent().index() + 1); + + // firefox needs this for the first cell of the new row + // to be selected (.focus() doesn't work reliably in + // IE7) + this.tableObj.cells[this.tableObj.cells.length - 1]._selectAll(this.wrapper.get(0)); + + jqEvent.stopPropagation(); + return; + } + } + }; + + /** + * The custom keyup event for a table-cell Checks if the cell is empty and + * inserts a space (\u00a0) + * + * @param e + * the event object which is given by jquery + * @return void + */ + TableCell.prototype._checkForEmptyEvent = function(jqEvent) { + var $wrapper = jQuery(this.wrapper), + text = $wrapper.text(); + + if ( $wrapper.children().length > 0) { + return; + } + + // if empty insert a blank space and blur and focus the wrapper + if ( text === '' ){ + this.wrapper.text('\u00a0'); + this.wrapper.get(0).blur(); + this.wrapper.get(0).focus(); + } + }; + + /** + * Given a cell, will return the container element of the contents + * of the cell. The container element may be the given cell itself, + * or a wrapper element, in the case of activated cells. + * + * @param {DomNode} cell + * the TH/TD of a TableCell that may or may not be actived. + * @return {DomNode} + * the element that contains the contents of the given cell. + */ + TableCell.getContainer = function ( cell ) { + if ( jQuery( cell.firstChild ).hasClass( "aloha-table-cell-editable" ) ) { + return cell.firstChild; + } else { + return cell; + } + }; + + return TableCell; +}); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-create-layer.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-create-layer.js new file mode 100644 index 00000000..fd46f838 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-create-layer.js @@ -0,0 +1,210 @@ +define( +['aloha/jquery'], +function (jQuery) { + /** + * Initialize of the CreateLayer object + */ + CreateLayer = function(TablePlugin){ + this.TablePlugin = TablePlugin; + }; + + /** + * Internal configuration of the create-table panel + */ + CreateLayer.prototype.parameters = { + elemId: 'aloha-table-createLayer', // id of the create-table panel + className: 'aloha-table-createdialog', // class-name of the create-table panel + numX: 10, // Number of cols in the create-layer + numY: 10, // Number of rows in the create-layer vertically + layer: undefined, // Attribute holding the create-layer + target: undefined // the clicktarget which was clicked on (mostly the button of the floatingmenu) + }; + + /** + * The configuration-object for the implementer of the plugin. All keys of + * the "parameters" object could be overwritten within this object and will + * simply be used instead. + */ + CreateLayer.prototype.config = new Object(); + + /** + * Flag wether the CreateLayer is currently visble or not + */ + CreateLayer.prototype.visible = false; + + /** + * This function checks if there is an create-table-layer. If no layer exists, it creates one and puts it into the configuration. + * If the layer was already created it sets the position of the panel and shows it. + * + * @return void + */ + CreateLayer.prototype.show = function(){ + var layer = this.get('layer'); + + // create the panel if the layer doesn't exist + if (layer == null) { + this.create(); + }else { + // or reposition, cleanup and show the layer + this.setPosition(layer); + layer.find('td').removeClass('hover'); + layer.show(); + } + this.visible = true; + }; + + /** + * Creates the div-layer which holds a table with the given number of rows and cols. + * It sets click and mouseover-events to the table data fields + * + * @return void + */ + CreateLayer.prototype.create = function () { + var that = this; + var layer = jQuery('
                              '); + layer.id = this.get('elemId'); + layer.addClass(this.get('className')); + + var table = jQuery('
                              '); + table.css('width', (this.get('numX') + 6) * 15); + var tr; + var td; + + for (var i = 0; i < this.get('numY'); i++) { + tr = jQuery(''); + + for (var j = 0; j < this.get('numX'); j++) { + td = jQuery('\u00a0'); + + if (i == 0 && j == 0) { + td.addClass('hover'); + } + + td.bind('mouseover', {rowId: i, colId: j}, function(e) { + that.handleMouseOver(e, table); + }); + + td.bind('click', {rowId: i, colId: j}, function(e){ + var rows = e.data.rowId + 1; + var cols = e.data.colId + 1; + + that.TablePlugin.createTable(cols, rows); + that.hide(); + }); + + tr.append(td); + } + table.append(tr); + } + layer.append(table); + + // set attributes + this.set('layer', layer); + this.setPosition(); + + // stop bubbling the click on the create-dialog up to the body event + layer.bind('click', function(e) { + e.stopPropagation(); + }).mousedown(function(e) { + e.stopPropagation(); + }); + + // append layer to body and + // hide the create layer if user clicks anywhere in the body + jQuery('body').append(layer).bind('click', function(e) { + if (e.target != that.get('target') && that.visible) { + that.hide(); + } + }); + }; + + /** + * handles the mose over state for a cell + * @param e event object + * @param table the aeffected table + * @return void + */ + CreateLayer.prototype.handleMouseOver = function(e, table) { + var rowId = e.data.rowId; + var colId = e.data.colId; + var innerRows = table.find('tr'); + + for (var n = 0; n <= innerRows.length; n++) { + var innerCells = jQuery(innerRows[n]).find('td'); + + for (var k = 0; k <= innerCells.length; k++) { + if (n <= rowId && k <= colId) { + jQuery(innerCells[k]).addClass('hover'); + } else { + jQuery(innerCells[k]).removeClass('hover'); + } + } + } + }; + + /** + * Sets the "left" and "top" style-attributes according to the clicked target-button + * + * @return void + */ + CreateLayer.prototype.setPosition = function() { + var targetObj = jQuery(this.get('target')); + var pos = targetObj.offset(); + this.get('layer').css('left', pos.left + 'px'); + this.get('layer').css('top', (pos.top + targetObj.height()) + 'px'); + }; + + /** + * Hides the create-table panel width the jQuery-method hide() + * + * @see jQuery().hide() + * @return void + */ + CreateLayer.prototype.hide = function() { + this.get('layer').hide(); + this.visible = false; + }; + + /** + * The "get"-method returns the value of the given key. First it searches in the + * config for the property. If there is no property with the given name in the + * "config"-object it returns the entry associated with in the parameters-object + * + * @param property + * @return void + */ + CreateLayer.prototype.get = function(property) { + // return param from the config + if (this.config[property]) { + return this.config[property]; + } + // if config-param was not found return param from the parameters-object + if (this.parameters[property]) { + return this.parameters[property]; + } + return undefined; + }; + + /** + * The "set"-method takes a key and a value. It checks if there is a key-value + * pair in the config-object. If so it saves the data in the config-object. If + * not it saves the data in the parameters-object. + * + * @param key + * the key which should be set + * @param value + * the value which should be set for the associated key + */ + CreateLayer.prototype.set = function (key, value) { + // if the key already exists in the config-object, set it to the config-object + if (this.config[key]) { + this.config[key] = value; + + // otherwise "add" it to the parameters-object + }else{ + this.parameters[key] = value; + } + }; + + return CreateLayer; +}); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin-utils.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin-utils.js new file mode 100644 index 00000000..458a161a --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin-utils.js @@ -0,0 +1,355 @@ +define( +['aloha/jquery'], +function ($) { + var Utils = { + /** + * Translates the DOM-Element column offset of a table-cell to the + * column offset of a grid-cell, which is the column index adjusted + * by other cells' rowspan and colspan values. + * + * @param rows the rows of a table as an array or jQuery object + * @param rowIdx the index in rows of the cell to get the grid column index of + * @param colIdx the index in rows[row].cells of the cell to get the grid column index of + * @return the grid column index of the cell at the given rowIdx and colIdx, or null + * if the given rowIdx and colIdx coordinates point to a cell outside of the table. + */ + 'cellIndexToGridColumn': function (rows, rowIdx, colIdx) { + var gridColumn = null; + Utils.walkCells(rows, function(ri, ci, walkedGridColumn, rowspan, colspan) { + if (ri === rowIdx && ci === colIdx) { + gridColumn = walkedGridColumn; + return false; + } + }); + return gridColumn; + }, + /** + * Walks the table-cells of the table represented by the given rows, + * invoking the given callback for each. + * @param callback will receive the following arguments + * o ri the row index of the table-cell + * o ci the column index of the table-cell as the offset of the DOM-Element + * o gridCi the column index of the table-cell in a virtual grid that overlays the table (see makeGrid()) + * o colspan the colspan attribute of the table-cell (as a number) + * o rowspan the rowspan attribute of the table-cell (as a number) + * returning false from the callback will terminate the walk early. + * @return void + */ + 'walkCells': function (rows, callback) { + var adjust = []; + for (var ri = 0; ri < rows.length; ri++) { + var cells = rows[ri].cells; + var skip = 0; + for (var ci = 0; ci < cells.length; ci++) { + var cell = cells[ci]; + var colspan = Utils.colspan(cell); + var rowspan = Utils.rowspan(cell); + + while (adjust[ci + skip]) { + adjust[ci + skip] -= 1; + skip += 1; + } + + if (false === callback(ri, ci, ci + skip, colspan, rowspan)) { + return; + } + + for (var i = 0; i < colspan; i++) { + if (adjust[ci + skip + i] ) { + throw "an impossible case has occurred"; + } + adjust[ci + skip + i] = rowspan - 1; + } + skip += colspan - 1; + } + for (; ci + skip < adjust.length; skip++) { + if (adjust[ci + skip]) { + adjust[ci + skip] -= 1; + } + } + } + }, + /** + * Makes a grid out of the table represented by the given rows. A + * grid will contain one or multiple grid-cells for each table-cell. + * A table-cell that has a colspan or rowspan greater than one will + * be represented by multiple cells (colspan*rowspan) in the + * grid. + * @parm rows either an array or an jQuery object holding the DOM + * rows of the table. + * @return the table translated to a grid of the form + * [ [cell11, cell12, cell13, ...], + * [cell21, cell22, cell23, ...], + * ... ] + * where each grid-cell is an object containing the following members: + * cell: the DOM object in the table that is rendered into the grid-cell + * colspan: the colspan attribute of the DOM object (as a number) + * rowspan: the rowspan attribute of the DOM object (as a number) + * spannedX: the row offset of the grid-cell in the table-cell (0 based) + * spannedY: the column offset of the grid-cll in the table-cell (0 based) + */ + 'makeGrid': function (rows) { + var grid = []; + Utils.walkCells(rows, function(ri, ci, gridCi, colspan, rowspan) { + var cell = rows[ri].cells[ci]; + for (var spannedY = 0; spannedY < rowspan; spannedY++) { + grid[ri + spannedY] = grid[ri + spannedY] || []; + for (var spannedX = 0; spannedX < colspan; spannedX++) { + grid[ri + spannedY][gridCi + spannedX] = { + 'cell' : cell, + 'colspan' : colspan, + 'rowspan' : rowspan, + 'spannedX': spannedX, + 'spannedY': spannedY + }; + } + } + }); + return grid; + }, + /** + * A grid-cell is said to contain a dom-cell if it is located in the + * upper-left corner of a table-cell. A table-cell may have a + * rowspan and colspan, and as such may be comprised of several + * grid-cells, of which only one (the upper-left corner one) + * contains a dom-cell. + * @param cellInfo a cell in the grid returned by makeGrid() + * @return whether the given grid-cell maps to a dom-cell + */ + 'containsDomCell': function (cellInfo) { + return 0 === cellInfo.spannedX && 0 === cellInfo.spannedY; + }, + /** + * A grid-cell may not contain a dom-cell (due to rowspan and + * colspan). If this function is given the coordinates of such a + * grid-cell, it will look to the left of the grid-cell, until it + * finds a grid-cell that contains a dom-cell and returns the + * DOM-Element of it. + * + * This function is useful to insert something into the DOM next to + * or in place of the grid-cell. + * + * @param grid the grid of the table (see makeGrid()) + * @param ri the row index into the grid + * @param ci the column index into the grid + * @return the DOM-Element either at or to the left of the grid-cell + * a the given coordinates. + */ + 'leftDomCell': function (grid, ri, gridCi) { + do { + var cellInfo = grid[ri][gridCi]; + if ( 0 === cellInfo.spannedY ) { + return cellInfo.cell; + } + gridCi -= cellInfo.spannedX + 1; + } while (gridCi >= 0); + return null; + }, + /** + * Given a cell of a table (td/th) with a colspan or rowspan + * greater than one, will set the rowspan and colspan of the + * cell to one and insert empty cells where the original cell + * spanned (the number of cells allocated with createCell will + * be rowspan * colspan - 1). + * + * @param cell + * the cell to split + * @param createCell + * a callback that will be invoked rowspan * colspan - 1 + * times, and which must return a table cell (td/th) that + * will be inserted into the table + */ + 'splitCell': function (cell, createCell) { + var $cell = $(cell); + var colspan = Utils.colspan( cell ); + var rowspan = Utils.rowspan( cell ); + + //catch the most common case early + if (1 === colspan && 1 === rowspan) { + return; + } + + var $row = $cell.parent(); + var $rows = $row.parent().children(); + var rowIdx = $row.index(); + var colIdx = $cell.index(); + var grid = Utils.makeGrid($rows); + var gridColumn = Utils.cellIndexToGridColumn($rows, rowIdx, colIdx); + for (var i = 0; i < rowspan; i++) { + for (var j = (0 === i ? 1 : 0); j < colspan; j++) { + var leftCell = Utils.leftDomCell(grid, rowIdx + i, gridColumn); + if (null == leftCell) { + $rows.eq(rowIdx + i).prepend(createCell()); + } else { + $( leftCell ).after(createCell()); + } + } + } + $cell.removeAttr('colspan'); + $cell.removeAttr('rowspan'); + }, + /** + * @param cell + * the DOM node for a table cell (td/th) + * @return + * a numeric value indicating the number of rows the cell spans + */ + 'rowspan': function (cell) { + return parseInt( $( cell ).attr('rowspan') ) || 1; + }, + /** + * @param cell + * the DOM node for a table cell (td/th) + * @return + * a numeric value indicating the number of columns the cell spans + */ + 'colspan': function (cell) { + return parseInt( $( cell ).attr('colspan') ) || 1; + }, + /** + * Calls the given callback with each object in the given + * two-dimensional array. + * + * @param grid + * A two-dimensional array. + * @param callback + * Invoked with each item in the given two-dimensional array. + * Accepts the following parameters: + * o item an item in the given two-dimensional array + * o x the offset in the nested array (horizontal axis) + * o y the offset in the outer array (veritcal axis) + * If the callback returns a value identical to false, + * the walk will be aborted early. + */ + 'walkGrid': function (grid, callback) { + for ( var i = 0; i < grid.length; i++ ) { + for ( var j = 0; j < grid[i].length; j++ ) { + if ( false === callback( grid[ i ][ j ], j, i ) ) { + return; + } + } + } + }, + /** + * Walks the cells of the given grid inside the given + * coordinates. + * + * @param {array} grid + * A two-dimensional array. + * @param {object} rect + * Must have the properties top, left, bottom, right + * each of which referring to a coordinate in the given grid. + * @param {function} callback + * A callback to invoke for each item in the given + * two-dimensional array. See walkGrid() for the + * specification of this parameter. + */ + 'walkGridInsideRect': function ( grid, rect, callback ) { + Utils.walkGrid( grid, function ( cellInfo, x, y ) { + if ( y >= rect.top && y < rect.bottom && x >= rect.left && x < rect.right ) { + return callback( cellInfo, x, y ); + } + }); + }, + /** + * Slices leading null or undefined items off of an array + * + * @param array + * the array to slice null or undefined items off from + * @return + * a new array with the remaining items + */ + 'leftTrimArray': function ( array ) { + for (var i = 0; i < array.length; i++) { + if ( null != array[i] ) { + return array.slice( i, array.length ); + } + } + return []; + }, + /** + * Given a two-dimensional array, will determine the smallest + * possible contour that contains all items for which + * hasCountour returns true. + * + * @param grid + * A two-dimensional array + * @param hasContour + * Invoked with each item in the given two dimensional array. + * Accepts the following parameters: + * o item an item in the given two-dimensional array + * o x the offset in the nested array (horizontal axis) + * o y the offset in the outer array (veritcal axis) + * Returns a boolean value indicating whether the item is + * considered to have a contour. + * @return + * A set of arrays that indicate a contour + * top: an array of the smallest vertical offsets + * right: an array of the greatest horizontal offsets + * bottom: an array of the greatest vertical offsets + * left: an array of the smallest horizontal offsets + */ + 'makeContour': function ( grid, hasContour ) { + var left = []; + var right = []; + var top = []; + var bottom = []; + Utils.walkGrid( grid, function ( item, x, y ) { + if ( hasContour( item, x, y ) ) { + if ( null == left[ y ] || x < left[ y ] ) { + left[ y ] = x; + } + if ( null == right[ y ] || x > right[ y ] ) { + right[ y ] = x; + } + if ( null == top[ x ] || y < top[ x ] ) { + top[ x ] = y; + } + if ( null == bottom[ x ] || y > bottom[ x ] ) { + bottom[ x ] = y; + } + } + }); + left = Utils.leftTrimArray(left); + right = Utils.leftTrimArray(right); + top = Utils.leftTrimArray(top); + bottom = Utils.leftTrimArray(bottom); + return {'left': left, 'right': right, 'top': top, 'bottom': bottom}; + }, + /** + * Returns the index of the first item that doesn't match the given value + * + * @param array + * An array that contains arbitrary items + * @param but + * A value to ignore while searching in the given array + * @return + * The offset of the first item in the given array that doesn't match the given value. + * If no such item was found, -1 is returned. + */ + 'indexOfAnyBut': function ( array, but ) { + for ( var i = 0; i < array.length; i++ ) { + if ( but !== array[ i ] ) { + return i; + } + } + return -1; + }, + /** + * @param array + * an array of integers + * @return + * true if each item in the given array has a + * difference to its neighbor of exactly 1 + */ + 'isConsecutive': function ( array ) { + for ( var i = 1; i < array.length; i++ ) { + if ( 1 !== Math.abs( array[ i ] - array[ i - 1 ] ) ) { + return false; + } + } + return true; + } + }; + return Utils; +}); diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin.js b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin.js new file mode 100644 index 00000000..c8feee57 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/common/table/lib/table-plugin.js @@ -0,0 +1,1498 @@ +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com - way to over-lawyer it up Andrew :/ +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +define( [ + 'aloha', + 'aloha/jquery', + 'aloha/plugin', + 'aloha/pluginmanager', + 'aloha/floatingmenu', + 'i18n!table/nls/i18n', + 'i18n!aloha/nls/i18n', + 'table/table-create-layer', + 'table/table', + 'table/table-plugin-utils', + 'css!table/css/table.css' +], function( Aloha, + jQuery, + Plugin, + PluginManager, + FloatingMenu, + i18n, + i18nCore, + CreateLayer, + Table, + Utils ) { + + var GENTICS = window.GENTICS; + + /** + * Register the TablePlugin as Aloha.Plugin + */ + var TablePlugin = new Plugin('table'); + + /** + * The Create-Layer Object of the TablePlugin + * + * @see Table.CreateLayer + */ + TablePlugin.createLayer = undefined; + + /** + * Configure the available languages + */ + TablePlugin.languages = ['en', 'de', 'fr', 'eo', 'fi', 'ru', 'it', 'pl']; + + /** + * default button configuration + */ + TablePlugin.config = [ 'table' ]; + + /** + * An Array which holds all newly created tables contains DOM-Nodes of + * table-objects + */ + TablePlugin.TableRegistry = new Array(); + + /** + * Holds the active table-object + */ + TablePlugin.activeTable = undefined; + + /** + * parameters-objects for tables + * + * @param className + * The class of activated tables + */ + TablePlugin.parameters = { + className : 'aloha-table', // class of editable tables + classSelectionRow : 'aloha-table-selectcolumn', // class for the upper table-row to select columns + classSelectionColumn : 'aloha-table-selectrow', // class for the left bound table-cells to select rows + classLeftUpperCorner : 'aloha-table-leftuppercorner', // class for the left upper corner cell + classTableWrapper : 'aloha-table-wrapper', // class of the outest table-wrapping div + classCellSelected : 'aloha-cell-selected', // class of cell which are selected (row/column selection) + waiRed : 'aloha-wai-red', // class that shows wai of div + waiGreen : 'aloha-wai-green', // class that shows wai of div + selectionArea : 10 // width/height of the selection rows (in pixel) + }; + + /** + * @hide + * {name:'green', text:'Green',tooltip:'Green',iconClass:'GENTICS_table GENTICS_button_green',cssClass:'green'} + */ + TablePlugin.checkConfig = function (c){ + + if (typeof c == 'object' && c.length) { + var newC = []; + + for (var i = 0; i < c.length; i++) { + if (c[i]) { + newC.push({ + text : c[i].text ? c[i].text : c[i].name, + tooltip : c[i].tooltip ? c[i].tooltip : c[i].text, + iconClass : c[i].iconClass ? c[i].iconClass : 'aloha-button-' + c[i].name, + cssClass : c[i].cssClass ? c[i].cssClass : c[i].name + }); + } + } + + c = newC; + } else { + c = []; + } + + return c; + }; + + /** + * Init method of the Table-plugin transforms all tables in the document + * + * @return void + */ + TablePlugin.init = function() { + + // apply settings + this.tableConfig = this.checkConfig(this.tableConfig||this.settings.tableConfig); + this.columnConfig = this.checkConfig(this.columnConfig||this.settings.columnConfig); + this.rowConfig = this.checkConfig(this.rowConfig||this.settings.rowConfig); + + // add reference to the create layer object + this.createLayer = new CreateLayer( this ); + + var that = this; + + // subscribe for the 'editableActivated' event to activate all tables in the editable + Aloha.bind( 'aloha-editable-created', function ( event, editable ) { + + // add a mousedown event to all created editables to check if focus leaves a table + editable.obj.bind( 'mousedown', function ( jqEvent ) { + TablePlugin.setFocusedTable( undefined ); + } ); + + editable.obj.find( 'table' ).each( function () { + // only convert tables which are editable + if ( that.isEditableTable( this ) && + !TablePlugin.isWithinTable( this ) ) { + var table = new Table( this, TablePlugin ); + table.parentEditable = editable; + // table.activate(); + TablePlugin.TableRegistry.push( table ); + } + + TablePlugin.checkForNestedTables( editable.obj ); + } ); + } ); + + // initialize the table buttons + this.initTableButtons(); + + Aloha.bind( 'aloha-table-selection-changed', function () { + if ( null != TablePlugin.activeTable && + 0 !== TablePlugin.activeTable.selection.selectedCells.length ) { + TablePlugin.updateFloatingMenuScope(); + } + }); + + Aloha.bind( 'aloha-selection-changed', function (event, rangeObject) { + // this case probably occurs when the selection is empty? + if ( null == rangeObject.startContainer ) { + return; + } + + if (Aloha.activeEditable) { + // get Plugin configuration + var config = that.getEditableConfig( Aloha.activeEditable.obj ); + + // show hide buttons regarding configuration and DOM position + if ( jQuery.inArray('table', config) != -1 && Aloha.Selection.mayInsertTag('table') ) { + that.createTableButton.show(); + } else { + that.createTableButton.hide(); + } + + var table = rangeObject.findMarkup(function () { + return this.nodeName.toLowerCase() == 'table'; + }, Aloha.activeEditable.obj); + + if ( that.activeTable ) { + // check wheater we are inside a table + if ( table ) { + TablePlugin.updateFloatingMenuScope(); + } else { + //reset cell selection flags + that.activeTable.selection.cellSelectionMode = false; + that.activeTable.selection.baseCellPosition = null; + that.activeTable.selection.lastSelectionRange = null; + + that.activeTable.focusOut(); + } + } + + // TODO this should not be necessary here! + FloatingMenu.doLayout(); + } + }); + + // subscribe for the 'editableActivated' event to activate all tables in the editable + Aloha.bind( 'aloha-editable-activated', function (event, props) { + props.editable.obj.find('table').each(function () { + // shortcut for TableRegistry + var tr = TablePlugin.TableRegistry; + for (var i = 0; i < tr.length; i++) { + if (tr[i].obj.attr('id') == jQuery(this).attr('id')) { + // activate the table + tr[i].activate(); + // and continue with the next table tag + return true; + } + } + + // if we come here, we did not find the table in our registry, so we need to create a new one + // only convert tables which are editable + if ( that.isEditableTable( this ) && + !TablePlugin.isWithinTable( this ) ) { + var table = new Table( this, TablePlugin ); + table.parentEditable = props.editable; + table.activate(); + TablePlugin.TableRegistry.push( table ); + } + + TablePlugin.checkForNestedTables( props.editable.obj ); + }); + }); + + // subscribe for the 'editableDeactivated' event to deactivate all tables in the editable + Aloha.bind( 'aloha-editable-deactivated', function (event, properties) { + if (TablePlugin.activeTable) { + TablePlugin.activeTable.selection.unselectCells(); + } + TablePlugin.setFocusedTable(undefined); + + // shortcut for TableRegistry + var tr = TablePlugin.TableRegistry; + for (var i = 0; i < tr.length; i++) { + // activate the table + tr[i].deactivate(); + } + }); + + Aloha.bind( 'aloha-smart-content-changed', function ( event ) { + if ( Aloha.activeEditable ) { + Aloha.activeEditable.obj.find( 'table' ).each( function () { + if ( TablePlugin.indexOfTableInRegistry( this ) == -1 && + !TablePlugin.isWithinTable( this ) ) { + this.id = GENTICS.Utils.guid(); + + var table = new Table( this, TablePlugin ); + table.parentEditable = Aloha.activeEditable; + TablePlugin.TableRegistry.push( table ); + table.activate(); + } + + TablePlugin.checkForNestedTables( Aloha.activeEditable.obj ); + } ); + } + } ); + + if ( this.settings.summaryinsidebar ) { + Aloha.ready( function () { + that.initSidebar( Aloha.Sidebar.right.show() ); + } ); + } + }; + + //namespace prefix for this plugin + var tableNamespace = 'aloha-table'; + + function nsSel () { + var stringBuilder = [], prefix = tableNamespace; + jQuery.each(arguments, function () { stringBuilder.push('.' + (this == '' ? prefix : prefix + '-' + this)); }); + return stringBuilder.join(' ').trim(); + }; + + //Creates string with this component's namepsace prefixed the each classname + function nsClass () { + var stringBuilder = [], prefix = tableNamespace; + jQuery.each(arguments, function () { stringBuilder.push(this == '' ? prefix : prefix + '-' + this); }); + return stringBuilder.join(' ').trim(); + }; + + TablePlugin.initSidebar = function(sidebar) { + var pl = this; + pl.sidebar = sidebar; + sidebar.addPanel({ + + id : nsClass('sidebar-panel'), + title : i18n.t('table.sidebar.title'), + content : '', + expanded : true, + activeOn : 'table', + + onInit : function () { + var that = this, + content = this.setContent( + '' + + '').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body'); + e2 = $('').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body'); + scrollbar_width = e1.width() - e2.width(); + e1.add(e2).remove(); + } + else { + e1 = $('
                              ').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: 0 }) + .prependTo('body').append('
                              ').find('div').css({ width: '100%', height: 200 }); + scrollbar_width = 100 - e1.width(); + e1.parent().remove(); + } + }); + $.jstree.plugin("ui", { + __init : function () { + this.data.ui.selected = $(); + this.data.ui.last_selected = false; + this.data.ui.hovered = null; + this.data.ui.to_select = this.get_settings().ui.initially_select; + + this.get_container() + .delegate("a", "click.jstree", $.proxy(function (event) { + event.preventDefault(); + event.currentTarget.blur(); + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.select_node(event.currentTarget, true, event); + } + }, this)) + .delegate("a", "mouseenter.jstree", $.proxy(function (event) { + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.hover_node(event.target); + } + }, this)) + .delegate("a", "mouseleave.jstree", $.proxy(function (event) { + if(!$(event.currentTarget).hasClass("jstree-loading")) { + this.dehover_node(event.target); + } + }, this)) + .bind("reopen.jstree", $.proxy(function () { + this.reselect(); + }, this)) + .bind("get_rollback.jstree", $.proxy(function () { + this.dehover_node(); + this.save_selected(); + }, this)) + .bind("set_rollback.jstree", $.proxy(function () { + this.reselect(); + }, this)) + .bind("close_node.jstree", $.proxy(function (event, data) { + var s = this._get_settings().ui, + obj = this._get_node(data.rslt.obj), + clk = (obj && obj.length) ? obj.children("ul").find("a.jstree-clicked") : $(), + _this = this; + if(s.selected_parent_close === false || !clk.length) { return; } + clk.each(function () { + _this.deselect_node(this); + if(s.selected_parent_close === "select_parent") { _this.select_node(obj); } + }); + }, this)) + .bind("delete_node.jstree", $.proxy(function (event, data) { + var s = this._get_settings().ui.select_prev_on_delete, + obj = this._get_node(data.rslt.obj), + clk = (obj && obj.length) ? obj.find("a.jstree-clicked") : [], + _this = this; + clk.each(function () { _this.deselect_node(this); }); + if(s && clk.length) { + data.rslt.prev.each(function () { + if(this.parentNode) { _this.select_node(this); return false; /* if return false is removed all prev nodes will be selected */} + }); + } + }, this)) + .bind("move_node.jstree", $.proxy(function (event, data) { + if(data.rslt.cy) { + data.rslt.oc.find("a.jstree-clicked").removeClass("jstree-clicked"); + } + }, this)); + }, + defaults : { + select_limit : -1, // 0, 1, 2 ... or -1 for unlimited + select_multiple_modifier : "ctrl", // on, or ctrl, shift, alt + select_range_modifier : "shift", + selected_parent_close : "select_parent", // false, "deselect", "select_parent" + selected_parent_open : true, + select_prev_on_delete : true, + disable_selecting_children : false, + initially_select : [] + }, + _fn : { + _get_node : function (obj, allow_multiple) { + if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; } + var $obj = $(obj, this.get_container()); + if($obj.is(".jstree") || obj == -1) { return -1; } + $obj = $obj.closest("li", this.get_container()); + return $obj.length ? $obj : false; + }, + _ui_notify : function (n, data) { + if(data.selected) { + this.select_node(n, false); + } + }, + save_selected : function () { + var _this = this; + this.data.ui.to_select = []; + this.data.ui.selected.each(function () { if(this.id) { _this.data.ui.to_select.push("#" + this.id.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); } }); + this.__callback(this.data.ui.to_select); + }, + reselect : function () { + var _this = this, + s = this.data.ui.to_select; + s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); + // this.deselect_all(); WHY deselect, breaks plugin state notifier? + $.each(s, function (i, val) { if(val && val !== "#") { _this.select_node(val); } }); + this.data.ui.selected = this.data.ui.selected.filter(function () { return this.parentNode; }); + this.__callback(); + }, + refresh : function (obj) { + this.save_selected(); + return this.__call_old(); + }, + hover_node : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + //if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; } + if(!obj.hasClass("jstree-hovered")) { this.dehover_node(); } + this.data.ui.hovered = obj.children("a").addClass("jstree-hovered").parent(); + this._fix_scroll(obj); + this.__callback({ "obj" : obj }); + }, + dehover_node : function () { + var obj = this.data.ui.hovered, p; + if(!obj || !obj.length) { return false; } + p = obj.children("a").removeClass("jstree-hovered").parent(); + if(this.data.ui.hovered[0] === p[0]) { this.data.ui.hovered = null; } + this.__callback({ "obj" : obj }); + }, + select_node : function (obj, check, e) { + obj = this._get_node(obj); + if(obj == -1 || !obj || !obj.length) { return false; } + var s = this._get_settings().ui, + is_multiple = (s.select_multiple_modifier == "on" || (s.select_multiple_modifier !== false && e && e[s.select_multiple_modifier + "Key"])), + is_range = (s.select_range_modifier !== false && e && e[s.select_range_modifier + "Key"] && this.data.ui.last_selected && this.data.ui.last_selected[0] !== obj[0] && this.data.ui.last_selected.parent()[0] === obj.parent()[0]), + is_selected = this.is_selected(obj), + proceed = true, + t = this; + if(check) { + if(s.disable_selecting_children && is_multiple && + ( + (obj.parentsUntil(".jstree","li").children("a.jstree-clicked").length) || + (obj.children("ul").find("a.jstree-clicked:eq(0)").length) + ) + ) { + return false; + } + proceed = false; + switch(!0) { + case (is_range): + this.data.ui.last_selected.addClass("jstree-last-selected"); + obj = obj[ obj.index() < this.data.ui.last_selected.index() ? "nextUntil" : "prevUntil" ](".jstree-last-selected").andSelf(); + if(s.select_limit == -1 || obj.length < s.select_limit) { + this.data.ui.last_selected.removeClass("jstree-last-selected"); + this.data.ui.selected.each(function () { + if(this !== t.data.ui.last_selected[0]) { t.deselect_node(this); } + }); + is_selected = false; + proceed = true; + } + else { + proceed = false; + } + break; + case (is_selected && !is_multiple): + this.deselect_all(); + is_selected = false; + proceed = true; + break; + case (!is_selected && !is_multiple): + if(s.select_limit == -1 || s.select_limit > 0) { + this.deselect_all(); + proceed = true; + } + break; + case (is_selected && is_multiple): + this.deselect_node(obj); + break; + case (!is_selected && is_multiple): + if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { + proceed = true; + } + break; + } + } + if(proceed && !is_selected) { + if(!is_range) { this.data.ui.last_selected = obj; } + obj.children("a").addClass("jstree-clicked"); + if(s.selected_parent_open) { + obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); }); + } + this.data.ui.selected = this.data.ui.selected.add(obj); + this._fix_scroll(obj.eq(0)); + this.__callback({ "obj" : obj, "e" : e }); + } + }, + _fix_scroll : function (obj) { + var c = this.get_container()[0], t; + if(c.scrollHeight > c.offsetHeight) { + obj = this._get_node(obj); + if(!obj || obj === -1 || !obj.length || !obj.is(":visible")) { return; } + t = obj.offset().top - this.get_container().offset().top; + if(t < 0) { + c.scrollTop = c.scrollTop + t - 1; + } + if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0) > c.offsetHeight) { + c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0)); + } + } + }, + deselect_node : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + if(this.is_selected(obj)) { + obj.children("a").removeClass("jstree-clicked"); + this.data.ui.selected = this.data.ui.selected.not(obj); + if(this.data.ui.last_selected.get(0) === obj.get(0)) { this.data.ui.last_selected = this.data.ui.selected.eq(0); } + this.__callback({ "obj" : obj }); + } + }, + toggle_select : function (obj) { + obj = this._get_node(obj); + if(!obj.length) { return false; } + if(this.is_selected(obj)) { this.deselect_node(obj); } + else { this.select_node(obj); } + }, + is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; }, + get_selected : function (context) { + return context ? $(context).find("a.jstree-clicked").parent() : this.data.ui.selected; + }, + deselect_all : function (context) { + var ret = context ? $(context).find("a.jstree-clicked").parent() : this.get_container().find("a.jstree-clicked").parent(); + ret.children("a.jstree-clicked").removeClass("jstree-clicked"); + this.data.ui.selected = $([]); + this.data.ui.last_selected = false; + this.__callback({ "obj" : ret }); + } + } + }); + // include the selection plugin by default + $.jstree.defaults.plugins.push("ui"); +})(jQuery); +//*/ + +/* + * jsTree CRRM plugin + * Handles creating/renaming/removing/moving nodes by user interaction. + */ +(function ($) { + $.jstree.plugin("crrm", { + __init : function () { + this.get_container() + .bind("move_node.jstree", $.proxy(function (e, data) { + if(this._get_settings().crrm.move.open_onmove) { + var t = this; + data.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function () { + t.open_node(this, false, true); + }); + } + }, this)); + }, + defaults : { + input_width_limit : 200, + move : { + always_copy : false, // false, true or "multitree" + open_onmove : true, + default_position : "last", + check_move : function (m) { return true; } + } + }, + _fn : { + _show_input : function (obj, callback) { + obj = this._get_node(obj); + var rtl = this._get_settings().core.rtl, + w = this._get_settings().crrm.input_width_limit, + w1 = obj.children("ins").width(), + w2 = obj.find("> a:visible > ins").width() * obj.find("> a:visible > ins").length, + t = this.get_text(obj), + h1 = $("
                              ", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"), + h2 = obj.css("position","relative").append( + $("", { + "value" : t, + "class" : "jstree-rename-input", + // "size" : t.length, + "css" : { + "padding" : "0", + "border" : "1px solid silver", + "position" : "absolute", + "left" : (rtl ? "auto" : (w1 + w2 + 4) + "px"), + "right" : (rtl ? (w1 + w2 + 4) + "px" : "auto"), + "top" : "0px", + "height" : (this.data.core.li_height - 2) + "px", + "lineHeight" : (this.data.core.li_height - 2) + "px", + "width" : "150px" // will be set a bit further down + }, + "blur" : $.proxy(function () { + var i = obj.children(".jstree-rename-input"), + v = i.val(); + if(v === "") { v = t; } + h1.remove(); + i.remove(); // rollback purposes + this.set_text(obj,t); // rollback purposes + this.rename_node(obj, v); + callback.call(this, obj, v, t); + obj.css("position",""); + }, this), + "keyup" : function (event) { + var key = event.keyCode || event.which; + if(key == 27) { this.value = t; this.blur(); return; } + else if(key == 13) { this.blur(); return; } + else { + h2.width(Math.min(h1.text("pW" + this.value).width(),w)); + } + }, + "keypress" : function(event) { + var key = event.keyCode || event.which; + if(key == 13) { return false; } + } + }) + ).children(".jstree-rename-input"); + this.set_text(obj, ""); + h1.css({ + fontFamily : h2.css('fontFamily') || '', + fontSize : h2.css('fontSize') || '', + fontWeight : h2.css('fontWeight') || '', + fontStyle : h2.css('fontStyle') || '', + fontStretch : h2.css('fontStretch') || '', + fontVariant : h2.css('fontVariant') || '', + letterSpacing : h2.css('letterSpacing') || '', + wordSpacing : h2.css('wordSpacing') || '' + }); + h2.width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); + }, + rename : function (obj) { + obj = this._get_node(obj); + this.__rollback(); + var f = this.__callback; + this._show_input(obj, function (obj, new_name, old_name) { + f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name }); + }); + }, + create : function (obj, position, js, callback, skip_rename) { + var t, _this = this; + obj = this._get_node(obj); + if(!obj) { obj = -1; } + this.__rollback(); + t = this.create_node(obj, position, js, function (t) { + var p = this._get_parent(t), + pos = $(t).index(); + if(callback) { callback.call(this, t); } + if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); } + if(!skip_rename) { + this._show_input(t, function (obj, new_name, old_name) { + _this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos }); + }); + } + else { _this.__callback({ "obj" : t, "name" : this.get_text(t), "parent" : p, "position" : pos }); } + }); + return t; + }, + remove : function (obj) { + obj = this._get_node(obj, true); + var p = this._get_parent(obj), prev = this._get_prev(obj); + this.__rollback(); + obj = this.delete_node(obj); + if(obj !== false) { this.__callback({ "obj" : obj, "prev" : prev, "parent" : p }); } + }, + check_move : function () { + if(!this.__call_old()) { return false; } + var s = this._get_settings().crrm.move; + if(!s.check_move.call(this, this._get_move())) { return false; } + return true; + }, + move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) { + var s = this._get_settings().crrm.move; + if(!is_prepared) { + if(typeof position === "undefined") { position = s.default_position; } + if(position === "inside" && !s.default_position.match(/^(before|after)$/)) { position = s.default_position; } + return this.__call_old(true, obj, ref, position, is_copy, false, skip_check); + } + // if the move is already prepared + if(s.always_copy === true || (s.always_copy === "multitree" && obj.rt.get_index() !== obj.ot.get_index() )) { + is_copy = true; + } + this.__call_old(true, obj, ref, position, is_copy, true, skip_check); + }, + + cut : function (obj) { + obj = this._get_node(obj, true); + if(!obj || !obj.length) { return false; } + this.data.crrm.cp_nodes = false; + this.data.crrm.ct_nodes = obj; + this.__callback({ "obj" : obj }); + }, + copy : function (obj) { + obj = this._get_node(obj, true); + if(!obj || !obj.length) { return false; } + this.data.crrm.ct_nodes = false; + this.data.crrm.cp_nodes = obj; + this.__callback({ "obj" : obj }); + }, + paste : function (obj) { + obj = this._get_node(obj); + if(!obj || !obj.length) { return false; } + var nodes = this.data.crrm.ct_nodes ? this.data.crrm.ct_nodes : this.data.crrm.cp_nodes; + if(!this.data.crrm.ct_nodes && !this.data.crrm.cp_nodes) { return false; } + if(this.data.crrm.ct_nodes) { this.move_node(this.data.crrm.ct_nodes, obj); this.data.crrm.ct_nodes = false; } + if(this.data.crrm.cp_nodes) { this.move_node(this.data.crrm.cp_nodes, obj, false, true); } + this.__callback({ "obj" : obj, "nodes" : nodes }); + } + } + }); + // include the crr plugin by default + // $.jstree.defaults.plugins.push("crrm"); +})(jQuery); +//*/ + +/* + * jsTree themes plugin + * Handles loading and setting themes, as well as detecting path to themes, etc. + */ +(function ($) { + var themes_loaded = []; + // this variable stores the path to the themes folder - if left as false - it will be autodetected + $.jstree._themes = false; + $.jstree.plugin("themes", { + __init : function () { + this.get_container() + .bind("init.jstree", $.proxy(function () { + var s = this._get_settings().themes; + this.data.themes.dots = s.dots; + this.data.themes.icons = s.icons; + this.set_theme(s.theme, s.url); + }, this)) + .bind("loaded.jstree", $.proxy(function () { + // bound here too, as simple HTML tree's won't honor dots & icons otherwise + if(!this.data.themes.dots) { this.hide_dots(); } + else { this.show_dots(); } + if(!this.data.themes.icons) { this.hide_icons(); } + else { this.show_icons(); } + }, this)); + }, + defaults : { + theme : "default", + url : false, + dots : true, + icons : true + }, + _fn : { + set_theme : function (theme_name, theme_url) { + if(!theme_name) { return false; } + if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; } + if($.inArray(theme_url, themes_loaded) == -1) { + $.vakata.css.add_sheet({ "url" : theme_url }); + themes_loaded.push(theme_url); + } + if(this.data.themes.theme != theme_name) { + this.get_container().removeClass('jstree-' + this.data.themes.theme); + this.data.themes.theme = theme_name; + } + this.get_container().addClass('jstree-' + theme_name); + if(!this.data.themes.dots) { this.hide_dots(); } + else { this.show_dots(); } + if(!this.data.themes.icons) { this.hide_icons(); } + else { this.show_icons(); } + this.__callback(); + }, + get_theme : function () { return this.data.themes.theme; }, + + show_dots : function () { this.data.themes.dots = true; this.get_container().children("ul").removeClass("jstree-no-dots"); }, + hide_dots : function () { this.data.themes.dots = false; this.get_container().children("ul").addClass("jstree-no-dots"); }, + toggle_dots : function () { if(this.data.themes.dots) { this.hide_dots(); } else { this.show_dots(); } }, + + show_icons : function () { this.data.themes.icons = true; this.get_container().children("ul").removeClass("jstree-no-icons"); }, + hide_icons : function () { this.data.themes.icons = false; this.get_container().children("ul").addClass("jstree-no-icons"); }, + toggle_icons: function () { if(this.data.themes.icons) { this.hide_icons(); } else { this.show_icons(); } } + } + }); + // autodetect themes path + $(function () { + if($.jstree._themes === false) { + $("script").each(function () { + if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { + $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; + return false; + } + }); + } + if($.jstree._themes === false) { $.jstree._themes = "themes/"; } + }); + // include the themes plugin by default + $.jstree.defaults.plugins.push("themes"); +})(jQuery); +//*/ + +/* + * jsTree hotkeys plugin + * Enables keyboard navigation for all tree instances + * Depends on the jstree ui & jquery hotkeys plugins + */ +(function ($) { + var bound = []; + function exec(i, event) { + var f = $.jstree._focused(), tmp; + if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { + tmp = f._get_settings().hotkeys[i]; + if(tmp) { return tmp.call(f, event); } + } + } + $.jstree.plugin("hotkeys", { + __init : function () { + if(typeof $.hotkeys === "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; } + if(!this.data.ui) { throw "jsTree hotkeys: jsTree UI plugin not included."; } + $.each(this._get_settings().hotkeys, function (i, v) { + if(v !== false && $.inArray(i, bound) == -1) { + $(document).bind("keydown", i, function (event) { return exec(i, event); }); + bound.push(i); + } + }); + this.get_container() + .bind("lock.jstree", $.proxy(function () { + if(this.data.hotkeys.enabled) { this.data.hotkeys.enabled = false; this.data.hotkeys.revert = true; } + }, this)) + .bind("unlock.jstree", $.proxy(function () { + if(this.data.hotkeys.revert) { this.data.hotkeys.enabled = true; } + }, this)); + this.enable_hotkeys(); + }, + defaults : { + "up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "ctrl+up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "shift+up" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_prev(o)); + return false; + }, + "down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "ctrl+down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "shift+down" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.hover_node(this._get_next(o)); + return false; + }, + "left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "ctrl+left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "shift+left" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o) { + if(o.hasClass("jstree-open")) { this.close_node(o); } + else { this.hover_node(this._get_prev(o)); } + } + return false; + }, + "right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "ctrl+right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "shift+right" : function () { + var o = this.data.ui.hovered || this.data.ui.last_selected; + if(o && o.length) { + if(o.hasClass("jstree-closed")) { this.open_node(o); } + else { this.hover_node(this._get_next(o)); } + } + return false; + }, + "space" : function () { + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } + return false; + }, + "ctrl+space" : function (event) { + event.type = "click"; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; + }, + "shift+space" : function (event) { + event.type = "click"; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; + }, + "f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); }, + "del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); } + }, + _fn : { + enable_hotkeys : function () { + this.data.hotkeys.enabled = true; + }, + disable_hotkeys : function () { + this.data.hotkeys.enabled = false; + } + } + }); +})(jQuery); +//*/ + +/* + * jsTree JSON plugin + * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions. + */ +(function ($) { + $.jstree.plugin("json_data", { + __init : function() { + var s = this._get_settings().json_data; + if(s.progressive_unload) { + this.get_container().bind("after_close.jstree", function (e, data) { + data.rslt.obj.children("ul").remove(); + }); + } + }, + defaults : { + // `data` can be a function: + // * accepts two arguments - node being loaded and a callback to pass the result to + // * will be executed in the current tree's scope & ajax won't be supported + data : false, + ajax : false, + correct_state : true, + progressive_render : false, + progressive_unload : false + }, + _fn : { + load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_json(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, + _is_loaded : function (obj) { + var s = this._get_settings().json_data; + obj = this._get_node(obj); + return obj == -1 || !obj || (!s.ajax && !s.progressive_render && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").length > 0; + }, + refresh : function (obj) { + obj = this._get_node(obj); + var s = this._get_settings().json_data; + if(obj && obj !== -1 && s.progressive_unload && ($.isFunction(s.data) || !!s.ajax)) { + obj.removeData("jstree-children"); + } + return this.__call_old(); + }, + load_node_json : function (obj, s_call, e_call) { + var s = this.get_settings().json_data, d, + error_func = function () {}, + success_func = function () {}; + obj = this._get_node(obj); + + if(obj && obj !== -1 && (s.progressive_render || s.progressive_unload) && !obj.is(".jstree-open, .jstree-leaf") && obj.children("ul").children("li").length === 0 && obj.data("jstree-children")) { + d = this._parse_json(obj.data("jstree-children"), obj); + if(d) { + obj.append(d); + if(!s.progressive_unload) { obj.removeData("jstree-children"); } + } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + return; + } + + if(obj && obj !== -1) { + if(obj.data("jstree-is-loading")) { return; } + else { obj.data("jstree-is-loading",true); } + } + switch(!0) { + case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied."; + // function option added here for easier model integration (also supporting async - see callback) + case ($.isFunction(s.data)): + s.data.call(this, obj, $.proxy(function (d) { + d = this._parse_json(d, obj); + if(!d) { + if(obj === -1 || !obj) { + if(s.correct_state) { this.get_container().children("ul").empty(); } + } + else { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { this.correct_state(obj); } + } + if(e_call) { e_call.call(this); } + } + else { + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + }, this)); + break; + case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)): + if(!obj || obj == -1) { + d = this._parse_json(s.data, obj); + if(d) { + this.get_container().children("ul").empty().append(d.children()); + this.clean_node(); + } + else { + if(s.correct_state) { this.get_container().children("ul").empty(); } + } + } + if(s_call) { s_call.call(this); } + break; + case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): + error_func = function (x, t, e) { + var ef = this.get_settings().json_data.ajax.error; + if(ef) { ef.call(this, x, t, e); } + if(obj != -1 && obj.length) { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(t === "success" && s.correct_state) { this.correct_state(obj); } + } + else { + if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); } + } + if(e_call) { e_call.call(this); } + }; + success_func = function (d, t, x) { + var sf = this.get_settings().json_data.ajax.success; + if(sf) { d = sf.call(this,d,t,x) || d; } + if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "") || (!$.isArray(d) && !$.isPlainObject(d))) { + return error_func.call(this, x, t, ""); + } + d = this._parse_json(d, obj); + if(d) { + if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); } + else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree-is-loading"); } + this.clean_node(obj); + if(s_call) { s_call.call(this); } + } + else { + if(obj === -1 || !obj) { + if(s.correct_state) { + this.get_container().children("ul").empty(); + if(s_call) { s_call.call(this); } + } + } + else { + obj.children("a.jstree-loading").removeClass("jstree-loading"); + obj.removeData("jstree-is-loading"); + if(s.correct_state) { + this.correct_state(obj); + if(s_call) { s_call.call(this); } + } + } + } + }; + s.ajax.context = this; + s.ajax.error = error_func; + s.ajax.success = success_func; + if(!s.ajax.dataType) { s.ajax.dataType = "json"; } + if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); } + if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); } + $.ajax(s.ajax); + break; + } + }, + _parse_json : function (js, obj, is_callback) { + var d = false, + p = this._get_settings(), + s = p.json_data, + t = p.core.html_titles, + tmp, i, j, ul1, ul2; + + if(!js) { return d; } + if(s.progressive_unload && obj && obj !== -1) { + obj.data("jstree-children", d); + } + if($.isArray(js)) { + d = $(); + if(!js.length) { return false; } + for(i = 0, j = js.length; i < j; i++) { + tmp = this._parse_json(js[i], obj, true); + if(tmp.length) { d = d.add(tmp); } + } + } + else { + if(typeof js == "string") { js = { data : js }; } + if(!js.data && js.data !== "") { return d; } + d = $("
                            • "); + if(js.attr) { d.attr(js.attr); } + if(js.metadata) { d.data(js.metadata); } + if(js.state) { d.addClass("jstree-" + js.state); } + if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); } + $.each(js.data, function (i, m) { + tmp = $(""); + if($.isFunction(m)) { m = m.call(this, js); } + if(typeof m == "string") { tmp.attr('href','#')[ t ? "html" : "text" ](m); } + else { + if(!m.attr) { m.attr = {}; } + if(!m.attr.href) { m.attr.href = '#'; } + tmp.attr(m.attr)[ t ? "html" : "text" ](m.title); + if(m.language) { tmp.addClass(m.language); } + } + tmp.prepend(" "); + if(!m.icon && js.icon) { m.icon = js.icon; } + if(m.icon) { + if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); } + else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); } + } + d.append(tmp); + }); + d.prepend(" "); + if(js.children) { + if(s.progressive_render && js.state !== "open") { + d.addClass("jstree-closed").data("jstree-children", js.children); + } + else { + if(s.progressive_unload) { d.data("jstree-children", js.children); } + if($.isArray(js.children) && js.children.length) { + tmp = this._parse_json(js.children, obj, true); + if(tmp.length) { + ul2 = $("
                            • "+(i[0]>0&&D==i[1]-1?'
                              ':""):"");L+=x}H+=L}H+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': +"");a._keyEvent=false;return H},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var k=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),j='
                              ',o="";if(h||!k)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(j+=o+(h||!(k&&l)?" ":""));if(h||!l)j+=''+c+"";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b, +i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(j+='"}j+=this._get(a,"yearSuffix");if(u)j+=(h||!(k&&l)?" ":"")+o;j+="
                              ";return j},_adjustInstDate:function(a,b,c){var e= +a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a, +"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a); +c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a, +"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker= +function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b)); +return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new J;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.1";window["DP_jQuery_"+y]=d})(jQuery); +;/* + * jQuery UI Progressbar 1.8.1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function(b){b.widget("ui.progressbar",{options:{value:0},_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=b("
                              ").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); +this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===undefined)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){switch(a){case "value":this.options.value=c;this._refreshValue();this._trigger("change");break}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;if(athis._valueMax())a=this._valueMax();return a}, +_valueMin:function(){return 0},_valueMax:function(){return 100},_refreshValue:function(){var a=this.value();this.valueDiv[a===this._valueMax()?"addClass":"removeClass"]("ui-corner-right").width(a+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.1"})})(jQuery); +;/* + * jQuery UI Effects 1.8.1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||function(f){function k(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], +16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return l.transparent;return l[f.trim(c).toLowerCase()]}function q(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return k(b)}function m(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, +a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function n(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in r||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function s(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function j(c,a,b,d){if(typeof c=="object"){d= +a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(f.isFunction(b)){d=b;b=null}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:f.fx.speeds[b]||f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=q(b.elem,a);b.end=k(b.end);b.colorInit= +true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var l={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189, +183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255, +165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},o=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){var e=f(this),g=e.attr("style")||" ",h=n(m.call(this)),p,t=e.attr("className");f.each(o,function(u, +i){c[i]&&e[i+"Class"](c[i])});p=n(m.call(this));e.attr("className",t);e.animate(s(h,p),a,b,function(){f.each(o,function(u,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a? +f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===undefined?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.1",save:function(c,a){for(var b=0;b
                              ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"}); +c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=j.apply(this,arguments);a={options:a[1],duration:a[2],callback:a[3]};var b=f.effects[c];return b&&!f.fx.off?b.call(this,a):this},_show:f.fn.show,show:function(c){if(!c|| +typeof c=="number"||f.fx.speeds[c])return this._show.apply(this,arguments);else{var a=j.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(!c||typeof c=="number"||f.fx.speeds[c])return this._hide.apply(this,arguments);else{var a=j.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||typeof c=="boolean"||f.isFunction(c))return this.__toggle.apply(this, +arguments);else{var a=j.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c, +a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+ +b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2, +10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)* +a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h
                              ").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ +e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); +;/* + * jQuery UI Effects Fold 1.8.1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * jquery.effects.core.js + */ +(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100* +f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); +;/* + * jQuery UI Effects Highlight 1.8.1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * jquery.effects.core.js + */ +(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& +this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); +;/* + * jQuery UI Effects Pulsate 1.8.1 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * jquery.effects.core.js + */ +(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c
                              ').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); +b.dequeue()})})}})(jQuery); +; \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/ui-layout.js b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/ui-layout.js new file mode 100644 index 00000000..f6a02bf3 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/browser/vendor/ui-layout.js @@ -0,0 +1,108 @@ +/* + jquery.layout 1.3.0 - Release Candidate 29.14 + $Date: 2011-02-13 08:00:00 (Sun, 13 Feb 2011) $ + $Rev: 302914 $ + + Copyright (c) 2010 + Fabrizio Balliano (http://www.fabrizioballiano.net) + Kevin Dalman (http://allpro.net) + + Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) + and MIT (http://www.opensource.org/licenses/mit-license.php) licenses. + + Changelog: http://layout.jquery-dev.net/changelog.cfm#1.3.0.rc29.13 + + Docs: http://layout.jquery-dev.net/documentation.html + Tips: http://layout.jquery-dev.net/tips.html + Help: http://groups.google.com/group/jquery-ui-layout +*/ +(function(f){var C=f.browser;f.layout={browser:{mozilla:!!C.mozilla,webkit:!!C.webkit||!!C.safari,msie:!!C.msie,isIE6:!!C.msie&&C.version==6,boxModel:!1},scrollbarWidth:function(){return window.scrollbarWidth||f.layout.getScrollbarSize("width")},scrollbarHeight:function(){return window.scrollbarHeight||f.layout.getScrollbarSize("height")},getScrollbarSize:function(j){var o=f('
                              ').appendTo("body"), +p={width:o.width()-o[0].clientWidth,height:o.height()-o[0].clientHeight};o.remove();window.scrollbarWidth=p.width;window.scrollbarHeight=p.height;return j.match(/^(width|height)$/i)?p[j]:p},showInvisibly:function(j,o){if(!j)return{};j.jquery||(j=f(j));var p={display:j.css("display"),visibility:j.css("visibility")};return o||p.display=="none"?(j.css({display:"block",visibility:"hidden"}),p):{}},getElemDims:function(j){var o={},p=o.css={},r={},F,ga,H=j.offset();o.offsetLeft=H.left;o.offsetTop=H.top; +f.each("Left,Right,Top,Bottom".split(","),function(x,z){F=p["border"+z]=f.layout.borderWidth(j,z);ga=p["padding"+z]=f.layout.cssNum(j,"padding"+z);r[z]=F+ga;o["inset"+z]=ga});o.offsetWidth=j.innerWidth();o.offsetHeight=j.innerHeight();o.outerWidth=j.outerWidth();o.outerHeight=j.outerHeight();o.innerWidth=o.outerWidth-r.Left-r.Right;o.innerHeight=o.outerHeight-r.Top-r.Bottom;p.width=j.width();p.height=j.height();return o},getElemCSS:function(f,o){var p={},r=f[0].style,F=o.split(","),ga="Top,Bottom,Left,Right".split(","), +H="Color,Style,Width".split(","),x,z,C,S,T,X;for(S=0;S=r&&H<=C&&x>=F&&x<=p}};f.fn.layout=function(j){function o(a){if(!a)return!0;var b=a.keyCode;if(b<33)return!0;var c={38:"north",40:"south",37:"west",39:"east"},d=a.shiftKey,e=a.ctrlKey,h,g,i,n;e&&b>=37&&b<=40&&m[c[b]].enableCursorHotkey?n=c[b]:(e||d)&&f.each(k.borderPanes.split(","),function(a,c){h=m[c];g=h.customHotkey;i=h.customHotkeyModifier;if(d&& +i=="SHIFT"||e&&i=="CTRL"||e&&d)if(g&&b==(isNaN(g)||g<=9?g.toUpperCase().charCodeAt(0):g))return n=c,!1});if(!n||!q[n]||!m[n].closable||l[n].isHidden)return!0;ca(n);a.stopPropagation();return a.returnValue=!1}function p(a){this&&this.tagName&&(a=this);var b;I(a)?b=q[a]:f(a).data("layoutRole")?b=f(a):f(a).parents().each(function(){if(f(this).data("layoutRole"))return b=f(this),!1});if(b&&b.length){var c=b.data("layoutEdge"),a=l[c];a.cssSaved&&r(c);if(a.isSliding||a.isResizing||a.isClosed)a.cssSaved= +!1;else{var d={zIndex:k.zIndex.pane_normal+2},e={},h=b.css("overflow"),g=b.css("overflowX"),i=b.css("overflowY");if(h!="visible")e.overflow=h,d.overflow="visible";if(g&&!g.match(/visible|auto/))e.overflowX=g,d.overflowX="visible";if(i&&!i.match(/visible|auto/))e.overflowY=g,d.overflowY="visible";a.cssSaved=e;b.css(d);f.each(k.allPanes.split(","),function(a,b){b!=c&&r(b)})}}}function r(a){this&&this.tagName&&(a=this);var b;I(a)?b=q[a]:f(a).data("layoutRole")?b=f(a):f(a).parents().each(function(){if(f(this).data("layoutRole"))return b= +f(this),!1});if(b&&b.length){var a=b.data("layoutEdge"),a=l[a],c=a.cssSaved||{};!a.isSliding&&!a.isResizing&&b.css("zIndex",k.zIndex.pane_normal);b.css(c);a.cssSaved=!1}}function F(a,b,c){var d=f(a);if(d.length)if(k.borderPanes.indexOf(b)==-1)alert(D.errButton+D.Pane.toLowerCase()+": "+b);else return a=m[b].buttonClass+"-"+c,d.addClass(a+" "+a+"-"+b).data("layoutName",m.name),d;else alert(D.errButton+D.selector+": "+a);return null}function C(a,b,c){switch(b.toLowerCase()){case "toggle":H(a,c);break; +case "open":x(a,c);break;case "close":z(a,c);break;case "pin":Ba(a,c);break;case "toggle-slide":H(a,c,!0);break;case "open-slide":x(a,c,!0)}}function H(a,b,c){(a=F(a,b,"toggle"))&&a.click(function(a){ca(b,!!c);a.stopPropagation()})}function x(a,b,c){(a=F(a,b,"open"))&&a.attr("title",D.Open).click(function(a){M(b,!!c);a.stopPropagation()})}function z(a,b){var c=F(a,b,"close");c&&c.attr("title",D.Close).click(function(a){J(b);a.stopPropagation()})}function Ba(a,b){var c=F(a,b,"pin");if(c){var d=l[b]; +c.click(function(a){T(f(this),b,d.isSliding||d.isClosed);d.isSliding||d.isClosed?M(b):J(b);a.stopPropagation()});T(c,b,!d.isClosed&&!d.isSliding);k[b].pins.push(a)}}function S(a,b){f.each(k[a].pins,function(c,d){T(f(d),a,b)})}function T(a,b,c){var d=a.attr("pin");if(!(d&&c==(d=="down"))){var d=m[b].buttonClass+"-pin",e=d+"-"+b,b=d+"-up "+e+"-up",d=d+"-down "+e+"-down";a.attr("pin",c?"down":"up").attr("title",c?D.Unpin:D.Pin).removeClass(c?b:d).addClass(c?d:b)}}function X(a){for(var a=f.extend({}, +m.cookie,a||{}).name||m.name||"Layout",b=document.cookie,b=b?b.split(";"):[],c,d=0,e=b.length;d0?h.setDate(h.getDate()+c.expires):(h.setYear(1970),g=!0));h&&(e+=";expires="+h.toUTCString());c.path&&(e+=";path="+c.path);c.domain&&(e+=";domain="+ +c.domain);c.secure&&(e+=";secure");g?(l.cookie={},document.cookie=d+"="+e):(l.cookie=qa(a||c.keys),document.cookie=d+"="+encodeURIComponent(Da(l.cookie))+e);return f.extend({},l.cookie)}function Ea(a){if(a=X(a))l.cookie=f.extend({},a),Fa(a);return a}function Fa(a,b){f.extend(!0,m,a);if(l.initialized){var c,d,e=!b;f.each(k.allPanes.split(","),function(b,g){c=a[g];if(typeof c=="object")d=c.initHidden,d===!0&&la(g,e),d===!1&&ha(g,!1,e),d=c.size,d>0&&Y(g,d),d=c.initClosed,d===!0&&J(g,!1,e),d===!1&&M(g, +!1,e)})}}function qa(a){var b={},c={isClosed:"initClosed",isHidden:"initHidden"},d,e,h;if(!a)a=m.cookie.keys;f.isArray(a)&&(a=a.join(","));for(var a=a.replace(/__/g,".").split(","),g=0,i=a.length;g=0&&d(h)):(g.doCallback=!0,g.callback=a+","+b+","+(c?1:0))}var e=[];f.each(k.borderPanes.split(","),function(a,b){if(k[b].isMoving)return d(b),!1})},Ha=function(a){a=k[a];k.isLayoutBusy=!1;delete a.isMoving;if(a.doCallback&&a.callback){a.doCallback=!1;var b=a.callback.split(","),c=b[2]>0?!0:!1;b[0]=="open"?M(b[1],c):b[0]=="close"&&J(b[1],c);if(!a.doCallback)a.callback= +null}},t=function(a,b){if(b){var c;try{if(typeof b=="function")c=b;else if(I(b))if(b.match(/,/)){var d=b.split(",");c=eval(d[0]);if(typeof c=="function"&&d.length>1)return c(d[1])}else c=eval(b);else return;if(typeof c=="function")return a&&q[a]?c(a,q[a],f.extend({},l[a]),m[a],m.name):c(da,f.extend({},l),m,m.name)}catch(e){}}},Ia=function(a,b){if(!a)return{};a.jquery||(a=f(a));var c={display:a.css("display"),visibility:a.css("visibility")};return b||c.display=="none"?(a.css({display:"block",visibility:"hidden"}), +c):{}},Ja=function(a){if(!l.browser.mozilla){var b=q[a];l[a].tagName=="IFRAME"?b.css(k.hidden).css(k.visible):b.find("IFRAME").css(k.hidden).css(k.visible)}},Z=function(a,b){a.jquery||(a=f(a));var c=Ia(a),d=parseInt(f.curCSS(a[0],b,!0),10)||0;a.css(c);return d},ia=function(a,b){a.jquery&&(a=a[0]);var c="border"+b.substr(0,1).toUpperCase()+b.substr(1);return f.curCSS(a,c+"Style",!0)=="none"?0:parseInt(f.curCSS(a,c+"Width",!0),10)||0},K=function(a,b){var c=I(a),d=c?q[a]:f(a);isNaN(b)&&(b=c?P(a):d.outerWidth()); +if(b<=0)return 0;if(!l.browser.boxModel)return b;c=b-ia(d,"Left")-ia(d,"Right")-Z(d,"paddingLeft")-Z(d,"paddingRight");return y(0,c)},L=function(a,b){var c=I(a),d=c?q[a]:f(a);isNaN(b)&&(b=c?P(a):d.outerHeight());if(b<=0)return 0;if(!l.browser.boxModel)return b;c=b-ia(d,"Top")-ia(d,"Bottom")-Z(d,"paddingTop")-Z(d,"paddingBottom");return y(0,c)},ma=function(a){var b=k[a].dir,a={minWidth:1001-K(a,1E3),minHeight:1001-L(a,1E3)};if(b=="horz")a.minSize=a.minHeight;if(b=="vert")a.minSize=a.minWidth;return a}, +Ua=function(a,b,c){var d=a;I(a)?d=q[a]:a.jquery||(d=f(a));a=L(d,b);d.css({height:a,visibility:"visible"});a>0&&d.innerWidth()>0?c&&d.data("autoHidden")&&(d.show().data("autoHidden",!1),l.browser.mozilla||d.css(k.hidden).css(k.visible)):c&&!d.data("autoHidden")&&d.hide().data("autoHidden",!0)},U=function(a,b,c){if(!c)c=k[a].dir;I(b)&&b.match(/%/)&&(b=parseInt(b,10)/100);if(b===0)return 0;else if(b>=1)return parseInt(b,10);else if(b>0){var a=m,d;c=="horz"?d=u.innerHeight-(q.north?a.north.spacing_open: +0)-(q.south?a.south.spacing_open:0):c=="vert"&&(d=u.innerWidth-(q.west?a.west.spacing_open:0)-(q.east?a.east.spacing_open:0));return Math.floor(d*b)}else if(a=="center")return 0;else{d=q[a];var c=c=="horz"?"height":"width",a=Ia(d),e=d.css(c);d.css(c,"auto");b=c=="height"?d.outerHeight():d.outerWidth();d.css(c,e).css(a);return b}},P=function(a,b){var c=q[a],d=m[a],e=l[a],h=b?d.spacing_open:0,d=b?d.spacing_closed:0;return!c||e.isHidden?0:e.isClosed||e.isSliding&&b?d:k[a].dir=="horz"?c.outerHeight()+ +h:c.outerWidth()+h},Q=function(a,b){var c=m[a],d=l[a],e=k[a],h=e.dir;e.side.toLowerCase();e.sizeType.toLowerCase();var e=b!=void 0?b:d.isSliding,g=c.spacing_open,i=k.altSide[a],f=l[i],O=q[i],A=!O||f.isVisible===!1||f.isSliding?0:h=="horz"?O.outerHeight():O.outerWidth(),i=(!O||f.isHidden?0:m[i][f.isClosed!==!1?"spacing_closed":"spacing_open"])||0,f=h=="horz"?u.innerHeight:u.innerWidth,O=ma("center"),O=h=="horz"?y(m.center.minHeight,O.minHeight):y(m.center.minWidth,O.minWidth),e=f-g-(e?0:U("center", +O,h)+A+i),h=d.minSize=y(U(a,c.minSize),ma(a).minSize),g=c.maxSize?U(a,c.maxSize):1E5,e=d.maxSize=Math.min(g,e),d=d.resizerPosition={},g=u.insetTop,A=u.insetLeft,i=u.innerWidth,f=u.innerHeight,c=c.spacing_open;switch(a){case "north":d.min=g+h;d.max=g+e;break;case "west":d.min=A+h;d.max=A+e;break;case "south":d.min=g+f-e-c;d.max=g+f-h-c;break;case "east":d.min=A+i-e-c,d.max=A+i-h-c}},$=function(a){var b={},c=b.css={},d={},e,h,g=a.offset();b.offsetLeft=g.left;b.offsetTop=g.top;f.each("Left,Right,Top,Bottom".split(","), +function(g,f){e=c["border"+f]=ia(a,f);h=c["padding"+f]=Z(a,"padding"+f);d[f]=e+h;b["inset"+f]=h});b.offsetWidth=a.innerWidth();b.offsetHeight=a.innerHeight();b.outerWidth=a.outerWidth();b.outerHeight=a.outerHeight();b.innerWidth=b.outerWidth-d.Left-d.Right;b.innerHeight=b.outerHeight-d.Top-d.Bottom;c.width=a.width();c.height=a.height();return b},na=function(a,b){var c={},d=a[0].style,e=b.split(","),f="Top,Bottom,Left,Right".split(","),g="Color,Style,Width".split(","),i,n,k,l,m,j;for(l=0;l0&&(E.clear("winResize"),E.set("winResize",function(){E.clear("winResize");E.clear("winResizeRepeater");ea()},a),E.data.winResizeRepeater||La())},La=function(){var a=Number(m.resizeWithWindowMaxDelay);a>0&&E.set("winResizeRepeater",function(){La();ea()},a)},Ma=function(){var a=m;l.cookie=qa();t(null,a.onunload_start);a.useStateCookie&&a.cookie.autoSave&&pa();t(null,a.onunload_end||a.onunload)},Na=function(a){if(!a||a=="all")a=k.borderPanes;f.each(a.split(","),function(a,c){var d=m[c];if(d.enableCursorHotkey|| +d.customHotkey)return f(document).bind("keydown."+v,o),!1})},Wa=function(){function a(a){for(var c in b)a[c]!=void 0&&(a[b[c]]=a[c],delete a[c])}j=Ta(j);var b={applyDefaultStyles:"applyDemoStyles"};a(j.defaults);f.each(k.allPanes.split(","),function(b,c){a(j[c])});j.effects&&(f.extend(ra,j.effects),delete j.effects);f.extend(m.cookie,j.cookie);f.each("name,containerClass,zIndex,scrollToBookmarkOnLoad,resizeWithWindow,resizeWithWindowDelay,resizeWithWindowMaxDelay,onresizeall,onresizeall_start,onresizeall_end,onload,onload_start,onload_end,onunload,onunload_start,onunload_end,autoBindCustomButtons,useStateCookie".split(","), +function(a,b){j[b]!==void 0?m[b]=j[b]:j.defaults[b]!==void 0&&(m[b]=j.defaults[b],delete j.defaults[b])});f.each("paneSelector,resizerCursor,customHotkey".split(","),function(a,b){delete j.defaults[b]});f.extend(!0,m.defaults,j.defaults);k.center=f.extend(!0,{},k.panes,k.center);var c=m.zIndex;if(c===0||c>0)k.zIndex.pane_normal=c,k.zIndex.resizer_normal=c+1,k.zIndex.iframe_mask=c+1;f.extend(m.center,j.center);var d=f.extend(!0,{},m.defaults,j.defaults,m.center),c="paneClass,contentSelector,applyDemoStyles,triggerEventsOnLoad,showOverflowOnHover,onresize,onresize_start,onresize_end,resizeNestedLayout,resizeContentWhileDragging,onsizecontent,onsizecontent_start,onsizecontent_end".split(","); +f.each(c,function(a,b){m.center[b]=d[b]});var e,h=m.defaults;f.each(k.borderPanes.split(","),function(a,b){k[b]=f.extend(!0,{},k.panes,k[b]);e=m[b]=f.extend(!0,{},m.defaults,m[b],j.defaults,j[b]);if(!e.paneClass)e.paneClass="ui-layout-pane";if(!e.resizerClass)e.resizerClass="ui-layout-resizer";if(!e.togglerClass)e.togglerClass="ui-layout-toggler";f.each(["_open","_close",""],function(a,c){var d="fxName"+c,g="fxSpeed"+c,k="fxSettings"+c;e[d]=j[b][d]||j[b].fxName||j.defaults[d]||j.defaults.fxName|| +e[d]||e.fxName||h[d]||h.fxName||"none";var l=e[d];if(l=="none"||!f.effects||!f.effects[l]||!ra[l]&&!e[k]&&!e.fxSettings)l=e[d]="none";l=ra[l]||{};d=l.all||{};l=l[b]||{};e[k]=f.extend({},d,l,h.fxSettings||{},h[k]||{},e.fxSettings,e[k],j.defaults.fxSettings,j.defaults[k]||{},j[b].fxSettings,j[b][k]||{});e[g]=j[b][g]||j[b].fxSpeed||j.defaults[g]||j.defaults.fxSpeed||e[g]||e[k].duration||e.fxSpeed||e.fxSettings.duration||h.fxSpeed||h.fxSettings.duration||l.duration||d.duration||"normal"})})},Oa=function(a){a= +m[a].paneSelector;if(a.substr(0,1)==="#")return G.find(a).eq(0);else{var b=G.children(a).eq(0);return b.length?b:G.children("form:first").children(a).eq(0)}},Xa=function(){f.each(k.allPanes.split(","),function(a,b){Pa(b)});va();f.each(k.borderPanes.split(","),function(a,b){q[b]&&l[b].isVisible&&(Q(b),V(b))});W("center");f.each(k.allPanes.split(","),function(a,b){var c=m[b];q[b]&&l[b].isVisible&&(c.triggerEventsOnLoad&&t(b,c.onresize_end||c.onresize),aa(b))});G.innerHeight()<2&&alert(D.errContainerHeight.replace(/CONTAINER/, +u.ref))},Pa=function(a){var b=m[a],c=l[a],d=k[a],e=d.dir,f=a=="center",g={},i=q[a],n;i?wa(a):N[a]=!1;i=q[a]=Oa(a);if(i.length){i.data("layoutCSS")||i.data("layoutCSS",na(i,"position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border"));i.data("parentLayout",da).data("layoutRole","pane").data("layoutEdge",a).css(d.cssReq).css("zIndex",k.zIndex.pane_normal).css(b.applyDemoStyles?d.cssDemo:{}).addClass(b.paneClass+" "+b.paneClass+"-"+a).bind("mouseenter."+ +v,ta).bind("mouseleave."+v,R);Qa(a,!1);if(!f)n=c.size=U(a,b.size),d=U(a,b.minSize)||1,f=U(a,b.maxSize)||1E5,n>0&&(n=y(Math.min(n,f),d)),c.isClosed=!1,c.isSliding=!1,c.isResizing=!1,c.isHidden=!1;c.tagName=i.attr("tagName");c.edge=a;c.noRoom=!1;c.isVisible=!0;switch(a){case "north":g.top=u.insetTop;g.left=u.insetLeft;g.right=u.insetRight;break;case "south":g.bottom=u.insetBottom;g.left=u.insetLeft;g.right=u.insetRight;break;case "west":g.left=u.insetLeft;break;case "east":g.right=u.insetRight}if(e== +"horz")g.height=y(1,L(a,n));else if(e=="vert")g.width=y(1,K(a,n));i.css(g);e!="horz"&&W(a,!0);c.noRoom||i.css({visibility:"visible",display:"block"});b.initClosed&&b.closable?J(a,!0,!0):(b.initHidden||b.initClosed)&&la(a);b.showOverflowOnHover&&i.hover(p,r);l.initialized&&(va(a),Na(a),ea(),c.isVisible&&(b.triggerEventsOnLoad&&t(a,b.onresize_end||b.onresize),aa(a)))}else q[a]=!1},va=function(a){if(!a||a=="all")a=k.borderPanes;f.each(a.split(","),function(a,c){var d=q[c];w[c]=!1;B[c]=!1;if(d){var d= +m[c],e=l[c],h=d.resizerClass,g=d.togglerClass;k[c].side.toLowerCase();var i="-"+c,n=w[c]=f("
                              "),j=d.closable?B[c]=f("
                              "):!1;!e.isVisible&&d.slidable&&n.attr("title",d.sliderTip).css("cursor",d.sliderCursor);n.attr("id",d.paneSelector.substr(0,1)=="#"?d.paneSelector.substr(1)+"-resizer":"").data("parentLayout",da).data("layoutRole","resizer").data("layoutEdge",c).css(k.resizers.cssReq).css("zIndex",k.zIndex.resizer_normal).css(d.applyDemoStyles?k.resizers.cssDemo:{}).addClass(h+ +" "+h+i).appendTo(G);j&&(j.attr("id",d.paneSelector.substr(0,1)=="#"?d.paneSelector.substr(1)+"-toggler":"").data("parentLayout",da).data("layoutRole","toggler").data("layoutEdge",c).css(k.togglers.cssReq).css(d.applyDemoStyles?k.togglers.cssDemo:{}).addClass(g+" "+g+i).appendTo(n),d.togglerContent_open&&f(""+d.togglerContent_open+"").data("layoutRole","togglerContent").data("layoutEdge",c).addClass("content content-open").css("display","none").appendTo(j),d.togglerContent_closed&&f(""+ +d.togglerContent_closed+"").data("layoutRole","togglerContent").data("layoutEdge",c).addClass("content content-closed").css("display","none").appendTo(j),Ra(c));Ya(c);e.isVisible?xa(c):(ya(c),ba(c,!0))}});ja("all")},Qa=function(a,b){var c=m[a],d=c.contentSelector,e=q[a],f;d&&(f=N[a]=c.findNestedContent?e.find(d).eq(0):e.children(d).eq(0));f&&f.length?(f.data("layoutCSS")||f.data("layoutCSS",na(f,"height")),f.css(k.content.cssReq),c.applyDemoStyles&&(f.css(k.content.cssDemo),e.css(k.content.cssDemoPane)), +l[a].content={},b!==!1&&fa(a)):N[a]=!1},Za=function(){var a;f.each("toggle,open,close,pin,toggle-slide,open-slide".split(","),function(b,c){f.each(k.borderPanes.split(","),function(b,e){f(".ui-layout-button-"+c+"-"+e).each(function(){a=f(this).data("layoutName")||f(this).attr("layoutName");(a==void 0||a==m.name)&&C(this,c,e)})})})},Ya=function(a){var b=typeof f.fn.draggable=="function",c;if(!a||a=="all")a=k.borderPanes;f.each(a.split(","),function(a,e){var h=m[e],g=l[e],i=k[e],n=i.dir=="horz"?"top": +"left",j,A;if(!b||!q[e]||!h.resizable)return h.resizable=!1,!0;var p=w[e],o=h.resizerClass,r=o+"-drag",y=o+"-"+e+"-drag",x=o+"-dragging",D=o+"-"+e+"-dragging",B=o+"-dragging-limit",C=o+"-"+e+"-dragging-limit",z=!1;g.isClosed||p.attr("title",h.resizerTip).css("cursor",h.resizerCursor);p.bind("mouseenter."+v,Ka).bind("mouseleave."+v,ua);p.draggable({containment:G[0],axis:i.dir=="horz"?"y":"x",delay:0,distance:1,helper:"clone",opacity:h.resizerDragOpacity,addClasses:!1,zIndex:k.zIndex.resizer_drag,start:function(){h= +m[e];g=l[e];A=h.resizeWhileDragging;if(!1===t(e,h.ondrag_start))return!1;k.isLayoutBusy=!0;g.isResizing=!0;E.clear(e+"_closeSlider");Q(e);j=g.resizerPosition;p.addClass(r+" "+y);z=!1;c=f(h.maskIframesOnResize===!0?"iframe":h.maskIframesOnResize).filter(":visible");var a,b=0;c.each(function(){a="ui-layout-mask-"+ ++b;f(this).data("layoutMaskID",a);f('
                              ').css({background:"#fff",opacity:"0.001",zIndex:k.zIndex.iframe_mask,position:"absolute", +width:this.offsetWidth+"px",height:this.offsetHeight+"px"}).css(f(this).position()).appendTo(this.parentNode)});f("body").disableSelection()},drag:function(a,b){z||(b.helper.addClass(x+" "+D).css({right:"auto",bottom:"auto"}).children().css("visibility","hidden"),z=!0,g.isSliding&&q[e].css("zIndex",k.zIndex.pane_sliding));var c=0;if(b.position[n]j.max)b.position[n]=j.max,c=1;c?(b.helper.addClass(B+" "+C),window.defaultStatus="Panel has reached its "+ +(c>0&&e.match(/north|west/)||c<0&&e.match(/south|east/)?"maximum":"minimum")+" size"):(b.helper.removeClass(B+" "+C),window.defaultStatus="");A&&F(a,b,e)},stop:function(a,b){f("body").enableSelection();window.defaultStatus="";p.removeClass(r+" "+y);g.isResizing=!1;k.isLayoutBusy=!1;F(a,b,e,!0)}});var F=function(a,b,d,e){var a=b.position,b=k[d],g;switch(d){case "north":g=a.top;break;case "west":g=a.left;break;case "south":g=u.offsetHeight-a.top-h.spacing_open;break;case "east":g=u.offsetWidth-a.left- +h.spacing_open}if(e){if(f("div.ui-layout-mask").each(function(){this.parentNode.removeChild(this)}),!1===t(d,h.ondrag_end||h.ondrag))return!1}else c.each(function(){f("#"+f(this).data("layoutMaskID")).css(f(this).position()).css({width:this.offsetWidth+"px",height:this.offsetHeight+"px"})});za(d,g-u["inset"+b.side])}})},wa=function(a,b,c){if(q[a]){var d=q[a],e=N[a],h=w[a],g=B[a],i=m[a].paneClass,n=i+"-"+a,i=[i,i+"-open",i+"-closed",i+"-sliding",n,n+"-open",n+"-closed",n+"-sliding"];f.merge(i,sa(d, +!0));d&&d.length&&(b&&!d.data("layoutContainer")&&(!e||!e.length||!e.data("layoutContainer"))?d.remove():(d.removeClass(i.join(" ")).removeData("layoutParent").removeData("layoutRole").removeData("layoutEdge").removeData("autoHidden").unbind("."+v),d.data("layoutContainer")||d.css(d.data("layoutCSS")).removeData("layoutCSS"),e&&e.length&&!e.data("layoutContainer")&&e.css(e.data("layoutCSS")).removeData("layoutCSS")));g&&g.length&&g.remove();h&&h.length&&h.remove();q[a]=N[a]=w[a]=B[a]=!1;c||(ea(), +l[a]={})}},la=function(a,b){var c=m[a],d=l[a],e=q[a],f=w[a];if(e&&!d.isHidden&&!(l.initialized&&!1===t(a,c.onhide_start)))if(d.isSliding=!1,f&&f.hide(),!l.initialized||d.isClosed){if(d.isClosed=!0,d.isHidden=!0,d.isVisible=!1,e.hide(),W(k[a].dir=="horz"?"all":"center"),l.initialized||c.triggerEventsOnLoad)t(a,c.onhide_end||c.onhide)}else d.isHiding=!0,J(a,!1,b)},ha=function(a,b,c,d){var e=l[a];if(q[a]&&e.isHidden&&!1!==t(a,m[a].onshow_start))e.isSliding=!1,e.isShowing=!0,b===!1?J(a,!0):M(a,!1,c,d)}, +ca=function(a,b){I(a)||(a.stopImmediatePropagation(),a=f(this).data("layoutEdge"));var c=l[I(a)?f.trim(a):a==void 0||a==null?"":a];c.isHidden?ha(a):c.isClosed?M(a,!!b):J(a)},$a=function(a){var b=l[a];q[a].hide();b.isClosed=!0;b.isVisible=!1},J=function(a,b,c,d){function e(){if(i.isClosed){ba(a,!0);var b=k.altSide[a];l[b].noRoom&&(Q(b),V(b));if(!d&&(l.initialized||g.triggerEventsOnLoad))n||t(a,g.onclose_end||g.onclose),n&&t(a,g.onshow_end||g.onshow),j&&t(a,g.onhide_end||g.onhide)}Ha(a)}if(l.initialized){var f= +q[a],g=m[a],i=l[a],c=!c&&!i.isClosed&&g.fxName_close!="none",n=i.isShowing,j=i.isHiding;delete i.isShowing;delete i.isHiding;if(f&&(g.closable||n||j)&&(b||!i.isClosed||n))if(k.isLayoutBusy)Ga("close",a,b);else if(n||!1!==t(a,g.onclose_start)){k[a].isMoving=!0;k.isLayoutBusy=!0;i.isClosed=!0;i.isVisible=!1;if(j)i.isHidden=!0;else if(n)i.isHidden=!1;i.isSliding?ka(a,!1):W(k[a].dir=="horz"?"all":"center",!1);ya(a);c?(oa(a,!0),f.hide(g.fxName_close,g.fxSettings_close,g.fxSpeed_close,function(){oa(a,!1); +e()})):(f.hide(),e())}}else $a(a)},ya=function(a){var b=w[a],c=B[a],d=m[a],e=k[a].side.toLowerCase(),h=d.resizerClass,g=d.togglerClass,i="-"+a;b.css(e,u["inset"+k[a].side]).removeClass(h+"-open "+h+i+"-open").removeClass(h+"-sliding "+h+i+"-sliding").addClass(h+"-closed "+h+i+"-closed").unbind("dblclick."+v);d.resizable&&typeof f.fn.draggable=="function"&&b.draggable("disable").removeClass("ui-state-disabled").css("cursor","default").attr("title","");c&&(c.removeClass(g+"-open "+g+i+"-open").addClass(g+ +"-closed "+g+i+"-closed").attr("title",d.togglerTip_closed),c.children(".content-open").hide(),c.children(".content-closed").css("display","block"));S(a,!1);l.initialized&&ja("all")},M=function(a,b,c,d){function e(){i.isVisible&&(Ja(a),i.isSliding||W(k[a].dir=="vert"?"center":"all",!1),xa(a));Ha(a)}var f=q[a],g=m[a],i=l[a],c=!c&&i.isClosed&&g.fxName_open!="none",n=i.isShowing;delete i.isShowing;if(f&&(g.resizable||g.closable||n)&&(!i.isVisible||i.isSliding))if(i.isHidden&&!n)ha(a,!0);else if(k.isLayoutBusy)Ga("open", +a,b);else if(Q(a,b),!1!==t(a,g.onopen_start))if(i.minSize>i.maxSize)S(a,!1),!d&&g.noRoomToOpenTip&&alert(g.noRoomToOpenTip);else{k[a].isMoving=!0;k.isLayoutBusy=!0;b?ka(a,!0):i.isSliding?ka(a,!1):g.slidable&&ba(a,!1);i.noRoom=!1;V(a);i.isVisible=!0;i.isClosed=!1;if(n)i.isHidden=!1;c?(oa(a,!0),f.show(g.fxName_open,g.fxSettings_open,g.fxSpeed_open,function(){oa(a,!1);e()})):(f.show(),e())}},xa=function(a,b){var c=q[a],d=w[a],e=B[a],h=m[a],g=l[a],i=k[a].side.toLowerCase(),n=h.resizerClass,j=h.togglerClass, +A="-"+a;d.css(i,u["inset"+k[a].side]+P(a)).removeClass(n+"-closed "+n+A+"-closed").addClass(n+"-open "+n+A+"-open");g.isSliding?d.addClass(n+"-sliding "+n+A+"-sliding"):d.removeClass(n+"-sliding "+n+A+"-sliding");h.resizerDblClickToggle&&d.bind("dblclick",ca);R(0,d);h.resizable&&typeof f.fn.draggable=="function"?d.draggable("enable").css("cursor",h.resizerCursor).attr("title",h.resizerTip):g.isSliding||d.css("cursor","default");e&&(e.removeClass(j+"-closed "+j+A+"-closed").addClass(j+"-open "+j+A+ +"-open").attr("title",h.togglerTip_open),R(0,e),e.children(".content-closed").hide(),e.children(".content-open").css("display","block"));S(a,!g.isSliding);f.extend(g,$(c));l.initialized&&(ja("all"),fa(a,!0));if(!b&&(l.initialized||h.triggerEventsOnLoad)&&c.is(":visible"))t(a,h.onopen_end||h.onopen),g.isShowing&&t(a,h.onshow_end||h.onshow),l.initialized&&(t(a,h.onresize_end||h.onresize),aa(a))},Sa=function(a){function b(){e.isClosed?k[d].isMoving||M(d,!0):ka(d,!0)}var c=I(a)?null:a,d=c?f(this).data("layoutEdge"): +a,e=l[d],a=m[d].slideDelay_open;c&&c.stopImmediatePropagation();e.isClosed&&c&&c.type=="mouseenter"&&a>0?E.set(d+"_openSlider",b,a):b()},Aa=function(a){function b(){e.isClosed?ka(d,!1):k[d].isMoving||J(d)}var c=I(a)?null:a,d=c?f(this).data("layoutEdge"):a,a=m[d],e=l[d],h=k[d].isMoving?1E3:300;if(!e.isClosed&&!e.isResizing)if(a.slideTrigger_close=="click")b();else if(!a.preventQuickSlideClose||!k.isLayoutBusy)if(!a.preventPrematureSlideClose||!c||!f.layout.isMouseOverElem(c,q[d]))c?E.set(d+"_closeSlider", +b,y(a.slideDelay_close,h)):b()},oa=function(a,b){var c=q[a];if(b)c.css({zIndex:k.zIndex.pane_animate}),a=="south"?c.css({top:u.insetTop+u.innerHeight-c.outerHeight()}):a=="east"&&c.css({left:u.insetLeft+u.innerWidth-c.outerWidth()});else{c.css({zIndex:l[a].isSliding?k.zIndex.pane_sliding:k.zIndex.pane_normal});a=="south"?c.css({top:"auto"}):a=="east"&&c.css({left:"auto"});var d=m[a];l.browser.msie&&d.fxOpacityFix&&d.fxName_open!="slide"&&c.css("filter")&&c.css("opacity")==1&&c[0].style.removeAttribute("filter")}}, +ba=function(a,b){var c=m[a],d=w[a],e=c.slideTrigger_open.toLowerCase();if(d&&(!b||c.slidable)){if(e.match(/mouseover/))e=c.slideTrigger_open="mouseenter";else if(!e.match(/click|dblclick|mouseenter/))e=c.slideTrigger_open="click";d[b?"bind":"unbind"](e+"."+v,Sa).css("cursor",b?c.sliderCursor:"default").attr("title",b?c.sliderTip:"")}},ka=function(a,b){function c(b){E.clear(a+"_closeSlider");b.stopPropagation()}var d=m[a],e=l[a],f=k.zIndex,g=d.slideTrigger_close.toLowerCase(),i=b?"bind":"unbind",n= +q[a],j=w[a];e.isSliding=b;E.clear(a+"_closeSlider");b&&ba(a,!1);n.css("zIndex",b?f.pane_sliding:f.pane_normal);j.css("zIndex",b?f.pane_sliding:f.resizer_normal);if(!g.match(/click|mouseleave/))g=d.slideTrigger_close="mouseleave";j[i](g,Aa);g=="mouseleave"&&(n[i]("mouseleave."+v,Aa),j[i]("mouseenter."+v,c),n[i]("mouseenter."+v,c));b?g=="click"&&!d.resizable&&(j.css("cursor",b?d.sliderCursor:"default"),j.attr("title",b?d.togglerTip_open:"")):E.clear(a+"_closeSlider")},V=function(a,b,c,d){var b=m[a], +e=l[a],f=k[a],g=q[a],i=w[a],n=f.dir=="vert",j=!1;if(a=="center"||n&&e.noVerticalRoom)if((j=e.maxHeight>0)&&e.noRoom){g.show();i&&i.show();e.isVisible=!0;e.noRoom=!1;if(n)e.noVerticalRoom=!1;Ja(a)}else if(!j&&!e.noRoom)g.hide(),i&&i.hide(),e.isVisible=!1,e.noRoom=!0;if(a!="center")if(e.minSize<=e.maxSize){if(e.size>e.maxSize?Y(a,e.maxSize,c,d):e.size +0&&k.height>0;if(!n&&!l.initialized&&h.minWidth>0){var j=h.minWidth-g.outerWidth,o=m.east.minSize||0,p=m.west.minSize||0,r=l.east.size,w=l.west.size,v=r,x=w;j>0&&l.east.isVisible&&r>o&&(v=y(r-o,r-j),j-=r-v);j>0&&l.west.isVisible&&w>p&&(x=y(w-p,w-j),j-=w-x);if(j==0){r!=o&&Y("east",v,!0);w!=p&&Y("west",x,!0);W("center",b,c);return}}}else{g.isVisible&&!g.noVerticalRoom&&f.extend(g,$(i),ma(e));if(!c&&!g.noVerticalRoom&&n.height==g.outerHeight)return!0;k.top=n.top;k.bottom=n.bottom;k.height=L(e,n.height); +g.maxHeight=y(0,k.height);n=g.maxHeight>0;if(!n)g.noVerticalRoom=!0}n?(!b&&l.initialized&&t(e,h.onresize_start),i.css(k),g.noRoom&&!g.isClosed&&!g.isHidden&&V(e),g.isVisible&&(f.extend(g,$(i)),l.initialized&&fa(e))):!g.noRoom&&g.isVisible&&V(e);if(!g.isVisible)return!0;if(e=="center")g=l.browser,g=g.isIE6||g.msie&&!g.boxModel,q.north&&(g||l.north.tagName=="IFRAME")&&q.north.css("width",K(q.north,u.innerWidth)),q.south&&(g||l.south.tagName=="IFRAME")&&q.south.css("width",K(q.south,u.innerWidth));!b&& +l.initialized&&(t(e,h.onresize_end||h.onresize),aa(e))}})},ea=function(){f.extend(l.container,$(G));if(u.outerHeight){if(!1===t(null,m.onresizeall_start))return!1;var a,b,c;f.each(["south","north","east","west"],function(a,e){q[e]&&(c=l[e],b=m[e],b.autoResize&&c.size!=b.size?Y(e,b.size,!0,!0):(Q(e),V(e,!1,!0,!0)))});W("all",!0,!0);ja("all");b=m;f.each(k.allPanes.split(","),function(c,e){if((a=q[e])&&l[e].isVisible)t(e,b[e].onresize_end||b[e].onresize),aa(e)});t(null,b.onresizeall_end||b.onresizeall)}}, +aa=function(a){var b=q[a],c=N[a];m[a].resizeNestedLayout&&(b.data("layoutContainer")?b.layout().resizeAll():c&&c.data("layoutContainer")&&c.layout().resizeAll())},fa=function(a,b){if(!a||a=="all")a=k.allPanes;f.each(a.split(","),function(a,d){function e(a){return y(j.css.paddingBottom,parseInt(a.css("marginBottom"),10)||0)}function f(){var a=m[d].contentIgnoreSelector,a=i.nextAll().not(a||":lt(0)"),b=a.filter(":visible"),c=b.filter(":last");o={top:i[0].offsetTop,height:i.outerHeight(),numFooters:a.length, +hiddenFooters:a.length-b.length,spaceBelow:0};o.spaceAbove=o.top;o.bottom=o.top+o.height;o.spaceBelow=c.length?c[0].offsetTop+c.outerHeight()-o.bottom+e(c):e(i)}var g=q[d],i=N[d],n=m[d],j=l[d],o=j.content;if(!g||!i||!g.is(":visible"))return!0;if(!1!==t(null,n.onsizecontent_start)){if(!k.isLayoutBusy||o.top==void 0||b||n.resizeContentWhileDragging)f(),o.hiddenFooters>0&&g.css("overflow")=="hidden"&&(g.css("overflow","visible"),f(),g.css("overflow","hidden"));g=j.innerHeight-(o.spaceAbove-j.css.paddingTop)- +(o.spaceBelow-j.css.paddingBottom);if(!i.is(":visible")||o.height!=g)Ua(i,g,!0),o.height=g;l.initialized&&(t(d,n.onsizecontent_end||n.onsizecontent),aa(d))}})},ja=function(a){if(!a||a=="all")a=k.borderPanes;f.each(a.split(","),function(a,c){var d=m[c],e=l[c],h=q[c],g=w[c],i=B[c],j;if(h&&g){var o=k[c].dir,p=e.isClosed?"_closed":"_open",r=d["spacing"+p],t=d["togglerAlign"+p],p=d["togglerLength"+p],v;if(r==0)g.hide();else{!e.noRoom&&!e.isHidden&&g.show();o=="horz"?(v=h.outerWidth(),e.resizerLength=v, +g.css({width:y(1,K(g,v)),height:y(0,L(g,r)),left:Z(h,"left")})):(v=h.outerHeight(),e.resizerLength=v,g.css({height:y(1,L(g,v)),width:y(0,K(g,r)),top:u.insetTop+P("north",!0)}));R(d,g);if(i){if(p==0||e.isSliding&&d.hideTogglerOnSlide){i.hide();return}else i.show();if(!(p>0)||p=="100%"||p>v)p=v,t=0;else if(I(t))switch(t){case "top":case "left":t=0;break;case "bottom":case "right":t=v-p;break;default:t=Math.floor((v-p)/2)}else h=parseInt(t,10),t=t>=0?h:v-p+h;if(o=="horz"){var x=K(i,p);i.css({width:y(0, +x),height:y(1,L(i,r)),left:t,top:0});i.children(".content").each(function(){j=f(this);j.css("marginLeft",Math.floor((x-j.outerWidth())/2))})}else{var z=L(i,p);i.css({height:y(0,z),width:y(1,K(i,r)),top:t,left:0});i.children(".content").each(function(){j=f(this);j.css("marginTop",Math.floor((z-j.outerHeight())/2))})}R(0,i)}if(!l.initialized&&(d.initHidden||e.noRoom))g.hide(),i&&i.hide()}}})},Ra=function(a){var b=B[a],c=m[a];if(b)c.closable=!0,b.bind("click."+v,function(b){b.stopPropagation();ca(a)}).bind("mouseenter."+ +v,ta).bind("mouseleave."+v,R).css("visibility","visible").css("cursor","pointer").attr("title",l[a].isClosed?c.togglerTip_closed:c.togglerTip_open).show()},G=f(this).eq(0);if(!G.length)return null;if(G.data("layoutContainer")&&G.data("layout"))return G.data("layout");var q={},N={},w={},B={},u=l.container,v=l.id,da={options:m,state:l,container:G,panes:q,contents:N,resizers:w,togglers:B,toggle:ca,hide:la,show:ha,open:M,close:J,slideOpen:Sa,slideClose:Aa,slideToggle:function(a){ca(a,!0)},initContent:Qa, +sizeContent:fa,sizePane:za,swapPanes:function(a,b){function c(a){var b=q[a],c=N[a];return!b?!1:{pane:a,P:b?b[0]:!1,C:c?c[0]:!1,state:f.extend({},l[a]),options:f.extend({},m[a])}}function d(a,b){if(a){var c=a.P,d=a.C,e=a.pane,h=k[b],j=h.side.toLowerCase(),o="inset"+h.side,p=f.extend({},l[b]),r=m[b],t={resizerCursor:r.resizerCursor};f.each("fxName,fxSpeed,fxSettings".split(","),function(a,b){t[b]=r[b];t[b+"_open"]=r[b+"_open"];t[b+"_close"]=r[b+"_close"]});q[b]=f(c).data("layoutEdge",b).css(k.hidden).css(h.cssReq); +N[b]=d?f(d):!1;m[b]=f.extend({},a.options,t);l[b]=f.extend({},a.state);c.className=c.className.replace(RegExp(r.paneClass+"-"+e,"g"),r.paneClass+"-"+b);va(b);h.dir!=k[e].dir?(c=g[b]||0,Q(b),c=y(c,l[b].minSize),za(b,c,!0)):w[b].css(j,u[o]+(l[b].isVisible?P(b):0));a.state.isVisible&&!p.isVisible?xa(b,!0):(ya(b),ba(b,!0));a=null}}l[a].edge=b;l[b].edge=a;var e=!1;!1===t(a,m[a].onswap_start)&&(e=!0);!e&&!1===t(b,m[b].onswap_start)&&(e=!0);if(e)l[a].edge=a,l[b].edge=b;else{var e=c(a),h=c(b),g={};g[a]=e? +e.state.size:0;g[b]=h?h.state.size:0;q[a]=!1;q[b]=!1;l[a]={};l[b]={};B[a]&&B[a].remove();B[b]&&B[b].remove();w[a]&&w[a].remove();w[b]&&w[b].remove();w[a]=w[b]=B[a]=B[b]=!1;d(e,b);d(h,a);e=h=g=null;q[a]&&q[a].css(k.visible);q[b]&&q[b].css(k.visible);ea();t(a,m[a].onswap_end||m[a].onswap);t(b,m[b].onswap_end||m[b].onswap)}},resizeAll:ea,destroy:function(){f(window).unbind("."+v);f(document).unbind("."+v);f.each(k.allPanes.split(","),function(a,c){wa(c,!1,!0)});var a=G.removeData("layout").removeData("layoutContainer").removeClass(m.containerClass); +!a.data("layoutEdge")&&a.data("layoutCSS")&&a.css(a.data("layoutCSS")).removeData("layoutCSS");u.tagName=="BODY"&&(a=f("html")).data("layoutCSS")&&a.css(a.data("layoutCSS")).removeData("layoutCSS");Ma()},addPane:Pa,removePane:wa,setSizeLimits:Q,bindButton:C,addToggleBtn:H,addOpenBtn:x,addCloseBtn:z,addPinBtn:Ba,allowOverflow:p,resetOverflow:r,encodeJSON:Da,decodeJSON:Ca,getState:qa,getCookie:X,saveCookie:pa,deleteCookie:function(){pa("",{expires:-1})},loadCookie:Ea,loadState:Fa,cssWidth:K,cssHeight:L, +enableClosable:Ra,disableClosable:function(a,b){var c=B[a];if(c)m[a].closable=!1,l[a].isClosed&&M(a,!1,!0),c.unbind("."+v).css("visibility",b?"hidden":"visible").css("cursor","default").attr("title","")},enableSlidable:function(a){var b=w[a];if(b&&b.data("draggable"))m[a].slidable=!0,s.isClosed&&ba(a,!0)},disableSlidable:function(a){var b=w[a];if(b)m[a].slidable=!1,l[a].isSliding?J(a,!1,!0):(ba(a,!1),b.css("cursor","default").attr("title",""),R(null,b[0]))},enableResizable:function(a){var b=w[a], +c=m[a];if(b&&b.data("draggable"))c.resizable=!0,b.draggable("enable").bind("mouseenter."+v,Ka).bind("mouseleave."+v,ua),l[a].isClosed||b.css("cursor",c.resizerCursor).attr("title",c.resizerTip)},disableResizable:function(a){var b=w[a];if(b&&b.data("draggable"))m[a].resizable=!1,b.draggable("disable").unbind("."+v).css("cursor","default").attr("title",""),R(null,b[0])}};(function(){Wa();var a=m;if(!1===t(null,a.onload_start))return!1;if(!Oa("center").length)return alert(D.errCenterPaneMissing),null; +a.useStateCookie&&a.cookie.autoLoad&&Ea();l.browser={mozilla:f.browser.mozilla,webkit:f.browser.webkit||f.browser.safari,msie:f.browser.msie,isIE6:f.browser.msie&&f.browser.version==6,boxModel:f.support.boxModel};var b=G,c=u.tagName=b.attr("tagName"),d=c=="BODY",e={};u.selector=b.selector.split(".slice")[0];u.ref=c+"/"+u.selector;b.data("layout",da).data("layoutContainer",v).addClass(m.containerClass);b.data("layoutCSS")||(d?(e=f.extend(na(b,"position,margin,padding,border"),{height:b.css("height"), +overflow:b.css("overflow"),overflowX:b.css("overflowX"),overflowY:b.css("overflowY")}),c=f("html"),c.data("layoutCSS",{height:"auto",overflow:c.css("overflow"),overflowX:c.css("overflowX"),overflowY:c.css("overflowY")})):e=na(b,"position,margin,padding,border,top,bottom,left,right,width,height,overflow,overflowX,overflowY"),b.data("layoutCSS",e));try{if(d)f("html").css({height:"100%",overflow:"hidden",overflowX:"hidden",overflowY:"hidden"}),f("body").css({position:"relative",height:"100%",overflow:"hidden", +overflowX:"hidden",overflowY:"hidden",margin:0,padding:0,border:"none"});else{var e={overflow:"hidden"},h=b.css("position");b.css("height");if(!b.data("layoutRole")&&(!h||!h.match(/fixed|absolute|relative/)))e.position="relative";b.css(e);b.is(":visible")&&b.innerHeight()<2&&alert(D.errContainerHeight.replace(/CONTAINER/,u.ref))}}catch(g){}f.extend(l.container,$(b));Xa();fa();if(a.scrollToBookmarkOnLoad)b=self.location,b.hash&&b.replace(b.hash);Na();a.autoBindCustomButtons&&Za();a.resizeWithWindow&& +!G.data("layoutRole")&&f(window).bind("resize."+v,Va);f(window).bind("unload."+v,Ma);l.initialized=!0;t(null,a.onload_end||a.onload)})();return da}})(jQuery); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/README b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/README new file mode 100644 index 00000000..e69de29b diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/css/cite.css b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/css/cite.css new file mode 100644 index 00000000..34cfe9bf --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/css/cite.css @@ -0,0 +1,49 @@ +.aloha-cite-button { + background: url(../img/icon_cite.png) no-repeat !important; +} +.aloha-cite-block-button { + background: url(../img/blockquote.png) no-repeat !important; + border: 1px solid none !important; + border-radius: 3px 3px 3px 3px; + height: 44px !important; + width: 54px !important; +} +.aloha-cite-pressed { + border: 2px solid #3B73D7 !important; +} + +.aloha-cite-wrapper { + /* background: #efd25d; */ + /* background: rgba(0, 0, 0, 0.1); */ +} +q.aloha-cite-wrapper { + /* background: #ffd25d; */ +} +blockquote.aloha-cite-wrapper { + /* background: #dfd25d; */ +} + +/* background: none repeat scroll 0 0 rgba(0, 0, 0, 0.3); +box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 7px 0 rgba(0, 0, 0, 0.8) inset; */ + +.aloha-cite-panel-label { + padding: 5px; +} +.aloha-cite-panel-field { +} +.aloha-cite-panel-btns { + padding: 5px; +} +.aloha-cite-panel-btns button { + width: 100%; +} + +.aloha-cite-panel-field input, +.aloha-cite-panel-field textarea { + width: 190px; + padding: 5px; + color: #555; + font-family: Arial, sans-serif; + font-size: 12px; + line-height: 1em; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/blockquote.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/blockquote.png new file mode 100644 index 0000000000000000000000000000000000000000..8d4db4a0cafbd8fb6b89935efaadb4796db326ea GIT binary patch literal 1533 zcmeH`{WIGK9LK-$&=$?ATicV`(drp<8eGJv{?M3IqM8x8jCD+|p;d+>R@!DBnk{M7 zL*tI5S%TVHA#7?|!{HL*9EqnOgoww)b37&TXzAaveeT|$*L~iD1Q z006*fR4CTM0E=*^tS#I8*1yXFP!={U1ZWa}zGgXW?jdd?0HC?l!AP(L0BayJ0*8db zU_n7a2m}I)#S)3c+}vC;nVg@WPoYq#R4R=|D=I1~DJdx{E2Got6%`egm6Z$zgUMvF zSS&W1&EasWs;X*hYq?x*eSJNT$7^hCY-wp}ZEbC9YwPIf=FMF~`2vAJC=?D2 z4T(e|u~a(7>;P^Wy-( zihvG9;9|nIDhye#ZaDTwEnOacb3q?Ip5mg3xXP`$`N*kZv|4gYL5M$?(I9BUC_TtR<+lfB+Vbf{o=1UTse+&`g~seQO1vFk_uR;h)?l0 zaInHXZJGBv2*Pm*27SO4dlb&{t*XeA4}EoO!YxHkjL=|@tHJD$s?fP6*nZm#;6!>|F``7T`J4jxp&BRtsfS^J8%q!iLGKBl&a8FTGoVhx?|DW%f4C*`V z)4R;6bGl+z9Yen66yU+flW#+wr7FBq2Y9{G5W*te*hlYmmh%U%%heaU)3qK@3pog= uW*|rKI74|h&n)Znm8%!Q={l6T-&yYCtHREfcs;59_?>7ZCbTIeq3~Z|6C_#y literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/icon_cite.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/img/icon_cite.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc64146e9542cfb5bf232d243946413c4e9e4f1 GIT binary patch literal 1610 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV3x~tb`J1#c2)=|%1_J8No8QD zU~CP!pM5z%pKTcrzf+GR}4O9?JiK}KQU6w@P04YHl8Q~ZV% zQ(n$q`&^(mcb25z#hR{r@|Lv)J@e{@B!Rx#qQchktv&e=X{IS~=;%>n(D`^nj5%7>4X2ih}x zI5qXjq-Z>t=){vaEBVN(A3kD|N?uDYWtN0gZnC&$tucApTN(F?lkt2z;>5m2Z`$$g z!S8u@Rj>E$5p6xXeesRJw_6)u?%E_gOS--^ap~f`hvqw<&X&$y&CL<`uj}bXkGRxR z{!M|`OU<552%i3@l>5BVly|CSLJ>T>)_jQjp_Rks-zt7+`u-~?&fQxpc)Fob$8Pn! z;Iqfxs9y59^g3n7{;sc1$0UAEFm#TZyHCY;PM77UTLIkaY~@X_pFN7vzs^2y_nFv- zzjku0)hkl&J0$+qwMOy7KI46M@!Rt|5|`iJcRA(tV#BD{yDv}NwP<72l>Xc5-)#F< z2}^F;xNl=!7>D+jMafxSn@ju|m{oKArhjIg{9dqyyQX8EZfF1Mr0@y;+FbcFdE%z? zc&_)jskgzp|1I;j;A^qZGUJOaKWi1dl>U48wVrt>Tb$&9i^Y243ye#jaBirH(|Ij= zTi#~g_J)bpx0Bb}<|gjywhLQ*yF@Qqj&V2t>Z|k5uey5o`ICC?ip77}Rw{E{JG3y~ z2$*3w3p^r=85p>QL70(Y)*J~22FAS1kcg59UmvUF{9L`nl>DSry^7odplSvNn+hu+ zGdHy)QK2F?C$HG5!d3~a!V1U+3F|8h+i#(Mch>H3D2mX`VkM*2oZx=P7{9O-#x!EwNQn0$BtH5O<~|!|f?3Ey@Agl9H^SnvVRe4>ugB*Cr*|s<<>MD>b~6SmU=KJYrt2dK+vsDew$TT<2+4&I?}J5w z{aMXjTQ?xfqTDjHm-jR9P1Y+o2+`N^gGB+5g1^syYJ?-(dy4g40s2KduPm_!A(yUSXrhfL#Uv~!A zz!f&Z@Ll<}@9Dyijj?ca`0I8LnGBd*4{}T`k%vGJn=SHi7@$23w=fUSj#D@XGvTjb*PJ z^S<|sufO(uQMZ5b?YBt=5*_(}gqL5|{PlNV!=wXe)0!`4s5o~f6rL?Vw0?p46t-Jy ozS_JmcUC@NUGS_&eFnom##8#YJSH(a7lP8Tr>mdKI;Vst0E4f*Z~y=R literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/lib/cite-plugin.js b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/lib/cite-plugin.js new file mode 100644 index 00000000..316b07be --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/lib/cite-plugin.js @@ -0,0 +1,539 @@ +/*! +* Aloha Editor +* Author & Copyright (c) 2010 Gentics Software GmbH +* aloha-sales@gentics.com +* Licensed unter the terms of http://www.aloha-editor.com/license.html +*/ + +define([ + 'aloha', + 'aloha/jquery', + 'aloha/plugin', + 'aloha/floatingmenu', + 'format/format-plugin', + 'util/dom', + 'i18n!cite/nls/i18n', + 'i18n!aloha/nls/i18n' +], function CiteClosure (Aloha, jQuery, Plugin, FloatingMenu, Format, domUtils, i18n, i18nCore) { + + + Aloha.require( ['css!cite/css/cite.css'] ); + + var + GENTICS = window.GENTICS, + $ = jQuery, + ns = 'aloha-cite', + uid = +new Date, + animating = false; + + // namespaced classnames + var nsClasses = { + quote : nsClass('quote'), + blockquote : nsClass('blockquote'), + 'panel-label' : nsClass('panel-label'), + 'panel-field' : nsClass('panel-field'), + 'panel-btns' : nsClass('panel-btns'), + 'link-field' : nsClass('link-field'), + 'note-field' : nsClass('note-field'), + references : nsClass('references') + }; + + // ------------------------------------------------------------------------ + // Local (helper) functions + // ------------------------------------------------------------------------ + + /** + * Simple templating + * + * @param {String} str - The string containing placeholder keys in curly + * brackets + * @param {Object} obj - Associative array of replacing placeholder keys + * with corresponding values + */ + function supplant (str, obj) { + return str.replace(/\{([a-z0-9\-\_]+)\}/ig, function (str, p1, offset, s) { + var replacement = obj[p1] || str; + return (typeof replacement === 'function') ? replacement() : replacement; + }); + }; + + /** + * Wrapper to call the supplant method on a given string, taking the + * nsClasses object as the associative array containing the replacement + * pairs + * + * @param {String} str + * @return {String} + */ + function renderTemplate (str) { + return (typeof str === 'string') ? supplant(str, nsClasses) : str; + }; + + /** + * Generates a selector string with this plugins's namespace prefixed the + * each classname + * + * Usage: + * nsSel('header,', 'main,', 'foooter ul') + * will return + * ".aloha-myplugin-header, .aloha-myplugin-main, .aloha-mypluzgin-footer ul" + * + * @return {String} + */ + function nsSel () { + var strBldr = [], prx = ns; + $.each(arguments, function () { strBldr.push('.' + (this == '' ? prx : prx + '-' + this)); }); + return $.trim(strBldr.join(' ')); + }; + + /** + * Generates a string with this plugins's namespace prefixed the each + * classname + * + * Usage: + * nsClass('header', 'innerheaderdiv') + * will return + * "aloha-myplugin-header aloha-myplugin-innerheaderdiv" + * + * @return {String} + */ + function nsClass () { + var strBldr = [], prx = ns; + $.each(arguments, function () { strBldr.push(this == '' ? prx : prx + '-' + this); }); + return $.trim(strBldr.join(' ')); + }; + + /** + * Coverts hexidecimal string #00ffcc into rgb array [0, 255, 127] + * + * @param {String} hex - Hexidecimal string representing color. In the form + * #ff3344 or #f34 + * @return {Array} rgb representation of hexidecimal color + */ + function hex2rgb (hex) { + var hex = hex.replace('#', '').split(''); + + if (hex.length == 3) { + hex[5] = hex[4] = hex[2]; + hex[3] = hex[2] = hex[1]; + hex[1] = hex[0]; + } + + var rgb = []; + + for (var i = 0; i < 3; ++i) { + rgb[i] = parseInt('0x' + hex[i * 2] + hex[i * 2 + 1], 16); + } + + return rgb; + }; + + // ------------------------------------------------------------------------ + // Plugin + // ------------------------------------------------------------------------ + + return Plugin.create('cite', { + + citations: [], + referenceContainer: null, + + init: function () { + var that = this; + + // Harverst configuration options that may be defined outside of + // the plugin + if (Aloha.settings && + Aloha.settings.plugins && + Aloha.settings.plugins.cite && + Aloha.settings.plugins.cite) { + var referenceContainer = $(Aloha.settings.plugins.cite.referenceContainer); + + if (referenceContainer.length > 0) { + this.referenceContainer = referenceContainer; + } + } + + // Add the inline quote button in the floating menu, in the + // standard manner... + this.buttons = []; + this.buttons[0] = new Aloha.ui.Button({ + name : 'quote', + text : 'Quote', // that.i18n('button.' + button + '.text'), + tooltip : i18n.t('cite.button.add.quote'), // that.i18n('button.' + button + '.tooltip'), + iconClass : nsClass('button','inline-button'), + size : 'small', + toggle : true, + onclick : function() { + that.addInlineQuote(); + } + }); + FloatingMenu.addButton( + 'Aloha.continuoustext', + this.buttons[0], + i18nCore.t('floatingmenu.tab.format'), + 1 + ); + + // We brute-forcishly push our button settings into the + // multiSplitButton. The multiSplitButton will pick it up and + // render it. Nevertheless, because this button is added so late, + // it means that it will not be automatically shown when doLayout + // is called on the FloatingMenu. We therefore have to do it + // ourselves at aloha-selection-changed. + Format.multiSplitButton.items.push({ + name : 'blockquote', + text : 'Blockquote', // that.i18n('button.' + button + '.text'), + tooltip : i18n.t('cite.button.add.blockquote'), // that.i18n('button.' + button + '.tooltip'), + iconClass : nsClass('button', 'block-button'), + click : function() { + that.addBlockQuote(); + } + }); + + this.sidebar = null; + + var citePlugin = this; + + // Note that if the sidebar is not loaded, + // aloha-sidebar-initialized will not fire and this listener will + // not be called, which is what we would want if there are no + // sidebars + Aloha.ready( function (ev) { + citePlugin.sidebar = Aloha.Sidebar.right.show(); + // citePlugin.sidebar.settings.overlayPage = false; + citePlugin.sidebar.addPanel({ + id : nsClass('sidebar-panel'), + title : 'Citation', + content : '', + expanded : true, + activeOn : '.aloha-cite-wrapper', + + // Executed once, when this panel object is instantialized + onInit : function () { + var that = this; + var content = this.setContent(renderTemplate( + '
                              Link:
                              \ + ' + + (citePlugin.referenceContainer + ? '
                              Note:
                              \ +
                              ' + : '') + )).content; + + content.find('input, textarea').bind('keypress change', function () { + var content = that.content; + + citePlugin.addCiteDetails( + content.attr('data-cite-id'), + content.find(nsSel('link-field input')).val(), + content.find(nsSel('note-field textarea')).val() + ); + }); + }, + + /** + * Invoked during aloha-selection-changed, if activeOn + * function returns true for the current selection. + * Will populate panel fields with the details of the + * selected citation if they are already available. + * If no citation exists for the selected quotation, then + * one will be created for it first. + */ + onActivate: function (effective) { + var uid = effective.attr('data-cite-id'); + var index = that.getIndexOfCitation(uid); + var content = this.content; + + if (index == -1) { + index = that.citations.push({ + uid : uid, + link : null, + notes : null + }) - 1; + } + + content.attr('data-cite-id', uid); + content.find(nsSel('link-field input')).val(effective.attr('cite')); //.focus(); + content.find(nsSel('note-field textarea')).val(that.citations[index].note); + } + + }); + }); + + Aloha.bind('aloha-selection-changed', function(event, rangeObject){ + Format.multiSplitButton.showItem('blockquote'); + + var buttons = $('button' + nsSel('button')); + + $.each(that.buttons, function(index, button) { + // set to false to prevent multiple buttons being active when they should not + var statusWasSet = false; + var tagName; + var effective = rangeObject.markupEffectiveAtStart; + var i = effective.length; + + // check whether any of the effective items are citation tags + while (i--) { + tagName = effective[i].tagName.toLowerCase(); + if ('q' == tagName || 'blockquote' == tagName) { + statusWasSet = true; + break; + } + } + + buttons.filter(nsSel('block-button')).removeClass(nsClass('pressed')); + that.buttons[0].setPressed(false); + + if (statusWasSet) { + if(tagName == 'q') { + that.buttons[0].setPressed(true); + } else { + buttons.filter(nsSel('block-button')) + .addClass(nsClass('pressed')); + } + + // We've got what we came for, so return false to break the each loop + return false; + } + }); + }); + }, + + /** + * Do a binary search through all citations for a given uid. + * The bit shifting may be a *bit* of an overkill, but with big lists + * it proves to be significantly more performant + * + * @param {String} uid - uid of citation + */ + getIndexOfCitation: function (uid) { + var c = this.citations; + var max = c.length; + var min = 0; + var mid; + var cuid; + + // Infinite loop guard for debugging. + // So your tab/browser doesn't freeze up like a Christmas turkey ;-) + // var __guard = 1000; + + while (min < max /* && --__guard */) { + mid = (min + max) >> 1; // Math.floor(i) / 2 == i >> 1 == ~~(i / 2) + if ((cuid = c[mid].uid) == uid) { + return mid; + } else if (cuid > uid) { + max = mid; + } else if (cuid < uid) { + min = mid + 1; + } + } + + return -1; + }, + + addBlockQuote: function () { + var classes = [nsClass('wrapper'), nsClass(++uid)].join(' '); + var markup = $(supplant( + '
                              ', + {uid:uid, classes:classes} + )); + + // now re enable the editable + if (Aloha.activeEditable) { + jQuery(Aloha.activeEditable.obj[0]).click(); + } + + Aloha.Selection.changeMarkupOnSelection(markup); + + this.referenceContainer && this.addCiteToReferences(uid); + + if (this.sidebar) { + this.sidebar.open(); + } + // .activatePanel(nsClass('sidebar-panel'), markup); + }, + + addInlineQuote: function () { + var classes = [nsClass('wrapper'), nsClass(++uid)].join(' '); + var markup = $(supplant( + '', + {uid:uid, classes:classes} + )); + var rangeObject = Aloha.Selection.rangeObject; + var foundMarkup; + + // now re enable the editable + if (Aloha.activeEditable) { + jQuery(Aloha.activeEditable.obj[0]).click(); + } + + // check whether the markup is found in the range (at the start of the range) + foundMarkup = rangeObject.findMarkup(function() { + if (this.nodeName && markup.get(0) && + (typeof this.nodeName === 'string') && + (typeof markup.get(0).nodeName === 'string')) { + return this.nodeName.toLowerCase() == markup.get(0).nodeName.toLowerCase(); + } + + return false; + }, Aloha.activeEditable.obj); + + if (foundMarkup) { + // remove the markup + if (rangeObject.isCollapsed()) { + // when the range is collapsed, we remove exactly the one DOM element + domUtils.removeFromDOM(foundMarkup, rangeObject, true); + } else { + // the range is not collapsed, so we remove the markup from the range + domUtils.removeMarkup(rangeObject, markup, Aloha.activeEditable.obj); + } + } else { + // when the range is collapsed, extend it to a word + if (rangeObject.isCollapsed()) { + domUtils.extendToWord(rangeObject); + } + + // add the markup + domUtils.addMarkup(rangeObject, markup); + } + + // select the modified range + rangeObject.select(); + + this.referenceContainer && this.addCiteToReferences(uid); + + if (this.sidebar) { + this.sidebar.open(); + } + // .activatePanel(nsClass('sidebar-panel'), markup); + + return false; + }, + + /** + * Adds an item for the citation matching the given uid to the + * references list. If no OL list for references exist, we create one. + * This method will assume that this.referenceContainer is a jQuery + * object container into which the references list should be built. + * + * @param {String} uid - uid of citation + */ + addCiteToReferences: function (uid) { + var index = this.getIndexOfCitation(uid); + + if (index == -1) { + return; + } + + var wrapper = $('.aloha-editable-active ' + nsSel(uid)); + var note = 'cite-note-' + uid; + var ref = 'cite-ref-' + uid; + + wrapper.append( + supplant( + '[{count}]', + { + ref : ref, + note : note, + count : index + 1 + } + ) + ); + + if (this.referenceContainer.find('ol.references').length == 0) { + this.referenceContainer + .append('

                              References

                              ') + .append('
                                '); + } + + this.referenceContainer.find('ol.references').append( + supplant( + '
                              1. ^  
                              2. ', + { + ref : ref, + note : note + } + ) + ); + }, + + /** + * Responsible for updating the citation reference in memory, and in + * the references list when a user adds or changes information for a + * given citation + * + * @param {String} uid + * @param {String} link + * @param {String} note + */ + addCiteDetails: function (uid, link, note) { + this.citations[this.getIndexOfCitation(uid)] = { + uid : uid, + link : link, + note : note + }; + + if (link) { + // Update link attribute + var el = $(nsSel(uid)).attr('cite', link); + + // Highlight animation for happy user + var round = Math.round; + var from = hex2rgb('#fdff9a'); + var to = hex2rgb('#fdff9a'); + + from.push(1); + to.push(0); + + var diff = [ to[0] - from[0], + to[1] - from[1], + to[2] - from[2], + to[3] - from[3] ]; + + el.css({ + __tick: 0, + 'background-color': 'rgba(' + from.join(',') + ')', + 'box-shadow': '0 0 20px rgba(' + from.join(',') + ')' + }) + if ( !animating ) { + animating = true; + el.animate({__tick: 1}, { + duration: 500, + easing: 'linear', + step: function (val, fx) { + var rgba = [ round(from[0] + diff[0] * val), + round(from[1] + diff[1] * val), + round(from[2] + diff[2] * val), + from[3] + diff[3] * val ]; + + $(this).css({ + 'background-color': 'rgba(' + rgba.join(',') + ')', + 'box-shadow': '0 0 ' + (20 * (1 - val)) + 'px rgba(' + from.join(',') + ')' + }); + }, + complete: function() { + animating = false; + } + }); + } + } + + // Update information in references list for this citation + if (this.referenceContainer) { + $('li#cite-note-' + uid + ' span').html( + supplant( + link ? '{url}' : '', + {url:link} + ) + (note ? '. ' + note : '') + ) + } + }, + + toString: function () { + return 'aloha-citiation-plugin'; + } + + }); + +}); + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/de/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/de/i18n.js new file mode 100644 index 00000000..dd1ac753 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/de/i18n.js @@ -0,0 +1 @@ +define({ "cite.button.add.quote": "Selektion als Zitat formatieren", "cite.button.add.blockquote": "Selektion als Blockzitat formatieren" }); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/en/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/en/i18n.js new file mode 100644 index 00000000..f4efd25e --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/en/i18n.js @@ -0,0 +1 @@ +define({ "cite.button.add.quote": "Format selection as quote", "cite.button.add.blockquote": "Format selection as blockquote" }); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/i18n.js b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/i18n.js new file mode 100644 index 00000000..02e5034b --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/nls/i18n.js @@ -0,0 +1,4 @@ +define({ + "de":true, + "en":true +}); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/package.json b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/package.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/cite/package.json @@ -0,0 +1 @@ +{} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/add-icon.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/add-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9b904d139835c1126f92046dfe76ddc9f230bfbc GIT binary patch literal 11957 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≤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 Z{0~$^AM~|8(31cF002ovPDHLkV1hhn@Oc0L literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/hr.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/comments/img/hr.png new file mode 100644 index 0000000000000000000000000000000000000000..da3034d6dc71fb5a865429da135b59f2ae730ab2 GIT binary patch literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr9!3HE}Hf~b~Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JibOqK978H@B_$*zTuA))|NsB;1_ovZZhjV(C{_PFpaKR@ LS3j3^P6g5a6HS9mD+g!ZL30X%Sf-dmG}H2pAt7!-m_ zGvCQXkjo;1dus?NN9@Ykyaz!Db9^rxa_V#pf-K&fo1M9VU1IGmF8}h^hn4+qFR$Q( zVdC^pKb5U*lz+9YKBFpDw$4DT99eAQ%v`ke!GqS@uZ|p5pZ>AJ*itqIhjdfa1oO*W-BV<(FxQYccXk#Ma32RoQ$eC((gx>9;~gj%fN_{L*1w5J-B zJlm&&=Qyx~M8>G1^!<(jPfBbNmt}P>WU*Pb;8846isJ?y7_tqC|><@{Qe`-^O1gd&H5#qkBV+YWd zaQIm%#*g)+8$m>W%b=F$St9dE;M-tQiOMER=Y%E0=EL0+`Fi(EvF;6jZ{f4qY@Fmz z0s0pL;c0FB{693$xj7gW=;~w$=cfG8*`5e=R_nuKm<<;;=b$5JY&M<{YN^)CMbbdP zAyr~n;iB`Afw^oKG&bZ*NIIQP(^w!qCKiiLS}{e_bDdTDTFV&-L3MQV0mndxKSRu& zwHk{~>WyXAO0%f$^U;LBG-Bp7d)GegzEY~GBBqRl^;oS|`$(^Xcl%V|*0}QfEohgt zJR@BqE4~rku23k*<+aq?Tbft`NJ^&QS-w7*euO)@V1;mpY<1!s6od~2qM7o&yZZx} z#^XJkMK$%Ob5R6O7Z|@5YHhMJ6I*lg(2vqcK1|Oh7iB?^CwU=}D`pAdj7IMOPS=!F zj|Ex`6;n|10UZPQ(4P2|JNqFTcbrJnIGs-W2;NW00Nc_*Qa%^~*iErS&rLtaw zfdq0r?la>C*eR{h$d#q@JZ|=s!)$jsEk4R7gx2pHm>E0DsmL%yQcI;m@TBiiM;C8JV* zwi|kTdqvke$?t!=spV~m;VIR0B3NPBR3H>;`Nq0~5Y1NAny|w3HV({9K?u%!Nt5-~ z&c!GSc}Wb}nO1H;j1IvGchn_NAPNohmg)0~m7}nWLx84x$KwLZK>*6pL}#O8V`Qor zg&%Yrg`pP#xa)N(X(%nSg$!BJ)qywBP~&~DTrOIOXVGNXG<%tT-j?0*kijy*;C&|{ zAEjj}kS9V?OAXAMYkc*-$F544W%Gg~<&`HNsH6YT?wlO zq!EJz>?~N80MmZ%f4y+PL26_8k|5L!&=|$QRj}?&qppHhqGEIwEL{jqMKVM7EoF#{ z%E`hMhRpoRylUtvh|Ba3;`UO}$ZAk>%q2jda0y6_C8|||M&1FXsn0^78+rh2i!-zr znvVfc;@k>&YYQ+G2ZSTgdpLkZ-PneMUZ?`truNJUXg&7hgh}+vd}xJQfon3Hdj=!h zfCfr8(V%I9i(-Ss5E!k*yy submit comment | + +(function (window, undefined) { + + + + var jQuery = window.alohaQuery || window.jQuery, + $ = jQuery, + GENTICS = window.GENTICS, + Aloha = window.Aloha; + + $.extend($.easing, { + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + } + }); + + var dom_util = GENTICS.Utils.Dom, + clss = 'aloha-comments', + uid = +(new Date), + add_box = $( + '
                                ' + + '
                                ' + + '

                                Comment:

                                ' + + '' + + '
                                ' + + '' + + '
                                ' + + '
                                  ' + + '' + + '' + + '
                                  ' + + '
                                  ' + + '
                                  ' + + '
                                  ' + + '
                                  ' + + '
                                  ' + ), + view_box = $( + '
                                  ' + + '
                                  ' + + '

                                  Comment:

                                  ' + + '' + + '
                                    ' + + '' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + ), + current_comment, + comments_hash = {}; + + Aloha.Comments = new (Aloha.Plugin.extend({ + + user : null, + comments : {}, + colors : { + 'Golden Yellow' : '#fc0', + 'Blood Red' : '#c33', + 'Sky Blue' : '#9cf', + 'Grass Green' : '#9c0' + }, + isModalOpen : false, + isRevealing : false, + bar : null, + isBarOpen : false, + + _constructor: function () { + this._super('comments'); + }, + + init: function () { + var that = this, + ul = add_box.find('.' + clss + '-colors'); + + $('body').append(add_box) + .mousedown(function () { + that.bodyClicked.apply(that, arguments); + }) + .mouseup(function () { + //console.log(Aloha.Selection); + }); + + $.each(this.colors, function (k, v) { + ul.append( + $('
                                  • ') + .click(function () {that.setColor(k);}) + ); + }); + + add_box.find('.' + clss + '-submit').click(function () { + that.submit(); + }); + + add_box.find('.' + clss + '-cancel').click(function () { + that.cancelAdd(); + }); + + this.preloadImages(); + this.initBtns(); + this.createBar(); + }, + + initBtns: function () { + var that = this, + add_btn = new Aloha.ui.Button({ + iconClass: 'aloha-button aloha-comments-toolbar-btn aloha-comments-btn-add', + onclick: function () { + if (!that.isModalOpen) { + that.addComment.apply(that, arguments); + } + }, + tooltip: 'Add comments to the selected range' + }), + reveal_btn = new Aloha.ui.Button({ + iconClass: 'aloha-button aloha-comments-toolbar-btn aloha-comments-btn-reveal', + onclick: function () { + if (!that.isModalOpen && !that.isBarOpen) { + that.revealComments.apply(that, arguments); + } + }, + tooltip: 'Show all comments on document' + }); + + Aloha.FloatingMenu.addButton( + 'Aloha.continuoustext', + add_btn, 'Comments', 1 + ); + + Aloha.FloatingMenu.addButton( + 'Aloha.continuoustext', + reveal_btn, 'Comments', 1 + ); + }, + + cancelAdd: function () { + //console.log(current_comment); + this.closeModal(); + this.removeHighlight(); + }, + + createBar: function () { + var that = this, + bar = this.bar = $( + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '
                                    ' + + '

                                    ' + + 'Comments:' + + '

                                    ' + + '
                                      ' + + '
                                      ' + + '
                                      ' + + '
                                      ' + + '
                                      ' + ).click(function () { + that.barClicked.apply(that, arguments); + }); + + $('body').append(bar); + + $(window).resize(function () { + that.setBarScrolling(); + }); + + this.bar.find('.' + clss + '-bar-toggle') + .click(function () { + if (that.isBarOpen) { + $(this).removeClass(clss + '-bar-toggle-opened'); + that.closeBar(); + } else { + $(this).addClass(clss + '-bar-toggle-opened'); + that.showBar(); + } + + + }); + + this.setBarScrolling(); + }, + + barClicked: function (event) { + var src = $(event.target), + li = src; + + if (!src[0].tagName != 'LI') { + li = li.parents('li'); + } + + if (li.length > 0) { + this.insertReplyTools(li.first()); + } + }, + + getGravatar: function (email, size) { + // MD5 (Message-Digest Algorithm) by WebToolkit + // http://www.webtoolkit.info/javascript-md5.html + var MD5 = function(s){function L(k,d){return(k<>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/\r\n/g,"\n");var d="";for(var F=0;F127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P'); + + dom_util.addMarkup(range, wrapper); + + // if the wrapper element does not exist, it means that there + // was nothing in the selection to wrap around, indicating an + // empty selection + if ($('.' + id).length == 0) { + // TODO: notify user + return; + } + + dom_util.doCleanup({'merge' : true, 'removeempty' : true}, range); + + var comment = current_comment = this.comments[id] = { + id : id, + timestamp : null, + email : null, + comment : null, + mom : null, + kids : [], + color : this.colors['Golden Yellow'], + elements : $('.' + id), + commonAncestor: $(range.getCommonAncestorContainer()) + }; + + comments_hash[id] = this.comments[id]; + + this.highlight(comment); + this.openModal(comment); + + $('.aloha-floatingmenu').hide(); + + comment.elements.click(function () { + that.commentClicked(comment); + }).hover( + function () {that.hover(comment, true);}, + function () {that.hover(comment, false);} + ); + }, + + // Toogle marking of commented text on and off + revealComments: function () { + if (this.isRevealing) { + $('.' + clss + '-active') + .removeClass(clss + '-active') + .css('background-color', ''); + } else { + $.each(this.comments, function (id, comment) { + comment.elements + .addClass(clss + '-active') + .css('background-color', comment.color); + }); + } + + this.isRevealing = !this.isRevealing; + }, + + openModal: function (comment) { + var that = this, + el = comment.elements.first(), + pos = el.offset(); + + add_box + .show() + .css('height', 'auto') + .find('input').val(this.user); + + var scroll_to, + content = add_box.find('.' + clss + '-content'), + input = add_box.find('input.' + clss + '-user').removeClass(clss + '-error'), + textarea = add_box.find('textarea').removeClass(clss + '-error').val(''), + h = content.height(), + ah = 30, + top = pos.top - (add_box.outerHeight(true) + ah); + + if (top <= 0) { + scroll_to = pos.top - ah; + el = comment.elements.last(); + pos = el.last().offset(); + top = pos.top + el.height() + ah; + add_box.addClass(clss + '-point-from-bottom'); + } else { + add_box.removeClass(clss + '-point-from-bottom'); + scroll_to = top - ah; + } + + add_box.css({ + left : pos.left + (el.width() / 2) - (add_box.outerWidth(true) / 2), + top : top, + marginTop : h, + opacity : 0 + }).animate({ + marginTop : 0, + opacity : 1 + }, 800, 'easeOutElastic'); + + $('body').animate({ + scrollTop: scroll_to + }, 1000, 'easeOutExpo'); + + if (this.user == '' || !this.user) { + input.select(); + } else { + input.val(this.user); + textarea.focus(); + } + + content + .css('height', 0) + .animate({height: h}, 800, 'easeOutElastic'); + + this.isModalOpen = true; + }, + + closeModal: function () { + /* + var content = add_box.find('.' + clss + '-content'), + h = content.height(); + content.animate({height: 0}, 250, 'linear', function () { + $(this).parent().hide(); + }); + + add_box.animate({ + 'margin-top': h + }, 250, 'linear'); + */ + + $('.aloha-floatingmenu').show(); + add_box.fadeOut(250); + this.isModalOpen = false; + }, + + highlight: function (comment) { + comment.elements + .css('background-color', comment.color) + .addClass(clss + '-active') + // traverse ancestors and mark them as such + .parents().addClass(clss + '-ancestor') + // find all siblings except floatingmenu -addbox -ancestor + .siblings(':not(' + + '.' + clss + '-addbox,' + + '.' + clss + '-ancestor,' + + '.' + clss + '-bar,' + + '.aloha-floatingmenu' + + ')').addClass(clss + '-grayed'); + + this.highlightElement(comment.commonAncestor); + + $('.' + clss + '-grayed').animate({opacity: 0.25}, 250); + + $('.' + clss + '-cleanme').each(function () { + if (dom_util.isEmpty(this)) { + $(this).remove(); + } + }); + }, + + highlightElement: function (element) { + var that = this; + + element.contents().each(function () { + var el = (this.nodeType == 3) + ? $(this).wrap('').parent() + : $(this); + + if (el.hasClass(clss + '-ancestor')) { + that.highlightElement(el); + } else if (!el.hasClass(clss + '-active')) { + el.addClass(clss + '-grayed'); + } + }); + + return element; + }, + + removeHighlight: function () { + $('.' + clss + '-grayed') + .removeClass(clss + '-grayed') + .css('opacity', ''); + + $('.' + clss + '-active') + .removeClass(clss + '-active') + .css('background-color', ''); + + $('.' + clss + '-ancestor') + .removeClass(clss + '-ancestor') + + if (typeof current_comment == 'object') { + current_comment.elements.css('background-color', ''); + current_comment = undefined; + } + }, + + hover: function (comment, onenter) { + var el = comment.elements; + if (!el.hasClass(clss + '-active')) { + if (onenter) { + el.addClass(clss + '-hover') + .css('background-color', comment.color); + } else { + el.removeClass(clss + '-hover') + .css('background-color', ''); + } + } + }, + + commentClicked: function (comment) { + this.showBar(comment); + }, + + showBar: function (comment) { + var that = this, + ul = this.bar.find('ul:first').html(''); + + this.bar.animate({ + 'width': 300 + }, 250, 'easeOutExpo'); + + $('body').animate({ + marginLeft: 300 + }, 250, 'easeOutExpo'); + + if (comment) { + this.highlight(comment); + this.printThread(ul, comment); + } else { + $.each(this.comments, function () { + that.printThread(ul, this); + }); + } + + this.isBarOpen = true; + this.setBarScrolling(); + }, + + setBarScrolling: function () { + var bottom = this.bar.find('.' + clss + '-bar-bottom').position(); + + this.bar + .find('.' + clss + '-bar-inner') + .css({ + height: $(window).height(), + 'overflow-y': (bottom.top > this.bar.height()) ? 'scroll' : 'auto' + }); + + this.bar + .find('.' + clss + '-bar-shadow') + .css('height', this.bar.height()); + }, + + closeBar: function () { + this.bar.animate({ + 'width': 0 + }, 250, 'easeOutExpo'); + + $('body').animate({ + marginLeft: 0 + }, 250, 'easeOutExpo'); + + this.removeHighlight(); + this.isBarOpen = false; + }, + + printThread: function (el, comment) { + var that = this, + li = $( + '
                                    • ' + + '
                                      ' + + '' + + '
                                      ' + + '' + comment.email + ' says:' + + '
                                      ' + comment.comment + '
                                      ' + + '
                                      ' + + '
                                      ' + + '
                                      ' + + '
                                    • ' + ); + + el.append(li); + + $.each(comment.kids, function () { + var ul = $('
                                        '); + li.append(ul); + that.printThread(ul, this); + }); + }, + + // Create reply textarea + insertReplyTools: function (li) { + var that = this, + reply = li.addClass(clss + '-bar-comment-active') + .find('.aloha-comments-bar-comment>.' + clss + '-bar-reply'); + + if (reply.length == 0) { + reply = $( + '
                                        ' + + '' + + '' + + '' + + '
                                        ' + ); + li.find('>div').append(reply); + li.find('button').click(function () { + that.submitReply.call(that, reply); + }); + + var h = reply.css('height', 'auto').height(); + reply.css('height', 0) + .animate({height: h}, 250, 'easeOutExpo'); + + reply.find('input, textarea') + .css('width', reply.width() - 12); + + reply.find('input').select(); + + this.bar.scrollTop(reply.offset().top); + } + }, + + submitReply: function (reply_tool) { + var that = this, + li = reply_tool.parents('li').first(), + mom_id = li.attr('data-aloha-comment'), + mom = comments_hash[mom_id]; + + if (typeof mom == 'object') { + var id = clss + '-' + (++uid), + email = reply_tool.find('input').val().trim(), + text = reply_tool.find('textarea') + .val().trim() + .replace(/[\r\n]/g, '
                                        '), + index = mom.kids.push({ + id : id, + timestamp : (new Date()).getTime(), + email : email, + comment : text, + kids : [], + mom : mom.id, + color : mom.color, // inherit + elements : mom.elements, // inherit + commonAncestor + : mom.elements // inherit + }); + + comments_hash[id] = mom.kids[index - 1]; + + reply_tool.animate( + {height: 0}, 250, 'easeOutExpo', + function () { + $(this).remove(); + var ul = $('
                                          '); + li.append(ul); + that.printThread(ul, comments_hash[id]); + } + ); + + this.user = email; + } + }, + + setColor: function (index) { + current_comment.color = this.colors[index]; + current_comment.elements.css('background-color', current_comment.color); + add_box.find('textarea').focus(); + }, + + submit: function () { + var textarea = add_box.find('textarea'), + input = add_box.find('.' + clss + '-user'), + email = input.val().trim(), + comment = textarea.val().trim(), + errors = false, + err_clss = clss + '-error'; + + if (email == '') { + input.focus().addClass(err_clss); + errors = true; + } else { + input.removeClass(err_clss); + } + + if (comment == '') { + textarea.focus().addClass(err_clss); + errors = true; + } else { + textarea.removeClass(err_clss); + } + + comment = comment.replace(/[\r\n]/g, '
                                          '); + + if (!errors) { + $.extend(current_comment, { + email : email, + comment : comment, + timestamp : (new Date()).getTime() + }); + this.insertComment(current_comment); + this.closeModal(); + this.showBar(current_comment); + textarea.val(''); + input.val(''); + } + + this.user = email; + }, + + insertComment: function (comment) { + comments_hash[comment.id] = + this.comments[comment.id] = comment; + }, + + bodyClicked: function (event) { + var el = $(event.target); + + if (this.isModalOpen && !el.hasClass(clss + '-addbox')) { + if (el.parents('.' + clss + '-addbox').length == 0) { + this.closeModal(); + this.removeHighlight(); + } + } + + if (!this.isModalOpen) { + if (!el.hasClass(clss + '-bar')) { + if (el.parents('.' + clss + '-bar').length == 0) { + this.removeHighlight(); + } + } + } + }, + + // What's the best way to determin the img path + preloadImages: function () { + $.each([ + 'hr.png', + 'textbox.png' + ], function () {(new Image()).src = '../../plugin/comments/img/' + this;}); + } + + }))(); // Aloha.Comments + +})(window); \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/AGPL3 b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/AGPL3 new file mode 100644 index 00000000..dba13ed2 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/AGPL3 @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/LICENSE b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/LICENSE new file mode 100644 index 00000000..ea74ee95 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/LICENSE @@ -0,0 +1,25 @@ +Aloha Editor +============ + +Aloha Editor is meant to be an free and open source for all now and in future. + +We encourage continuous, selfsustainable development supported by both the open source +community and commercial stakeholders. This way both parties (community and commercial users) +profit from each other by code and financial ressources for core developement. +Therefore we adopted a dual licensing approach for Aloha Editor. + +Opensource Software License +=========================== +The Open Source version of Aloha Editor is released under the terms of AGPLv3 License. +http://www.gnu.org/licenses/agpl.html + +Commercial Software License +============================ +The commercial version of Aloha Editor allows to use, modify, copy and distrubute without +any restrictions as stated in the commerical license agreement. + +Translation License +=================== +All contributions to translations of dictionary entries apply to the Creative Commons +Attribution License V3.0 BY. By contributing transaltions you agree to the license terms. +http://creativecommons.org/licenses/by/3.0/ diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/README.md b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/README.md new file mode 100644 index 00000000..a762524f --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/README.md @@ -0,0 +1,5 @@ +Aloha Editor Plugin for handling drop of files from user's desktop +Configurable options +* max file size object +* max dropped files count +Copyright (c) 2010 Nicolas Karageuzian \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/TODO.md b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/TODO.md new file mode 100644 index 00000000..d550ee42 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/TODO.md @@ -0,0 +1,2 @@ +* More config options : file-type filter +* Configurable Uploader \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.css b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.css new file mode 100644 index 00000000..841d36f5 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.css @@ -0,0 +1,47 @@ +body { + font-family: sans-serif; +} + +body { + background-image: url("images/background.png"); +} + +#bodyContent { + font-size:0.9em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: sans-serif; + padding-bottom:0.1em; + padding-top:0.5em; +} +h1 { + border-bottom:1px solid #AAAAAA; +} + +h1 { font-size: 188%; } +h2 { font-size: 150%; } +h3 { font-size: 132%; } +h4 { font-size: 116%; } +h5 { font-size: 100%; } +h6 { font-size: 80%; } + +#main { + width: 650px; + margin-top: 40px; + margin-left: auto ; + margin-right: auto ; + padding: 70px; + background-color: white; + border-radius: 1px; + -moz-border-radius: 1px; + box-shadow: 5px 5px rgba(0,0,0,0.3); + -webkit-box-shadow: 5px 5px rgba(0,0,0,0.3); + -moz-box-shadow: 5px 5px rgba(0,0,0,0.3); +} + +a.external { + background: url(images/external-link-ltr-icon.png) no-repeat 100% 50%; + padding: 0px 13px 0px 0px; +} + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.html b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.html new file mode 100644 index 00000000..8a19bbf2 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/index.html @@ -0,0 +1,101 @@ + + + + +Aloha, Drag And Drop Files ! + + + + + + + + + + +
                                          +
                                          +
                                          +

                                          Aloha

                                          +

                                          Etymology

                                          +

                                          The word aloha derives from the Proto-Polynesian root *qalofa. It has cognates in other Polynesian languages, such as Samoan alofa +and Māori aroha, also meaning "love."

                                          +

                                          Aloha Editor is the word's most advanced browser based Editor made with aloha passion.

                                          +

                                          A folk etymology claims that it derives from a compound of the Hawaiian words alo meaning "presence", "front", "face", or "share"; and +ha, meaning "breath of life" or "essence of life." Although alo does indeed mean "presence" etc., the word for breath is spelled with a macron +or kahakō over the a (hā) whereas the word aloha does not have a long a.

                                          +

                                          Usage

                                          +

                                          Before contact with the West, the words used for greeting were welina and anoai. Today, "aloha kakahiaka" is the phrase for "good +morning." "Aloha ʻauinalā" means "good afternoon" and "aloha ahiahi" means "good evening." "Aloha kākou" is a common form of "welcome to all."

                                          +

                                          In modern Hawaiʻi, numerous businesses have aloha in their names, with more than 3 pages of listings in the Oʻahu phone book alone.

                                          +

                                          Trends

                                          +

                                          Recent trends are popularizing the term elsewhere in the United States. Popular entertainer, Broadway star and Hollywood actress Bette +Midler, born in Honolulu, uses the greeting frequently in national appearances. The word was also used frequently in the hit television drama +Hawaii Five-O. In the influential 1982 film comedy Fast Times at Ridgemont High, the eccentric teacher Mr. Hand makes use of the greeting. The +Aloha Spirit is a major concept in Lilo and Stitch, a very popular Disney series of movies and TV shows, set in Hawaiʻi. The drama series Lost, +shot in Hawaiʻi, has a thank you note at the end of the credits saying "We thank the people of Hawaiʻi and their Aloha Spirit". Aloha is a term +also used in the Nickelodeon program Rocket Power.

                                          +
                                            +
                                          • Arguably the most famous historical Hawaiian song, "Aloha ʻOe" was written by the last queen of Hawaii, Liliʻuokalani.
                                          • +
                                          • The term inspired the name of the ALOHA Protocol introduced in the 1970s by the University of Hawaii.
                                          • +
                                          • In Hawaii someone can be said to have or show aloha in the way they treat others; whether family, friend, neighbor or stranger.
                                          • +
                                          +
                                          +
                                          +
                                          + + + \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.css b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.css new file mode 100644 index 00000000..9a5a0dd1 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.css @@ -0,0 +1,189 @@ +body { + font-family: sans-serif; + background-image: url("images/background.png"); +} + +#bodyContent { + font-size:0.8em; +} + +p { + margin-bottom: 10px; +} + +h1, h2, h3, h4, h5, h6 { + font-family: sans-serif; + color: #1c94c4; + border-bottom:1px solid #AAAAAA; + padding-bottom:0.17em; + padding-top:0.5em; +} + +h1 { font-size: 188%; } +h2 { font-size: 150%; } +h3 { font-size: 132%; } +h4 { font-size: 116%; } +h5 { font-size: 100%; } +h6 { font-size: 80%; } + +#main { + width: 50%; + position: absolute; + top: 10%; + left: 25%; + padding: 30px; + background-color: white; + border-radius: 10px; + color: #444444; + -moz-border-radius: 10px; + box-shadow: 5px 5px rgba(0,0,0,0.3); + -webkit-box-shadow: 5px 5px rgba(0,0,0,0.3); + -moz-box-shadow: 5px 5px rgba(0,0,0,0.3); +} + +a.aloha { + background: url(../common/external-link-ltr-icon.png) no-repeat 100% 50%; + padding: 0px 13px 0px 0px; +} + +/* Abbreviation styling */ +abbr, acronym +{ + border-bottom: .1em dotted; + cursor: help; +} + +/* A basic table styling */ +.aloha_example table +{ + padding: 0; + margin: 0; + border-collapse: collapse; + border: 1px solid #333; + color: #000; +} + +.aloha_example table caption +{ + caption-side: bottom; + font-size: 0.8em; + font-style: italic; + text-align: right; + padding: 0.5em 0; +} + +.aloha_example table th, +.aloha_example table td +{ + border: 1px solid #666; + padding: 0.5em; + text-align: left; +} + +.aloha_example th { + background-color: #dfd; +} + +table caption +{ + caption-side: bottom; + font-size: 0.8em; + font-style: italic; + text-align: right; + padding: 0.5em 0; +} + +#main ol, ul { + list-style-position: inside; +} + +#main ol { + list-style-type: decimal; +} + +#main ul { + list-style-type: disc; +} + +/** + * basic table styles + */ +.hor-minimalist-a +{ + background: #fff; + border-collapse: collapse; + text-align: left; +} +.hor-minimalist-a th +{ + font-size: 130%; + font-weight: normal; + padding: 10px 8px; + border-bottom: 2px solid #6678b1; +} +.hor-minimalist-a td +{ + padding: 9px 8px 0px 8px; +} +.hor-minimalist-a tbody tr:hover td +{ + color: #009; +} + +.box-table-a +{ + text-align: left; + border-collapse: collapse; +} +.box-table-a th +{ + font-size: 115%; + font-weight: normal; + padding: 8px; + background: #b9c9fe; + border-top: 4px solid #aabcfe; + border-bottom: 1px solid #fff; +} +.box-table-a td +{ + padding: 8px; + background: #e8edff; + border-bottom: 1px solid #fff; + border-top: 1px solid transparent; +} +.box-table-a tr:hover td +{ + background: #d0dafd; +} + +.hor-zebra +{ + text-align: left; + border-collapse: collapse; +} +.hor-zebra th +{ + font-size: 130%; + font-weight: bold; + padding: 10px 8px; + border-bottom: 2px solid #6678b1; + +} +.hor-zebra td +{ + padding: 8px; +} +.hor-zebra tr:nth-child(2n+1) td +{ + background: #e8edff; +} + +td.bigbold { + font-size: 200%; + font-weight: bold; +} +td.redwhite { + background-color: red; + color: white; + font-weight: bold; +} diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.html b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.html new file mode 100644 index 00000000..c408ba6f --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/migration/index.html @@ -0,0 +1,321 @@ + + + + + Aloha, World! + + + + + + + + + + +
                                          +
                                          +

                                          Aloha, World!

                                          +
                                          +
                                          +

                                          + Aloha in the Hawaiian language means affection, love, peace, compassion and mercy. Since the middle of the 19th century, it also + has come to be used as an English greeting to say goodbye and hello. Currently, it is mostly used in the sense of hello; however, + it is used as the above. +

                                          +
                                          +
                                          +

                                          Etymology

                                          +

                                          + The word aloha derives from the Proto-Polynesian root *qalofa. It has cognates in other Polynesian languages, such as Samoan alofa + and Māori aroha, also meaning "love." +

                                          + + + + + +
                                          Aloha Editor supports table captions.
                                          Thisisatable
                                          withsomedummydata
                                          totestAlohatables.
                                          +

                                          + A folk etymology claims that it derives from a compound of the Hawaiian words alo meaning "presence", "front", "face", or "share"; and + ha, meaning "breath of life" or "essence of life." Although alo does indeed mean "presence" etc., the word for breath is spelled with a macron + or kahakō over the a (hā) whereas the word aloha does not have a long a. +

                                          + +

                                          Usage

                                          +

                                          + Before contact with the West, the words used for greeting were welina and anoai. Today, "aloha kakahiaka" is the phrase for "good + morning." "Aloha ʻauinalā" means "good afternoon" and "aloha ahiahi" means "good evening." "Aloha kākou" is a common form of "welcome to all." +

                                          +

                                          + In modern Hawaiʻi, numerous businesses have aloha in their names, with more than 3 pages of listings in the Oʻahu phone book alone. +

                                          + +

                                          Trends

                                          +

                                          + Recent trends are popularizing the term elsewhere in the United States. Popular entertainer, Broadway star and Hollywood actress Bette + Midler, born in Honolulu, uses the greeting frequently in national appearances. The word was also used frequently in the hit television drama + Hawaii Five-O. In the influential 1982 film comedy Fast Times at Ridgemont High, the eccentric teacher Mr. Hand makes use of the greeting. The + Aloha Spirit is a major concept in Lilo and Stitch, a very popular Disney series of movies and TV shows, set in Hawaiʻi. The drama series Lost, + shot in Hawaiʻi, has a thank you note at the end of the credits saying "We thank the people of Hawaiʻi and their Aloha Spirit". Aloha is a term + also used in the Nickelodeon program Rocket Power. +

                                          + +
                                            +
                                          • Arguably the most famous historical Hawaiian song, "Aloha ʻOe" was written by the last queen of Hawaii, Liliʻuokalani.
                                          • +
                                          • The term inspired the name of the ALOHA Protocol introduced in the 1970s by the University of Hawaii.
                                          • +
                                          • In Hawaii someone can be said to have or show aloha in the way they treat others; whether family, friend, neighbor or stranger.
                                          • +
                                          + +

                                          Placeholder

                                          +
                                          + +

                                          Inline Placeholder

                                          + + +
                                          +
                                          +
                                          + + + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/specs/DragnDropnImage.graphml b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/specs/DragnDropnImage.graphml new file mode 100644 index 00000000..58f3d76e --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/specs/DragnDropnImage.graphml @@ -0,0 +1,677 @@ + + + + + + + + + + + + + + + + + + + + + DragnDropFiles + + + + + + + + + + ImagePlugin + + + + + + + + + + UploadRepository + + + + + + + + + + target is editable ? + + + + + + + + + + file-type == image + + + + + + + + + + read Image file + + + + + + + + + + + + + + + + + + + + + + + + + + + insert image object + + + + + + + + + + Navigator drop file event + + + + + + + + + + + + + + + + + Event + +DropFilesInEditable(items) + + + + + + + + + + calculate range + + + + + + + + + + Process upload + + + + + + + + + + is upload OK + + + + + + + + + + Event + +FileUploaded(repoItem) + + + + + + + + + + do some src replace + + + + + + + + + + Copyright (c) 2010 Nicolas Karageuzian + + + + + + + + + + + for each file + + + + + + + + + + + Event + +UploadFailure(repoItem) + + + + + + + + + + repoItem: addFileUpload + + + + + + + + + + + for each file + + + + + + + + + + + Event + +DropFilesInPage(itemIds) + + + + + + + + + + trigger + + + + + + + + + + + trigger + + + + + + + + + + + schedule upload + + + + + + + + + + + Invoke + + + + + + + + + + + invoke + + + + + + + + + + + Invoke + + + + + + + + + + + Invoke + + + + + + + + + + + remove image object + + + + + + + + + + (async thread) + + + + + + + + + + + HandleResize + + + + + + + + + + + + + + + + + + + + + + + + + subscribe + + + + + + + + + + + + + subscribe + + + + + + + + + + + + + + + + + + + + + YES + + + + + + + + + + + + + YES + + + + + + + + + + + + + NO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NO + + + + + + + + + + + YES + + + + + + + + + + + + + + + + + + + + + Subscribe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/style.css b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/style.css new file mode 100644 index 00000000..841d36f5 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/style.css @@ -0,0 +1,47 @@ +body { + font-family: sans-serif; +} + +body { + background-image: url("images/background.png"); +} + +#bodyContent { + font-size:0.9em; +} + +h1, h2, h3, h4, h5, h6 { + font-family: sans-serif; + padding-bottom:0.1em; + padding-top:0.5em; +} +h1 { + border-bottom:1px solid #AAAAAA; +} + +h1 { font-size: 188%; } +h2 { font-size: 150%; } +h3 { font-size: 132%; } +h4 { font-size: 116%; } +h5 { font-size: 100%; } +h6 { font-size: 80%; } + +#main { + width: 650px; + margin-top: 40px; + margin-left: auto ; + margin-right: auto ; + padding: 70px; + background-color: white; + border-radius: 1px; + -moz-border-radius: 1px; + box-shadow: 5px 5px rgba(0,0,0,0.3); + -webkit-box-shadow: 5px 5px rgba(0,0,0,0.3); + -moz-box-shadow: 5px 5px rgba(0,0,0,0.3); +} + +a.external { + background: url(images/external-link-ltr-icon.png) no-repeat 100% 50%; + padding: 0px 13px 0px 0px; +} + diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/upload.php b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/upload.php new file mode 100644 index 00000000..475c7684 --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/demo/upload.php @@ -0,0 +1,26 @@ +writeFile($HTTP_RAW_POST_DATA); + +?> \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/en.json b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/en.json new file mode 100644 index 00000000..1e05bfde --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/en.json @@ -0,0 +1 @@ +{"floatingmenu.tab.file":"File"} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/fr.json b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/fr.json new file mode 100644 index 00000000..e1ee502b --- /dev/null +++ b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/i18n/fr.json @@ -0,0 +1 @@ +{"floatingmenu.tab.file":"Fichier"} \ No newline at end of file diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/cross.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..1514d51a3cf1b67e1c5b9ada36f1fd474e2d214a GIT binary patch literal 655 zcmV;A0&x9_P)uEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8#P)9Rl#FaScf1rbdiwsJlF($-D2a$MB1QH?*P$(@5T4@;&OA53{ z62x9;g=MzM@3B}Z6q2JnuH-? zUBh=^5nso`tIMpW;}SD*?>znX))|eYdi7(c&C5YW8_t?tIU z>Ny7&^Pebhjth`srpO|asbD=?gpU+WKXx%hg}DA%|J1=w1E3bQW2brAk)glQS%iL- z`SP4IjX^57**EKJK0N;yU_Z*GguxzUVD)Dq(FOHK%^eAtSc;pSVFoq==$r8wjtx+n z;uq8_iQsA|i!@V3bf!VptWTH>59QQ$XGs&d#Zun48g&^nWN z^4`U@k2?PS6UX#XYTlj3cBYJ6iA9-|t1JhG+#TUO+}j1X$SI>}h@{JnYgEm?zE ~NwO_yO%;SvZ5MdNYf|QNy-I*%yJaj+uTdt+qbZ z4E`Fzb8m}I&!N8OKmWEcCmrLs^Hs&3i)mt@hQVdcqghkaBs*D}tG_lKew4?rTjzIZ z9tSone1TS+TR7tu^CunG)Y7Jg#sw#)sG9C!c0I%LEzP)9;hqRf&)s$D8d5Db{TBs% zgl0~5QQ91luq4Q9tJgt4QLbaxZvAaKeCM9!oy85dg4k>TdBSVqjHub_PG=PO&J-rx z7oYTuF+kH|tG-UK+EkUhDjYx?zW?T|lx>+aOQm zzL$v$zBLo4Cj=G&tw{H}dW?tlTkS)SY4<#NS92z*EY-MMB6Ftp`R=*=*Ev7cS+X%W zMCur^FdlokL}1Y+&aasU2J4#EOuNlnb9CmqgLCGTSY!1BD42pkHY^XidQ5=>YQx%` z*%Pm9D!CkBu&tMWm(%-ejACVWGS2RX5=QOJ$1*tr7F}F+*-OA+Ly&Isg|AEuUYicA z#%IG6kPXkHt{zk2M6zK@Vu^4Q(1zE$?yY6M!^&jQ+2^E?!p7{g*|X6}vuRC3p@jk0 W117c83?+LXEZI4G$p&LV25SKE>nb+@ literal 0 HcmV?d00001 diff --git a/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/page.png b/vendor/assets/javascripts/locomotive/aloha/plugins/extra/draganddropfiles/img/page.png new file mode 100644 index 0000000000000000000000000000000000000000..03ddd799fa0a3aec561c75d4221f195db65d6eb9 GIT binary patch literal 635 zcmV->0)+jEP);68^d)m`eN0o>(5%D`Q(1;j>g@G;xlf`0VBQ`PFY?6)!N&f?*K}$p; zB!U=NBn{eB8${1}&-2_L*HuZp@ZP1@clS@cHp)4iM1ewzw59vko7eMM{e9z|%NNdX z0V;`?KKSzTCvTm5bc{L^CIKLUxc2X{i{ISz$8Sgf{q)1nXTP{`{s?9mQ$4&hPiKC- zY8q7(Y1Xu5iCf33=O4Vy(+|zQ?rW#gkKB0f%}?+6{G*qT22|DQB-73`YzA{N4W^=s zq0kQYcbtFfz zLz)H<&|z(Y4kHs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1p